@bejibun/core 0.1.20 → 0.1.22

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.
Files changed (57) hide show
  1. package/dist/bases/BaseController.d.ts +10 -0
  2. package/dist/bases/BaseController.js +126 -0
  3. package/dist/bases/BaseModel.d.ts +33 -0
  4. package/dist/bases/BaseModel.js +68 -0
  5. package/dist/bases/BaseValidator.d.ts +5 -0
  6. package/dist/bases/BaseValidator.js +7 -0
  7. package/dist/bootstrap.d.ts +1 -0
  8. package/dist/bootstrap.js +11 -0
  9. package/dist/builders/ChalkBuilder.d.ts +14 -0
  10. package/dist/builders/ChalkBuilder.js +48 -0
  11. package/dist/builders/EnumBuilder.d.ts +4 -0
  12. package/dist/builders/ResponseBuilder.d.ts +11 -0
  13. package/dist/builders/ResponseBuilder.js +41 -0
  14. package/dist/builders/RouterBuilder.d.ts +19 -0
  15. package/dist/builders/RouterBuilder.js +128 -0
  16. package/dist/config/cors.d.ts +2 -0
  17. package/dist/config/cors.js +9 -0
  18. package/dist/config/database.d.ts +3 -0
  19. package/dist/config/database.js +24 -0
  20. package/dist/enums/CorsHeaderEnum.d.ts +8 -0
  21. package/dist/enums/CorsHeaderEnum.js +9 -0
  22. package/dist/enums/HttpMethodEnum.d.ts +12 -0
  23. package/dist/enums/HttpMethodEnum.js +13 -0
  24. package/dist/exceptions/ModelNotFoundException.d.ts +4 -0
  25. package/dist/exceptions/ModelNotFoundException.js +11 -0
  26. package/dist/exceptions/RouterInvalidException.d.ts +4 -0
  27. package/dist/exceptions/RouterInvalidException.js +11 -0
  28. package/dist/exceptions/ValidatorException.d.ts +4 -0
  29. package/dist/exceptions/ValidatorException.js +11 -0
  30. package/dist/facades/Chalk.d.ts +4 -0
  31. package/dist/facades/Chalk.js +6 -0
  32. package/dist/{utils → facades}/Enum.d.ts +2 -0
  33. package/dist/facades/Response.d.ts +6 -0
  34. package/dist/facades/Response.js +12 -0
  35. package/dist/facades/Router.d.ts +21 -0
  36. package/dist/facades/Router.js +66 -0
  37. package/dist/facades/SoftDeletes.d.ts +11 -0
  38. package/dist/facades/SoftDeletes.js +50 -0
  39. package/dist/index.d.ts +0 -2
  40. package/dist/index.js +0 -2
  41. package/dist/types/index.d.ts +2 -0
  42. package/dist/types/middleware.d.ts +7 -0
  43. package/dist/types/router.d.ts +5 -0
  44. package/dist/types/validator.d.ts +3 -0
  45. package/dist/types/vine.d.ts +13 -0
  46. package/dist/utils/utils.d.ts +1 -0
  47. package/dist/utils/utils.js +30 -1
  48. package/dist/utils/vine.d.ts +2 -0
  49. package/dist/utils/vine.js +2 -0
  50. package/dist/utils/vines/exists.d.ts +1 -0
  51. package/dist/utils/vines/exists.js +28 -0
  52. package/dist/utils/vines/unique.d.ts +1 -0
  53. package/dist/utils/vines/unique.js +28 -0
  54. package/package.json +35 -10
  55. /package/dist/{utils → facades}/Enum.js +0 -0
  56. /package/dist/{utils → facades}/Str.d.ts +0 -0
  57. /package/dist/{utils → facades}/Str.js +0 -0
