mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 12:37:20 +00:00
added auth strategies migration, fixed rebuild of modules on migrations
This commit is contained in:
@@ -33,7 +33,7 @@ export const AppEvents = { AppConfigUpdatedEvent, AppBuiltEvent, AppFirstBoot }
|
||||
|
||||
export type AppOptions = {
|
||||
plugins?: AppPlugin[];
|
||||
seed?: (ctx: ModuleBuildContext) => Promise<void>;
|
||||
seed?: (ctx: ModuleBuildContext & { app: App }) => Promise<void>;
|
||||
manager?: Omit<ModuleManagerOptions, "initial" | "onUpdated" | "seed">;
|
||||
};
|
||||
export type CreateAppConfig = {
|
||||
@@ -67,7 +67,6 @@ export class App {
|
||||
this.modules = new ModuleManager(connection, {
|
||||
...(options?.manager ?? {}),
|
||||
initial: _initialConfig,
|
||||
seed: options?.seed,
|
||||
onUpdated: async (key, config) => {
|
||||
// if the EventManager was disabled, we assume we shouldn't
|
||||
// respond to events, such as "onUpdated".
|
||||
@@ -115,15 +114,18 @@ export class App {
|
||||
await Promise.all(this.plugins.map((plugin) => plugin(this)));
|
||||
}
|
||||
|
||||
$console.log("App built");
|
||||
await this.emgr.emit(new AppBuiltEvent({ app: this }));
|
||||
|
||||
// first boot is set from ModuleManager when there wasn't a config table
|
||||
if (this.trigger_first_boot) {
|
||||
this.trigger_first_boot = false;
|
||||
await this.emgr.emit(new AppFirstBoot({ app: this }));
|
||||
await this.options?.seed?.({
|
||||
...this.modules.ctx(),
|
||||
app: this,
|
||||
});
|
||||
}
|
||||
|
||||
$console.log("App built");
|
||||
}
|
||||
|
||||
mutateConfig<Module extends keyof Modules>(module: Module) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
type Strategy,
|
||||
} from "auth";
|
||||
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
||||
import { type DB, Exception, type PrimaryFieldType } from "core";
|
||||
import { $console, type DB, Exception, type PrimaryFieldType } from "core";
|
||||
import { type Static, secureRandomString, transformObject } from "core/utils";
|
||||
import type { Entity, EntityManager } from "data";
|
||||
import { type FieldSchema, em, entity, enumm, text } from "data/prototype";
|
||||
@@ -41,6 +41,12 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: password strategy is required atm
|
||||
if (!to.strategies?.password?.enabled) {
|
||||
$console.warn("Password strategy cannot be disabled.");
|
||||
to.strategies!.password!.enabled = true;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@@ -89,6 +95,9 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
|
||||
isStrategyEnabled(strategy: Strategy | string) {
|
||||
const name = typeof strategy === "string" ? strategy : strategy.getName();
|
||||
// for now, password is always active
|
||||
if (name === "password") return true;
|
||||
|
||||
return this.config.strategies?.[name]?.enabled ?? false;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,14 +252,12 @@ export class DataController extends Controller {
|
||||
tb("param", Type.Object({ entity: Type.String() })),
|
||||
tb("query", querySchema),
|
||||
async (c) => {
|
||||
//console.log("request", c.req.raw);
|
||||
const { entity } = c.req.param();
|
||||
if (!this.entityExists(entity)) {
|
||||
console.warn("not found:", entity, definedEntities);
|
||||
return this.notFound(c);
|
||||
}
|
||||
const options = c.req.valid("query") as RepoQuery;
|
||||
//console.log("before", this.ctx.emgr.Events);
|
||||
const result = await this.em.repository(entity).findMany(options);
|
||||
|
||||
return c.json(this.repoResult(result), { status: result.data ? 200 : 404 });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Guard } from "auth";
|
||||
import { BkndError, DebugLogger, withDisabledConsole } from "core";
|
||||
import { $console, BkndError, DebugLogger, withDisabledConsole } from "core";
|
||||
import { EventManager } from "core/events";
|
||||
import { clone, diff } from "core/object/diff";
|
||||
import {
|
||||
@@ -153,7 +153,6 @@ export class ModuleManager {
|
||||
this.modules = {} as Modules;
|
||||
this.emgr = new EventManager();
|
||||
this.logger = new DebugLogger(this.verbosity === Verbosity.log);
|
||||
const context = this.ctx(true);
|
||||
let initial = {} as Partial<ModuleConfigs>;
|
||||
|
||||
if (options?.initial) {
|
||||
@@ -169,15 +168,29 @@ export class ModuleManager {
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in MODULES) {
|
||||
const moduleConfig = key in initial ? initial[key] : {};
|
||||
const module = new MODULES[key](moduleConfig, context) as Module;
|
||||
module.setListener(async (c) => {
|
||||
await this.onModuleConfigUpdated(key, c);
|
||||
});
|
||||
this.createModules(initial);
|
||||
}
|
||||
|
||||
this.modules[key] = module;
|
||||
private createModules(initial: Partial<ModuleConfigs>) {
|
||||
this.logger.context("createModules").log("creating modules");
|
||||
try {
|
||||
const context = this.ctx(true);
|
||||
|
||||
for (const key in MODULES) {
|
||||
const moduleConfig = key in initial ? initial[key] : {};
|
||||
const module = new MODULES[key](moduleConfig, context) as Module;
|
||||
module.setListener(async (c) => {
|
||||
await this.onModuleConfigUpdated(key, c);
|
||||
});
|
||||
|
||||
this.modules[key] = module;
|
||||
}
|
||||
this.logger.log("modules created");
|
||||
} catch (e) {
|
||||
this.logger.log("failed to create modules", e);
|
||||
throw e;
|
||||
}
|
||||
this.logger.clear();
|
||||
}
|
||||
|
||||
private get verbosity() {
|
||||
@@ -197,7 +210,7 @@ export class ModuleManager {
|
||||
if (this.options?.onUpdated) {
|
||||
await this.options.onUpdated(key as any, config);
|
||||
} else {
|
||||
this.buildModules();
|
||||
await this.buildModules();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,15 +381,27 @@ export class ModuleManager {
|
||||
}
|
||||
|
||||
private async migrate() {
|
||||
const state = {
|
||||
success: false,
|
||||
migrated: false,
|
||||
version: {
|
||||
before: this.version(),
|
||||
after: this.version(),
|
||||
},
|
||||
};
|
||||
this.logger.context("migrate").log("migrating?", this.version(), CURRENT_VERSION);
|
||||
|
||||
if (this.version() < CURRENT_VERSION) {
|
||||
state.version.before = this.version();
|
||||
|
||||
this.logger.log("there are migrations, verify version");
|
||||
// sync __bknd table
|
||||
await this.syncConfigTable();
|
||||
|
||||
// modules must be built before migration
|
||||
this.logger.log("building modules");
|
||||
await this.buildModules({ graceful: true });
|
||||
this.logger.log("modules built");
|
||||
|
||||
try {
|
||||
const state = await this.fetch();
|
||||
@@ -405,17 +430,27 @@ export class ModuleManager {
|
||||
version = _version;
|
||||
configs = _configs;
|
||||
|
||||
this.setConfigs(configs);
|
||||
|
||||
this._version = version;
|
||||
state.version.after = version;
|
||||
state.migrated = true;
|
||||
this.ctx().flags.sync_required = true;
|
||||
|
||||
this.logger.log("setting configs");
|
||||
this.createModules(configs);
|
||||
await this.buildModules();
|
||||
|
||||
this.logger.log("migrated to", version);
|
||||
$console.log("Migrated config from", state.version.before, "to", state.version.after);
|
||||
|
||||
await this.save();
|
||||
} else {
|
||||
this.logger.log("no migrations needed");
|
||||
}
|
||||
|
||||
state.success = true;
|
||||
this.logger.clear();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private setConfigs(configs: ModuleConfigs): void {
|
||||
@@ -480,10 +515,16 @@ export class ModuleManager {
|
||||
}
|
||||
|
||||
// migrate to latest if needed
|
||||
await this.migrate();
|
||||
this.logger.log("check migrate");
|
||||
const migration = await this.migrate();
|
||||
if (migration.success && migration.migrated) {
|
||||
this.logger.log("skipping build after migration");
|
||||
} else {
|
||||
this.logger.log("trigger build modules");
|
||||
await this.buildModules();
|
||||
}
|
||||
|
||||
this.logger.log("building");
|
||||
await this.buildModules();
|
||||
this.logger.log("done");
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -496,7 +537,7 @@ export class ModuleManager {
|
||||
reloaded: false,
|
||||
};
|
||||
|
||||
this.logger.log("buildModules() triggered", options, this._built);
|
||||
this.logger.context("buildModules").log("triggered", options, this._built);
|
||||
if (options?.graceful && this._built) {
|
||||
this.logger.log("skipping build (graceful)");
|
||||
return state;
|
||||
@@ -536,8 +577,10 @@ export class ModuleManager {
|
||||
}
|
||||
|
||||
// reset all falgs
|
||||
this.logger.log("resetting flags");
|
||||
ctx.flags = Module.ctx_flags;
|
||||
|
||||
this.logger.clear();
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { _jsonp } from "core/utils";
|
||||
import { _jsonp, transformObject } from "core/utils";
|
||||
import { type Kysely, sql } from "kysely";
|
||||
import { set } from "lodash-es";
|
||||
|
||||
@@ -72,13 +72,25 @@ export const migrations: Migration[] = [
|
||||
};
|
||||
},
|
||||
},
|
||||
/*{
|
||||
{
|
||||
version: 8,
|
||||
up: async (config, { db }) => {
|
||||
await db.deleteFrom(TABLE_NAME).where("type", "=", "diff").execute();
|
||||
return config;
|
||||
}
|
||||
}*/
|
||||
up: async (config) => {
|
||||
const strategies = transformObject(config.auth.strategies, (strategy) => {
|
||||
return {
|
||||
...strategy,
|
||||
enabled: true,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...config,
|
||||
auth: {
|
||||
...config.auth,
|
||||
strategies: strategies,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const CURRENT_VERSION = migrations[migrations.length - 1]?.version ?? 0;
|
||||
|
||||
@@ -238,7 +238,6 @@ export function FormContextOverride({
|
||||
...overrides,
|
||||
...additional,
|
||||
};
|
||||
console.log("context", context);
|
||||
|
||||
return <FormContext.Provider value={context}>{children}</FormContext.Provider>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user