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",
"sideEffects": false,
"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.",
"homepage": "https://bknd.io",
"repository": {

View File

@@ -3,12 +3,13 @@ import type { PasswordStrategy } from "auth/authenticate/strategies";
import type { DB } from "core";
import { $console, secureRandomString, transformObject } from "core/utils";
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 { AuthController } from "./api/AuthController";
import { type AppAuthSchema, authConfigSchema, STRATEGIES } from "./auth-schema";
import { AppUserPool } from "auth/AppUserPool";
import type { AppEntity } from "core/config";
import { usersFields } from "./auth-entities";
export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>;
declare module "core" {
@@ -125,18 +126,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
return this.em.entity(entity_name) as any;
}
static 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(),
};
static usersFields = usersFields;
registerEntities() {
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 { autoFormatString } from "core/utils";
import { AppAuth, AppMedia } from "modules";
import { usersFields } from "auth/auth-entities";
import { mediaFields } from "media/media-entities";
export type TEntityTSType = {
name: string;
@@ -32,8 +33,8 @@ export type EntityTypescriptOptions = {
// keep a local copy here until properties have a type
const systemEntities = {
users: AppAuth.usersFields,
media: AppMedia.mediaFields,
users: usersFields,
media: mediaFields,
};
export class EntityTypescript {

View File

@@ -3,16 +3,13 @@ import { EntityManager } from "data/entities/EntityManager";
import type { Generated } from "kysely";
import { MediaField, type MediaFieldConfig, type MediaItem } from "media/MediaField";
import type { ModuleConfigs } from "modules";
import {
BooleanField,
type BooleanFieldConfig,
type Connection,
DateField,
type DateFieldConfig,
Entity,
type EntityConfig,
EntityIndex,
type EntityRelation,
EnumField,
type EnumFieldConfig,
type Field,
@@ -20,20 +17,27 @@ import {
type JsonFieldConfig,
JsonSchemaField,
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,
type ManyToManyRelationConfig,
ManyToOneRelation,
type ManyToOneRelationConfig,
NumberField,
type NumberFieldConfig,
OneToOneRelation,
type OneToOneRelationConfig,
PolymorphicRelation,
type PolymorphicRelationConfig,
type TEntityType,
TextField,
type TextFieldConfig,
} from "../index";
} from "data/relations";
type Options<Config = any> = {
entity: { name: string; fields: Record<string, Field<any, any, any>> };
@@ -61,6 +65,46 @@ const FieldMap = {
} as const;
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(
config?: Omit<TextFieldConfig, "required">,
): 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");
}
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<
EntityName extends string,
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 {
App,
createApp,

View File

@@ -3,18 +3,10 @@ import { $console } from "core/utils";
import type { Entity, EntityManager } from "data";
import { type FileUploadedEventData, Storage, type StorageAdapter, MediaPermissions } from "media";
import { Module } from "modules/Module";
import {
type FieldSchema,
boolean,
datetime,
em,
entity,
json,
number,
text,
} from "../data/prototype";
import { type FieldSchema, em, entity } from "../data/prototype";
import { MediaController } from "./api/MediaController";
import { buildMediaSchema, type mediaConfigSchema, registry } from "./media-schema";
import { mediaFields } from "./media-entities";
export type MediaFieldSchema = FieldSchema<typeof AppMedia.mediaFields>;
declare module "core" {
@@ -95,18 +87,7 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
};
}
static 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(),
};
static mediaFields = mediaFields;
getMediaEntity(forceCreate?: boolean): Entity<"media", typeof AppMedia.mediaFields> {
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(),
};