mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
update & fix typing, updated examples
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"bin": "./dist/cli/index.js",
|
"bin": "./dist/cli/index.js",
|
||||||
"version": "0.3.4-alpha1",
|
"version": "0.4.0-rc1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:all": "NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli",
|
"build:all": "NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export class Api {
|
|||||||
private token_transport: "header" | "cookie" | "none" = "header";
|
private token_transport: "header" | "cookie" | "none" = "header";
|
||||||
|
|
||||||
public system!: SystemApi;
|
public system!: SystemApi;
|
||||||
public data!: DataApi<DB>;
|
public data!: DataApi;
|
||||||
public auth!: AuthApi;
|
public auth!: AuthApi;
|
||||||
public media!: MediaApi;
|
public media!: MediaApi;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as SystemPermissions from "modules/permissions";
|
|||||||
import { AdminController, type AdminControllerOptions } from "modules/server/AdminController";
|
import { AdminController, type AdminControllerOptions } from "modules/server/AdminController";
|
||||||
import { SystemController } from "modules/server/SystemController";
|
import { SystemController } from "modules/server/SystemController";
|
||||||
|
|
||||||
export type AppPlugin<DB> = (app: App<DB>) => void;
|
export type AppPlugin = (app: App) => void;
|
||||||
|
|
||||||
abstract class AppEvent<A = {}> extends Event<{ app: App } & A> {}
|
abstract class AppEvent<A = {}> extends Event<{ app: App } & A> {}
|
||||||
export class AppConfigUpdatedEvent extends AppEvent {
|
export class AppConfigUpdatedEvent extends AppEvent {
|
||||||
@@ -32,13 +32,13 @@ export type CreateAppConfig = {
|
|||||||
config: LibSqlCredentials;
|
config: LibSqlCredentials;
|
||||||
};
|
};
|
||||||
initialConfig?: InitialModuleConfigs;
|
initialConfig?: InitialModuleConfigs;
|
||||||
plugins?: AppPlugin<any>[];
|
plugins?: AppPlugin[];
|
||||||
options?: Omit<ModuleManagerOptions, "initial" | "onUpdated">;
|
options?: Omit<ModuleManagerOptions, "initial" | "onUpdated">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AppConfig = InitialModuleConfigs;
|
export type AppConfig = InitialModuleConfigs;
|
||||||
|
|
||||||
export class App<DB = any> {
|
export class App {
|
||||||
modules: ModuleManager;
|
modules: ModuleManager;
|
||||||
static readonly Events = AppEvents;
|
static readonly Events = AppEvents;
|
||||||
adminController?: AdminController;
|
adminController?: AdminController;
|
||||||
@@ -47,7 +47,7 @@ export class App<DB = any> {
|
|||||||
constructor(
|
constructor(
|
||||||
private connection: Connection,
|
private connection: Connection,
|
||||||
_initialConfig?: InitialModuleConfigs,
|
_initialConfig?: InitialModuleConfigs,
|
||||||
private plugins: AppPlugin<DB>[] = [],
|
private plugins: AppPlugin[] = [],
|
||||||
moduleManagerOptions?: ModuleManagerOptions
|
moduleManagerOptions?: ModuleManagerOptions
|
||||||
) {
|
) {
|
||||||
this.modules = new ModuleManager(connection, {
|
this.modules = new ModuleManager(connection, {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type AuthAction, Authenticator, type ProfileExchange, Role, type Strategy } from "auth";
|
import { type AuthAction, Authenticator, type ProfileExchange, Role, type Strategy } from "auth";
|
||||||
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
||||||
import { Exception } from "core";
|
import { Exception, type PrimaryFieldType } from "core";
|
||||||
import { type Static, secureRandomString, transformObject } from "core/utils";
|
import { type Static, secureRandomString, transformObject } from "core/utils";
|
||||||
import { type Entity, EntityIndex, type EntityManager } from "data";
|
import { type Entity, EntityIndex, type EntityManager } from "data";
|
||||||
import { type FieldSchema, entity, enumm, make, text } from "data/prototype";
|
import { type FieldSchema, entity, enumm, make, text } from "data/prototype";
|
||||||
@@ -10,9 +10,9 @@ import { AuthController } from "./api/AuthController";
|
|||||||
import { type AppAuthSchema, STRATEGIES, authConfigSchema } from "./auth-schema";
|
import { type AppAuthSchema, STRATEGIES, authConfigSchema } from "./auth-schema";
|
||||||
|
|
||||||
export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>;
|
export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>;
|
||||||
declare global {
|
declare module "core" {
|
||||||
interface DB {
|
interface DB {
|
||||||
users: UserFieldSchema;
|
users: { id: PrimaryFieldType } & UserFieldSchema;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
return this._authenticator!;
|
return this._authenticator!;
|
||||||
}
|
}
|
||||||
|
|
||||||
get em(): EntityManager<DB> {
|
get em(): EntityManager {
|
||||||
return this.ctx.em as any;
|
return this.ctx.em as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,9 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
|
|
||||||
const users = this.getUsersEntity();
|
const users = this.getUsersEntity();
|
||||||
this.toggleStrategyValueVisibility(true);
|
this.toggleStrategyValueVisibility(true);
|
||||||
const result = await this.em.repo(users).findOne({ email: profile.email! });
|
const result = await this.em
|
||||||
|
.repo(users as unknown as "users")
|
||||||
|
.findOne({ email: profile.email! });
|
||||||
this.toggleStrategyValueVisibility(false);
|
this.toggleStrategyValueVisibility(false);
|
||||||
if (!result.data) {
|
if (!result.data) {
|
||||||
throw new Exception("User not found", 404);
|
throw new Exception("User not found", 404);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { password as $password, text as $text } from "@clack/prompts";
|
import { password as $password, text as $text } from "@clack/prompts";
|
||||||
|
import type { App } from "App";
|
||||||
|
import type { BkndConfig } from "adapter";
|
||||||
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
||||||
import type { App, BkndConfig } from "bknd";
|
|
||||||
import { makeConfigApp } from "cli/commands/run";
|
import { makeConfigApp } from "cli/commands/run";
|
||||||
import { getConfigPath } from "cli/commands/run/platform";
|
import { getConfigPath } from "cli/commands/run/platform";
|
||||||
import type { CliCommand } from "cli/types";
|
import type { CliCommand } from "cli/types";
|
||||||
@@ -37,7 +38,7 @@ async function action(action: "create" | "update", options: any) {
|
|||||||
async function create(app: App, options: any) {
|
async function create(app: App, options: any) {
|
||||||
const config = app.module.auth.toJSON(true);
|
const config = app.module.auth.toJSON(true);
|
||||||
const strategy = app.module.auth.authenticator.strategy("password") as PasswordStrategy;
|
const strategy = app.module.auth.authenticator.strategy("password") as PasswordStrategy;
|
||||||
const users_entity = config.entity_name;
|
const users_entity = config.entity_name as "users";
|
||||||
|
|
||||||
const email = await $text({
|
const email = await $text({
|
||||||
message: "Enter email",
|
message: "Enter email",
|
||||||
@@ -83,7 +84,7 @@ async function create(app: App, options: any) {
|
|||||||
async function update(app: App, options: any) {
|
async function update(app: App, options: any) {
|
||||||
const config = app.module.auth.toJSON(true);
|
const config = app.module.auth.toJSON(true);
|
||||||
const strategy = app.module.auth.authenticator.strategy("password") as PasswordStrategy;
|
const strategy = app.module.auth.authenticator.strategy("password") as PasswordStrategy;
|
||||||
const users_entity = config.entity_name;
|
const users_entity = config.entity_name as "users";
|
||||||
const em = app.modules.ctx().em;
|
const em = app.modules.ctx().em;
|
||||||
|
|
||||||
const email = (await $text({
|
const email = (await $text({
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import type { Generated } from "kysely";
|
|||||||
|
|
||||||
export type PrimaryFieldType = number | Generated<number>;
|
export type PrimaryFieldType = number | Generated<number>;
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noEmptyInterface: <explanation>
|
||||||
|
export interface DB {}
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
data: {
|
data: {
|
||||||
default_primary_field: "id"
|
default_primary_field: "id"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Hono, MiddlewareHandler } from "hono";
|
|||||||
export { tbValidator } from "./server/lib/tbValidator";
|
export { tbValidator } from "./server/lib/tbValidator";
|
||||||
export { Exception, BkndError } from "./errors";
|
export { Exception, BkndError } from "./errors";
|
||||||
export { isDebug } from "./env";
|
export { isDebug } from "./env";
|
||||||
export { type PrimaryFieldType, config } from "./config";
|
export { type PrimaryFieldType, config, type DB } from "./config";
|
||||||
export { AwsClient } from "./clients/aws/AwsClient";
|
export { AwsClient } from "./clients/aws/AwsClient";
|
||||||
export {
|
export {
|
||||||
SimpleRenderer,
|
SimpleRenderer,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Module } from "modules/Module";
|
|||||||
import { DataController } from "./api/DataController";
|
import { DataController } from "./api/DataController";
|
||||||
import { type AppDataConfig, dataConfigSchema } from "./data-schema";
|
import { type AppDataConfig, dataConfigSchema } from "./data-schema";
|
||||||
|
|
||||||
export class AppData<DB> extends Module<typeof dataConfigSchema> {
|
export class AppData extends Module<typeof dataConfigSchema> {
|
||||||
override async build() {
|
override async build() {
|
||||||
const entities = transformObject(this.config.entities ?? {}, (entityConfig, name) => {
|
const entities = transformObject(this.config.entities ?? {}, (entityConfig, name) => {
|
||||||
return constructEntity(name, entityConfig);
|
return constructEntity(name, entityConfig);
|
||||||
@@ -59,7 +59,7 @@ export class AppData<DB> extends Module<typeof dataConfigSchema> {
|
|||||||
return dataConfigSchema;
|
return dataConfigSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
get em(): EntityManager<DB> {
|
get em(): EntityManager {
|
||||||
this.throwIfNotBuilt();
|
this.throwIfNotBuilt();
|
||||||
return this.ctx.em;
|
return this.ctx.em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { DB } from "core";
|
||||||
import type { EntityData, RepoQuery, RepositoryResponse } from "data";
|
import type { EntityData, RepoQuery, RepositoryResponse } from "data";
|
||||||
import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules";
|
import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules";
|
||||||
|
|
||||||
@@ -5,7 +6,7 @@ export type DataApiOptions = BaseModuleApiOptions & {
|
|||||||
defaultQuery?: Partial<RepoQuery>;
|
defaultQuery?: Partial<RepoQuery>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DataApi<DB> extends ModuleApi<DataApiOptions> {
|
export class DataApi extends ModuleApi<DataApiOptions> {
|
||||||
protected override getDefaultOptions(): Partial<DataApiOptions> {
|
protected override getDefaultOptions(): Partial<DataApiOptions> {
|
||||||
return {
|
return {
|
||||||
basepath: "/api/data",
|
basepath: "/api/data",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { DB as DefaultDB } from "core";
|
||||||
import { EventManager } from "core/events";
|
import { EventManager } from "core/events";
|
||||||
import { sql } from "kysely";
|
import { sql } from "kysely";
|
||||||
import { Connection } from "../connection/Connection";
|
import { Connection } from "../connection/Connection";
|
||||||
@@ -14,15 +15,18 @@ import { SchemaManager } from "../schema/SchemaManager";
|
|||||||
import { Entity } from "./Entity";
|
import { Entity } from "./Entity";
|
||||||
import { type EntityData, Mutator, Repository } from "./index";
|
import { type EntityData, Mutator, Repository } from "./index";
|
||||||
|
|
||||||
type EntitySchema<E extends Entity | string, DB = any> = E extends Entity<infer Name>
|
type EntitySchema<
|
||||||
? Name extends keyof DB
|
TBD extends object = DefaultDB,
|
||||||
|
E extends Entity | keyof TBD | string = string
|
||||||
|
> = E extends Entity<infer Name>
|
||||||
|
? Name extends keyof TBD
|
||||||
? Name
|
? Name
|
||||||
: never
|
: never
|
||||||
: E extends keyof DB
|
: E extends keyof TBD
|
||||||
? E
|
? E
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
export class EntityManager<DB> {
|
export class EntityManager<TBD extends object = DefaultDB> {
|
||||||
connection: Connection;
|
connection: Connection;
|
||||||
|
|
||||||
private _entities: Entity[] = [];
|
private _entities: Entity[] = [];
|
||||||
@@ -58,7 +62,7 @@ export class EntityManager<DB> {
|
|||||||
* Forks the EntityManager without the EventManager.
|
* Forks the EntityManager without the EventManager.
|
||||||
* This is useful when used inside an event handler.
|
* This is useful when used inside an event handler.
|
||||||
*/
|
*/
|
||||||
fork(): EntityManager<DB> {
|
fork(): EntityManager {
|
||||||
return new EntityManager(this._entities, this.connection, this._relations, this._indices);
|
return new EntityManager(this._entities, this.connection, this._relations, this._indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,16 +99,17 @@ export class EntityManager<DB> {
|
|||||||
this.entities.push(entity);
|
this.entities.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
entity(e: Entity | string): Entity {
|
entity(e: Entity | keyof TBD | string): Entity {
|
||||||
let entity: Entity | undefined;
|
let entity: Entity | undefined;
|
||||||
if (typeof e === "string") {
|
if (typeof e === "string") {
|
||||||
entity = this.entities.find((entity) => entity.name === e);
|
entity = this.entities.find((entity) => entity.name === e);
|
||||||
} else {
|
} else if (e instanceof Entity) {
|
||||||
entity = e;
|
entity = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
throw new EntityNotDefinedException(typeof e === "string" ? e : e.name);
|
// @ts-ignore
|
||||||
|
throw new EntityNotDefinedException(e instanceof Entity ? e.name : e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
@@ -176,15 +181,17 @@ export class EntityManager<DB> {
|
|||||||
return this.relations.relationReferencesOf(this.entity(entity_name));
|
return this.relations.relationReferencesOf(this.entity(entity_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
repository<E extends Entity | string>(entity: E): Repository<DB, EntitySchema<E, DB>> {
|
repository<E extends Entity | keyof TBD | string>(
|
||||||
|
entity: E
|
||||||
|
): Repository<TBD, EntitySchema<TBD, E>> {
|
||||||
return this.repo(entity);
|
return this.repo(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
repo<E extends Entity | string>(entity: E): Repository<DB, EntitySchema<E, DB>> {
|
repo<E extends Entity | keyof TBD | string>(entity: E): Repository<TBD, EntitySchema<TBD, E>> {
|
||||||
return new Repository(this, this.entity(entity), this.emgr);
|
return new Repository(this, this.entity(entity), this.emgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutator<E extends Entity | string>(entity: E): Mutator<DB, EntitySchema<E, DB>> {
|
mutator<E extends Entity | keyof TBD | string>(entity: E): Mutator<TBD, EntitySchema<TBD, E>> {
|
||||||
return new Mutator(this, this.entity(entity), this.emgr);
|
return new Mutator(this, this.entity(entity), this.emgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PrimaryFieldType } from "core";
|
import type { DB as DefaultDB, PrimaryFieldType } from "core";
|
||||||
import { type EmitsEvents, EventManager } from "core/events";
|
import { type EmitsEvents, EventManager } from "core/events";
|
||||||
import type { DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from "kysely";
|
import type { DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from "kysely";
|
||||||
import { type TActionContext, WhereBuilder } from "..";
|
import { type TActionContext, WhereBuilder } from "..";
|
||||||
@@ -26,13 +26,13 @@ export type MutatorResponse<T = EntityData[]> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class Mutator<
|
export class Mutator<
|
||||||
DB = any,
|
TBD extends object = DefaultDB,
|
||||||
TB extends keyof DB = any,
|
TB extends keyof TBD = any,
|
||||||
Output = DB[TB],
|
Output = TBD[TB],
|
||||||
Input = Omit<Output, "id">
|
Input = Omit<Output, "id">
|
||||||
> implements EmitsEvents
|
> implements EmitsEvents
|
||||||
{
|
{
|
||||||
em: EntityManager<DB>;
|
em: EntityManager<TBD>;
|
||||||
entity: Entity;
|
entity: Entity;
|
||||||
static readonly Events = MutatorEvents;
|
static readonly Events = MutatorEvents;
|
||||||
emgr: EventManager<typeof MutatorEvents>;
|
emgr: EventManager<typeof MutatorEvents>;
|
||||||
@@ -43,7 +43,7 @@ export class Mutator<
|
|||||||
this.__unstable_disable_system_entity_creation = value;
|
this.__unstable_disable_system_entity_creation = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(em: EntityManager<DB>, entity: Entity, emgr?: EventManager<any>) {
|
constructor(em: EntityManager<TBD>, entity: Entity, emgr?: EventManager<any>) {
|
||||||
this.em = em;
|
this.em = em;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.emgr = emgr ?? new EventManager(MutatorEvents);
|
this.emgr = emgr ?? new EventManager(MutatorEvents);
|
||||||
@@ -163,7 +163,7 @@ export class Mutator<
|
|||||||
return res as any;
|
return res as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOne(id: PrimaryFieldType, data: Input): Promise<MutatorResponse<Output>> {
|
async updateOne(id: PrimaryFieldType, data: Partial<Input>): Promise<MutatorResponse<Output>> {
|
||||||
const entity = this.entity;
|
const entity = this.entity;
|
||||||
if (!Number.isInteger(id)) {
|
if (!Number.isInteger(id)) {
|
||||||
throw new Error("ID must be provided for update");
|
throw new Error("ID must be provided for update");
|
||||||
@@ -270,7 +270,10 @@ export class Mutator<
|
|||||||
return (await this.many(qb)) as any;
|
return (await this.many(qb)) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateWhere(data: Partial<Input>, where?: RepoQuery["where"]): Promise<MutatorResponse<Output[]>> {
|
async updateWhere(
|
||||||
|
data: Partial<Input>,
|
||||||
|
where?: RepoQuery["where"]
|
||||||
|
): Promise<MutatorResponse<Output[]>> {
|
||||||
const entity = this.entity;
|
const entity = this.entity;
|
||||||
const validatedData = await this.getValidatedData(data, "update");
|
const validatedData = await this.getValidatedData(data, "update");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PrimaryFieldType } from "core";
|
import type { DB as DefaultDB, PrimaryFieldType } from "core";
|
||||||
import { type EmitsEvents, EventManager } from "core/events";
|
import { type EmitsEvents, EventManager } from "core/events";
|
||||||
import { type SelectQueryBuilder, sql } from "kysely";
|
import { type SelectQueryBuilder, sql } from "kysely";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
@@ -43,13 +43,15 @@ export type RepositoryExistsResponse = RepositoryRawResponse & {
|
|||||||
exists: boolean;
|
exists: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Repository<DB = any, TB extends keyof DB = any> implements EmitsEvents {
|
export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = any>
|
||||||
em: EntityManager<DB>;
|
implements EmitsEvents
|
||||||
|
{
|
||||||
|
em: EntityManager<TBD>;
|
||||||
entity: Entity;
|
entity: Entity;
|
||||||
static readonly Events = RepositoryEvents;
|
static readonly Events = RepositoryEvents;
|
||||||
emgr: EventManager<typeof Repository.Events>;
|
emgr: EventManager<typeof Repository.Events>;
|
||||||
|
|
||||||
constructor(em: EntityManager<DB>, entity: Entity, emgr?: EventManager<any>) {
|
constructor(em: EntityManager<TBD>, entity: Entity, emgr?: EventManager<any>) {
|
||||||
this.em = em;
|
this.em = em;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.emgr = emgr ?? new EventManager(MutatorEvents);
|
this.emgr = emgr ?? new EventManager(MutatorEvents);
|
||||||
@@ -272,7 +274,7 @@ export class Repository<DB = any, TB extends keyof DB = any> implements EmitsEve
|
|||||||
async findId(
|
async findId(
|
||||||
id: PrimaryFieldType,
|
id: PrimaryFieldType,
|
||||||
_options?: Partial<Omit<RepoQuery, "where" | "limit" | "offset">>
|
_options?: Partial<Omit<RepoQuery, "where" | "limit" | "offset">>
|
||||||
): Promise<RepositoryResponse<DB[TB] | undefined>> {
|
): Promise<RepositoryResponse<TBD[TB] | undefined>> {
|
||||||
const { qb, options } = this.buildQuery(
|
const { qb, options } = this.buildQuery(
|
||||||
{
|
{
|
||||||
..._options,
|
..._options,
|
||||||
@@ -288,7 +290,7 @@ export class Repository<DB = any, TB extends keyof DB = any> implements EmitsEve
|
|||||||
async findOne(
|
async findOne(
|
||||||
where: RepoQuery["where"],
|
where: RepoQuery["where"],
|
||||||
_options?: Partial<Omit<RepoQuery, "where" | "limit" | "offset">>
|
_options?: Partial<Omit<RepoQuery, "where" | "limit" | "offset">>
|
||||||
): Promise<RepositoryResponse<DB[TB] | undefined>> {
|
): Promise<RepositoryResponse<TBD[TB] | undefined>> {
|
||||||
const { qb, options } = this.buildQuery({
|
const { qb, options } = this.buildQuery({
|
||||||
..._options,
|
..._options,
|
||||||
where,
|
where,
|
||||||
@@ -298,7 +300,7 @@ export class Repository<DB = any, TB extends keyof DB = any> implements EmitsEve
|
|||||||
return this.single(qb, options) as any;
|
return this.single(qb, options) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findMany(_options?: Partial<RepoQuery>): Promise<RepositoryResponse<DB[TB][]>> {
|
async findMany(_options?: Partial<RepoQuery>): Promise<RepositoryResponse<TBD[TB][]>> {
|
||||||
const { qb, options } = this.buildQuery(_options);
|
const { qb, options } = this.buildQuery(_options);
|
||||||
//console.log("findMany:options", options);
|
//console.log("findMany:options", options);
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,15 @@
|
|||||||
|
import type { PrimaryFieldType } from "core";
|
||||||
import { EntityIndex, type EntityManager } from "data";
|
import { EntityIndex, type EntityManager } from "data";
|
||||||
import { type FileUploadedEventData, Storage, type StorageAdapter } from "media";
|
import { type FileUploadedEventData, Storage, type StorageAdapter } from "media";
|
||||||
import { Module } from "modules/Module";
|
import { Module } from "modules/Module";
|
||||||
import {
|
import { type FieldSchema, boolean, datetime, entity, json, number, text } from "../data/prototype";
|
||||||
type FieldSchema,
|
|
||||||
type InferFields,
|
|
||||||
type Schema,
|
|
||||||
boolean,
|
|
||||||
datetime,
|
|
||||||
entity,
|
|
||||||
json,
|
|
||||||
number,
|
|
||||||
text
|
|
||||||
} from "../data/prototype";
|
|
||||||
import { MediaController } from "./api/MediaController";
|
import { MediaController } from "./api/MediaController";
|
||||||
import { ADAPTERS, buildMediaSchema, type mediaConfigSchema, registry } from "./media-schema";
|
import { ADAPTERS, buildMediaSchema, type mediaConfigSchema, registry } from "./media-schema";
|
||||||
|
|
||||||
export type MediaFieldSchema = FieldSchema<typeof AppMedia.mediaFields>;
|
export type MediaFieldSchema = FieldSchema<typeof AppMedia.mediaFields>;
|
||||||
declare global {
|
declare module "core" {
|
||||||
interface DB {
|
interface DB {
|
||||||
media: MediaFieldSchema;
|
media: { id: PrimaryFieldType } & MediaFieldSchema;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,14 +103,14 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
|
|||||||
return this.em.entity(entity_name);
|
return this.em.entity(entity_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
get em(): EntityManager<DB> {
|
get em(): EntityManager {
|
||||||
return this.ctx.em;
|
return this.ctx.em;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupListeners() {
|
private setupListeners() {
|
||||||
//const media = this._entity;
|
//const media = this._entity;
|
||||||
const { emgr, em } = this.ctx;
|
const { emgr, em } = this.ctx;
|
||||||
const media = this.getMediaEntity();
|
const media = this.getMediaEntity().name as "media";
|
||||||
|
|
||||||
// when file is uploaded, sync with media entity
|
// when file is uploaded, sync with media entity
|
||||||
// @todo: need a way for singleton events!
|
// @todo: need a way for singleton events!
|
||||||
@@ -140,10 +131,10 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
|
|||||||
Storage.Events.FileDeletedEvent,
|
Storage.Events.FileDeletedEvent,
|
||||||
async (e) => {
|
async (e) => {
|
||||||
// simple file deletion sync
|
// simple file deletion sync
|
||||||
const item = await em.repo(media).findOne({ path: e.params.name });
|
const { data } = await em.repo(media).findOne({ path: e.params.name });
|
||||||
if (item.data) {
|
if (data) {
|
||||||
console.log("item.data", item.data);
|
console.log("item.data", data);
|
||||||
await em.mutator(media).deleteOne(item.data.id);
|
await em.mutator(media).deleteOne(data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("App:storage:file deleted", e);
|
console.log("App:storage:file deleted", e);
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import type { Static, TSchema } from "core/utils";
|
|||||||
import type { Connection, EntityManager } from "data";
|
import type { Connection, EntityManager } from "data";
|
||||||
import type { Hono } from "hono";
|
import type { Hono } from "hono";
|
||||||
|
|
||||||
export type ModuleBuildContext<DB = any> = {
|
export type ModuleBuildContext = {
|
||||||
connection: Connection;
|
connection: Connection;
|
||||||
server: Hono<any>;
|
server: Hono<any>;
|
||||||
em: EntityManager<DB>;
|
em: EntityManager;
|
||||||
emgr: EventManager<any>;
|
emgr: EventManager<any>;
|
||||||
guard: Guard;
|
guard: Guard;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Guard } from "auth";
|
import { Guard } from "auth";
|
||||||
import { BkndError, DebugLogger, Exception, isDebug } from "core";
|
import { BkndError, DebugLogger } from "core";
|
||||||
import { EventManager } from "core/events";
|
import { EventManager } from "core/events";
|
||||||
import { clone, diff } from "core/object/diff";
|
import { clone, diff } from "core/object/diff";
|
||||||
import {
|
import {
|
||||||
@@ -39,7 +39,7 @@ export type { ModuleBuildContext };
|
|||||||
|
|
||||||
export const MODULES = {
|
export const MODULES = {
|
||||||
server: AppServer,
|
server: AppServer,
|
||||||
data: AppData<any>,
|
data: AppData,
|
||||||
auth: AppAuth,
|
auth: AppAuth,
|
||||||
media: AppMedia,
|
media: AppMedia,
|
||||||
flows: AppFlows
|
flows: AppFlows
|
||||||
@@ -112,9 +112,9 @@ const __bknd = entity(TABLE_NAME, {
|
|||||||
updated_at: datetime()
|
updated_at: datetime()
|
||||||
});
|
});
|
||||||
type ConfigTable2 = Schema<typeof __bknd>;
|
type ConfigTable2 = Schema<typeof __bknd>;
|
||||||
type T_INTERNAL_EM = {
|
interface T_INTERNAL_EM {
|
||||||
__bknd: ConfigTable2;
|
__bknd: ConfigTable2;
|
||||||
};
|
}
|
||||||
|
|
||||||
// @todo: cleanup old diffs on upgrade
|
// @todo: cleanup old diffs on upgrade
|
||||||
// @todo: cleanup multiple backups on upgrade
|
// @todo: cleanup multiple backups on upgrade
|
||||||
@@ -123,7 +123,7 @@ export class ModuleManager {
|
|||||||
// internal em for __bknd config table
|
// internal em for __bknd config table
|
||||||
__em!: EntityManager<T_INTERNAL_EM>;
|
__em!: EntityManager<T_INTERNAL_EM>;
|
||||||
// ctx for modules
|
// ctx for modules
|
||||||
em!: EntityManager<any>;
|
em!: EntityManager;
|
||||||
server!: Hono;
|
server!: Hono;
|
||||||
emgr!: EventManager;
|
emgr!: EventManager;
|
||||||
guard!: Guard;
|
guard!: Guard;
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import type { DataApi } from "data/api/DataApi";
|
|
||||||
import { useApi } from "ui/client";
|
|
||||||
|
|
||||||
type OmitFirstArg<F> = F extends (x: any, ...args: infer P) => any
|
|
||||||
? (...args: P) => ReturnType<F>
|
|
||||||
: never;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps all DataApi functions and omits
|
|
||||||
* the first argument "entity" for convenience
|
|
||||||
* @param entity
|
|
||||||
*/
|
|
||||||
export const useData = <T extends keyof DataApi<DB>>(entity: string) => {
|
|
||||||
const api = useApi().data;
|
|
||||||
const methods = [
|
|
||||||
"readOne",
|
|
||||||
"readMany",
|
|
||||||
"readManyByReference",
|
|
||||||
"createOne",
|
|
||||||
"updateOne",
|
|
||||||
"deleteOne"
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
return methods.reduce(
|
|
||||||
(acc, method) => {
|
|
||||||
// @ts-ignore
|
|
||||||
acc[method] = (...params) => {
|
|
||||||
// @ts-ignore
|
|
||||||
return api[method](entity, ...params);
|
|
||||||
};
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{} as {
|
|
||||||
[K in (typeof methods)[number]]: OmitFirstArg<(typeof api)[K]>;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PrimaryFieldType } from "core";
|
import type { DB, PrimaryFieldType } from "core";
|
||||||
import { encodeSearch, objectTransform } from "core/utils";
|
import { encodeSearch, objectTransform } from "core/utils";
|
||||||
import type { EntityData, RepoQuery } from "data";
|
import type { EntityData, RepoQuery } from "data";
|
||||||
import type { ModuleApi, ResponseObject } from "modules/ModuleApi";
|
import type { ModuleApi, ResponseObject } from "modules/ModuleApi";
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export {
|
|||||||
} from "./ClientProvider";
|
} from "./ClientProvider";
|
||||||
|
|
||||||
export * from "./api/use-api";
|
export * from "./api/use-api";
|
||||||
export * from "./api/use-data";
|
|
||||||
export * from "./api/use-entity";
|
export * from "./api/use-entity";
|
||||||
export { useAuth } from "./schema/auth/use-auth";
|
export { useAuth } from "./schema/auth/use-auth";
|
||||||
export { Api } from "../../Api";
|
export { Api } from "../../Api";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { App } from "bknd";
|
import { Api, App } from "bknd";
|
||||||
import { serve } from "bknd/adapter/astro";
|
import { serve } from "bknd/adapter/astro";
|
||||||
import { registerLocalMediaAdapter } from "bknd/adapter/node";
|
import { registerLocalMediaAdapter } from "bknd/adapter/node";
|
||||||
import { boolean, em, entity, text } from "bknd/data";
|
import { boolean, em, entity, text } from "bknd/data";
|
||||||
@@ -9,6 +9,20 @@ export const prerender = false;
|
|||||||
// since we're running in node, we can register the local media adapter
|
// since we're running in node, we can register the local media adapter
|
||||||
registerLocalMediaAdapter();
|
registerLocalMediaAdapter();
|
||||||
|
|
||||||
|
// the em() function makes it easy to create an initial schema
|
||||||
|
const schema = em({
|
||||||
|
todos: entity("todos", {
|
||||||
|
title: text(),
|
||||||
|
done: boolean()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// register your schema to get automatic type completion
|
||||||
|
type Database = (typeof schema)["DB"];
|
||||||
|
declare module "bknd/core" {
|
||||||
|
interface DB extends Database {}
|
||||||
|
}
|
||||||
|
|
||||||
export const ALL = serve({
|
export const ALL = serve({
|
||||||
// we can use any libsql config, and if omitted, uses in-memory
|
// we can use any libsql config, and if omitted, uses in-memory
|
||||||
connection: {
|
connection: {
|
||||||
@@ -19,13 +33,7 @@ export const ALL = serve({
|
|||||||
},
|
},
|
||||||
// an initial config is only applied if the database is empty
|
// an initial config is only applied if the database is empty
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
// the em() function makes it easy to create an initial schema
|
data: schema.toJSON(),
|
||||||
data: em({
|
|
||||||
todos: entity("todos", {
|
|
||||||
title: text(),
|
|
||||||
done: boolean()
|
|
||||||
})
|
|
||||||
}).toJSON(),
|
|
||||||
// we're enabling auth ...
|
// we're enabling auth ...
|
||||||
auth: {
|
auth: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
@@ -7,6 +7,19 @@ import { secureRandomString } from "bknd/utils";
|
|||||||
// since we're running in node, we can register the local media adapter
|
// since we're running in node, we can register the local media adapter
|
||||||
registerLocalMediaAdapter();
|
registerLocalMediaAdapter();
|
||||||
|
|
||||||
|
const schema = em({
|
||||||
|
todos: entity("todos", {
|
||||||
|
title: text(),
|
||||||
|
done: boolean()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// register your schema to get automatic type completion
|
||||||
|
type Database = (typeof schema)["DB"];
|
||||||
|
declare module "bknd/core" {
|
||||||
|
interface DB extends Database {}
|
||||||
|
}
|
||||||
|
|
||||||
const handler = serve({
|
const handler = serve({
|
||||||
// we can use any libsql config, and if omitted, uses in-memory
|
// we can use any libsql config, and if omitted, uses in-memory
|
||||||
connection: {
|
connection: {
|
||||||
@@ -17,13 +30,7 @@ const handler = serve({
|
|||||||
},
|
},
|
||||||
// an initial config is only applied if the database is empty
|
// an initial config is only applied if the database is empty
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
// the em() function makes it easy to create an initial schema
|
data: schema.toJSON(),
|
||||||
data: em({
|
|
||||||
todos: entity("todos", {
|
|
||||||
title: text(),
|
|
||||||
done: boolean()
|
|
||||||
})
|
|
||||||
}).toJSON(),
|
|
||||||
// we're enabling auth ...
|
// we're enabling auth ...
|
||||||
auth: {
|
auth: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ export default defineConfig({
|
|||||||
v3_relativeSplatPath: true,
|
v3_relativeSplatPath: true,
|
||||||
v3_throwAbortReason: true,
|
v3_throwAbortReason: true,
|
||||||
v3_singleFetch: true,
|
v3_singleFetch: true,
|
||||||
v3_lazyRouteDiscovery: true,
|
v3_lazyRouteDiscovery: true
|
||||||
},
|
}
|
||||||
}),
|
}) as any,
|
||||||
tsconfigPaths(),
|
tsconfigPaths()
|
||||||
],
|
]
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user