@bejibun/core 0.1.41 → 0.1.43

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/CHANGELOG.md CHANGED
@@ -3,6 +3,43 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  ---
5
5
 
6
+ ## [v0.1.43](https://github.com/crenata/bejibun-core/compare/v0.1.42...v0.1.43) - 2025-10-21
7
+
8
+ ### 🩹 Fixes
9
+
10
+ ### 📖 Changes
11
+ What's New :
12
+ - Adding `maintenance:down` to turn app into maintenance mode
13
+ - Adding `maintenance:up` to turn app into live mode
14
+ - Adding maintenance middleware
15
+
16
+ ### ❤️Contributors
17
+ - Havea Crenata ([@crenata](https://github.com/crenata))
18
+ - Ghulje ([@ghulje](https://github.com/ghulje))
19
+
20
+ **Full Changelog**: https://github.com/crenata/bejibun-core/blob/master/CHANGELOG.md
21
+
22
+ ---
23
+
24
+ ## [v0.1.42](https://github.com/crenata/bejibun-core/compare/v0.1.41...v0.1.42) - 2025-10-21
25
+
26
+ ### 🩹 Fixes
27
+ - Fix controller path on router builder
28
+
29
+ ### 📖 Changes
30
+ What's New :
31
+ - Adding base exception handler
32
+ - Adding runtime exception
33
+ - Adding `server.ts` for init serve
34
+
35
+ ### ❤️Contributors
36
+ - Havea Crenata ([@crenata](https://github.com/crenata))
37
+ - Ghulje ([@ghulje](https://github.com/ghulje))
38
+
39
+ **Full Changelog**: https://github.com/crenata/bejibun-core/blob/master/CHANGELOG.md
40
+
41
+ ---
42
+
6
43
  ## [v0.1.41](https://github.com/crenata/bejibun-core/compare/v0.1.40...v0.1.41) - 2025-10-20
7
44
 
8
45
  ### 🩹 Fixes
@@ -26,7 +26,7 @@ export default class BaseModel extends Model {
26
26
  static QueryBuilder = BunQueryBuilder;
27
27
  static get namespace() {
28
28
  const filePath = fileURLToPath(import.meta.url);
29
- const rel = relative(App.rootPath(), filePath);
29
+ const rel = relative(App.Path.rootPath(), filePath);
30
30
  const withoutExt = rel.replace(/\.[tj]s$/, "");
31
31
  const namespaces = withoutExt.split(sep);
32
32
  namespaces.pop();
@@ -110,8 +110,8 @@ export default class RouterBuilder {
110
110
  if (isEmpty(controllerName) || isEmpty(methodName)) {
111
111
  throw new RouterInvalidException(`Invalid router controller definition: ${definition}.`);
112
112
  }
113
- const controllerPath = path.resolve(App.rootPath(), this.baseNamespace);
114
- const location = Bun.resolveSync(`${controllerName}.ts`, controllerPath);
113
+ const controllerPath = path.resolve(App.Path.rootPath(), this.baseNamespace);
114
+ const location = Bun.resolveSync(`./${controllerName}.ts`, controllerPath);
115
115
  let ControllerClass;
116
116
  try {
117
117
  ControllerClass = require(location).default;
@@ -1,5 +1,4 @@
1
1
  import type { Command } from "commander";
2
2
  export default class Kernel {
3
3
  static registerCommands(program: Command): void;
4
- private static commands;
5
4
  }
@@ -1,12 +1,18 @@
1
1
  import App from "@bejibun/app";
2
2
  import { defineValue, isEmpty } from "@bejibun/utils";
3
- import { readdirSync } from "fs";
4
- import path from "path";
5
3
  export default class Kernel {
6
4
  static registerCommands(program) {
7
- const commandsDirectoryCore = path.resolve(__dirname);
8
- const files = this.commands(commandsDirectoryCore)
9
- .concat(this.commands(App.commandsPath()));
5
+ const rootCommands = Array.from(new Bun.Glob("**/*.ts").scanSync({
6
+ absolute: true,
7
+ cwd: App.Path.commandsPath()
8
+ }));
9
+ const internalCommands = Array.from(new Bun.Glob("**/*").scanSync({
10
+ absolute: true,
11
+ cwd: __dirname
12
+ }));
13
+ const files = internalCommands.concat(rootCommands).filter(value => (/\.(m?js|ts)$/.test(value) &&
14
+ !value.endsWith(".d.ts") &&
15
+ !value.includes("Kernel"))).reverse();
10
16
  for (const file of files) {
11
17
  const { default: CommandClass } = require(file);
12
18
  const instance = new CommandClass();
@@ -33,22 +39,4 @@ export default class Kernel {
33
39
  });
34
40
  }
35
41
  }
36
- static commands(directory) {
37
- const entries = readdirSync(directory, {
38
- withFileTypes: true
39
- });
40
- const files = [];
41
- for (const entry of entries) {
42
- const fullPath = path.join(directory, entry.name);
43
- if (entry.isDirectory()) {
44
- files.push(...this.commands(fullPath));
45
- }
46
- else if (/\.(m?js|ts)$/.test(entry.name) &&
47
- !entry.name.endsWith(".d.ts") &&
48
- !entry.name.includes("Kernel")) {
49
- files.push(fullPath);
50
- }
51
- }
52
- return files;
53
- }
54
42
  }
@@ -1,4 +1,4 @@
1
- import App from "@bejibun/app";
1
+ import AppConfig from "@bejibun/app/config/app";
2
2
  import Logger from "@bejibun/logger";
3
3
  import { DateTime } from "luxon";
4
4
  export default class MaintenanceDownCommand {
@@ -29,7 +29,7 @@ export default class MaintenanceDownCommand {
29
29
  */
30
30
  $arguments = [];
31
31
  async handle(options, args) {
32
- await Bun.write(App.storagePath("framework/maintenance.down.json"), JSON.stringify({
32
+ await Bun.write(AppConfig.maintenance.file, JSON.stringify({
33
33
  message: "🚧 We're doing maintenance. Please check back soon.",
34
34
  status: 503,
35
35
  allows: options.allows,
@@ -0,0 +1,27 @@
1
+ export default class MaintenanceUpCommand {
2
+ /**
3
+ * The name and signature of the console command.
4
+ *
5
+ * @var $signature string
6
+ */
7
+ protected $signature: string;
8
+ /**
9
+ * The console command description.
10
+ *
11
+ * @var $description string
12
+ */
13
+ protected $description: string;
14
+ /**
15
+ * The options or optional flag of the console command.
16
+ *
17
+ * @var $options Array<Array<any>>
18
+ */
19
+ protected $options: Array<Array<any>>;
20
+ /**
21
+ * The arguments of the console command.
22
+ *
23
+ * @var $arguments Array<Array<string>>
24
+ */
25
+ protected $arguments: Array<Array<string>>;
26
+ handle(options: any, args: Array<string>): Promise<void>;
27
+ }
@@ -0,0 +1,33 @@
1
+ import AppConfig from "@bejibun/app/config/app";
2
+ import Logger from "@bejibun/logger";
3
+ export default class MaintenanceUpCommand {
4
+ /**
5
+ * The name and signature of the console command.
6
+ *
7
+ * @var $signature string
8
+ */
9
+ $signature = "maintenance:up";
10
+ /**
11
+ * The console command description.
12
+ *
13
+ * @var $description string
14
+ */
15
+ $description = "Turn app into live mode";
16
+ /**
17
+ * The options or optional flag of the console command.
18
+ *
19
+ * @var $options Array<Array<any>>
20
+ */
21
+ $options = [];
22
+ /**
23
+ * The arguments of the console command.
24
+ *
25
+ * @var $arguments Array<Array<string>>
26
+ */
27
+ $arguments = [];
28
+ async handle(options, args) {
29
+ if (await Bun.file(AppConfig.maintenance.file).exists())
30
+ await Bun.file(AppConfig.maintenance.file).delete();
31
+ Logger.setContext("APP").info("Application turned into live mode.");
32
+ }
33
+ }
@@ -25,7 +25,7 @@ const config = {
25
25
  }
26
26
  };
27
27
  export const initDatabase = () => {
28
- const configPath = App.configPath("database.ts");
28
+ const configPath = App.Path.configPath("database.ts");
29
29
  let _config;
30
30
  if (fs.existsSync(configPath))
31
31
  _config = require(configPath).default;
@@ -0,0 +1,7 @@
1
+ import { ValidationError } from "objection";
2
+ import ModelNotFoundException from "../exceptions/ModelNotFoundException";
3
+ import ValidatorException from "../exceptions/ValidatorException";
4
+ export default class ExceptionHandler {
5
+ handle(error: Bun.ErrorLike | ModelNotFoundException | ValidatorException | ValidationError): globalThis.Response;
6
+ route(request: Bun.BunRequest): globalThis.Response;
7
+ }
@@ -0,0 +1,33 @@
1
+ import Logger from "@bejibun/logger";
2
+ import { defineValue } from "@bejibun/utils";
3
+ import HttpMethodEnum from "@bejibun/utils/enums/HttpMethodEnum";
4
+ import { ValidationError } from "objection";
5
+ import ModelNotFoundException from "../exceptions/ModelNotFoundException";
6
+ import ValidatorException from "../exceptions/ValidatorException";
7
+ import Response from "../facades/Response";
8
+ export default class ExceptionHandler {
9
+ handle(error) {
10
+ Logger.setContext("APP").error(error.message).trace(error.stack);
11
+ if (error instanceof ModelNotFoundException ||
12
+ error instanceof ValidatorException)
13
+ return Response
14
+ .setMessage(error.message)
15
+ .setStatus(error.code)
16
+ .send();
17
+ if (error instanceof ValidationError)
18
+ return Response
19
+ .setMessage(error.message)
20
+ .setStatus(error.statusCode)
21
+ .send();
22
+ return Response
23
+ .setMessage(defineValue(error.message, "Internal server error."))
24
+ .setStatus(500)
25
+ .send();
26
+ }
27
+ route(request) {
28
+ return Response
29
+ .setMessage("What are you looking for doesn't exists.")
30
+ .setStatus(request.method === HttpMethodEnum.Options ? 204 : 404)
31
+ .send();
32
+ }
33
+ }
@@ -0,0 +1,4 @@
1
+ export default class RuntimeException extends Error {
2
+ code: number;
3
+ constructor(message?: string, code?: number);
4
+ }
@@ -0,0 +1,14 @@
1
+ import Logger from "@bejibun/logger";
2
+ import { defineValue } from "@bejibun/utils";
3
+ export default class RuntimeException extends Error {
4
+ code;
5
+ constructor(message, code) {
6
+ super(message);
7
+ this.name = "RuntimeException";
8
+ this.code = defineValue(code, 500);
9
+ Logger.setContext(this.name).error(this.message).trace(this.stack);
10
+ if (Error.captureStackTrace) {
11
+ Error.captureStackTrace(this, RuntimeException);
12
+ }
13
+ }
14
+ }
@@ -1,3 +1,4 @@
1
+ export * from "../exceptions/ExceptionHandler";
1
2
  export * from "../exceptions/ModelNotFoundException";
2
3
  export * from "../exceptions/RouterInvalidException";
3
4
  export * from "../exceptions/ValidatorException";
@@ -1,3 +1,4 @@
1
+ export * from "../exceptions/ExceptionHandler";
1
2
  export * from "../exceptions/ModelNotFoundException";
2
3
  export * from "../exceptions/RouterInvalidException";
3
4
  export * from "../exceptions/ValidatorException";
@@ -0,0 +1,4 @@
1
+ import type { HandlerType } from "../types/router";
2
+ export default class MaintenanceMiddleware {
3
+ handle(handler: HandlerType): HandlerType;
4
+ }
@@ -0,0 +1,16 @@
1
+ import App from "@bejibun/app";
2
+ import Response from "../facades/Response";
3
+ export default class MaintenanceMiddleware {
4
+ handle(handler) {
5
+ return async (request) => {
6
+ if (await App.Maintenance.isMaintenanceMode()) {
7
+ const maintenance = await App.Maintenance.getData();
8
+ return Response
9
+ .setMessage(maintenance.message)
10
+ .setStatus(maintenance.status)
11
+ .send();
12
+ }
13
+ return handler(request);
14
+ };
15
+ }
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bejibun/core",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
4
4
  "author": "Havea Crenata <havea.crenata@gmail.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,8 +9,8 @@
9
9
  "main": "index.js",
10
10
  "module": "index.js",
11
11
  "dependencies": {
12
- "@bejibun/app": "^0.1.12",
13
- "@bejibun/cors": "^0.1.11",
12
+ "@bejibun/app": "^0.1.19",
13
+ "@bejibun/cors": "^0.1.12",
14
14
  "@bejibun/logger": "^0.1.18",
15
15
  "@bejibun/utils": "^0.1.14",
16
16
  "@vinejs/vine": "^3.0.1",
package/server.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/server.js ADDED
@@ -0,0 +1,49 @@
1
+ import App from "@bejibun/app";
2
+ import Logger from "@bejibun/logger";
3
+ import RuntimeException from "./exceptions/RuntimeException";
4
+ import Router from "./facades/Router";
5
+ import MaintenanceMiddleware from "./middlewares/MaintenanceMiddleware";
6
+ import(App.Path.rootPath("bootstrap.ts"));
7
+ const exceptionHandlerPath = App.Path.appPath("exceptions/handler.ts");
8
+ let ExceptionHandler;
9
+ try {
10
+ ExceptionHandler = require(exceptionHandlerPath).default;
11
+ }
12
+ catch {
13
+ throw new RuntimeException(`Missing exception handler class [${exceptionHandlerPath}].`);
14
+ }
15
+ const apiRoutesPath = App.Path.routesPath("api.ts");
16
+ let ApiRoutes;
17
+ try {
18
+ ApiRoutes = require(apiRoutesPath).default;
19
+ }
20
+ catch {
21
+ throw new RuntimeException(`Missing api file on routes directory [${apiRoutesPath}].`);
22
+ }
23
+ const webRoutesPath = App.Path.routesPath("web.ts");
24
+ let WebRoutes;
25
+ try {
26
+ WebRoutes = require(webRoutesPath).default;
27
+ }
28
+ catch {
29
+ throw new RuntimeException(`Missing web file on routes directory [${webRoutesPath}].`);
30
+ }
31
+ const server = Bun.serve({
32
+ development: Bun.env.NODE_ENV !== "production" && {
33
+ // Enable browser hot reloading in development
34
+ hmr: true,
35
+ // Echo console logs from the browser to the server
36
+ console: true
37
+ },
38
+ error: new ExceptionHandler().handle,
39
+ port: Bun.env.APP_PORT,
40
+ routes: {
41
+ "/": require(App.Path.publicPath("index.html")),
42
+ ...Router.middleware(new MaintenanceMiddleware()).group([
43
+ Router.namespace("app/exceptions").any("/*", "Handler@route"),
44
+ ApiRoutes,
45
+ WebRoutes
46
+ ])
47
+ }
48
+ });
49
+ Logger.setContext("APP").info(`🚀 Server running at ${server.url.origin}`);
package/types/router.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import type {BunRequest} from "bun";
2
-
3
- export type HandlerType = (request: BunRequest) => Promise<Response>;
1
+ export type HandlerType = (request: Bun.BunRequest) => Promise<Response>;
4
2
  export type RouterGroup = Record<string, Record<string, HandlerType>>;
5
3
  export type ResourceAction = "index" | "store" | "show" | "update" | "destroy";