@@ -0,0 +1,10 @@
1
+ import { VineValidator } from "@vinejs/vine";
2
+ import { BunRequest } from "bun";
3
+ import Response from "../facades/Response";
4
+ export default class BaseController {
5
+ parse(request: BunRequest): Promise<Record<string, any>>;
6
+ get response(): typeof Response;
7
+ validate(validator: VineValidator<any, Record<string, any> | undefined>, body: Record<string, any>): Promise<any>;
8
+ private serialize;
9
+ private parseForm;
10
+ }
@@ -0,0 +1,126 @@
1
+ import { DateTime } from "luxon";
2
+ import ValidatorException from "../exceptions/ValidatorException";
3
+ import Response from "../facades/Response";
4
+ import { defineValue, isEmpty, isNotEmpty } from "../utils/utils";
5
+ export default class BaseController {
6
+ async parse(request) {
7
+ const contentType = defineValue(request.headers.get("content-type"), "");
8
+ const formData = new FormData();
9
+ try {
10
+ if (contentType.includes("application/json"))
11
+ return await request.json();
12
+ for (const [key, value] of Object.entries(request.params)) {
13
+ formData.append(key, value);
14
+ }
15
+ const url = new URL(request.url);
16
+ for (const [key, value] of url.searchParams) {
17
+ formData.append(key, value);
18
+ }
19
+ if (contentType.includes("multipart/form-data") ||
20
+ contentType.includes("application/x-www-form-urlencoded")) {
21
+ const body = await request.formData();
22
+ for (const [key, value] of body) {
23
+ formData.append(key, value);
24
+ }
25
+ }
26
+ const text = await request.text();
27
+ if (isNotEmpty(text))
28
+ formData.append("text", text);
29
+ }
30
+ catch {
31
+ // do nothing
32
+ }
33
+ return this.parseForm(formData);
34
+ }
35
+ get response() {
36
+ return Response;
37
+ }
38
+ async validate(validator, body) {
39
+ try {
40
+ return await validator.validate(body);
41
+ }
42
+ catch (error) {
43
+ throw new ValidatorException(error.messages[0].message);
44
+ }
45
+ }
46
+ serialize(data) {
47
+ if (Array.isArray(data))
48
+ return data.map((value) => this.serialize(value));
49
+ if (data === null || data === undefined)
50
+ return null;
51
+ if (data instanceof DateTime)
52
+ return data.isValid ? data.toISO() : null;
53
+ if (data instanceof Date)
54
+ return Number.isNaN(data.getTime()) ? null : data.toISOString();
55
+ if (typeof data === "object" && !(data instanceof File)) {
56
+ if (Object.keys(data).length === 0)
57
+ return null;
58
+ const nested = {};
59
+ Object.keys(data).forEach((key) => {
60
+ nested[key] = this.serialize(data[key]);
61
+ });
62
+ return nested;
63
+ }
64
+ if (typeof data === "string") {
65
+ const trimmed = data.trim();
66
+ if (trimmed === "")
67
+ return null;
68
+ if (trimmed === "true")
69
+ return true;
70
+ if (trimmed === "false")
71
+ return false;
72
+ const numeric = Number(trimmed);
73
+ if (!Number.isNaN(numeric) && trimmed === numeric.toString())
74
+ return numeric;
75
+ return trimmed;
76
+ }
77
+ return data;
78
+ }
79
+ parseForm(formData) {
80
+ const result = {};
81
+ for (const [key, value] of formData.entries()) {
82
+ const keys = key.replace(/]/g, "").split("[");
83
+ let current = result;
84
+ for (let i = 0; i < keys.length; i++) {
85
+ const part = keys[i];
86
+ const nextPart = keys[i + 1];
87
+ if (i === keys.length - 1) {
88
+ let convertedValue;
89
+ if (value instanceof File) {
90
+ convertedValue = value;
91
+ }
92
+ else if (value.trim() === "") {
93
+ convertedValue = null;
94
+ }
95
+ else if (Number.isNaN(value)) {
96
+ convertedValue = Number(value);
97
+ }
98
+ else if (value === "true" || value === "false") {
99
+ convertedValue = value === "true";
100
+ }
101
+ else {
102
+ try {
103
+ convertedValue = JSON.parse(value);
104
+ }
105
+ catch {
106
+ convertedValue = value;
107
+ }
108
+ }
109
+ if (current[part] === undefined)
110
+ current[part] = convertedValue;
111
+ else if (Array.isArray(current[part]))
112
+ current[part].push(convertedValue);
113
+ else
114
+ current[part] = [current[part], convertedValue];
115
+ }
116
+ else {
117
+ const isArrayIndex = /^\d+$/.test(nextPart);
118
+ if (isEmpty(current[part]))
119
+ current[part] = isArrayIndex ? [] : {};
120
+ current = current[part];
121
+ }
122
+ }
123
+ }
124
+ return result;
125
+ }
126
+ }
@@ -0,0 +1,33 @@
1
+ import { DateTime } from "luxon";
2
+ import { Constructor, Model, ModelOptions, PartialModelObject, QueryBuilder, QueryBuilderType, QueryContext, TransactionOrKnex } from "objection";
3
+ import SoftDeletes from "../facades/SoftDeletes";
4
+ export interface BaseColumns {
5
+ id: bigint | number;
6
+ created_at: DateTime | string;
7
+ updated_at: DateTime | string;
8
+ deleted_at: DateTime | string | null;
9
+ }
10
+ declare class BunQueryBuilder<M extends Model, R = M[]> extends SoftDeletes<M, R> {
11
+ update(payload: PartialModelObject<M>): Promise<QueryBuilder<M, R>>;
12
+ }
13
+ export default class BaseModel extends Model implements BaseColumns {
14
+ static tableName: string;
15
+ static idColumn: string;
16
+ static deletedColumn: string;
17
+ static QueryBuilder: typeof BunQueryBuilder;
18
+ id: number | bigint;
19
+ created_at: DateTime | string;
20
+ updated_at: DateTime | string;
21
+ deleted_at: DateTime | string | null;
22
+ static get namespace(): string;
23
+ $beforeInsert(queryContext: QueryContext): void;
24
+ $beforeUpdate(opt: ModelOptions, queryContext: QueryContext): void;
25
+ static query<T extends Model>(this: Constructor<T>, trxOrKnex?: TransactionOrKnex): QueryBuilderType<T>;
26
+ static withTrashed<T extends Model>(this: T): QueryBuilderType<T>;
27
+ static onlyTrashed<T extends Model>(this: T): QueryBuilderType<T>;
28
+ static all<T extends Model>(this: T): QueryBuilderType<T>;
29
+ static create<T extends Model>(this: T, payload: Record<string, any>): QueryBuilderType<T>;
30
+ static find<T extends Model>(this: T, id: bigint | number | string): QueryBuilderType<T>;
31
+ static findOrFail<T extends Model>(this: T, id: bigint | number | string): Promise<T>;
32
+ }
33
+ export {};
@@ -0,0 +1,68 @@
1
+ import { DateTime } from "luxon";
2
+ import { Model } from "objection";
3
+ import { relative, sep } from "path";
4
+ import { fileURLToPath } from "url";
5
+ import ModelNotFoundException from "../exceptions/ModelNotFoundException";
6
+ import SoftDeletes from "../facades/SoftDeletes";
7
+ import Str from "../facades/Str";
8
+ import { defineValue, isEmpty } from "../utils/utils";
9
+ class BunQueryBuilder extends SoftDeletes {
10
+ // @ts-ignore
11
+ async update(payload) {
12
+ const cloneQuery = this.clone();
13
+ const beforeRows = await cloneQuery;
14
+ if (isEmpty(beforeRows))
15
+ return defineValue(beforeRows);
16
+ await super.update(payload);
17
+ return cloneQuery;
18
+ }
19
+ }
20
+ // @ts-ignore
21
+ class BaseModel extends Model {
22
+ static get namespace() {
23
+ const filePath = fileURLToPath(import.meta.url);
24
+ const appRoot = process.cwd();
25
+ const rel = relative(appRoot, filePath);
26
+ const withoutExt = rel.replace(/\.[tj]s$/, "");
27
+ const namespaces = withoutExt.split(sep);
28
+ namespaces.pop();
29
+ namespaces.push(this.name);
30
+ return namespaces.map(part => Str.toPascalCase(part)).join("/");
31
+ }
32
+ $beforeInsert(queryContext) {
33
+ const now = DateTime.now();
34
+ this.created_at = now;
35
+ this.updated_at = now;
36
+ }
37
+ $beforeUpdate(opt, queryContext) {
38
+ this.updated_at = DateTime.now();
39
+ }
40
+ static query(trxOrKnex) {
41
+ return super.query(trxOrKnex);
42
+ }
43
+ ;
44
+ static withTrashed() {
45
+ return this.query().withTrashed();
46
+ }
47
+ static onlyTrashed() {
48
+ return this.query().onlyTrashed();
49
+ }
50
+ static all() {
51
+ return this.query().select();
52
+ }
53
+ static create(payload) {
54
+ return this.query().insert(payload);
55
+ }
56
+ static find(id) {
57
+ return this.query().findById(id);
58
+ }
59
+ static async findOrFail(id) {
60
+ const result = await this.find(id);
61
+ if (isEmpty(result))
62
+ throw new ModelNotFoundException(`[ModelNotFoundException]: No query results for model [${this.namespace}] [${id}].`);
63
+ return result;
64
+ }
65
+ }
66
+ BaseModel.deletedColumn = "deleted_at";
67
+ BaseModel.QueryBuilder = BunQueryBuilder;
68
+ export default BaseModel;
@@ -0,0 +1,5 @@
1
+ import vine from "@vinejs/vine";
2
+ import "../utils/vine";
3
+ export default class BaseValidator {
4
+ static get validator(): typeof vine;
5
+ }
@@ -0,0 +1,7 @@
1
+ import vine from "@vinejs/vine";
2
+ import "../utils/vine";
3
+ export default class BaseValidator {
4
+ static get validator() {
5
+ return vine;
6
+ }
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import BaseModel from "./bases/BaseModel";
2
+ import fs from "fs";
3
+ import knex from "knex";
4
+ import path from "path";
5
+ const configPath = path.resolve(process.cwd(), "config/database.ts");
6
+ let config;
7
+ if (fs.existsSync(configPath))
8
+ config = require(configPath).default;
9
+ else
10
+ config = require("./config/database").default;
11
+ BaseModel.knex(knex(config));
@@ -0,0 +1,14 @@
1
+ export default class ChalkBuilder {
2
+ protected value: string;
3
+ protected isNewLine: boolean;
4
+ protected clk: any;
5
+ constructor();
6
+ setValue(value: string): ChalkBuilder;
7
+ inline(): ChalkBuilder;
8
+ bold(): ChalkBuilder;
9
+ danger(): ChalkBuilder;
10
+ info(): ChalkBuilder;
11
+ line(): void;
12
+ show(): string;
13
+ private get _value();
14
+ }
@@ -0,0 +1,48 @@
1
+ import chalk from "chalk";
2
+ import os from "os";
3
+ export default class ChalkBuilder {
4
+ constructor() {
5
+ this.value = "";
6
+ this.isNewLine = true;
7
+ }
8
+ setValue(value) {
9
+ this.value = value;
10
+ return this;
11
+ }
12
+ inline() {
13
+ this.isNewLine = false;
14
+ return this;
15
+ }
16
+ bold() {
17
+ if (this.clk)
18
+ this.clk = this.clk.bold;
19
+ else
20
+ this.clk = chalk.bold;
21
+ return this;
22
+ }
23
+ danger() {
24
+ if (this.clk)
25
+ this.clk = this.clk.red;
26
+ else
27
+ this.clk = chalk.red;
28
+ return this;
29
+ }
30
+ info() {
31
+ if (this.clk)
32
+ this.clk = this.clk.hex("#0CCAF0");
33
+ else
34
+ this.clk = chalk.hex("#0CCAF0");
35
+ return this;
36
+ }
37
+ line() {
38
+ console.log("-".repeat(process.stdout.columns));
39
+ }
40
+ show() {
41
+ return this.clk(this._value);
42
+ }
43
+ get _value() {
44
+ if (this.isNewLine)
45
+ return `${this.value}${os.EOL}`;
46
+ return this.value;
47
+ }
48
+ }
@@ -1,3 +1,7 @@
1
+ export type EnumItem = {
2
+ name: string;
3
+ value: number;
4
+ };
1
5
  export default class EnumBuilder {
2
6
  protected enums: any;
3
7
  constructor(enums: any);
@@ -0,0 +1,11 @@
1
+ export default class ResponseBuilder {
2
+ protected data?: any;
3
+ protected message: string;
4
+ protected status: number;
5
+ constructor();
6
+ setData(data?: any): ResponseBuilder;
7
+ setMessage(message: string): ResponseBuilder;
8
+ setStatus(status: number): ResponseBuilder;
9
+ send(): globalThis.Response;
10
+ stream(options?: ResponseInit): globalThis.Response;
11
+ }
@@ -0,0 +1,41 @@
1
+ import { cors } from "../utils/utils";
2
+ export default class ResponseBuilder {
3
+ constructor() {
4
+ this.data = null;
5
+ this.message = "Success";
6
+ this.status = 200;
7
+ }
8
+ setData(data) {
9
+ this.data = data;
10
+ return this;
11
+ }
12
+ setMessage(message) {
13
+ this.message = message;
14
+ return this;
15
+ }
16
+ setStatus(status) {
17
+ this.status = status;
18
+ return this;
19
+ }
20
+ send() {
21
+ return globalThis.Response.json({
22
+ data: this.data,
23
+ message: this.message,
24
+ status: this.status
25
+ }, {
26
+ headers: {
27
+ ...cors()
28
+ },
29
+ status: this.status
30
+ });
31
+ }
32
+ stream(options = {}) {
33
+ return new globalThis.Response(Bun.file(this.data), {
34
+ ...options,
35
+ headers: {
36
+ ...cors()
37
+ },
38
+ status: this.status
39
+ });
40
+ }
41
+ }
@@ -0,0 +1,19 @@
1
+ import type { IMiddleware } from "@/types/middleware";
2
+ import type { HandlerType, ResourceAction, RouterGroup } from "@/types/router";
3
+ import HttpMethodEnum from "../enums/HttpMethodEnum";
4
+ export interface ResourceOptions {
5
+ only?: Array<ResourceAction>;
6
+ except?: Array<ResourceAction>;
7
+ }
8
+ export default class RouterBuilder {
9
+ private basePath;
10
+ private middlewares;
11
+ prefix(basePath: string): RouterBuilder;
12
+ middleware(...middlewares: Array<IMiddleware>): RouterBuilder;
13
+ group(routes: RouterGroup | Array<RouterGroup>): RouterGroup;
14
+ resources(controller: Record<string, HandlerType>, options?: ResourceOptions): RouterGroup;
15
+ buildSingle(method: HttpMethodEnum, path: string, handler: string | HandlerType): RouterGroup;
16
+ private joinPaths;
17
+ private resolveControllerString;
18
+ private resolveIncludedActions;
19
+ }
@@ -0,0 +1,128 @@
1
+ import RouterInvalidException from "../exceptions/RouterInvalidException";
2
+ import { isEmpty } from "../utils/utils";
3
+ import path from "path";
4
+ export default class RouterBuilder {
5
+ constructor() {
6
+ this.basePath = "";
7
+ this.middlewares = [];
8
+ }
9
+ prefix(basePath) {
10
+ this.basePath = basePath;
11
+ return this;
12
+ }
13
+ middleware(...middlewares) {
14
+ this.middlewares.push(...middlewares);
15
+ return this;
16
+ }
17
+ group(routes) {
18
+ const routeList = Array.isArray(routes) ? routes : [routes];
19
+ const newRoutes = {};
20
+ for (const route of routeList) {
21
+ for (const path in route) {
22
+ const fullPath = this.joinPaths(this.basePath, path);
23
+ const routeHandlers = route[path];
24
+ const wrappedHandlers = {};
25
+ for (const method in routeHandlers) {
26
+ let handler = routeHandlers[method];
27
+ for (const middleware of this.middlewares) {
28
+ handler = middleware.handle(handler);
29
+ }
30
+ wrappedHandlers[method] = handler;
31
+ }
32
+ if (isEmpty(newRoutes[fullPath]))
33
+ newRoutes[fullPath] = {};
34
+ Object.assign(newRoutes[fullPath], wrappedHandlers);
35
+ }
36
+ }
37
+ return newRoutes;
38
+ }
39
+ resources(controller, options) {
40
+ const allRoutes = {
41
+ "": {
42
+ GET: "index",
43
+ POST: "store"
44
+ },
45
+ ":id": {
46
+ GET: "show",
47
+ PUT: "update",
48
+ DELETE: "destroy"
49
+ }
50
+ };
51
+ const includedActions = this.resolveIncludedActions(options);
52
+ const filteredRoutes = {};
53
+ for (const path in allRoutes) {
54
+ const methods = allRoutes[path];
55
+ const methodHandlers = {};
56
+ for (const method in methods) {
57
+ const action = methods[method];
58
+ if (includedActions.has(action) && controller[action]) {
59
+ methodHandlers[method] = controller[action];
60
+ }
61
+ }
62
+ if (Object.keys(methodHandlers).length > 0) {
63
+ filteredRoutes[path] = methodHandlers;
64
+ }
65
+ }
66
+ return this.group(filteredRoutes);
67
+ }
68
+ buildSingle(method, path, handler) {
69
+ const cleanPath = this.joinPaths(this.basePath, path);
70
+ let resolvedHandler = typeof handler === "string" ?
71
+ this.resolveControllerString(handler) :
72
+ handler;
73
+ for (const middleware of this.middlewares) {
74
+ resolvedHandler = middleware.handle(resolvedHandler);
75
+ }
76
+ return {
77
+ [cleanPath]: {
78
+ [method]: resolvedHandler
79
+ }
80
+ };
81
+ }
82
+ joinPaths(base, path) {
83
+ base = base.replace(/\/+$/, "");
84
+ path = path.replace(/^\/+/, "");
85
+ return "/" + [base, path].filter(Boolean).join("/");
86
+ }
87
+ resolveControllerString(definition) {
88
+ const [controllerName, methodName] = definition.split("@");
89
+ if (isEmpty(controllerName) || isEmpty(methodName)) {
90
+ throw new RouterInvalidException(`[RouterInvalidException]: Invalid router controller definition: ${definition}.`);
91
+ }
92
+ const controllerPath = path.resolve(process.cwd(), "app/controllers");
93
+ const location = `${controllerPath}/${controllerName}`;
94
+ let ControllerClass;
95
+ try {
96
+ ControllerClass = require(location).default;
97
+ }
98
+ catch {
99
+ return async (...args) => {
100
+ const module = await import(location);
101
+ const ESMController = module.default;
102
+ const instance = new ESMController();
103
+ if (typeof instance[methodName] !== "function") {
104
+ throw new RouterInvalidException(`[RouterInvalidException]: Method "${methodName}" not found in ${controllerName}.`);
105
+ }
106
+ return instance[methodName](...args);
107
+ };
108
+ }
109
+ if (isEmpty(ControllerClass)) {
110
+ throw new RouterInvalidException(`[RouterInvalidException]: Controller not found: ${controllerName}.`);
111
+ }
112
+ const instance = new ControllerClass();
113
+ if (typeof instance[methodName] !== "function") {
114
+ throw new RouterInvalidException(`[RouterInvalidException]: Method "${methodName}" not found in ${controllerName}.`);
115
+ }
116
+ return instance[methodName].bind(instance);
117
+ }
118
+ resolveIncludedActions(options) {
119
+ const all = ["index", "store", "show", "update", "destroy"];
120
+ if (options?.only) {
121
+ return new Set(options.only);
122
+ }
123
+ if (options?.except) {
124
+ return new Set(all.filter(action => !options.except.includes(action)));
125
+ }
126
+ return new Set(all);
127
+ }
128
+ }
@@ -0,0 +1,2 @@
1
+ declare const config: Record<string, any>;
2
+ export default config;
@@ -0,0 +1,9 @@
1
+ const config = {
2
+ allowedHeaders: "*",
3
+ credentials: false,
4
+ exposedHeaders: [],
5
+ maxAge: 86400,
6
+ methods: "*",
7
+ origin: "*"
8
+ };
9
+ export default config;
@@ -0,0 +1,3 @@
1
+ import type { Knex } from "knex";
2
+ declare const config: Knex.Config;
3
+ export default config;
@@ -0,0 +1,24 @@
1
+ const config = {
2
+ client: "pg",
3
+ connection: {
4
+ host: "127.0.0.1",
5
+ port: 5432,
6
+ user: "postgres",
7
+ password: "",
8
+ database: "bejibun"
9
+ },
10
+ migrations: {
11
+ extension: "ts",
12
+ directory: "./database/migrations",
13
+ tableName: "migrations"
14
+ },
15
+ pool: {
16
+ min: 0,
17
+ max: 1
18
+ },
19
+ seeds: {
20
+ extension: "ts",
21
+ directory: "./database/seeders"
22
+ }
23
+ };
24
+ export default config;
@@ -0,0 +1,8 @@
1
+ declare enum CorsHeaderEnum {
2
+ Accept = "Accept",
3
+ Authorization = "Authorization",
4
+ ContentType = "Content-Type",
5
+ Origin = "Origin",
6
+ XRequestedWith = "X-Requested-With"
7
+ }
8
+ export default CorsHeaderEnum;
@@ -0,0 +1,9 @@
1
+ var CorsHeaderEnum;
2
+ (function (CorsHeaderEnum) {
3
+ CorsHeaderEnum["Accept"] = "Accept";
4
+ CorsHeaderEnum["Authorization"] = "Authorization";
5
+ CorsHeaderEnum["ContentType"] = "Content-Type";
6
+ CorsHeaderEnum["Origin"] = "Origin";
7
+ CorsHeaderEnum["XRequestedWith"] = "X-Requested-With";
8
+ })(CorsHeaderEnum || (CorsHeaderEnum = {}));
9
+ export default CorsHeaderEnum;
@@ -0,0 +1,12 @@
1
+ declare enum HttpMethodEnum {
2
+ Connect = "CONNECT",
3
+ Delete = "DELETE",
4
+ Get = "GET",
5
+ Head = "HEAD",
6
+ Options = "OPTIONS",
7
+ Patch = "PATCH",
8
+ Post = "POST",
9
+ Put = "PUT",
10
+ Trace = "TRACE"
11
+ }
12
+ export default HttpMethodEnum;
@@ -0,0 +1,13 @@
1
+ var HttpMethodEnum;
2
+ (function (HttpMethodEnum) {
3
+ HttpMethodEnum["Connect"] = "CONNECT";
4
+ HttpMethodEnum["Delete"] = "DELETE";
5
+ HttpMethodEnum["Get"] = "GET";
6
+ HttpMethodEnum["Head"] = "HEAD";
7
+ HttpMethodEnum["Options"] = "OPTIONS";
8
+ HttpMethodEnum["Patch"] = "PATCH";
9
+ HttpMethodEnum["Post"] = "POST";
10
+ HttpMethodEnum["Put"] = "PUT";
11
+ HttpMethodEnum["Trace"] = "TRACE";
12
+ })(HttpMethodEnum || (HttpMethodEnum = {}));
13
+ export default HttpMethodEnum;
@@ -0,0 +1,4 @@
1
+ export default class ModelNotFoundException extends Error {
2
+ code: number;
3
+ constructor(message?: string, code?: number);
4
+ }
@@ -0,0 +1,11 @@
1
+ import { defineValue } from "../utils/utils";
2
+ export default class ModelNotFoundException extends Error {
3
+ constructor(message, code) {
4
+ super(message);
5
+ this.name = "ModelNotFoundException";
6
+ this.code = defineValue(code, 404);
7
+ if (Error.captureStackTrace) {
8
+ Error.captureStackTrace(this, ModelNotFoundException);
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,4 @@
1
+ export default class RouterInvalidException extends Error {
2
+ code: number;
3
+ constructor(message?: string, code?: number);
4
+ }
@@ -0,0 +1,11 @@
1
+ import { defineValue } from "../utils/utils";
2
+ export default class RouterInvalidException extends Error {
3
+ constructor(message, code) {
4
+ super(message);
5
+ this.name = "RouterInvalidException";
6
+ this.code = defineValue(code, 500);
7
+ if (Error.captureStackTrace) {
8
+ Error.captureStackTrace(this, RouterInvalidException);
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,4 @@
1
+ export default class ValidatorException extends Error {
2
+ code: number;
3
+ constructor(message?: string, code?: number);
4
+ }
@@ -0,0 +1,11 @@
1
+ import { defineValue } from "../utils/utils";
2
+ export default class ValidatorException extends Error {
3
+ constructor(message, code) {
4
+ super(message);
5
+ this.name = "ValidatorException";
6
+ this.code = defineValue(code, 422);
7
+ if (Error.captureStackTrace) {
8
+ Error.captureStackTrace(this, ValidatorException);
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,4 @@
1
+ import ChalkBuilder from "../builders/ChalkBuilder";
2
+ export default class Chalk {
3
+ static setValue(value: string): ChalkBuilder;
4
+ }
@@ -0,0 +1,6 @@
1
+ import ChalkBuilder from "../builders/ChalkBuilder";
2
+ export default class Chalk {
3
+ static setValue(value) {
4
+ return new ChalkBuilder().setValue(value);
5
+ }
6
+ }
@@ -1,4 +1,6 @@
1
1
  import EnumBuilder from "../builders/EnumBuilder";
2
+ import type { EnumItem } from "../builders/EnumBuilder";
3
+ export type { EnumItem };
2
4
  export default class Enum {
3
5
  static setEnums(enums: any): EnumBuilder;
4
6
  }
@@ -0,0 +1,6 @@
1
+ import ResponseBuilder from "../builders/ResponseBuilder";
2
+ export default class Response {
3
+ static setData(data?: any): ResponseBuilder;
4
+ static setMessage(message: string): ResponseBuilder;
5
+ static setStatus(status: number): ResponseBuilder;
6
+ }
@@ -0,0 +1,12 @@
1
+ import ResponseBuilder from "../builders/ResponseBuilder";
2
+ export default class Response {
3
+ static setData(data) {
4
+ return new ResponseBuilder().setData(data);
5
+ }
6
+ static setMessage(message) {
7
+ return new ResponseBuilder().setMessage(message);
8
+ }
9
+ static setStatus(status) {
10
+ return new ResponseBuilder().setStatus(status);
11
+ }
12
+ }
@@ -0,0 +1,21 @@
1
+ import type { IMiddleware } from "@/types/middleware";
2
+ import type { HandlerType, RouterGroup } from "@/types/router";
3
+ import RouterBuilder, { ResourceOptions } from "../builders/RouterBuilder";
4
+ import HttpMethodEnum from "../enums/HttpMethodEnum";
5
+ export default class Router {
6
+ static prefix(basePath: string): RouterBuilder;
7
+ static middleware(...middlewares: Array<IMiddleware>): RouterBuilder;
8
+ static resources(controller: Record<string, HandlerType>, options?: ResourceOptions): RouterGroup;
9
+ static group(routes: RouterGroup, prefix?: string, middlewares?: Array<IMiddleware>): RouterGroup;
10
+ static connect(path: string, handler: string | HandlerType): RouterGroup;
11
+ static delete(path: string, handler: string | HandlerType): RouterGroup;
12
+ static get(path: string, handler: string | HandlerType): RouterGroup;
13
+ static head(path: string, handler: string | HandlerType): RouterGroup;
14
+ static options(path: string, handler: string | HandlerType): RouterGroup;
15
+ static patch(path: string, handler: string | HandlerType): RouterGroup;
16
+ static post(path: string, handler: string | HandlerType): RouterGroup;
17
+ static put(path: string, handler: string | HandlerType): RouterGroup;
18
+ static trace(path: string, handler: string | HandlerType): RouterGroup;
19
+ static match(methods: Array<HttpMethodEnum>, path: string, handler: string | HandlerType): RouterGroup;
20
+ static any(path: string, handler: string | HandlerType): RouterGroup;
21
+ }
@@ -0,0 +1,66 @@
1
+ import RouterBuilder from "../builders/RouterBuilder";
2
+ import HttpMethodEnum from "../enums/HttpMethodEnum";
3
+ import Enum from "../facades/Enum";
4
+ import { isEmpty } from "../utils/utils";
5
+ export default class Router {
6
+ static prefix(basePath) {
7
+ return new RouterBuilder().prefix(basePath);
8
+ }
9
+ static middleware(...middlewares) {
10
+ return new RouterBuilder().middleware(...middlewares);
11
+ }
12
+ static resources(controller, options) {
13
+ return new RouterBuilder().resources(controller, options);
14
+ }
15
+ static group(routes, prefix, middlewares) {
16
+ const builder = new RouterBuilder();
17
+ if (prefix)
18
+ builder.prefix(prefix);
19
+ if (middlewares?.length)
20
+ builder.middleware(...middlewares);
21
+ return builder.group(routes);
22
+ }
23
+ static connect(path, handler) {
24
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Connect, path, handler);
25
+ }
26
+ static delete(path, handler) {
27
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Delete, path, handler);
28
+ }
29
+ static get(path, handler) {
30
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Get, path, handler);
31
+ }
32
+ static head(path, handler) {
33
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Head, path, handler);
34
+ }
35
+ static options(path, handler) {
36
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Options, path, handler);
37
+ }
38
+ static patch(path, handler) {
39
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Patch, path, handler);
40
+ }
41
+ static post(path, handler) {
42
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Post, path, handler);
43
+ }
44
+ static put(path, handler) {
45
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Put, path, handler);
46
+ }
47
+ static trace(path, handler) {
48
+ return new RouterBuilder().buildSingle(HttpMethodEnum.Trace, path, handler);
49
+ }
50
+ static match(methods, path, handler) {
51
+ const builder = new RouterBuilder();
52
+ const routeMap = {};
53
+ for (const method of methods) {
54
+ const single = builder.buildSingle(method, path, handler);
55
+ const fullPath = Object.keys(single)[0];
56
+ const handlers = single[fullPath];
57
+ if (isEmpty(routeMap[fullPath]))
58
+ routeMap[fullPath] = {};
59
+ Object.assign(routeMap[fullPath], handlers);
60
+ }
61
+ return routeMap;
62
+ }
63
+ static any(path, handler) {
64
+ return this.match(Enum.setEnums(HttpMethodEnum).toArray(), path, handler);
65
+ }
66
+ }
@@ -0,0 +1,11 @@
1
+ import { QueryBuilder, ModelClass, Model } from "objection";
2
+ export default class SoftDeletes<M extends Model, R = M[]> extends QueryBuilder<M, R> {
3
+ private hasFilterApplied;
4
+ constructor(modelClass: ModelClass<M>);
5
+ withTrashed(): this;
6
+ onlyTrashed(): this;
7
+ delete(): QueryBuilder<M, number>;
8
+ del(): QueryBuilder<M, number>;
9
+ forceDelete(): QueryBuilder<M, number>;
10
+ restore(): QueryBuilder<M, number>;
11
+ }
@@ -0,0 +1,50 @@
1
+ import { DateTime } from "luxon";
2
+ import { QueryBuilder } from "objection";
3
+ export default class SoftDeletes extends QueryBuilder {
4
+ constructor(modelClass) {
5
+ // @ts-ignore
6
+ super(modelClass);
7
+ this.hasFilterApplied = false;
8
+ this.onBuild((builder) => {
9
+ const context = this.context();
10
+ if (!this.hasFilterApplied) {
11
+ const tableName = this.modelClass().tableName;
12
+ if (context.onlyTrashed) {
13
+ builder.whereNotNull(`${tableName}.${this.modelClass().deletedColumn}`);
14
+ }
15
+ else if (!context.withTrashed) {
16
+ builder.whereNull(`${tableName}.${this.modelClass().deletedColumn}`);
17
+ }
18
+ this.hasFilterApplied = true;
19
+ }
20
+ });
21
+ }
22
+ withTrashed() {
23
+ return this.context({
24
+ ...this.context(),
25
+ withTrashed: true
26
+ });
27
+ }
28
+ onlyTrashed() {
29
+ return this.context({
30
+ ...this.context(),
31
+ onlyTrashed: true
32
+ });
33
+ }
34
+ delete() {
35
+ return this.update({
36
+ [this.modelClass().deletedColumn]: DateTime.now()
37
+ });
38
+ }
39
+ del() {
40
+ return this.delete();
41
+ }
42
+ forceDelete() {
43
+ return super.delete();
44
+ }
45
+ restore() {
46
+ return this.onlyTrashed().update({
47
+ [this.modelClass().deletedColumn]: null
48
+ });
49
+ }
50
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1 @@
1
- export * from "./utils/Enum";
2
- export * from "./utils/Str";
3
1
  export * from "./utils/utils";
package/dist/index.js CHANGED
@@ -1,3 +1 @@
1
- export * from "./utils/Enum";
2
- export * from "./utils/Str";
3
1
  export * from "./utils/utils";
@@ -0,0 +1,2 @@
1
+ export * from "@/types/middleware";
2
+ export * from "@/types/router";
@@ -0,0 +1,7 @@
1
+ import type {HandlerType} from "@/types/router";
2
+
3
+ export type MiddlewareType = (handler: HandlerType) => HandlerType;
4
+
5
+ export interface IMiddleware {
6
+ handle(handler: HandlerType): HandlerType;
7
+ }
@@ -0,0 +1,5 @@
1
+ import {BunRequest} from "bun";
2
+
3
+ export type HandlerType = (request: BunRequest) => Promise<Response>;
4
+ export type RouterGroup = Record<string, Record<string, HandlerType>>;
5
+ export type ResourceAction = "index" | "store" | "show" | "update" | "destroy";
@@ -0,0 +1,3 @@
1
+ import {SchemaTypes, VineValidator} from "@vinejs/vine";
2
+
3
+ export type ValidatorType<T extends SchemaTypes = SchemaTypes> = VineValidator<SchemaTypes, Record<string, any> | undefined>;
@@ -0,0 +1,13 @@
1
+ declare module "@vinejs/vine" {
2
+ interface VineNumber {
3
+ exists(tableOrOptions: string | { table: string; column?: string }, column?: string): this;
4
+ unique(tableOrOptions: string | { table: string; column?: string }, column?: string): this;
5
+ }
6
+
7
+ interface VineString {
8
+ exists(tableOrOptions: string | { table: string; column?: string }, column?: string): this;
9
+ unique(tableOrOptions: string | { table: string; column?: string }, column?: string): this;
10
+ }
11
+ }
12
+
13
+ export {};
@@ -2,3 +2,4 @@ export declare const isEmpty: (value: any) => boolean;
2
2
  export declare const isNotEmpty: (value: any) => boolean;
3
3
  export declare const defineValue: (value: any, defaultValue?: any) => any;
4
4
  export declare const ask: (question: string) => Promise<string>;
5
+ export declare const cors: () => Record<string, string>;
@@ -1,4 +1,9 @@
1
+ import fs from "fs";
2
+ import path from "path";
1
3
  import readline from "readline";
4
+ import CorsHeaderEnum from "../enums/CorsHeaderEnum";
5
+ import HttpMethodEnum from "../enums/HttpMethodEnum";
6
+ import Enum from "../facades/Enum";
2
7
  export const isEmpty = (value) => {
3
8
  return (value === undefined ||
4
9
  value === null ||
@@ -22,10 +27,34 @@ export const ask = (question) => {
22
27
  input: process.stdin,
23
28
  output: process.stdout
24
29
  });
25
- return new Promise((resolve, reject) => {
30
+ return new Promise(resolve => {
26
31
  return rl.question(question, (answer) => {
27
32
  rl.close();
28
33
  resolve(answer.trim());
29
34
  });
30
35
  });
31
36
  };
37
+ export const cors = () => {
38
+ const configPath = path.resolve(process.cwd(), "config/cors.ts");
39
+ let corsConfig;
40
+ if (fs.existsSync(configPath))
41
+ corsConfig = require(configPath).default;
42
+ else
43
+ corsConfig = require("../config/cors").default;
44
+ const headers = {
45
+ "Access-Control-Allow-Origin": corsConfig.origin,
46
+ "Access-Control-Allow-Headers": Array.isArray(corsConfig.allowedHeaders)
47
+ ? corsConfig.allowedHeaders.join(", ")
48
+ : Enum.setEnums(CorsHeaderEnum).toArray().map((value) => value.value).join(", "),
49
+ "Access-Control-Allow-Methods": Array.isArray(corsConfig.methods)
50
+ ? corsConfig.methods.join(", ")
51
+ : Enum.setEnums(HttpMethodEnum).toArray().map((value) => value.value).join(", ")
52
+ };
53
+ if (corsConfig.exposedHeaders.length > 0)
54
+ headers["Access-Control-Expose-Headers"] = corsConfig.exposedHeaders.join(", ");
55
+ if (corsConfig.credentials)
56
+ headers["Access-Control-Allow-Credentials"] = "true";
57
+ if (corsConfig.maxAge)
58
+ headers["Access-Control-Max-Age"] = corsConfig.maxAge.toString();
59
+ return headers;
60
+ };
@@ -0,0 +1,2 @@
1
+ import "../utils/vines/exists";
2
+ import "../utils/vines/unique";
@@ -0,0 +1,2 @@
1
+ import "../utils/vines/exists";
2
+ import "../utils/vines/unique";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import vine, { VineNumber, VineString } from "@vinejs/vine";
2
+ import BaseModel from "../../bases/BaseModel";
3
+ import { defineValue, isEmpty } from "../../utils/utils";
4
+ const exists = async (value, options, field) => {
5
+ if (!field.isValid)
6
+ return;
7
+ const column = defineValue(options.column, field.name);
8
+ let query = options.table;
9
+ if (options.withTrashed)
10
+ query = query.withTrashed();
11
+ else
12
+ query = query.query();
13
+ const row = await query.where(column, value).first();
14
+ if (isEmpty(row))
15
+ field.report("The {{ field }} field doesn't exists", "exists", field);
16
+ };
17
+ const existsRule = vine.createRule(exists, { isAsync: true });
18
+ const registerExistsMacro = (Type) => {
19
+ Type.macro("exists", function (tableOrOptions, column, withTrashed) {
20
+ const isModel = typeof tableOrOptions === "function" && Object.prototype.isPrototypeOf.call(BaseModel, tableOrOptions);
21
+ const options = isModel
22
+ ? { table: tableOrOptions, column, withTrashed }
23
+ : tableOrOptions;
24
+ return this.use(existsRule(options));
25
+ });
26
+ };
27
+ registerExistsMacro(VineString);
28
+ registerExistsMacro(VineNumber);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import vine, { VineNumber, VineString } from "@vinejs/vine";
2
+ import BaseModel from "../../bases/BaseModel";
3
+ import { defineValue, isNotEmpty } from "../../utils/utils";
4
+ const unique = async (value, options, field) => {
5
+ if (!field.isValid)
6
+ return;
7
+ const column = defineValue(options.column, field.name);
8
+ let query = options.table;
9
+ if (options.withTrashed)
10
+ query = query.withTrashed();
11
+ else
12
+ query = query.query();
13
+ const row = await query.where(column, value).first();
14
+ if (isNotEmpty(row))
15
+ field.report("The {{ field }} field is already exists", "unique", field);
16
+ };
17
+ const uniqueRule = vine.createRule(unique, { isAsync: true });
18
+ const registerUniqueMacro = (Type) => {
19
+ Type.macro("unique", function (tableOrOptions, column, withTrashed) {
20
+ const isModel = typeof tableOrOptions === "function" && Object.prototype.isPrototypeOf.call(BaseModel, tableOrOptions);
21
+ const options = isModel
22
+ ? { table: tableOrOptions, column, withTrashed }
23
+ : tableOrOptions;
24
+ return this.use(uniqueRule(options));
25
+ });
26
+ };
27
+ registerUniqueMacro(VineString);
28
+ registerUniqueMacro(VineNumber);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bejibun/core",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Core of Bejibun Framework",
5
5
  "keywords": [
6
6
  "bun",
@@ -22,19 +22,35 @@
22
22
  "type": "module",
23
23
  "main": "./dist/index.js",
24
24
  "module": "./dist/index.js",
25
- "types": "./dist/index.d.ts",
25
+ "types": "./types/index.d.ts",
26
26
  "exports": {
27
27
  ".": {
28
28
  "import": "./dist/index.js",
29
29
  "types": "./dist/index.d.ts"
30
30
  },
31
- "./enum": {
32
- "import": "./dist/facades/Enum.js",
33
- "types": "./dist/facades/Enum.d.ts"
31
+ "./bootstrap": {
32
+ "import": "./dist/bootstrap.js",
33
+ "types": "./dist/bootstrap.d.ts"
34
34
  },
35
- "./str": {
36
- "import": "./dist/facades/Str.js",
37
- "types": "./dist/facades/Str.d.ts"
35
+ "./bases/*": {
36
+ "import": "./dist/bases/*.js",
37
+ "types": "./dist/bases/*.d.ts"
38
+ },
39
+ "./enums/*": {
40
+ "import": "./dist/enums/*.js",
41
+ "types": "./dist/enums/*.d.ts"
42
+ },
43
+ "./exceptions/*": {
44
+ "import": "./dist/exceptions/*.js",
45
+ "types": "./dist/exceptions/*.d.ts"
46
+ },
47
+ "./facades/*": {
48
+ "import": "./dist/facades/*.js",
49
+ "types": "./dist/facades/*.d.ts"
50
+ },
51
+ "./types/*": {
52
+ "import": "./dist/types/*.js",
53
+ "types": "./dist/types/*.d.ts"
38
54
  }
39
55
  },
40
56
  "files": [
@@ -42,11 +58,20 @@
42
58
  ],
43
59
  "scripts": {
44
60
  "clean": "rm -rf dist",
45
- "build": "bun run clean && tsc -p tsconfig.json && tsc-alias -p tsconfig.json"
61
+ "build": "bun run clean && tsc -p tsconfig.json && tsc-alias -p tsconfig.json && cp -rf src/types dist/types",
62
+ "publish": "bun run build && npm publish --access public"
63
+ },
64
+ "dependencies": {
65
+ "@vinejs/vine": "^3.0.1",
66
+ "chalk": "^5.6.2",
67
+ "knex": "^3.1.0",
68
+ "luxon": "^3.7.2",
69
+ "objection": "^3.1.5",
70
+ "pg": "^8.16.3"
46
71
  },
47
- "dependencies": {},
48
72
  "devDependencies": {
49
73
  "@types/bun": "latest",
74
+ "@types/luxon": "^3.7.1",
50
75
  "tsc-alias": "^1.8.16",
51
76
  "typescript": "^5.9.3"
52
77
  },
File without changes
File without changes
File without changes