mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-02 16:16:02 +00:00
103 lines
3.5 KiB
TypeScript
103 lines
3.5 KiB
TypeScript
import { objectTransform } from "bknd/utils";
|
|
import { MediaField, mediaFieldConfigSchema } from "../media/MediaField";
|
|
import { FieldClassMap } from "data/fields";
|
|
import { RelationClassMap, RelationFieldClassMap } from "data/relations";
|
|
import { entityConfigSchema, entityTypes } from "data/entities";
|
|
import { primaryFieldTypes, baseFieldConfigSchema } from "./fields";
|
|
import { s } from "bknd/utils";
|
|
import { $object, $record } from "modules/mcp";
|
|
|
|
export const FIELDS = {
|
|
...FieldClassMap,
|
|
...RelationFieldClassMap,
|
|
media: { schema: mediaFieldConfigSchema, field: MediaField },
|
|
};
|
|
export const FIELD_TYPES = Object.keys(FIELDS);
|
|
export type FieldType = keyof typeof FIELDS;
|
|
|
|
export const RELATIONS = RelationClassMap;
|
|
|
|
export const fieldsSchemaObject = objectTransform(FIELDS, (field, name) => {
|
|
return s.strictObject(
|
|
{
|
|
name: s.string().optional(), // @todo: verify, old schema wasn't strict (req in UI)
|
|
type: s.literal(name),
|
|
config: field.schema.optional(),
|
|
},
|
|
{
|
|
title: name,
|
|
},
|
|
);
|
|
});
|
|
export const fieldsSchema = s.anyOf(Object.values(fieldsSchemaObject));
|
|
export const entityFields = s.record(fieldsSchema, { default: {} });
|
|
export type TAppDataField = s.Static<typeof fieldsSchema>;
|
|
export type TAppDataEntityFields = s.Static<typeof entityFields>;
|
|
|
|
export const entitiesSchema = s.strictObject({
|
|
name: s.string().optional(), // @todo: verify, old schema wasn't strict (req in UI)
|
|
type: s.string({ enum: entityTypes, default: "regular" }).optional(),
|
|
config: entityConfigSchema.optional(),
|
|
fields: entityFields.optional(),
|
|
});
|
|
export type TAppDataEntity = s.Static<typeof entitiesSchema>;
|
|
export const simpleEntitiesSchema = s.strictObject({
|
|
type: s.string({ enum: entityTypes, default: "regular" }).optional(),
|
|
config: entityConfigSchema.optional(),
|
|
fields: s
|
|
.record(
|
|
s.object({
|
|
type: s.anyOf([s.string({ enum: FIELD_TYPES }), s.string()]),
|
|
config: baseFieldConfigSchema.optional(),
|
|
}),
|
|
{ default: {} },
|
|
)
|
|
.optional(),
|
|
});
|
|
|
|
export const relationsSchema = Object.entries(RelationClassMap).map(([name, relationClass]) => {
|
|
return s.strictObject(
|
|
{
|
|
type: s.literal(name),
|
|
source: s.string(),
|
|
target: s.string(),
|
|
config: relationClass.schema.optional(),
|
|
},
|
|
{
|
|
title: name,
|
|
},
|
|
);
|
|
});
|
|
export type TAppDataRelation = s.Static<(typeof relationsSchema)[number]>;
|
|
|
|
export const indicesSchema = s.strictObject({
|
|
entity: s.string(),
|
|
fields: s.array(s.string(), { minItems: 1 }),
|
|
unique: s.boolean({ default: false }).optional(),
|
|
});
|
|
|
|
export const dataConfigSchema = $object("config_data", {
|
|
basepath: s.string({ default: "/api/data" }).optional(),
|
|
default_primary_format: s.string({ enum: primaryFieldTypes, default: "integer" }).optional(),
|
|
entities: $record("config_data_entities", entitiesSchema, { default: {} }).optional(),
|
|
relations: $record(
|
|
"config_data_relations",
|
|
s.anyOf(relationsSchema),
|
|
{
|
|
default: {},
|
|
},
|
|
s.strictObject({
|
|
type: s.string({ enum: Object.keys(RelationClassMap) }),
|
|
source: s.string(),
|
|
target: s.string(),
|
|
config: s.object({}).optional(),
|
|
}),
|
|
).optional(),
|
|
indices: $record("config_data_indices", indicesSchema, {
|
|
default: {},
|
|
mcp: { update: false },
|
|
}).optional(),
|
|
}).strict();
|
|
|
|
export type AppDataConfig = s.Static<typeof dataConfigSchema>;
|