refactor/imports (#217)

* refactored core and core/utils imports

* refactored core and core/utils imports

* refactored media imports

* refactored auth imports

* refactored data imports

* updated package json exports, fixed mm config

* fix tests
This commit is contained in:
dswbx
2025-07-22 20:17:11 +02:00
committed by GitHub
parent 1ec3ba0e92
commit ca55503e66
214 changed files with 680 additions and 791 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
import { afterAll, beforeAll, describe, expect, it } from "bun:test"; import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { Guard } from "../../src/auth"; import { Guard } from "../../src/auth/authorize/Guard";
import { DataApi } from "../../src/data/api/DataApi"; import { DataApi } from "../../src/data/api/DataApi";
import { DataController } from "../../src/data/api/DataController"; import { DataController } from "../../src/data/api/DataController";
import { dataConfigSchema } from "../../src/data/data-schema"; import { dataConfigSchema } from "../../src/data/data-schema";
import * as proto from "../../src/data/prototype"; import * as proto from "../../src/data/prototype";
import { schemaToEm } from "../helper"; import { schemaToEm } from "../helper";
import { disableConsoleLog, enableConsoleLog } from "core/utils/test"; import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
import { parse } from "bknd/core"; import { parse } from "core/utils/schema";
beforeAll(disableConsoleLog); beforeAll(disableConsoleLog);
afterAll(enableConsoleLog); afterAll(enableConsoleLog);
+1 -43
View File
@@ -1,45 +1,3 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Authenticator, type User, type UserPool } from "../../src/auth";
import { cookieConfig } from "../../src/auth/authenticate/Authenticator";
import { PasswordStrategy } from "../../src/auth/authenticate/strategies/PasswordStrategy";
import { parse } from "bknd/core";
/*class MemoryUserPool implements UserPool { describe("Authenticator", async () => {});
constructor(private users: User[] = []) {}
async findBy(prop: "id" | "email" | "username", value: string | number) {
return this.users.find((user) => user[prop] === value);
}
async create(user: Pick<User, "email" | "password">) {
const id = this.users.length + 1;
const newUser = { ...user, id, username: user.email };
this.users.push(newUser);
return newUser;
}
}*/
describe("Authenticator", async () => {
test("cookie options", async () => {
console.log("parsed", parse(cookieConfig, undefined));
console.log(cookieConfig.template({}));
});
/*const userpool = new MemoryUserPool([
{ id: 1, email: "d", username: "test", password: await hash.sha256("test") },
]);
test("sha256 login", async () => {
const auth = new Authenticator(userpool, {
password: new PasswordStrategy({
hashing: "sha256",
}),
});
const { token } = await auth.login("password", { email: "d", password: "test" });
expect(token).toBeDefined();
const { iat, ...decoded } = decodeJwt<any>(token);
expect(decoded).toEqual({ id: 1, email: "d", username: "test" });
expect(await auth.verify(token)).toBe(true);
});*/
});
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Guard } from "../../../src/auth"; import { Guard } from "../../../src/auth/authorize/Guard";
describe("authorize", () => { describe("authorize", () => {
test("basic", async () => { test("basic", async () => {
+2 -2
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Registry } from "core"; import { Registry } from "core/registry/Registry";
import { s } from "bknd/core"; import { s } from "core/utils/schema";
type Constructor<T> = new (...args: any[]) => T; type Constructor<T> = new (...args: any[]) => T;
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { SchemaObject } from "../../../src/core"; import { s } from "core/utils/schema";
import { s } from "bknd/core"; import { SchemaObject } from "core/object/SchemaObject";
describe("SchemaObject", async () => { describe("SchemaObject", async () => {
test("basic", async () => { test("basic", async () => {
+6 -9
View File
@@ -1,19 +1,16 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { Guard } from "../../src/auth"; import { Guard } from "../../src/auth/authorize/Guard";
import { parse } from "bknd/core"; import { parse } from "core/utils/schema";
import {
Entity,
type EntityData,
EntityManager,
ManyToOneRelation,
TextField,
} from "../../src/data";
import { DataController } from "../../src/data/api/DataController"; import { DataController } from "../../src/data/api/DataController";
import { dataConfigSchema } from "../../src/data/data-schema"; import { dataConfigSchema } from "../../src/data/data-schema";
import { disableConsoleLog, enableConsoleLog, getDummyConnection } from "../helper"; import { disableConsoleLog, enableConsoleLog, getDummyConnection } from "../helper";
import type { RepositoryResultJSON } from "data/entities/query/RepositoryResult"; import type { RepositoryResultJSON } from "data/entities/query/RepositoryResult";
import type { MutatorResultJSON } from "data/entities/mutation/MutatorResult"; import type { MutatorResultJSON } from "data/entities/mutation/MutatorResult";
import { Entity, EntityManager, type EntityData } from "data/entities";
import { TextField } from "data/fields";
import { ManyToOneRelation } from "data/relations";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
beforeAll(() => disableConsoleLog(["log", "warn"])); beforeAll(() => disableConsoleLog(["log", "warn"]));
+2 -8
View File
@@ -1,12 +1,6 @@
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { import { Entity, EntityManager } from "data/entities";
Entity, import { TextField, PrimaryField, NumberField } from "data/fields";
EntityManager,
NumberField,
PrimaryField,
Repository,
TextField,
} from "../../src/data";
import { getDummyConnection } from "./helper"; import { getDummyConnection } from "./helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+1 -1
View File
@@ -2,7 +2,7 @@ import { unlink } from "node:fs/promises";
import type { SqliteDatabase } from "kysely"; import type { SqliteDatabase } from "kysely";
// @ts-ignore // @ts-ignore
import Database from "libsql"; import Database from "libsql";
import { SqliteLocalConnection } from "../../src/data"; import { SqliteLocalConnection } from "data/connection/sqlite/SqliteLocalConnection";
export function getDummyDatabase(memory: boolean = true): { export function getDummyDatabase(memory: boolean = true): {
dummyDb: SqliteDatabase; dummyDb: SqliteDatabase;
+5 -8
View File
@@ -1,13 +1,10 @@
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { import { Entity } from "data/entities";
Entity, import { EntityManager } from "data/entities/EntityManager";
EntityManager, import { ManyToOneRelation } from "data/relations";
ManyToOneRelation, import { NumberField, TextField } from "data/fields";
NumberField, import { SchemaManager } from "data/schema/SchemaManager";
SchemaManager,
TextField,
} from "../../src/data";
import { getDummyConnection } from "./helper"; import { getDummyConnection } from "./helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+3 -2
View File
@@ -1,7 +1,8 @@
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { Entity, EntityManager, Mutator, NumberField, TextField } from "../../src/data"; import { Entity, EntityManager } from "data/entities";
import { TransformPersistFailedException } from "../../src/data/errors"; import { NumberField, TextField } from "data/fields";
import { TransformPersistFailedException } from "data/errors";
import { getDummyConnection } from "./helper"; import { getDummyConnection } from "./helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+4 -2
View File
@@ -1,6 +1,8 @@
import { afterAll, expect as bunExpect, describe, test } from "bun:test"; import { afterAll, expect as bunExpect, describe, test } from "bun:test";
import { stripMark } from "bknd/core"; import { stripMark } from "core/utils/schema";
import { Entity, EntityManager, PolymorphicRelation, TextField } from "../../src/data"; import { Entity, EntityManager } from "data/entities";
import { TextField } from "data/fields";
import { PolymorphicRelation } from "data/relations";
import { getDummyConnection } from "./helper"; import { getDummyConnection } from "./helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+12 -11
View File
@@ -2,19 +2,20 @@ import { describe, expect, test } from "bun:test";
import { import {
BooleanField, BooleanField,
DateField, DateField,
Entity,
EntityIndex,
EntityManager,
EnumField, EnumField,
JsonField, JsonField,
NumberField,
TextField,
EntityIndex,
} from "data/fields";
import { Entity, EntityManager } from "data/entities";
import {
ManyToManyRelation, ManyToManyRelation,
ManyToOneRelation, ManyToOneRelation,
NumberField,
OneToOneRelation, OneToOneRelation,
PolymorphicRelation, PolymorphicRelation,
TextField, } from "data/relations";
} from "../../src/data"; import { DummyConnection } from "data/connection/DummyConnection";
import { DummyConnection } from "../../src/data/connection/DummyConnection";
import { import {
FieldPrototype, FieldPrototype,
type FieldSchema, type FieldSchema,
@@ -32,8 +33,8 @@ import {
number, number,
relation, relation,
text, text,
} from "../../src/data/prototype"; } from "data/prototype";
import { MediaField } from "../../src/media/MediaField"; import { MediaField } from "media/MediaField";
describe("prototype", () => { describe("prototype", () => {
test("...", () => { test("...", () => {
@@ -296,9 +297,9 @@ describe("prototype", () => {
new Entity("posts", [new TextField("name"), new TextField("slug", { required: true })]), new Entity("posts", [new TextField("name"), new TextField("slug", { required: true })]),
new Entity("comments", [new TextField("some")]), new Entity("comments", [new TextField("some")]),
new Entity("users", [new TextField("email")]), new Entity("users", [new TextField("email")]),
]; ] as const;
const _em2 = new EntityManager( const _em2 = new EntityManager(
es, [...es],
new DummyConnection(), new DummyConnection(),
[new ManyToOneRelation(es[0], es[1]), new ManyToOneRelation(es[0], es[2])], [new ManyToOneRelation(es[0], es[1]), new ManyToOneRelation(es[0], es[2])],
[ [
+11 -10
View File
@@ -1,13 +1,14 @@
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { Entity, EntityManager, TextField } from "../../src/data"; import { Entity, EntityManager } from "data/entities";
import { TextField } from "data/fields";
import { import {
ManyToManyRelation, ManyToManyRelation,
ManyToOneRelation, ManyToOneRelation,
OneToOneRelation, OneToOneRelation,
PolymorphicRelation, PolymorphicRelation,
RelationField, RelationField,
} from "../../src/data/relations"; } from "data/relations";
import { getDummyConnection } from "./helper"; import { getDummyConnection } from "./helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
@@ -77,7 +78,7 @@ describe("Relations", async () => {
const em = new EntityManager(entities, dummyConnection, relations); const em = new EntityManager(entities, dummyConnection, relations);
// verify naming // verify naming
const rel = em.relations.all[0]; const rel = em.relations.all[0]!;
expect(rel.source.entity.name).toBe(posts.name); expect(rel.source.entity.name).toBe(posts.name);
expect(rel.source.reference).toBe(posts.name); expect(rel.source.reference).toBe(posts.name);
expect(rel.target.entity.name).toBe(users.name); expect(rel.target.entity.name).toBe(users.name);
@@ -89,11 +90,11 @@ describe("Relations", async () => {
// verify low level relation // verify low level relation
expect(em.relationsOf(users.name).length).toBe(1); expect(em.relationsOf(users.name).length).toBe(1);
expect(em.relationsOf(users.name).length).toBe(1); expect(em.relationsOf(users.name).length).toBe(1);
expect(em.relationsOf(users.name)[0].source.entity).toBe(posts); expect(em.relationsOf(users.name)[0]!.source.entity).toBe(posts);
expect(posts.field("author_id")).toBeInstanceOf(RelationField); expect(posts.field("author_id")).toBeInstanceOf(RelationField);
expect(em.relationsOf(users.name).length).toBe(1); expect(em.relationsOf(users.name).length).toBe(1);
expect(em.relationsOf(users.name).length).toBe(1); expect(em.relationsOf(users.name).length).toBe(1);
expect(em.relationsOf(users.name)[0].source.entity).toBe(posts); expect(em.relationsOf(users.name)[0]!.source.entity).toBe(posts);
// verify high level relation (from users) // verify high level relation (from users)
const userPostsRel = em.relationOf(users.name, "posts"); const userPostsRel = em.relationOf(users.name, "posts");
@@ -191,7 +192,7 @@ describe("Relations", async () => {
const em = new EntityManager(entities, dummyConnection, relations); const em = new EntityManager(entities, dummyConnection, relations);
// verify naming // verify naming
const rel = em.relations.all[0]; const rel = em.relations.all[0]!;
expect(rel.source.entity.name).toBe(users.name); expect(rel.source.entity.name).toBe(users.name);
expect(rel.source.reference).toBe(users.name); expect(rel.source.reference).toBe(users.name);
expect(rel.target.entity.name).toBe(settings.name); expect(rel.target.entity.name).toBe(settings.name);
@@ -202,8 +203,8 @@ describe("Relations", async () => {
expect(em.relationsOf(users.name).length).toBe(1); expect(em.relationsOf(users.name).length).toBe(1);
expect(em.relationsOf(users.name).length).toBe(1); expect(em.relationsOf(users.name).length).toBe(1);
expect(em.relationsOf(users.name)[0].source.entity).toBe(users); expect(em.relationsOf(users.name)[0]!.source.entity).toBe(users);
expect(em.relationsOf(users.name)[0].target.entity).toBe(settings); expect(em.relationsOf(users.name)[0]!.target.entity).toBe(settings);
// verify high level relation (from users) // verify high level relation (from users)
const userSettingRel = em.relationOf(users.name, settings.name); const userSettingRel = em.relationOf(users.name, settings.name);
@@ -323,7 +324,7 @@ describe("Relations", async () => {
); );
// mutation info // mutation info
expect(relations[0].helper(posts.name)!.getMutationInfo()).toEqual({ expect(relations[0]!.helper(posts.name)!.getMutationInfo()).toEqual({
reference: "categories", reference: "categories",
local_field: undefined, local_field: undefined,
$set: false, $set: false,
@@ -334,7 +335,7 @@ describe("Relations", async () => {
cardinality: undefined, cardinality: undefined,
relation_type: "m:n", relation_type: "m:n",
}); });
expect(relations[0].helper(categories.name)!.getMutationInfo()).toEqual({ expect(relations[0]!.helper(categories.name)!.getMutationInfo()).toEqual({
reference: "posts", reference: "posts",
local_field: undefined, local_field: undefined,
$set: false, $set: false,
+2 -2
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Entity, NumberField, TextField } from "data"; import { Entity } from "data/entities";
import * as p from "data/prototype"; import { NumberField, TextField } from "data/fields";
describe("[data] Entity", async () => { describe("[data] Entity", async () => {
const entity = new Entity("test", [ const entity = new Entity("test", [
@@ -1,12 +1,8 @@
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { import { Entity, EntityManager } from "data/entities";
Entity, import { ManyToManyRelation, ManyToOneRelation } from "data/relations";
EntityManager, import { SchemaManager } from "data/schema/SchemaManager";
ManyToManyRelation, import { UnableToConnectException } from "data/errors";
ManyToOneRelation,
SchemaManager,
} from "../../../src/data";
import { UnableToConnectException } from "../../../src/data/errors";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+4 -2
View File
@@ -1,6 +1,8 @@
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { Entity, EntityManager, ManyToOneRelation, TextField } from "../../../src/data"; import { Entity, EntityManager } from "data/entities";
import { JoinBuilder } from "../../../src/data/entities/query/JoinBuilder"; import { ManyToOneRelation } from "data/relations";
import { TextField } from "data/fields";
import { JoinBuilder } from "data/entities/query/JoinBuilder";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+6 -8
View File
@@ -1,18 +1,16 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import type { EventManager } from "../../../src/core/events"; import type { EventManager } from "../../../src/core/events";
import { Entity, EntityManager } from "data/entities";
import { import {
Entity,
EntityManager,
ManyToOneRelation, ManyToOneRelation,
MutatorEvents,
NumberField,
OneToOneRelation, OneToOneRelation,
type RelationField, RelationField,
RelationMutator, RelationMutator,
TextField, } from "data/relations";
} from "../../../src/data"; import { NumberField, TextField } from "data/fields";
import * as proto from "../../../src/data/prototype"; import * as proto from "data/prototype";
import { getDummyConnection, disableConsoleLog, enableConsoleLog } from "../../helper"; import { getDummyConnection, disableConsoleLog, enableConsoleLog } from "../../helper";
import { MutatorEvents } from "data/events";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
afterAll(afterAllCleanup); afterAll(afterAllCleanup);
+5 -12
View File
@@ -1,17 +1,10 @@
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import type { Kysely, Transaction } from "kysely"; import type { Kysely, Transaction } from "kysely";
import { Perf } from "core/utils"; import { TextField } from "data/fields";
import { import { em as $em, entity as $entity, text as $text } from "data/prototype";
Entity, import { Entity, EntityManager } from "data/entities";
EntityManager, import { ManyToOneRelation } from "data/relations";
LibsqlConnection, import { RepositoryEvents } from "data/events";
ManyToOneRelation,
RepositoryEvents,
TextField,
entity as $entity,
text as $text,
em as $em,
} from "data";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
type E = Kysely<any> | Transaction<any>; type E = Kysely<any> | Transaction<any>;
@@ -1,7 +1,9 @@
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { randomString } from "../../../src/core/utils"; import { randomString } from "core/utils";
import { Entity, EntityIndex, EntityManager, SchemaManager, TextField } from "../../../src/data"; import { Entity, EntityManager } from "data/entities";
import { TextField, EntityIndex } from "data/fields";
import { SchemaManager } from "data/schema/SchemaManager";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, test, expect } from "bun:test"; import { describe, test, expect } from "bun:test";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
import { type WhereQuery, WhereBuilder } from "data"; import { WhereBuilder, type WhereQuery } from "data/entities/query/WhereBuilder";
function qb() { function qb() {
const c = getDummyConnection(); const c = getDummyConnection();
+5 -10
View File
@@ -1,14 +1,9 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { import { Entity, EntityManager } from "data/entities";
Entity, import { ManyToManyRelation, ManyToOneRelation, PolymorphicRelation } from "data/relations";
EntityManager, import { TextField } from "data/fields";
ManyToManyRelation, import * as proto from "data/prototype";
ManyToOneRelation, import { WithBuilder } from "data/entities/query/WithBuilder";
PolymorphicRelation,
TextField,
WithBuilder,
} from "../../../src/data";
import * as proto from "../../../src/data/prototype";
import { schemaToEm } from "../../helper"; import { schemaToEm } from "../../helper";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
@@ -1,5 +1,5 @@
import { afterAll, describe, expect, test } from "bun:test"; import { afterAll, describe, expect, test } from "bun:test";
import { EntityManager } from "../../../../src/data"; import { EntityManager } from "data/entities/EntityManager";
import { getDummyConnection } from "../../helper"; import { getDummyConnection } from "../../helper";
const { dummyConnection, afterAllCleanup } = getDummyConnection(); const { dummyConnection, afterAllCleanup } = getDummyConnection();
@@ -1,9 +1,10 @@
import { bunTestRunner } from "adapter/bun/test";
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { BooleanField } from "../../../../src/data"; import { BooleanField } from "data/fields";
import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite"; import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite";
describe("[data] BooleanField", async () => { describe("[data] BooleanField", async () => {
fieldTestSuite({ expect, test }, BooleanField, { defaultValue: true, schemaType: "boolean" }); fieldTestSuite(bunTestRunner, BooleanField, { defaultValue: true, schemaType: "boolean" });
test("transformRetrieve", async () => { test("transformRetrieve", async () => {
const field = new BooleanField("test"); const field = new BooleanField("test");
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, test } from "bun:test";
import { DateField, dateFieldConfigSchema } from "../../../../src/data"; import { DateField } from "data/fields";
import { fieldTestSuite } from "data/fields/field-test-suite"; import { fieldTestSuite } from "data/fields/field-test-suite";
import { bunTestRunner } from "adapter/bun/test"; import { bunTestRunner } from "adapter/bun/test";
@@ -1,5 +1,6 @@
import { bunTestRunner } from "adapter/bun/test";
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { EnumField } from "../../../../src/data"; import { EnumField } from "data/fields";
import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite"; import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite";
function options(strings: string[]) { function options(strings: string[]) {
@@ -8,7 +9,7 @@ function options(strings: string[]) {
describe("[data] EnumField", async () => { describe("[data] EnumField", async () => {
fieldTestSuite( fieldTestSuite(
{ expect, test }, bunTestRunner,
// @ts-ignore // @ts-ignore
EnumField, EnumField,
{ defaultValue: "a", schemaType: "text" }, { defaultValue: "a", schemaType: "text" },
+1 -1
View File
@@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test";
import { baseFieldConfigSchema, Field } from "../../../../src/data/fields/Field"; import { baseFieldConfigSchema, Field } from "../../../../src/data/fields/Field";
import { fieldTestSuite } from "data/fields/field-test-suite"; import { fieldTestSuite } from "data/fields/field-test-suite";
import { bunTestRunner } from "adapter/bun/test"; import { bunTestRunner } from "adapter/bun/test";
import { stripMark } from "bknd/core"; import { stripMark } from "core/utils/schema";
describe("[data] Field", async () => { describe("[data] Field", async () => {
class FieldSpec extends Field { class FieldSpec extends Field {
@@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Entity, EntityIndex, Field } from "../../../../src/data"; import { Entity } from "data/entities";
import { s } from "bknd/core"; import { Field, EntityIndex } from "data/fields";
import { s } from "core/utils/schema";
class TestField extends Field { class TestField extends Field {
protected getSchema(): any { protected getSchema(): any {
@@ -1,10 +1,11 @@
import { bunTestRunner } from "adapter/bun/test";
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { JsonField } from "../../../../src/data"; import { JsonField } from "data/fields";
import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite"; import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite";
describe("[data] JsonField", async () => { describe("[data] JsonField", async () => {
const field = new JsonField("test"); const field = new JsonField("test");
fieldTestSuite({ expect, test }, JsonField, { fieldTestSuite(bunTestRunner, JsonField, {
defaultValue: { a: 1 }, defaultValue: { a: 1 },
sampleValues: ["string", { test: 1 }, 1], sampleValues: ["string", { test: 1 }, 1],
schemaType: "text", schemaType: "text",
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { JsonSchemaField } from "../../../../src/data"; import { JsonSchemaField } from "data/fields";
import { fieldTestSuite } from "data/fields/field-test-suite"; import { fieldTestSuite } from "data/fields/field-test-suite";
describe("[data] JsonSchemaField", async () => { describe("[data] JsonSchemaField", async () => {
@@ -1,5 +1,6 @@
import { bunTestRunner } from "adapter/bun/test";
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { NumberField } from "../../../../src/data"; import { NumberField } from "data/fields";
import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite"; import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite";
describe("[data] NumberField", async () => { describe("[data] NumberField", async () => {
@@ -15,5 +16,5 @@ describe("[data] NumberField", async () => {
expect(transformPersist(field2, 10000)).resolves.toBe(10000); expect(transformPersist(field2, 10000)).resolves.toBe(10000);
}); });
fieldTestSuite({ expect, test }, NumberField, { defaultValue: 12, schemaType: "integer" }); fieldTestSuite(bunTestRunner, NumberField, { defaultValue: 12, schemaType: "integer" });
}); });
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { PrimaryField } from "../../../../src/data"; import { PrimaryField } from "data/fields";
describe("[data] PrimaryField", async () => { describe("[data] PrimaryField", async () => {
const field = new PrimaryField("primary"); const field = new PrimaryField("primary");
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { TextField, textFieldConfigSchema } from "../../../../src/data"; import { TextField } from "data/fields";
import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite"; import { fieldTestSuite, transformPersist } from "data/fields/field-test-suite";
import { bunTestRunner } from "adapter/bun/test"; import { bunTestRunner } from "adapter/bun/test";
@@ -1,11 +1,11 @@
import { describe, expect, it, test } from "bun:test"; import { describe, expect, it, test } from "bun:test";
import { Entity, type EntityManager } from "../../../../src/data"; import { Entity, type EntityManager } from "data/entities";
import { import {
type BaseRelationConfig, type BaseRelationConfig,
EntityRelation, EntityRelation,
EntityRelationAnchor, EntityRelationAnchor,
RelationTypes, RelationTypes,
} from "../../../../src/data/relations"; } from "data/relations";
class TestEntityRelation extends EntityRelation { class TestEntityRelation extends EntityRelation {
constructor(config?: BaseRelationConfig) { constructor(config?: BaseRelationConfig) {
@@ -24,11 +24,11 @@ class TestEntityRelation extends EntityRelation {
return this; return this;
} }
buildWith(a: any, b: any, c: any): any { buildWith(): any {
return; return;
} }
buildJoin(a: any, b: any): any { buildJoin(): any {
return; return;
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Flow, LogTask, SubFlowTask, RenderTask, Task } from "../../src/flows"; import { Flow, LogTask, SubFlowTask, RenderTask, Task } from "../../src/flows";
import { s } from "bknd/core"; import { s } from "core/utils/schema";
export class StringifyTask<Output extends string> extends Task< export class StringifyTask<Output extends string> extends Task<
typeof StringifyTask.schema, typeof StringifyTask.schema,
+1 -1
View File
@@ -1,7 +1,7 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Task } from "../../src/flows"; import { Task } from "../../src/flows";
import { dynamic } from "../../src/flows/tasks/Task"; import { dynamic } from "../../src/flows/tasks/Task";
import { s } from "bknd/core"; import { s } from "core/utils/schema";
describe.skip("Task", async () => { describe.skip("Task", async () => {
test("resolveParams: template with parse", async () => { test("resolveParams: template with parse", async () => {
+1 -1
View File
@@ -1,7 +1,7 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { Hono } from "hono"; import { Hono } from "hono";
import { Event, EventManager } from "../../src/core/events"; import { Event, EventManager } from "../../src/core/events";
import { s, parse } from "bknd/core"; import { s, parse } from "core/utils/schema";
import { EventTrigger, Flow, HttpTrigger, type InputsMap, Task } from "../../src/flows"; import { EventTrigger, Flow, HttpTrigger, type InputsMap, Task } from "../../src/flows";
import { dynamic } from "../../src/flows/tasks/Task"; import { dynamic } from "../../src/flows/tasks/Task";
+1 -1
View File
@@ -2,7 +2,7 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { isEqual } from "lodash-es"; import { isEqual } from "lodash-es";
import { _jsonp, withDisabledConsole } from "../../src/core/utils"; import { _jsonp, withDisabledConsole } from "../../src/core/utils";
import { s } from "bknd/core"; import { s } from "core/utils/schema";
import { Condition, ExecutionEvent, FetchTask, Flow, LogTask, Task } from "../../src/flows"; import { Condition, ExecutionEvent, FetchTask, Flow, LogTask, Task } from "../../src/flows";
/*beforeAll(disableConsoleLog); /*beforeAll(disableConsoleLog);
+2 -1
View File
@@ -2,11 +2,12 @@ import { unlink } from "node:fs/promises";
import type { SelectQueryBuilder, SqliteDatabase } from "kysely"; import type { SelectQueryBuilder, SqliteDatabase } from "kysely";
import Database from "libsql"; import Database from "libsql";
import { format as sqlFormat } from "sql-formatter"; import { format as sqlFormat } from "sql-formatter";
import { type Connection, EntityManager, SqliteLocalConnection } from "../src/data";
import type { em as protoEm } from "../src/data/prototype"; import type { em as protoEm } from "../src/data/prototype";
import { writeFile } from "node:fs/promises"; import { writeFile } from "node:fs/promises";
import { join } from "node:path"; import { join } from "node:path";
import { slugify } from "core/utils/strings"; import { slugify } from "core/utils/strings";
import { type Connection, SqliteLocalConnection } from "data/connection";
import { EntityManager } from "data/entities/EntityManager";
export function getDummyDatabase(memory: boolean = true): { export function getDummyDatabase(memory: boolean = true): {
dummyDb: SqliteDatabase; dummyDb: SqliteDatabase;
+1 -1
View File
@@ -1,7 +1,7 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { type FileBody, Storage } from "../../src/media/storage/Storage"; import { type FileBody, Storage } from "../../src/media/storage/Storage";
import * as StorageEvents from "../../src/media/storage/events"; import * as StorageEvents from "../../src/media/storage/events";
import { StorageAdapter } from "media"; import { StorageAdapter } from "media/storage/StorageAdapter";
class TestAdapter extends StorageAdapter { class TestAdapter extends StorageAdapter {
files: Record<string, FileBody> = {}; files: Record<string, FileBody> = {};
+2 -3
View File
@@ -1,10 +1,9 @@
import { afterAll, beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test"; import { afterAll, beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
import { createApp } from "core/test/utils"; import { createApp } from "core/test/utils";
import { AuthController } from "../../src/auth/api/AuthController"; import { AuthController } from "../../src/auth/api/AuthController";
import { em, entity, make, text } from "../../src/data"; import { em, entity, make, text } from "data/prototype";
import { AppAuth, type ModuleBuildContext } from "../../src/modules"; import { AppAuth, type ModuleBuildContext } from "modules";
import { disableConsoleLog, enableConsoleLog } from "../helper"; import { disableConsoleLog, enableConsoleLog } from "../helper";
// @ts-ignore
import { makeCtx, moduleTestSuite } from "./module-test-suite"; import { makeCtx, moduleTestSuite } from "./module-test-suite";
describe("AppAuth", () => { describe("AppAuth", () => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, test } from "bun:test"; import { beforeEach, describe, expect, test } from "bun:test";
import { parse } from "bknd/core"; import { parse } from "core/utils/schema";
import { fieldsSchema } from "../../src/data/data-schema"; import { fieldsSchema } from "../../src/data/data-schema";
import { AppData, type ModuleBuildContext } from "../../src/modules"; import { AppData, type ModuleBuildContext } from "../../src/modules";
import { makeCtx, moduleTestSuite } from "./module-test-suite"; import { makeCtx, moduleTestSuite } from "./module-test-suite";
+2 -3
View File
@@ -1,10 +1,9 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { registries } from "../../src";
import { createApp } from "core/test/utils"; import { createApp } from "core/test/utils";
import { em, entity, text } from "../../src/data"; import { em, entity, text } from "data/prototype";
import { registries } from "modules/registries";
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter"; import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
import { AppMedia } from "../../src/media/AppMedia"; import { AppMedia } from "../../src/media/AppMedia";
import { mediaConfigSchema } from "../../src/media/media-schema";
import { moduleTestSuite } from "./module-test-suite"; import { moduleTestSuite } from "./module-test-suite";
describe("AppMedia", () => { describe("AppMedia", () => {
+3 -2
View File
@@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { s, stripMark } from "bknd/core"; import { s, stripMark } from "core/utils/schema";
import { EntityManager, em, entity, index, text } from "../../src/data"; import { em, entity, index, text } from "data/prototype";
import { EntityManager } from "data/entities/EntityManager";
import { DummyConnection } from "../../src/data/connection/DummyConnection"; import { DummyConnection } from "../../src/data/connection/DummyConnection";
import { Module } from "../../src/modules/Module"; import { Module } from "../../src/modules/Module";
import { ModuleHelper } from "modules/ModuleHelper"; import { ModuleHelper } from "modules/ModuleHelper";
+4 -2
View File
@@ -1,11 +1,13 @@
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"; import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
import { disableConsoleLog, enableConsoleLog } from "core/utils"; import { disableConsoleLog, enableConsoleLog } from "core/utils";
import { Connection, entity, text } from "data";
import { Module } from "modules/Module"; import { Module } from "modules/Module";
import { type ConfigTable, getDefaultConfig, ModuleManager } from "modules/ModuleManager"; import { type ConfigTable, getDefaultConfig, ModuleManager } from "modules/ModuleManager";
import { CURRENT_VERSION, TABLE_NAME } from "modules/migrations"; import { CURRENT_VERSION, TABLE_NAME } from "modules/migrations";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
import { s, stripMark } from "bknd/core"; import { s, stripMark } from "core/utils/schema";
import { Connection } from "data/connection/Connection";
import { entity, text } from "data/prototype";
describe("ModuleManager", async () => { describe("ModuleManager", async () => {
test("s1: no config, no build", async () => { test("s1: no config, no build", async () => {
+5 -5
View File
@@ -1,11 +1,11 @@
import { beforeEach, describe, expect, it } from "bun:test"; import { beforeEach, describe, expect, it } from "bun:test";
import { Hono } from "hono"; import { Hono } from "hono";
import { Guard } from "../../src/auth"; import { Guard } from "auth/authorize/Guard";
import { DebugLogger } from "../../src/core"; import { DebugLogger } from "core/utils/DebugLogger";
import { EventManager } from "../../src/core/events"; import { EventManager } from "core/events";
import { EntityManager } from "../../src/data"; import { EntityManager } from "data/entities/EntityManager";
import { Module, type ModuleBuildContext } from "../../src/modules/Module"; import { Module, type ModuleBuildContext } from "modules/Module";
import { getDummyConnection } from "../helper"; import { getDummyConnection } from "../helper";
import { ModuleHelper } from "modules/ModuleHelper"; import { ModuleHelper } from "modules/ModuleHelper";
+1 -8
View File
@@ -79,14 +79,7 @@ async function buildApi() {
sourcemap, sourcemap,
watch, watch,
define, define,
entry: [ entry: ["src/index.ts", "src/core/utils/index.ts", "src/plugins/index.ts"],
"src/index.ts",
"src/core/index.ts",
"src/core/utils/index.ts",
"src/data/index.ts",
"src/media/index.ts",
"src/plugins/index.ts",
],
outDir: "dist", outDir: "dist",
external: [...external], external: [...external],
metafile: true, metafile: true,
+1 -19
View File
@@ -99,7 +99,7 @@
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"jotai": "^2.12.2", "jotai": "^2.12.2",
"jsdom": "^26.0.0", "jsdom": "^26.0.0",
"jsonv-ts": "^0.3.1", "jsonv-ts": "^0.3.2",
"kysely-d1": "^0.3.0", "kysely-d1": "^0.3.0",
"kysely-generic-sqlite": "^1.2.1", "kysely-generic-sqlite": "^1.2.1",
"libsql-stateless-easy": "^1.8.0", "libsql-stateless-easy": "^1.8.0",
@@ -160,16 +160,6 @@
"import": "./dist/ui/client/index.js", "import": "./dist/ui/client/index.js",
"require": "./dist/ui/client/index.js" "require": "./dist/ui/client/index.js"
}, },
"./data": {
"types": "./dist/types/data/index.d.ts",
"import": "./dist/data/index.js",
"require": "./dist/data/index.js"
},
"./core": {
"types": "./dist/types/core/index.d.ts",
"import": "./dist/core/index.js",
"require": "./dist/core/index.js"
},
"./utils": { "./utils": {
"types": "./dist/types/core/utils/index.d.ts", "types": "./dist/types/core/utils/index.d.ts",
"import": "./dist/core/utils/index.js", "import": "./dist/core/utils/index.js",
@@ -180,11 +170,6 @@
"import": "./dist/cli/index.js", "import": "./dist/cli/index.js",
"require": "./dist/cli/index.js" "require": "./dist/cli/index.js"
}, },
"./media": {
"types": "./dist/types/media/index.d.ts",
"import": "./dist/media/index.js",
"require": "./dist/media/index.js"
},
"./plugins": { "./plugins": {
"types": "./dist/types/plugins/index.d.ts", "types": "./dist/types/plugins/index.d.ts",
"import": "./dist/plugins/index.js", "import": "./dist/plugins/index.js",
@@ -255,11 +240,8 @@
}, },
"typesVersions": { "typesVersions": {
"*": { "*": {
"data": ["./dist/types/data/index.d.ts"],
"core": ["./dist/types/core/index.d.ts"],
"utils": ["./dist/types/core/utils/index.d.ts"], "utils": ["./dist/types/core/utils/index.d.ts"],
"cli": ["./dist/types/cli/index.d.ts"], "cli": ["./dist/types/cli/index.d.ts"],
"media": ["./dist/types/media/index.d.ts"],
"plugins": ["./dist/types/plugins/index.d.ts"], "plugins": ["./dist/types/plugins/index.d.ts"],
"adapter": ["./dist/types/adapter/index.d.ts"], "adapter": ["./dist/types/adapter/index.d.ts"],
"adapter/cloudflare": ["./dist/types/adapter/cloudflare/index.d.ts"], "adapter/cloudflare": ["./dist/types/adapter/cloudflare/index.d.ts"],
+1 -1
View File
@@ -1,4 +1,4 @@
import type { SafeUser } from "auth"; import type { SafeUser } from "bknd";
import { AuthApi, type AuthApiOptions } from "auth/api/AuthApi"; import { AuthApi, type AuthApiOptions } from "auth/api/AuthApi";
import { DataApi, type DataApiOptions } from "data/api/DataApi"; import { DataApi, type DataApiOptions } from "data/api/DataApi";
import { decode } from "hono/jwt"; import { decode } from "hono/jwt";
+1 -2
View File
@@ -3,10 +3,9 @@
import path from "node:path"; import path from "node:path";
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter"; import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
import { registerLocalMediaAdapter } from "."; import { registerLocalMediaAdapter } from ".";
import { config } from "bknd/core"; import { config, type App } from "bknd";
import type { ServeOptions } from "bun"; import type { ServeOptions } from "bun";
import { serveStatic } from "hono/bun"; import { serveStatic } from "hono/bun";
import type { App } from "App";
type BunEnv = Bun.Env; type BunEnv = Bun.Env;
export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> & Omit<ServeOptions, "fetch">; export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> & Omit<ServeOptions, "fetch">;
@@ -1,5 +1,5 @@
import { Database } from "bun:sqlite"; import { Database } from "bun:sqlite";
import { genericSqlite, type GenericSqliteConnection } from "bknd/data"; import { genericSqlite, type GenericSqliteConnection } from "bknd";
export type BunSqliteConnection = GenericSqliteConnection<Database>; export type BunSqliteConnection = GenericSqliteConnection<Database>;
export type BunSqliteConnectionConfig = { export type BunSqliteConnectionConfig = {
+3 -3
View File
@@ -1,16 +1,16 @@
/// <reference types="@cloudflare/workers-types" /> /// <reference types="@cloudflare/workers-types" />
import { Connection } from "bknd";
import { sqlite } from "bknd/adapter/sqlite";
import { makeConfig as makeAdapterConfig } from "bknd/adapter";
import { registerMedia } from "./storage/StorageR2Adapter"; import { registerMedia } from "./storage/StorageR2Adapter";
import { getBinding } from "./bindings"; import { getBinding } from "./bindings";
import { d1Sqlite } from "./connection/D1Connection"; import { d1Sqlite } from "./connection/D1Connection";
import { Connection } from "bknd/data";
import type { CloudflareBkndConfig, CloudflareEnv } from "."; import type { CloudflareBkndConfig, CloudflareEnv } from ".";
import { App } from "bknd"; import { App } from "bknd";
import { makeConfig as makeAdapterConfig } from "bknd/adapter";
import type { Context, ExecutionContext } from "hono"; import type { Context, ExecutionContext } from "hono";
import { $console } from "core/utils"; import { $console } from "core/utils";
import { setCookie } from "hono/cookie"; import { setCookie } from "hono/cookie";
import { sqlite } from "bknd/adapter/sqlite";
export const constants = { export const constants = {
exec_async_event_id: "cf_register_waituntil", exec_async_event_id: "cf_register_waituntil",
@@ -1,6 +1,6 @@
/// <reference types="@cloudflare/workers-types" /> /// <reference types="@cloudflare/workers-types" />
import { genericSqlite, type GenericSqliteConnection } from "bknd/data"; import { genericSqlite, type GenericSqliteConnection } from "bknd";
import type { QueryResult } from "kysely"; import type { QueryResult } from "kysely";
export type D1SqliteConnection = GenericSqliteConnection<D1Database>; export type D1SqliteConnection = GenericSqliteConnection<D1Database>;
@@ -1,6 +1,6 @@
/// <reference types="@cloudflare/workers-types" /> /// <reference types="@cloudflare/workers-types" />
import { genericSqlite, type GenericSqliteConnection } from "bknd/data"; import { genericSqlite, type GenericSqliteConnection } from "bknd";
import type { QueryResult } from "kysely"; import type { QueryResult } from "kysely";
export type D1SqliteConnection = GenericSqliteConnection<D1Database>; export type D1SqliteConnection = GenericSqliteConnection<D1Database>;
@@ -1,8 +1,7 @@
import { registries } from "bknd"; import { registries, isDebug, guessMimeType } from "bknd";
import { isDebug } from "bknd/core";
import { guessMimeType as guess, StorageAdapter, type FileBody } from "bknd/media";
import { getBindings } from "../bindings"; import { getBindings } from "../bindings";
import { s } from "bknd/core"; import { s } from "bknd/utils";
import { StorageAdapter, type FileBody } from "bknd";
export function makeSchema(bindings: string[] = []) { export function makeSchema(bindings: string[] = []) {
return s.object( return s.object(
@@ -90,7 +89,7 @@ export class StorageR2Adapter extends StorageAdapter {
const responseHeaders = new Headers({ const responseHeaders = new Headers({
"Accept-Ranges": "bytes", "Accept-Ranges": "bytes",
"Content-Type": guess(key), "Content-Type": guessMimeType(key),
}); });
const range = headers.has("range"); const range = headers.has("range");
@@ -142,7 +141,7 @@ export class StorageR2Adapter extends StorageAdapter {
if (!metadata || Object.keys(metadata).length === 0) { if (!metadata || Object.keys(metadata).length === 0) {
// guessing is especially required for dev environment (miniflare) // guessing is especially required for dev environment (miniflare)
metadata = { metadata = {
contentType: guess(object.key), contentType: guessMimeType(object.key),
}; };
} }
@@ -159,7 +158,7 @@ export class StorageR2Adapter extends StorageAdapter {
} }
return { return {
type: String(head.httpMetadata?.contentType ?? guess(key)), type: String(head.httpMetadata?.contentType ?? guessMimeType(key)),
size: head.size, size: head.size,
}; };
} }
+2 -7
View File
@@ -1,13 +1,8 @@
import { App, type CreateAppConfig } from "bknd"; import { config as $config, App, type CreateAppConfig, Connection, guessMimeType } from "bknd";
import { config as $config } from "bknd/core";
import { $console } from "bknd/utils"; import { $console } from "bknd/utils";
import type { Context, MiddlewareHandler, Next } from "hono"; import type { Context, MiddlewareHandler, Next } from "hono";
import type { AdminControllerOptions } from "modules/server/AdminController"; import type { AdminControllerOptions } from "modules/server/AdminController";
import { Connection } from "bknd/data";
import type { Manifest } from "vite"; import type { Manifest } from "vite";
import { guessMimeType } from "media";
export { Connection } from "bknd/data";
export type BkndConfig<Args = any> = CreateAppConfig & { export type BkndConfig<Args = any> = CreateAppConfig & {
app?: CreateAppConfig | ((args: Args) => CreateAppConfig); app?: CreateAppConfig | ((args: Args) => CreateAppConfig);
@@ -74,7 +69,7 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
const sqlite = (await import("bknd/adapter/sqlite")).sqlite; const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
const conf = appConfig.connection ?? { url: ":memory:" }; const conf = appConfig.connection ?? { url: ":memory:" };
connection = sqlite(conf); connection = sqlite(conf);
$console.info(`Using ${connection.name} connection`, conf.url); $console.info(`Using ${connection!.name} connection`, conf.url);
} }
appConfig.connection = connection; appConfig.connection = connection;
} }
@@ -1,4 +1,4 @@
import { genericSqlite } from "bknd/data"; import { genericSqlite } from "bknd";
import { DatabaseSync } from "node:sqlite"; import { DatabaseSync } from "node:sqlite";
export type NodeSqliteConnectionConfig = { export type NodeSqliteConnectionConfig = {
+2 -3
View File
@@ -3,9 +3,8 @@ import { serve as honoServe } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static"; import { serveStatic } from "@hono/node-server/serve-static";
import { registerLocalMediaAdapter } from "adapter/node/storage"; import { registerLocalMediaAdapter } from "adapter/node/storage";
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter"; import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
import { config as $config } from "bknd/core"; import { config as $config, type App } from "bknd";
import { $console } from "core/utils"; import { $console } from "bknd/utils";
import type { App } from "App";
type NodeEnv = NodeJS.ProcessEnv; type NodeEnv = NodeJS.ProcessEnv;
export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & { export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
@@ -1,8 +1,7 @@
import { readFile, readdir, stat, unlink, writeFile } from "node:fs/promises"; import { readFile, readdir, stat, unlink, writeFile } from "node:fs/promises";
import { isFile } from "bknd/utils"; import type { FileBody, FileListObject, FileMeta, FileUploadPayload } from "bknd";
import type { FileBody, FileListObject, FileMeta, FileUploadPayload } from "bknd/media"; import { StorageAdapter, guessMimeType } from "bknd";
import { StorageAdapter, guessMimeType as guess } from "bknd/media"; import { parse, s, isFile } from "bknd/utils";
import { parse, s } from "bknd/core";
export const localAdapterConfig = s.object( export const localAdapterConfig = s.object(
{ {
@@ -84,7 +83,7 @@ export class StorageLocalAdapter extends StorageAdapter {
async getObject(key: string, headers: Headers): Promise<Response> { async getObject(key: string, headers: Headers): Promise<Response> {
try { try {
const content = await readFile(`${this.config.path}/${key}`); const content = await readFile(`${this.config.path}/${key}`);
const mimeType = guess(key); const mimeType = guessMimeType(key);
return new Response(content, { return new Response(content, {
status: 200, status: 200,
@@ -106,7 +105,7 @@ export class StorageLocalAdapter extends StorageAdapter {
async getObjectMeta(key: string): Promise<FileMeta> { async getObjectMeta(key: string): Promise<FileMeta> {
const stats = await stat(`${this.config.path}/${key}`); const stats = await stat(`${this.config.path}/${key}`);
return { return {
type: guess(key) || "application/octet-stream", type: guessMimeType(key) || "application/octet-stream",
size: stats.size, size: stats.size,
}; };
} }
+1 -1
View File
@@ -1,4 +1,4 @@
import type { Connection } from "bknd/data"; import type { Connection } from "bknd";
import { bunSqlite } from "../bun/connection/BunSqliteConnection"; import { bunSqlite } from "../bun/connection/BunSqliteConnection";
export function sqlite(config?: { url: string }): Connection { export function sqlite(config?: { url: string }): Connection {
+1 -1
View File
@@ -1,4 +1,4 @@
import { type Connection, libsql } from "bknd/data"; import { type Connection, libsql } from "bknd";
export function sqlite(config: { url: string }): Connection { export function sqlite(config: { url: string }): Connection {
return libsql(config); return libsql(config);
+1 -1
View File
@@ -1,4 +1,4 @@
import type { Connection } from "bknd/data"; import type { Connection } from "bknd";
import { nodeSqlite } from "../node/connection/NodeSqliteConnection"; import { nodeSqlite } from "../node/connection/NodeSqliteConnection";
export function sqlite(config?: { url: string }): Connection { export function sqlite(config?: { url: string }): Connection {
+9 -6
View File
@@ -1,8 +1,9 @@
import { Authenticator, AuthPermissions, Role, type Strategy } from "auth"; import type { DB } from "bknd";
import type { PasswordStrategy } from "auth/authenticate/strategies"; import * as AuthPermissions from "auth/auth-permissions";
import type { DB } from "core"; import type { AuthStrategy } from "auth/authenticate/strategies/Strategy";
import type { PasswordStrategy } from "auth/authenticate/strategies/PasswordStrategy";
import { $console, secureRandomString, transformObject } from "core/utils"; import { $console, secureRandomString, transformObject } from "core/utils";
import type { Entity, EntityManager } from "data"; import type { Entity, EntityManager } from "data/entities";
import { em, entity, enumm, type FieldSchema } from "data/prototype"; import { em, entity, enumm, type FieldSchema } from "data/prototype";
import { Module } from "modules/Module"; import { Module } from "modules/Module";
import { AuthController } from "./api/AuthController"; import { AuthController } from "./api/AuthController";
@@ -10,9 +11,11 @@ import { type AppAuthSchema, authConfigSchema, STRATEGIES } from "./auth-schema"
import { AppUserPool } from "auth/AppUserPool"; import { AppUserPool } from "auth/AppUserPool";
import type { AppEntity } from "core/config"; import type { AppEntity } from "core/config";
import { usersFields } from "./auth-entities"; import { usersFields } from "./auth-entities";
import { Authenticator } from "./authenticate/Authenticator";
import { Role } from "./authorize/Role";
export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>; export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>;
declare module "core" { declare module "bknd" {
interface Users extends AppEntity, UserFieldSchema {} interface Users extends AppEntity, UserFieldSchema {}
interface DB { interface DB {
users: Users; users: Users;
@@ -88,7 +91,7 @@ export class AppAuth extends Module<AppAuthSchema> {
this.ctx.guard.registerPermissions(AuthPermissions); this.ctx.guard.registerPermissions(AuthPermissions);
} }
isStrategyEnabled(strategy: Strategy | string) { isStrategyEnabled(strategy: AuthStrategy | string) {
const name = typeof strategy === "string" ? strategy : strategy.getName(); const name = typeof strategy === "string" ? strategy : strategy.getName();
// for now, password is always active // for now, password is always active
if (name === "password") return true; if (name === "password") return true;
+2 -2
View File
@@ -1,6 +1,6 @@
import type { AuthActionResponse } from "auth/api/AuthController"; import type { AuthActionResponse } from "auth/api/AuthController";
import type { AppAuthSchema } from "auth/auth-schema"; import type { AppAuthSchema } from "auth/auth-schema";
import type { AuthResponse, SafeUser, Strategy } from "auth/authenticate/Authenticator"; import type { AuthResponse, SafeUser, AuthStrategy } from "bknd";
import { type BaseModuleApiOptions, ModuleApi } from "modules/ModuleApi"; import { type BaseModuleApiOptions, ModuleApi } from "modules/ModuleApi";
export type AuthApiOptions = BaseModuleApiOptions & { export type AuthApiOptions = BaseModuleApiOptions & {
@@ -39,7 +39,7 @@ export class AuthApi extends ModuleApi<AuthApiOptions> {
} }
async actionSchema(strategy: string, action: string) { async actionSchema(strategy: string, action: string) {
return this.get<Strategy>([strategy, "actions", action, "schema.json"]); return this.get<AuthStrategy>([strategy, "actions", action, "schema.json"]);
} }
async action(strategy: string, action: string, input: any) { async action(strategy: string, action: string, input: any) {
+7 -5
View File
@@ -1,9 +1,11 @@
import { type AppAuth, AuthPermissions, type SafeUser, type Strategy } from "auth"; import type { SafeUser } from "bknd";
import { transformObject } from "core/utils"; import type { AuthStrategy } from "auth/authenticate/strategies/Strategy";
import { DataPermissions } from "data"; import type { AppAuth } from "auth/AppAuth";
import * as AuthPermissions from "auth/auth-permissions";
import * as DataPermissions from "data/permissions";
import type { Hono } from "hono"; import type { Hono } from "hono";
import { Controller, type ServerEnv } from "modules/Controller"; import { Controller, type ServerEnv } from "modules/Controller";
import { describeRoute, jsc, s, parse, InvalidSchemaError } from "bknd/core"; import { describeRoute, jsc, s, parse, InvalidSchemaError, transformObject } from "bknd/utils";
export type AuthActionResponse = { export type AuthActionResponse = {
success: boolean; success: boolean;
@@ -30,7 +32,7 @@ export class AuthController extends Controller {
return this.em.repo(entity_name as "users"); return this.em.repo(entity_name as "users");
} }
private registerStrategyActions(strategy: Strategy, mainHono: Hono<ServerEnv>) { private registerStrategyActions(strategy: AuthStrategy, mainHono: Hono<ServerEnv>) {
if (!this.auth.isStrategyEnabled(strategy)) { if (!this.auth.isStrategyEnabled(strategy)) {
return; return;
} }
+1 -1
View File
@@ -1,4 +1,4 @@
import { Permission } from "core"; import { Permission } from "core/security/Permission";
export const createUser = new Permission("auth.user.create"); export const createUser = new Permission("auth.user.create");
//export const updateUser = new Permission("auth.user.update"); //export const updateUser = new Permission("auth.user.update");
+1 -2
View File
@@ -1,7 +1,6 @@
import { cookieConfig, jwtConfig } from "auth/authenticate/Authenticator"; import { cookieConfig, jwtConfig } from "auth/authenticate/Authenticator";
import { CustomOAuthStrategy, OAuthStrategy, PasswordStrategy } from "auth/authenticate/strategies"; import { CustomOAuthStrategy, OAuthStrategy, PasswordStrategy } from "auth/authenticate/strategies";
import { objectTransform } from "core/utils"; import { objectTransform, s } from "bknd/utils";
import { s } from "bknd/core";
export const Strategies = { export const Strategies = {
password: { password: {
+12 -20
View File
@@ -1,14 +1,15 @@
import { type DB, Exception } from "core"; import type { DB } from "bknd";
import { Exception } from "core/errors";
import { addFlashMessage } from "core/server/flash"; import { addFlashMessage } from "core/server/flash";
import { runtimeSupports, truncate, $console } from "core/utils"; import type { Context } from "hono";
import type { Context, Hono } from "hono";
import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie"; import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
import { sign, verify } from "hono/jwt"; import { sign, verify } from "hono/jwt";
import { type CookieOptions, serializeSigned } from "hono/utils/cookie"; import { type CookieOptions, serializeSigned } from "hono/utils/cookie";
import type { ServerEnv } from "modules/Controller"; import type { ServerEnv } from "modules/Controller";
import { pick } from "lodash-es"; import { pick } from "lodash-es";
import { InvalidConditionsException } from "auth/errors"; import { InvalidConditionsException } from "auth/errors";
import { s, parse, secret } from "bknd/core"; import { s, parse, secret, runtimeSupports, truncate, $console } from "bknd/utils";
import type { AuthStrategy } from "./strategies/Strategy";
type Input = any; // workaround type Input = any; // workaround
export type JWTPayload = Parameters<typeof sign>[0]; export type JWTPayload = Parameters<typeof sign>[0];
@@ -21,17 +22,6 @@ export type StrategyAction<S extends s.ObjectSchema = s.ObjectSchema> = {
}; };
export type StrategyActions = Partial<Record<StrategyActionName, StrategyAction>>; export type StrategyActions = Partial<Record<StrategyActionName, StrategyAction>>;
// @todo: add schema to interface to ensure proper inference
// @todo: add tests (e.g. invalid strategy_value)
export interface Strategy {
getController: (auth: Authenticator) => Hono<any>;
getType: () => string;
getMode: () => "form" | "external";
getName: () => string;
toJSON: (secrets?: boolean) => any;
getActions?: () => StrategyActions;
}
export type User = DB["users"]; export type User = DB["users"];
export type ProfileExchange = { export type ProfileExchange = {
@@ -98,7 +88,7 @@ export type AuthResolveOptions = {
}; };
export type AuthUserResolver = ( export type AuthUserResolver = (
action: AuthAction, action: AuthAction,
strategy: Strategy, strategy: AuthStrategy,
profile: ProfileExchange, profile: ProfileExchange,
opts?: AuthResolveOptions, opts?: AuthResolveOptions,
) => Promise<ProfileExchange | undefined>; ) => Promise<ProfileExchange | undefined>;
@@ -108,7 +98,9 @@ type AuthClaims = SafeUser & {
exp?: number; exp?: number;
}; };
export class Authenticator<Strategies extends Record<string, Strategy> = Record<string, Strategy>> { export class Authenticator<
Strategies extends Record<string, AuthStrategy> = Record<string, AuthStrategy>,
> {
private readonly config: AuthConfig; private readonly config: AuthConfig;
constructor( constructor(
@@ -121,7 +113,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
async resolveLogin( async resolveLogin(
c: Context, c: Context,
strategy: Strategy, strategy: AuthStrategy,
profile: Partial<SafeUser>, profile: Partial<SafeUser>,
verify: (user: User) => Promise<void>, verify: (user: User) => Promise<void>,
opts?: AuthResolveOptions, opts?: AuthResolveOptions,
@@ -159,7 +151,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
async resolveRegister( async resolveRegister(
c: Context, c: Context,
strategy: Strategy, strategy: AuthStrategy,
profile: CreateUser, profile: CreateUser,
verify: (user: User) => Promise<void>, verify: (user: User) => Promise<void>,
opts?: AuthResolveOptions, opts?: AuthResolveOptions,
@@ -228,7 +220,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
strategy< strategy<
StrategyName extends keyof Strategies, StrategyName extends keyof Strategies,
Strat extends Strategy = Strategies[StrategyName], Strat extends AuthStrategy = Strategies[StrategyName],
>(strategy: StrategyName): Strat { >(strategy: StrategyName): Strat {
try { try {
return this.strategies[strategy] as unknown as Strat; return this.strategies[strategy] as unknown as Strat;
@@ -1,9 +1,11 @@
import { type Authenticator, InvalidCredentialsException, type User } from "auth"; import type { User } from "bknd";
import type { Authenticator } from "auth/authenticate/Authenticator";
import { InvalidCredentialsException } from "auth/errors";
import { hash, $console } from "core/utils"; import { hash, $console } from "core/utils";
import { Hono } from "hono"; import { Hono } from "hono";
import { compare as bcryptCompare, genSalt as bcryptGenSalt, hash as bcryptHash } from "bcryptjs"; import { compare as bcryptCompare, genSalt as bcryptGenSalt, hash as bcryptHash } from "bcryptjs";
import { Strategy } from "./Strategy"; import { AuthStrategy } from "./Strategy";
import { s, parse, jsc } from "bknd/core"; import { s, parse, jsc } from "bknd/utils";
const schema = s const schema = s
.object({ .object({
@@ -14,7 +16,7 @@ const schema = s
export type PasswordStrategyOptions = s.Static<typeof schema>; export type PasswordStrategyOptions = s.Static<typeof schema>;
export class PasswordStrategy extends Strategy<typeof schema> { export class PasswordStrategy extends AuthStrategy<typeof schema> {
constructor(config: Partial<PasswordStrategyOptions> = {}) { constructor(config: Partial<PasswordStrategyOptions> = {}) {
super(config as any, "password", "password", "form"); super(config as any, "password", "password", "form");
@@ -5,11 +5,11 @@ import type {
StrategyActions, StrategyActions,
} from "../Authenticator"; } from "../Authenticator";
import type { Hono } from "hono"; import type { Hono } from "hono";
import { type s, parse } from "bknd/core"; import { type s, parse } from "bknd/utils";
export type StrategyMode = "form" | "external"; export type StrategyMode = "form" | "external";
export abstract class Strategy<Schema extends s.Schema = s.Schema> { export abstract class AuthStrategy<Schema extends s.Schema = s.Schema> {
protected actions: StrategyActions = {}; protected actions: StrategyActions = {};
constructor( constructor(
@@ -1,6 +1,6 @@
import type * as oauth from "oauth4webapi"; import type * as oauth from "oauth4webapi";
import { OAuthStrategy } from "./OAuthStrategy"; import { OAuthStrategy } from "./OAuthStrategy";
import { s } from "bknd/core"; import { s } from "bknd/utils";
type SupportedTypes = "oauth2" | "oidc"; type SupportedTypes = "oauth2" | "oidc";
@@ -1,12 +1,12 @@
import type { AuthAction, Authenticator } from "auth"; import type { Authenticator, AuthAction } from "auth/authenticate/Authenticator";
import { Exception, isDebug } from "core";
import { filterKeys } from "core/utils";
import { type Context, Hono } from "hono"; import { type Context, Hono } from "hono";
import { getSignedCookie, setSignedCookie } from "hono/cookie"; import { getSignedCookie, setSignedCookie } from "hono/cookie";
import * as oauth from "oauth4webapi"; import * as oauth from "oauth4webapi";
import * as issuers from "./issuers"; import * as issuers from "./issuers";
import { Strategy } from "auth/authenticate/strategies/Strategy"; import { s, filterKeys } from "bknd/utils";
import { s } from "bknd/core"; import { Exception } from "core/errors";
import { isDebug } from "core/env";
import { AuthStrategy } from "../Strategy";
type ConfiguredIssuers = keyof typeof issuers; type ConfiguredIssuers = keyof typeof issuers;
type SupportedTypes = "oauth2" | "oidc"; type SupportedTypes = "oauth2" | "oidc";
@@ -70,7 +70,7 @@ export class OAuthCallbackException extends Exception {
} }
} }
export class OAuthStrategy extends Strategy<typeof schemaProvided> { export class OAuthStrategy extends AuthStrategy<typeof schemaProvided> {
constructor(config: ProvidedOAuthConfig) { constructor(config: ProvidedOAuthConfig) {
super(config, "oauth", config.name, "external"); super(config, "oauth", config.name, "external");
} }
+2 -1
View File
@@ -1,5 +1,6 @@
import { Exception, Permission } from "core"; import { Exception } from "core/errors";
import { $console, objectTransform } from "core/utils"; import { $console, objectTransform } from "core/utils";
import { Permission } from "core/security/Permission";
import type { Context } from "hono"; import type { Context } from "hono";
import type { ServerEnv } from "modules/Controller"; import type { ServerEnv } from "modules/Controller";
import { Role } from "./Role"; import { Role } from "./Role";
+1 -1
View File
@@ -1,4 +1,4 @@
import { Permission } from "core"; import { Permission } from "core/security/Permission";
export class RolePermission { export class RolePermission {
constructor( constructor(
+3 -2
View File
@@ -1,5 +1,6 @@
import { Exception, isDebug } from "core"; import { Exception } from "core/errors";
import { HttpStatus } from "core/utils"; import { isDebug } from "core/env";
import { HttpStatus } from "bknd/utils";
export class AuthException extends Exception { export class AuthException extends Exception {
getSafeErrorAndCode() { getSafeErrorAndCode() {
-22
View File
@@ -1,22 +0,0 @@
export { UserExistsException, UserNotFoundException, InvalidCredentialsException } from "./errors";
export {
type ProfileExchange,
type Strategy,
type User,
type SafeUser,
type CreateUser,
type AuthResponse,
type UserPool,
type AuthAction,
type AuthUserResolver,
Authenticator,
authenticatorConfig,
jwtConfig,
} from "./authenticate/Authenticator";
export { AppAuth, type UserFieldSchema } from "./AppAuth";
export { Guard, type GuardUserContext, type GuardConfig } from "./authorize/Guard";
export { Role } from "./authorize/Role";
export * as AuthPermissions from "./auth-permissions";
+2 -2
View File
@@ -1,5 +1,5 @@
import type { Permission } from "core"; import type { Permission } from "core/security/Permission";
import { $console, patternMatch } from "core/utils"; import { $console, patternMatch } from "bknd/utils";
import type { Context } from "hono"; import type { Context } from "hono";
import { createMiddleware } from "hono/factory"; import { createMiddleware } from "hono/factory";
import type { ServerEnv } from "modules/Controller"; import type { ServerEnv } from "modules/Controller";
+1 -1
View File
@@ -5,7 +5,7 @@ import type { CliCommand } from "cli/types";
import { typewriter, wait } from "cli/utils/cli"; import { typewriter, wait } from "cli/utils/cli";
import { execAsync, getVersion } from "cli/utils/sys"; import { execAsync, getVersion } from "cli/utils/sys";
import { Option } from "commander"; import { Option } from "commander";
import { env } from "core"; import { env } from "bknd";
import color from "picocolors"; import color from "picocolors";
import { overridePackageJson, updateBkndPackages } from "./npm"; import { overridePackageJson, updateBkndPackages } from "./npm";
import { type Template, templates, type TemplateSetupCtx } from "./templates"; import { type Template, templates, type TemplateSetupCtx } from "./templates";
+3 -4
View File
@@ -1,9 +1,8 @@
import type { Config } from "@libsql/client/node"; import type { Config } from "@libsql/client/node";
import type { App, CreateAppConfig } from "App";
import { StorageLocalAdapter } from "adapter/node/storage"; import { StorageLocalAdapter } from "adapter/node/storage";
import type { CliBkndConfig, CliCommand } from "cli/types"; import type { CliBkndConfig, CliCommand } from "cli/types";
import { Option } from "commander"; import { Option } from "commander";
import { config } from "core"; import { config, type App, type CreateAppConfig } from "bknd";
import dotenv from "dotenv"; import dotenv from "dotenv";
import { registries } from "modules/registries"; import { registries } from "modules/registries";
import c from "picocolors"; import c from "picocolors";
@@ -16,8 +15,8 @@ import {
serveStatic, serveStatic,
startServer, startServer,
} from "./platform"; } from "./platform";
import { createRuntimeApp, makeConfig } from "adapter"; import { createRuntimeApp, makeConfig } from "bknd/adapter";
import { colorizeConsole, isBun } from "core/utils"; import { colorizeConsole, isBun } from "bknd/utils";
const env_files = [".env", ".dev.vars"]; const env_files = [".env", ".dev.vars"];
dotenv.config({ dotenv.config({
+2 -2
View File
@@ -1,7 +1,7 @@
import { PostHog } from "posthog-js-lite"; import { PostHog } from "posthog-js-lite";
import { getVersion } from "cli/utils/sys"; import { getVersion } from "cli/utils/sys";
import { env, isDebug } from "core"; import { env, isDebug } from "bknd";
import { $console } from "core/utils"; import { $console } from "bknd/utils";
type Properties = { [p: string]: any }; type Properties = { [p: string]: any };
-20
View File
@@ -6,23 +6,3 @@ export interface IEmailDriver<Data = unknown, Options = object> {
options?: Options, options?: Options,
): Promise<Data>; ): Promise<Data>;
} }
import type { BkndConfig } from "bknd";
import { resendEmail, memoryCache } from "bknd/core";
export default {
onBuilt: async (app) => {
app.server.get("/send-email", async (c) => {
if (await app.drivers?.email?.send("test@test.com", "Test", "Test")) {
return c.text("success");
}
return c.text("failed");
});
},
options: {
drivers: {
email: resendEmail({ apiKey: "..." }),
cache: memoryCache(),
},
},
} as const satisfies BkndConfig;
-51
View File
@@ -1,51 +0,0 @@
import type { Hono, MiddlewareHandler } from "hono";
export { Exception, BkndError } from "./errors";
export { isDebug, env } from "./env";
export { type PrimaryFieldType, config, type DB, type AppEntity } from "./config";
export { AwsClient } from "./clients/aws/AwsClient";
export {
SimpleRenderer,
type TemplateObject,
type TemplateTypes,
type SimpleRendererOptions,
} from "./template/SimpleRenderer";
export { SchemaObject } from "./object/SchemaObject";
export { DebugLogger } from "./utils/DebugLogger";
export { Permission } from "./security/Permission";
export {
exp,
makeValidator,
type FilterQuery,
type Primitive,
isPrimitive,
type TExpression,
type BooleanLike,
isBooleanLike,
} from "./object/query/query";
export { Registry, type Constructor } from "./registry/Registry";
export { getFlashMessage } from "./server/flash";
export {
s,
stripMark,
mark,
stringIdentifier,
secret,
parse,
jsc,
describeRoute,
schemaToSpec,
openAPISpecs,
type ParseOptions,
InvalidSchemaError,
} from "./object/schema";
export * from "./drivers";
export * from "./events";
// compatibility
export type Middleware = MiddlewareHandler<any, any, any>;
export interface ClassController {
getController: () => Hono<any, any, any>;
getMiddleware?: MiddlewareHandler<any, any, any>;
}
+13 -12
View File
@@ -1,6 +1,5 @@
import { get, has, omit, set } from "lodash-es"; import { get, has, omit, set } from "lodash-es";
import { getFullPathKeys, mergeObjectWith } from "../utils"; import { type s, parse, stripMark, getFullPathKeys, mergeObjectWith, deepFreeze } from "bknd/utils";
import { type s, parse, stripMark } from "bknd/core";
export type SchemaObjectOptions<Schema extends s.Schema> = { export type SchemaObjectOptions<Schema extends s.Schema> = {
onUpdate?: (config: s.Static<Schema>) => void | Promise<void>; onUpdate?: (config: s.Static<Schema>) => void | Promise<void>;
@@ -26,14 +25,16 @@ export class SchemaObject<Schema extends TSchema = TSchema> {
initial?: Partial<s.Static<Schema>>, initial?: Partial<s.Static<Schema>>,
private options?: SchemaObjectOptions<Schema>, private options?: SchemaObjectOptions<Schema>,
) { ) {
this._default = _schema.template({}, { withOptional: true }) as any; this._default = deepFreeze(_schema.template({}, { withOptional: true }) as any);
this._value = parse(_schema, structuredClone(initial ?? {}), { this._value = deepFreeze(
withDefaults: true, parse(_schema, structuredClone(initial ?? {}), {
withExtendedDefaults: true, withDefaults: true,
forceParse: this.isForceParse(), withExtendedDefaults: true,
skipMark: this.isForceParse(), forceParse: this.isForceParse(),
}); skipMark: this.isForceParse(),
this._config = Object.freeze(this._value); }),
);
this._config = deepFreeze(this._value);
} }
protected isForceParse(): boolean { protected isForceParse(): boolean {
@@ -76,8 +77,8 @@ export class SchemaObject<Schema extends TSchema = TSchema> {
// regardless of "noEmit" this should always be triggered // regardless of "noEmit" this should always be triggered
const updatedConfig = await this.onBeforeUpdate(this._config, valid); const updatedConfig = await this.onBeforeUpdate(this._config, valid);
this._value = updatedConfig; this._value = deepFreeze(updatedConfig);
this._config = Object.freeze(updatedConfig); this._config = deepFreeze(updatedConfig);
if (noEmit !== true) { if (noEmit !== true) {
await this.options?.onUpdate?.(this._config); await this.options?.onUpdate?.(this._config);
+1 -1
View File
@@ -1,4 +1,4 @@
import type { PrimaryFieldType } from "core"; import type { PrimaryFieldType } from "core/config";
export type Primitive = PrimaryFieldType | string | number | boolean; export type Primitive = PrimaryFieldType | string | number | boolean;
export function isPrimitive(value: any): value is Primitive { export function isPrimitive(value: any): value is Primitive {
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { SimpleRenderer } from "core"; import { SimpleRenderer } from "./SimpleRenderer";
describe(SimpleRenderer, () => { describe(SimpleRenderer, () => {
const renderer = new SimpleRenderer( const renderer = new SimpleRenderer(
+2 -2
View File
@@ -1,6 +1,6 @@
import { datetimeStringLocal } from "core/utils"; import { datetimeStringLocal } from "./dates";
import colors from "picocolors"; import colors from "picocolors";
import { env } from "core"; import { env } from "core/env";
function hasColors() { function hasColors() {
try { try {
+15
View File
@@ -13,3 +13,18 @@ export * from "./uuid";
export * from "./test"; export * from "./test";
export * from "./runtime"; export * from "./runtime";
export * from "./numbers"; export * from "./numbers";
export {
s,
stripMark,
mark,
stringIdentifier,
SecretSchema,
secret,
parse,
jsc,
describeRoute,
schemaToSpec,
openAPISpecs,
type ParseOptions,
InvalidSchemaError,
} from "./schema";
+26 -10
View File
@@ -94,16 +94,14 @@ export function transformObject<T extends Record<string, any>, U>(
object: T, object: T,
transform: (value: T[keyof T], key: keyof T) => U | undefined, transform: (value: T[keyof T], key: keyof T) => U | undefined,
): { [K in keyof T]: U } { ): { [K in keyof T]: U } {
return Object.entries(object).reduce( const result = {} as { [K in keyof T]: U };
(acc, [key, value]) => { for (const [key, value] of Object.entries(object) as [keyof T, T[keyof T]][]) {
const t = transform(value, key as keyof T); const t = transform(value, key);
if (typeof t !== "undefined") { if (typeof t !== "undefined") {
acc[key as keyof T] = t; result[key] = t;
} }
return acc; }
}, return result;
{} as { [K in keyof T]: U },
);
} }
export const objectTransform = transformObject; export const objectTransform = transformObject;
@@ -419,3 +417,21 @@ export function pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pi
{} as Pick<T, K>, {} as Pick<T, K>,
); );
} }
export function deepFreeze<T extends object>(object: T): T {
if (Object.isFrozen(object)) return object;
// Retrieve the property names defined on object
const propNames = Reflect.ownKeys(object);
// Freeze properties before freezing self
for (const name of propNames) {
const value = object[name];
if ((value && typeof value === "object") || typeof value === "function") {
deepFreeze(value);
}
}
return Object.freeze(object);
}
@@ -3,7 +3,7 @@ import * as s from "jsonv-ts";
export { validator as jsc, type Options } from "jsonv-ts/hono"; export { validator as jsc, type Options } from "jsonv-ts/hono";
export { describeRoute, schemaToSpec, openAPISpecs } from "jsonv-ts/hono"; export { describeRoute, schemaToSpec, openAPISpecs } from "jsonv-ts/hono";
export { secret } from "./secret"; export { secret, SecretSchema } from "./secret";
export { s }; export { s };
+5 -8
View File
@@ -1,15 +1,12 @@
import { transformObject } from "core/utils"; import { transformObject } from "core/utils";
import {
DataPermissions,
type Entity,
EntityIndex,
type EntityManager,
constructEntity,
constructRelation,
} from "data";
import { Module } from "modules/Module"; 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";
import { constructEntity, constructRelation } from "./schema/constructor";
import type { Entity, EntityManager } from "data/entities";
import { EntityIndex } from "data/fields";
import * as DataPermissions from "data/permissions";
export class AppData extends Module<AppDataConfig> { export class AppData extends Module<AppDataConfig> {
override async build() { override async build() {
+3 -2
View File
@@ -1,8 +1,9 @@
import type { DB } from "core"; import type { DB, EntityData, RepoQueryIn } from "bknd";
import type { EntityData, RepoQueryIn, RepositoryResultJSON } from "data";
import type { Insertable, Selectable, Updateable } from "kysely"; import type { Insertable, Selectable, Updateable } from "kysely";
import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules"; import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules";
import type { FetchPromise, ResponseObject } from "modules/ModuleApi"; import type { FetchPromise, ResponseObject } from "modules/ModuleApi";
import type { RepositoryResultJSON } from "data/entities/query/RepositoryResult";
export type DataApiOptions = BaseModuleApiOptions & { export type DataApiOptions = BaseModuleApiOptions & {
queryLengthLimit: number; queryLengthLimit: number;
+4 -9
View File
@@ -1,17 +1,12 @@
import {
DataPermissions,
type EntityData,
type EntityManager,
type RepoQuery,
repoQuery,
} from "data";
import type { Handler } from "hono/types"; import type { Handler } from "hono/types";
import type { ModuleBuildContext } from "modules"; import type { ModuleBuildContext } from "modules";
import { Controller } from "modules/Controller"; import { Controller } from "modules/Controller";
import { jsc, s, describeRoute, schemaToSpec } from "bknd/core"; import { jsc, s, describeRoute, schemaToSpec, omitKeys } from "bknd/utils";
import * as SystemPermissions from "modules/permissions"; import * as SystemPermissions from "modules/permissions";
import type { AppDataConfig } from "../data-schema"; import type { AppDataConfig } from "../data-schema";
import { omitKeys } from "core/utils"; import type { EntityManager, EntityData } from "data/entities";
import * as DataPermissions from "data/permissions";
import { repoQuery, type RepoQuery } from "data/server/query";
export class DataController extends Controller { export class DataController extends Controller {
constructor( constructor(
+2 -1
View File
@@ -18,7 +18,8 @@ import {
sql, sql,
} from "kysely"; } from "kysely";
import type { BaseIntrospector, BaseIntrospectorConfig } from "./BaseIntrospector"; import type { BaseIntrospector, BaseIntrospectorConfig } from "./BaseIntrospector";
import type { Constructor, DB } from "core"; import type { DB } from "bknd";
import type { Constructor } from "core/registry/Registry";
import { KyselyPluginRunner } from "data/plugins/KyselyPluginRunner"; import { KyselyPluginRunner } from "data/plugins/KyselyPluginRunner";
import type { Field } from "data/fields/Field"; import type { Field } from "data/fields/Field";
@@ -8,7 +8,7 @@ import {
} from "kysely"; } from "kysely";
import { jsonArrayFrom, jsonBuildObject, jsonObjectFrom } from "kysely/helpers/sqlite"; import { jsonArrayFrom, jsonBuildObject, jsonObjectFrom } from "kysely/helpers/sqlite";
import { Connection, type DbFunctions, type FieldSpec, type SchemaResponse } from "../Connection"; import { Connection, type DbFunctions, type FieldSpec, type SchemaResponse } from "../Connection";
import type { Constructor } from "core"; import type { Constructor } from "core/registry/Registry";
import { customIntrospector } from "../Connection"; import { customIntrospector } from "../Connection";
import { SqliteIntrospector } from "./SqliteIntrospector"; import { SqliteIntrospector } from "./SqliteIntrospector";
import type { Field } from "data/fields/Field"; import type { Field } from "data/fields/Field";
+1 -1
View File
@@ -4,7 +4,7 @@ import { FieldClassMap } from "data/fields";
import { RelationClassMap, RelationFieldClassMap } from "data/relations"; import { RelationClassMap, RelationFieldClassMap } from "data/relations";
import { entityConfigSchema, entityTypes } from "data/entities"; import { entityConfigSchema, entityTypes } from "data/entities";
import { primaryFieldTypes } from "./fields"; import { primaryFieldTypes } from "./fields";
import { s } from "bknd/core"; import { s } from "bknd/utils";
export const FIELDS = { export const FIELDS = {
...FieldClassMap, ...FieldClassMap,
+2 -3
View File
@@ -1,5 +1,5 @@
import { config } from "core"; import { config } from "core/config";
import { snakeToPascalWithSpaces, transformObject, $console } from "core/utils"; import { snakeToPascalWithSpaces, transformObject, $console, s, parse } from "bknd/utils";
import { import {
type Field, type Field,
PrimaryField, PrimaryField,
@@ -7,7 +7,6 @@ import {
type TActionContext, type TActionContext,
type TRenderContext, type TRenderContext,
} from "../fields"; } from "../fields";
import { s, parse } from "bknd/core";
// @todo: entity must be migrated to typebox // @todo: entity must be migrated to typebox
export const entityConfigSchema = s export const entityConfigSchema = s
+2 -2
View File
@@ -1,5 +1,5 @@
import type { DB as DefaultDB } from "core"; import type { DB as DefaultDB } from "bknd";
import { $console } from "core/utils"; import { $console } from "bknd/utils";
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";
+2 -1
View File
@@ -1,4 +1,5 @@
import type { Entity, EntityManager, EntityRelation, TEntityType } from "data"; import type { Entity, EntityManager, TEntityType } from "data/entities";
import type { EntityRelation } from "data/relations";
import { autoFormatString } from "core/utils"; import { autoFormatString } from "core/utils";
import { usersFields } from "auth/auth-entities"; import { usersFields } from "auth/auth-entities";
import { mediaFields } from "media/media-entities"; import { mediaFields } from "media/media-entities";
+1 -1
View File
@@ -1,4 +1,4 @@
import { isDebug } from "core"; import { isDebug } from "core/env";
import { pick } from "core/utils"; import { pick } from "core/utils";
import type { Connection } from "data/connection"; import type { Connection } from "data/connection";
import type { import type {
+2 -3
View File
@@ -1,7 +1,7 @@
import type { DB as DefaultDB, PrimaryFieldType } from "core"; import type { DB as DefaultDB, PrimaryFieldType } from "bknd";
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 } from "../.."; import type { TActionContext } from "data/fields";
import { WhereBuilder } from "../query/WhereBuilder"; import { WhereBuilder } from "../query/WhereBuilder";
import type { Entity, EntityData, EntityManager } from "../../entities"; import type { Entity, EntityData, EntityManager } from "../../entities";
import { InvalidSearchParamsException } from "../../errors"; import { InvalidSearchParamsException } from "../../errors";
@@ -9,7 +9,6 @@ import { MutatorEvents } from "../../events";
import { RelationMutator } from "../../relations"; import { RelationMutator } from "../../relations";
import type { RepoQuery } from "../../server/query"; import type { RepoQuery } from "../../server/query";
import { MutatorResult, type MutatorResultOptions } from "./MutatorResult"; import { MutatorResult, type MutatorResultOptions } from "./MutatorResult";
import { transformObject } from "core/utils";
type MutatorQB = type MutatorQB =
| InsertQueryBuilder<any, any, any> | InsertQueryBuilder<any, any, any>

Some files were not shown because too many files have changed in this diff Show More