refactor auth/media entities to separate files, suppress node:sqlite warning

This commit is contained in:
dswbx
2025-07-02 16:36:06 +02:00
parent 80034b9b0a
commit 45138c25f0
8 changed files with 104 additions and 89 deletions

View File

@@ -3,7 +3,7 @@
"type": "module", "type": "module",
"sideEffects": false, "sideEffects": false,
"bin": "./dist/cli/index.js", "bin": "./dist/cli/index.js",
"version": "0.15.0-rc.7", "version": "0.15.0-rc.8",
"description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.", "description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.",
"homepage": "https://bknd.io", "homepage": "https://bknd.io",
"repository": { "repository": {

View File

@@ -3,12 +3,13 @@ import type { PasswordStrategy } from "auth/authenticate/strategies";
import type { DB } from "core"; import type { DB } from "core";
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";
import { em, entity, enumm, type FieldSchema, text } 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";
import { type AppAuthSchema, authConfigSchema, STRATEGIES } from "./auth-schema"; 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";
export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>; export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>;
declare module "core" { declare module "core" {
@@ -125,18 +126,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
return this.em.entity(entity_name) as any; return this.em.entity(entity_name) as any;
} }
static usersFields = { static usersFields = usersFields;
email: text().required(),
strategy: text({
fillable: ["create"],
hidden: ["update", "form"],
}).required(),
strategy_value: text({
fillable: ["create"],
hidden: ["read", "table", "update", "form"],
}).required(),
role: text(),
};
registerEntities() { registerEntities() {
const users = this.getUsersEntity(true); const users = this.getUsersEntity(true);

View File

@@ -0,0 +1,14 @@
import { text } from "data/prototype";
export const usersFields = {
email: text().required(),
strategy: text({
fillable: ["create"],
hidden: ["update", "form"],
}).required(),
strategy_value: text({
fillable: ["create"],
hidden: ["read", "table", "update", "form"],
}).required(),
role: text(),
};

View File

@@ -1,6 +1,7 @@
import type { Entity, EntityManager, EntityRelation, TEntityType } from "data"; import type { Entity, EntityManager, EntityRelation, TEntityType } from "data";
import { autoFormatString } from "core/utils"; import { autoFormatString } from "core/utils";
import { AppAuth, AppMedia } from "modules"; import { usersFields } from "auth/auth-entities";
import { mediaFields } from "media/media-entities";
export type TEntityTSType = { export type TEntityTSType = {
name: string; name: string;
@@ -32,8 +33,8 @@ export type EntityTypescriptOptions = {
// keep a local copy here until properties have a type // keep a local copy here until properties have a type
const systemEntities = { const systemEntities = {
users: AppAuth.usersFields, users: usersFields,
media: AppMedia.mediaFields, media: mediaFields,
}; };
export class EntityTypescript { export class EntityTypescript {

View File

@@ -3,16 +3,13 @@ import { EntityManager } from "data/entities/EntityManager";
import type { Generated } from "kysely"; import type { Generated } from "kysely";
import { MediaField, type MediaFieldConfig, type MediaItem } from "media/MediaField"; import { MediaField, type MediaFieldConfig, type MediaItem } from "media/MediaField";
import type { ModuleConfigs } from "modules"; import type { ModuleConfigs } from "modules";
import { import {
BooleanField, BooleanField,
type BooleanFieldConfig, type BooleanFieldConfig,
type Connection,
DateField, DateField,
type DateFieldConfig, type DateFieldConfig,
Entity,
type EntityConfig,
EntityIndex, EntityIndex,
type EntityRelation,
EnumField, EnumField,
type EnumFieldConfig, type EnumFieldConfig,
type Field, type Field,
@@ -20,20 +17,27 @@ import {
type JsonFieldConfig, type JsonFieldConfig,
JsonSchemaField, JsonSchemaField,
type JsonSchemaFieldConfig, type JsonSchemaFieldConfig,
NumberField,
type NumberFieldConfig,
TextField,
type TextFieldConfig,
} from "data/fields";
import { Entity, type EntityConfig, type TEntityType } from "data/entities";
import type { Connection } from "data/connection";
import {
type EntityRelation,
ManyToManyRelation, ManyToManyRelation,
type ManyToManyRelationConfig, type ManyToManyRelationConfig,
ManyToOneRelation, ManyToOneRelation,
type ManyToOneRelationConfig, type ManyToOneRelationConfig,
NumberField,
type NumberFieldConfig,
OneToOneRelation, OneToOneRelation,
type OneToOneRelationConfig, type OneToOneRelationConfig,
PolymorphicRelation, PolymorphicRelation,
type PolymorphicRelationConfig, type PolymorphicRelationConfig,
type TEntityType, } from "data/relations";
TextField,
type TextFieldConfig,
} from "../index";
type Options<Config = any> = { type Options<Config = any> = {
entity: { name: string; fields: Record<string, Field<any, any, any>> }; entity: { name: string; fields: Record<string, Field<any, any, any>> };
@@ -61,6 +65,46 @@ const FieldMap = {
} as const; } as const;
type TFieldType = keyof typeof FieldMap; type TFieldType = keyof typeof FieldMap;
export class FieldPrototype {
constructor(
public type: TFieldType,
public config: any,
public is_required: boolean,
) {}
required() {
this.is_required = true;
return this;
}
getField(o: Options): Field {
if (!FieldMap[this.type]) {
throw new Error(`Unknown field type: ${this.type}`);
}
try {
return FieldMap[this.type](o) as unknown as Field;
} catch (e) {
throw new Error(`Faild to construct field "${this.type}": ${e}`);
}
}
make(field_name: string): Field {
if (!FieldMap[this.type]) {
throw new Error(`Unknown field type: ${this.type}`);
}
try {
return FieldMap[this.type]({
entity: { name: "unknown", fields: {} },
field_name,
config: this.config,
is_required: this.is_required,
}) as unknown as Field;
} catch (e) {
throw new Error(`Faild to construct field "${this.type}": ${e}`);
}
}
}
export function text( export function text(
config?: Omit<TextFieldConfig, "required">, config?: Omit<TextFieldConfig, "required">,
): TextField<false> & { required: () => TextField<true> } { ): TextField<false> & { required: () => TextField<true> } {
@@ -132,46 +176,6 @@ export function make<Actual extends Field<any, any>>(name: string, field: Actual
throw new Error("Invalid field"); throw new Error("Invalid field");
} }
export class FieldPrototype {
constructor(
public type: TFieldType,
public config: any,
public is_required: boolean,
) {}
required() {
this.is_required = true;
return this;
}
getField(o: Options): Field {
if (!FieldMap[this.type]) {
throw new Error(`Unknown field type: ${this.type}`);
}
try {
return FieldMap[this.type](o) as unknown as Field;
} catch (e) {
throw new Error(`Faild to construct field "${this.type}": ${e}`);
}
}
make(field_name: string): Field {
if (!FieldMap[this.type]) {
throw new Error(`Unknown field type: ${this.type}`);
}
try {
return FieldMap[this.type]({
entity: { name: "unknown", fields: {} },
field_name,
config: this.config,
is_required: this.is_required,
}) as unknown as Field;
} catch (e) {
throw new Error(`Faild to construct field "${this.type}": ${e}`);
}
}
}
export function entity< export function entity<
EntityName extends string, EntityName extends string,
Fields extends Record<string, Field<any, any, any>>, Fields extends Record<string, Field<any, any, any>>,

View File

@@ -1,3 +1,14 @@
try {
/**
* Adding this to avoid warnings from node:sqlite being experimental
*/
const { emitWarning } = process;
process.emitWarning = (warning: string, ...args: any[]) => {
if (warning.includes("SQLite is an experimental feature")) return;
return emitWarning(warning, ...args);
};
} catch (e) {}
export { export {
App, App,
createApp, createApp,

View File

@@ -3,18 +3,10 @@ import { $console } from "core/utils";
import type { Entity, EntityManager } from "data"; import type { Entity, EntityManager } from "data";
import { type FileUploadedEventData, Storage, type StorageAdapter, MediaPermissions } from "media"; import { type FileUploadedEventData, Storage, type StorageAdapter, MediaPermissions } from "media";
import { Module } from "modules/Module"; import { Module } from "modules/Module";
import { import { type FieldSchema, em, entity } from "../data/prototype";
type FieldSchema,
boolean,
datetime,
em,
entity,
json,
number,
text,
} from "../data/prototype";
import { MediaController } from "./api/MediaController"; import { MediaController } from "./api/MediaController";
import { buildMediaSchema, type mediaConfigSchema, registry } from "./media-schema"; import { buildMediaSchema, type mediaConfigSchema, registry } from "./media-schema";
import { mediaFields } from "./media-entities";
export type MediaFieldSchema = FieldSchema<typeof AppMedia.mediaFields>; export type MediaFieldSchema = FieldSchema<typeof AppMedia.mediaFields>;
declare module "core" { declare module "core" {
@@ -95,18 +87,7 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
}; };
} }
static mediaFields = { static mediaFields = mediaFields;
path: text().required(),
folder: boolean({ default_value: false, hidden: true, fillable: ["create"] }),
mime_type: text(),
size: number(),
scope: text({ hidden: true, fillable: ["create"] }),
etag: text(),
modified_at: datetime(),
reference: text(),
entity_id: number(),
metadata: json(),
};
getMediaEntity(forceCreate?: boolean): Entity<"media", typeof AppMedia.mediaFields> { getMediaEntity(forceCreate?: boolean): Entity<"media", typeof AppMedia.mediaFields> {
const entity_name = this.config.entity_name; const entity_name = this.config.entity_name;

View File

@@ -0,0 +1,14 @@
import { boolean, datetime, json, number, text } from "data/prototype";
export const mediaFields = {
path: text().required(),
folder: boolean({ default_value: false, hidden: true, fillable: ["create"] }),
mime_type: text(),
size: number(),
scope: text({ hidden: true, fillable: ["create"] }),
etag: text(),
modified_at: datetime(),
reference: text(),
entity_id: number(),
metadata: json(),
};