mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-04 00:56:01 +00:00
initial refactor
This commit is contained in:
@@ -5,7 +5,7 @@ import type { SafeUser } from "auth";
|
||||
import type { EntityManager } from "data";
|
||||
import { s } from "core/object/schema";
|
||||
|
||||
export type ServerEnv = Env & {
|
||||
export interface ServerEnv extends Env {
|
||||
Variables: {
|
||||
app: App;
|
||||
// to prevent resolving auth multiple times
|
||||
@@ -17,7 +17,22 @@ export type ServerEnv = Env & {
|
||||
};
|
||||
html?: string;
|
||||
};
|
||||
};
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/* export type ServerEnv = Env & {
|
||||
Variables: {
|
||||
app: App;
|
||||
// to prevent resolving auth multiple times
|
||||
auth?: {
|
||||
resolved: boolean;
|
||||
registered: boolean;
|
||||
skip: boolean;
|
||||
user?: SafeUser;
|
||||
};
|
||||
html?: string;
|
||||
};
|
||||
}; */
|
||||
|
||||
export class Controller {
|
||||
protected middlewares = middlewares;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import type { Guard } from "auth";
|
||||
import { type DebugLogger, SchemaObject } from "core";
|
||||
import type { EventManager } from "core/events";
|
||||
import type { Static, TSchema } from "core/utils";
|
||||
import type { Connection, EntityManager } from "data";
|
||||
import type { Hono } from "hono";
|
||||
import type { ServerEnv } from "modules/Controller";
|
||||
import type { ModuleHelper } from "./ModuleHelper";
|
||||
import type { s } from "core/object/schema";
|
||||
|
||||
type PartialRec<T> = { [P in keyof T]?: PartialRec<T[P]> };
|
||||
|
||||
export type ModuleBuildContext = {
|
||||
connection: Connection;
|
||||
@@ -18,13 +20,13 @@ export type ModuleBuildContext = {
|
||||
helper: ModuleHelper;
|
||||
};
|
||||
|
||||
export abstract class Module<Schema extends TSchema = TSchema, ConfigSchema = Static<Schema>> {
|
||||
export abstract class Module<Schema extends object = object> {
|
||||
private _built = false;
|
||||
private _schema: SchemaObject<ReturnType<(typeof this)["getSchema"]>>;
|
||||
private _listener: any = () => null;
|
||||
|
||||
constructor(
|
||||
initial?: Partial<Static<Schema>>,
|
||||
initial?: PartialRec<Schema>,
|
||||
protected _ctx?: ModuleBuildContext,
|
||||
) {
|
||||
this._schema = new SchemaObject(this.getSchema(), initial, {
|
||||
@@ -47,7 +49,7 @@ export abstract class Module<Schema extends TSchema = TSchema, ConfigSchema = St
|
||||
ctx_reload_required: boolean;
|
||||
};
|
||||
|
||||
onBeforeUpdate(from: ConfigSchema, to: ConfigSchema): ConfigSchema | Promise<ConfigSchema> {
|
||||
onBeforeUpdate(from: Schema, to: Schema): Schema | Promise<Schema> {
|
||||
return to;
|
||||
}
|
||||
|
||||
@@ -75,11 +77,13 @@ export abstract class Module<Schema extends TSchema = TSchema, ConfigSchema = St
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get configDefault(): Static<ReturnType<(typeof this)["getSchema"]>> {
|
||||
return this._schema.default();
|
||||
//get configDefault(): s.Static<ReturnType<(typeof this)["getSchema"]>> {
|
||||
get configDefault(): Schema {
|
||||
return this._schema.default() as any;
|
||||
}
|
||||
|
||||
get config(): Static<ReturnType<(typeof this)["getSchema"]>> {
|
||||
//get config(): s.Static<ReturnType<(typeof this)["getSchema"]>> {
|
||||
get config(): Schema {
|
||||
return this._schema.get();
|
||||
}
|
||||
|
||||
@@ -130,7 +134,8 @@ export abstract class Module<Schema extends TSchema = TSchema, ConfigSchema = St
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(secrets?: boolean): Static<ReturnType<(typeof this)["getSchema"]>> {
|
||||
//toJSON(secrets?: boolean): s.Static<ReturnType<(typeof this)["getSchema"]>> {
|
||||
toJSON(secrets?: boolean): Schema {
|
||||
return this.config;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,7 @@ import { Guard } from "auth";
|
||||
import { $console, BkndError, DebugLogger, env } from "core";
|
||||
import { EventManager } from "core/events";
|
||||
import * as $diff from "core/object/diff";
|
||||
import {
|
||||
Default,
|
||||
type Static,
|
||||
StringEnum,
|
||||
mark,
|
||||
objectEach,
|
||||
stripMark,
|
||||
transformObject,
|
||||
} from "core/utils";
|
||||
import { objectEach, transformObject } from "core/utils";
|
||||
import type { Connection, Schema } from "data";
|
||||
import { EntityManager } from "data/entities/EntityManager";
|
||||
import * as proto from "data/prototype";
|
||||
@@ -26,18 +18,17 @@ import { AppFlows } from "../flows/AppFlows";
|
||||
import { AppMedia } from "../media/AppMedia";
|
||||
import type { ServerEnv } from "./Controller";
|
||||
import { Module, type ModuleBuildContext } from "./Module";
|
||||
import * as tbbox from "@sinclair/typebox";
|
||||
import { ModuleHelper } from "./ModuleHelper";
|
||||
const { Type } = tbbox;
|
||||
import { s, mark, stripMark } from "core/object/schema";
|
||||
|
||||
export type { ModuleBuildContext };
|
||||
|
||||
export const MODULES = {
|
||||
server: AppServer,
|
||||
data: AppData,
|
||||
data: AppData, // @todo:
|
||||
auth: AppAuth,
|
||||
media: AppMedia,
|
||||
flows: AppFlows,
|
||||
flows: AppFlows, // @todo:
|
||||
} as const;
|
||||
|
||||
// get names of MODULES as an array
|
||||
@@ -53,7 +44,7 @@ export type ModuleSchemas = {
|
||||
};
|
||||
|
||||
export type ModuleConfigs = {
|
||||
[K in keyof ModuleSchemas]: Static<ModuleSchemas[K]>;
|
||||
[K in keyof ModuleSchemas]: s.Static<ModuleSchemas[K]>;
|
||||
};
|
||||
type PartialRec<T> = { [P in keyof T]?: PartialRec<T[P]> };
|
||||
|
||||
@@ -101,14 +92,14 @@ export type ConfigTable<Json = ModuleConfigs> = {
|
||||
updated_at?: Date;
|
||||
};
|
||||
|
||||
const configJsonSchema = Type.Union([
|
||||
const configJsonSchema = s.anyOf([
|
||||
getDefaultSchema(),
|
||||
Type.Array(
|
||||
Type.Object({
|
||||
t: StringEnum(["a", "r", "e"]),
|
||||
p: Type.Array(Type.Union([Type.String(), Type.Number()])),
|
||||
o: Type.Optional(Type.Any()),
|
||||
n: Type.Optional(Type.Any()),
|
||||
s.array(
|
||||
s.strictObject({
|
||||
t: s.string({ enum: ["a", "r", "e"] }),
|
||||
p: s.array(s.anyOf([s.string(), s.number()])),
|
||||
o: s.any().optional(),
|
||||
n: s.any().optional(),
|
||||
}),
|
||||
),
|
||||
]);
|
||||
@@ -717,7 +708,8 @@ export function getDefaultSchema() {
|
||||
|
||||
export function getDefaultConfig(): ModuleConfigs {
|
||||
const config = transformObject(MODULES, (module) => {
|
||||
return Default(module.prototype.getSchema(), {});
|
||||
return module.prototype.getSchema().template();
|
||||
//return Default(module.prototype.getSchema(), {});
|
||||
});
|
||||
|
||||
return config as any;
|
||||
|
||||
@@ -1,37 +1,27 @@
|
||||
import { Exception, isDebug, $console } from "core";
|
||||
import { type Static, StringEnum } from "core/utils";
|
||||
import { cors } from "hono/cors";
|
||||
import { Module } from "modules/Module";
|
||||
import * as tbbox from "@sinclair/typebox";
|
||||
import { AuthException } from "auth/errors";
|
||||
const { Type } = tbbox;
|
||||
import { s } from "core/object/schema";
|
||||
|
||||
const serverMethods = ["GET", "POST", "PATCH", "PUT", "DELETE"];
|
||||
const serverMethods = ["GET", "POST", "PATCH", "PUT", "DELETE"] as const;
|
||||
|
||||
export const serverConfigSchema = Type.Object(
|
||||
{
|
||||
cors: Type.Object(
|
||||
{
|
||||
origin: Type.String({ default: "*" }),
|
||||
allow_methods: Type.Array(StringEnum(serverMethods), {
|
||||
default: serverMethods,
|
||||
uniqueItems: true,
|
||||
}),
|
||||
allow_headers: Type.Array(Type.String(), {
|
||||
default: ["Content-Type", "Content-Length", "Authorization", "Accept"],
|
||||
}),
|
||||
},
|
||||
{ default: {}, additionalProperties: false },
|
||||
),
|
||||
},
|
||||
{
|
||||
additionalProperties: false,
|
||||
},
|
||||
);
|
||||
export const serverConfigSchema = s.strictObject({
|
||||
cors: s.strictObject({
|
||||
origin: s.string({ default: "*" }),
|
||||
allow_methods: s.array(s.string({ enum: serverMethods }), {
|
||||
default: serverMethods,
|
||||
uniqueItems: true,
|
||||
}),
|
||||
allow_headers: s.array(s.string(), {
|
||||
default: ["Content-Type", "Content-Length", "Authorization", "Accept"],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export type AppServerConfig = Static<typeof serverConfigSchema>;
|
||||
export type AppServerConfig = s.Static<typeof serverConfigSchema>;
|
||||
|
||||
export class AppServer extends Module<typeof serverConfigSchema> {
|
||||
export class AppServer extends Module<AppServerConfig> {
|
||||
override getRestrictedPaths() {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import type { App } from "App";
|
||||
import { $console, tbValidator as tb } from "core";
|
||||
import {
|
||||
StringEnum,
|
||||
TypeInvalidError,
|
||||
datetimeStringLocal,
|
||||
datetimeStringUTC,
|
||||
getTimezone,
|
||||
getTimezoneOffset,
|
||||
} from "core/utils";
|
||||
import { $console } from "core";
|
||||
import { datetimeStringLocal, datetimeStringUTC, getTimezone, getTimezoneOffset } from "core/utils";
|
||||
import { getRuntimeKey } from "core/utils";
|
||||
import type { Context, Hono } from "hono";
|
||||
import { Controller } from "modules/Controller";
|
||||
@@ -20,11 +13,11 @@ import {
|
||||
type ModuleConfigs,
|
||||
type ModuleSchemas,
|
||||
type ModuleKey,
|
||||
getDefaultConfig,
|
||||
} from "modules/ModuleManager";
|
||||
import * as SystemPermissions from "modules/permissions";
|
||||
import { jsc, s, describeRoute } from "core/object/schema";
|
||||
import { jsc, s, describeRoute, InvalidSchemaError } from "core/object/schema";
|
||||
import { getVersion } from "core/env";
|
||||
|
||||
export type ConfigUpdate<Key extends ModuleKey = ModuleKey> = {
|
||||
success: true;
|
||||
module: Key;
|
||||
@@ -104,7 +97,7 @@ export class SystemController extends Controller {
|
||||
} catch (e) {
|
||||
$console.error("config update error", e);
|
||||
|
||||
if (e instanceof TypeInvalidError) {
|
||||
if (e instanceof InvalidSchemaError) {
|
||||
return c.json(
|
||||
{ success: false, type: "type-invalid", errors: e.errors },
|
||||
{ status: 400 },
|
||||
@@ -234,11 +227,13 @@ export class SystemController extends Controller {
|
||||
permission(SystemPermissions.schemaRead),
|
||||
jsc(
|
||||
"query",
|
||||
s.partialObject({
|
||||
config: s.boolean(),
|
||||
secrets: s.boolean(),
|
||||
fresh: s.boolean(),
|
||||
}),
|
||||
s
|
||||
.object({
|
||||
config: s.boolean(),
|
||||
secrets: s.boolean(),
|
||||
fresh: s.boolean(),
|
||||
})
|
||||
.partial(),
|
||||
),
|
||||
async (c) => {
|
||||
const module = c.req.param("module") as ModuleKey | undefined;
|
||||
|
||||
Reference in New Issue
Block a user