@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1,575 lines (1,552 loc) • 44.7 kB
JavaScript
import {
create_cdn_url_default,
formatters_default,
objectify_translations_default
} from "./chunk-URI3PAN7.js";
import {
constants_default,
translations_default
} from "./chunk-ZMWDUGJW.js";
// src/libs/custom-fields/fields/checkbox.ts
import z from "zod";
// src/libs/custom-fields/utils/zod-safe-parse.ts
import { fromError } from "zod-validation-error";
var zodSafeParse = (value, schema) => {
const response = schema.safeParse(value);
if (response?.success) {
return {
valid: true
};
}
const errorMessage = fromError(response.error).message.replace(
"Validation error: ",
""
);
return {
valid: false,
message: errorMessage ?? translations_default("an_unknown_error_occurred_validating_the_field")
};
};
var zod_safe_parse_default = zodSafeParse;
// src/libs/custom-fields/custom-field.ts
var CustomField = class {
repeater = null;
// Methods
validate(props) {
if (this.config.type === "tab") return { valid: true };
const fieldTypeRes = this.fieldTypeValidation(props.type);
if (fieldTypeRes.valid === false) return fieldTypeRes;
const requiredRes = this.requiredCheck(props.value);
if (!requiredRes.valid) return requiredRes;
const zodRes = this.zodCheck(props.value);
if (!zodRes.valid) return zodRes;
if (props.value === null || props.value === void 0) {
return { valid: true };
}
return this.cfSpecificValidation(props.value, props.relationData);
}
fieldTypeValidation(type) {
if (this.errors.fieldType.condition?.(type)) {
return {
valid: false,
message: translations_default("field_type_mismatch", {
received: type,
expected: this.config.type
})
};
}
return { valid: true };
}
requiredCheck(value) {
if (this.config.type === "tab") return { valid: true };
if (this.config.type === "repeater") return { valid: true };
if (this.config.validation?.required === true && this.errors.required.condition?.(value)) {
return {
valid: false,
message: this.errors.required.message
};
}
return { valid: true };
}
zodCheck(value) {
if (this.config.type === "tab") return { valid: true };
if (this.config.type === "repeater") return { valid: true };
if (this.config.type === "media") return { valid: true };
if (this.config.type === "checkbox") return { valid: true };
if (this.config.type === "select") return { valid: true };
if (this.config.type === "colour") return { valid: true };
if (this.config.type === "link") return { valid: true };
if (this.config.type === "user") return { valid: true };
if (this.config.type === "wysiwyg") return { valid: true };
if (this.config.type === "document") return { valid: true };
if (!this.config.validation?.zod) return { valid: true };
return zod_safe_parse_default(value, this.config.validation?.zod);
}
// Getters
get errors() {
return {
fieldType: {
condition: (value) => value !== this.type,
message: translations_default("field_type_mismatch", {
received: "unknown",
expected: this.config.type
})
},
required: {
condition: (value) => value === void 0 || value === null || value === "",
message: translations_default("generic_field_required")
},
zod: {
message: translations_default("generic_field_invalid")
}
};
}
};
var custom_field_default = CustomField;
// src/libs/custom-fields/fields/checkbox.ts
import merge from "lodash.merge";
// src/libs/custom-fields/utils/key-to-title.ts
var keyToTitle = (key) => {
if (typeof key !== "string") return key;
const title = key.split(/[-_]/g).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
return title;
};
var key_to_title_default = keyToTitle;
// src/libs/custom-fields/fields/checkbox.ts
var CheckboxCustomField = class extends custom_field_default {
type = "checkbox";
column = "bool_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
true: this.props?.details?.true,
false: this.props?.details?.false
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default ?? 0,
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.bool_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
let value = props.item.value;
if (typeof value === "string") {
value = value === "true" ? 1 : 0;
} else if (typeof value === "boolean") {
value = value ? 1 : 0;
} else if (typeof value === "number") {
value = value === 1 ? 1 : 0;
} else {
value = void 0;
}
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: null,
intValue: null,
boolValue: value,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z.union([z.literal(1), z.literal(0), z.boolean()]);
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
return {
valid: true
};
}
// Getters
get errors() {
return merge(super.errors, {
required: {
condition: (value) => value === void 0 || value === null || value === 0,
message: translations_default("checkbox_field_required")
}
});
}
};
var checkbox_default = CheckboxCustomField;
// src/libs/custom-fields/fields/colour.ts
import z2 from "zod";
var ColourCustomField = class extends custom_field_default {
type = "colour";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary
},
presets: this.props?.presets ?? [],
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default ?? "",
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.text_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: props.item.value,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z2.string();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
return {
valid: true
};
}
};
var colour_default = ColourCustomField;
// src/libs/custom-fields/fields/datetime.ts
import z3 from "zod";
import { isValid } from "date-fns";
var DatetimeCustomField = class extends custom_field_default {
type = "datetime";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default ?? "",
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.text_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: props.item.value,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z3.union([z3.string(), z3.number(), z3.date()]);
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
const date = new Date(value);
if (!isValid(date)) {
return {
valid: false,
message: translations_default("field_date_invalid")
};
}
return {
valid: true
};
}
};
var datetime_default = DatetimeCustomField;
// src/libs/custom-fields/fields/json.ts
import z4 from "zod";
var JsonCustomField = class extends custom_field_default {
type = "json";
column = "json_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default || {},
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: formatters_default.parseJSON(props.data.json_value) ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: null,
intValue: null,
boolValue: null,
jsonValue: formatters_default.stringifyJSON(props.item.value),
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z4.record(z4.unknown());
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
return {
valid: true
};
}
};
var json_default = JsonCustomField;
// src/libs/custom-fields/fields/link.ts
import z5 from "zod";
var LinkCustomField = class extends custom_field_default {
type = "link";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default ?? {
url: null,
label: null,
target: null
},
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
const linkVal = formatters_default.parseJSON(props.data.json_value);
return {
value: {
url: linkVal?.url ?? this.config.config.default.url ?? null,
label: linkVal?.label ?? this.config.config.default.label ?? null,
target: linkVal?.target ?? this.config.config.default.target ?? null
},
meta: null
};
}
getInsertField(props) {
const value = props.item.value;
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: value ? value.url : null,
intValue: null,
boolValue: null,
jsonValue: value ? formatters_default.stringifyJSON({
target: value.target,
label: value.label
}) : null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z5.object({
url: z5.string().optional().nullable(),
target: z5.string().optional().nullable(),
label: z5.string().optional().nullable()
});
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
const val = value;
if (val.target && !constants_default.customFields.link.targets.includes(val.target)) {
return {
valid: false,
message: translations_default("field_link_target_error_message", {
valid: constants_default.customFields.link.targets.join(", ")
})
};
}
return {
valid: true
};
}
};
var link_default = LinkCustomField;
// src/libs/custom-fields/fields/media.ts
import z6 from "zod";
var MediaCustomField = class extends custom_field_default {
type = "media";
column = "media_id";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data?.media_id ?? null,
meta: {
id: props.data?.media_id ?? null,
url: create_cdn_url_default(props.formatMeta.host, props.data?.media_key ?? ""),
key: props.data?.media_key ?? null,
mimeType: props.data?.media_mime_type ?? null,
extension: props.data?.media_file_extension ?? null,
fileSize: props.data?.media_file_size ?? null,
width: props.data?.media_width ?? null,
height: props.data?.media_height ?? null,
blurHash: props.data?.media_blur_hash ?? null,
averageColour: props.data?.media_average_colour ?? null,
isDark: props.data?.media_is_dark ?? null,
isLight: props.data?.media_is_light ?? null,
title: objectify_translations_default(
props.data?.media_title_translations || [],
props.formatMeta.localisation.locales
),
alt: objectify_translations_default(
props.data?.media_alt_translations || [],
props.formatMeta.localisation.locales
),
type: props.data?.media_type ?? null
}
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: null,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: props.item.value,
userId: null
};
}
cfSpecificValidation(value, relationData) {
const valueSchema = z6.number();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
const findMedia = relationData?.find((m) => m.id === value);
if (findMedia === void 0) {
return {
valid: false,
message: translations_default("field_media_not_found")
};
}
if (this.config.validation?.extensions?.length) {
const extension = findMedia.file_extension;
if (!this.config.validation.extensions.includes(extension)) {
return {
valid: false,
message: translations_default("field_media_extension", {
extensions: this.config.validation.extensions.join(", ")
})
};
}
}
if (this.config.validation?.type) {
const type = findMedia.type;
if (!type) {
return {
valid: false,
message: translations_default("field_media_doenst_have_type")
};
}
if (this.config.validation.type !== type) {
return {
valid: false,
message: translations_default("field_media_type", {
type: this.config.validation.type
})
};
}
}
if (this.config.validation?.width && findMedia.type === "image") {
const width = findMedia.width;
if (!width) {
return {
valid: false,
message: translations_default("field_media_doenst_have_width")
};
}
if (this.config.validation.width.min && width < this.config.validation.width.min) {
return {
valid: false,
message: translations_default("field_media_min_width", {
min: this.config.validation.width.min
})
};
}
if (this.config.validation.width.max && width > this.config.validation.width.max) {
return {
valid: false,
message: translations_default("field_media_max_width", {
max: this.config.validation.width.max
})
};
}
}
if (this.config.validation?.height && findMedia.type === "image") {
const height = findMedia.height;
if (!height) {
return {
valid: false,
message: translations_default("field_media_doenst_have_height")
};
}
if (this.config.validation.height.min && height < this.config.validation.height.min) {
return {
valid: false,
message: translations_default("field_media_min_height", {
min: this.config.validation.height.min
})
};
}
if (this.config.validation.height.max && height > this.config.validation.height.max) {
return {
valid: false,
message: translations_default("field_media_max_height", {
max: this.config.validation.height.max
})
};
}
}
return { valid: true };
}
};
var media_default = MediaCustomField;
// src/libs/custom-fields/fields/number.ts
import z7 from "zod";
var NumberCustomField = class extends custom_field_default {
type = "number";
column = "int_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default,
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.int_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: null,
intValue: props.item.value,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z7.number();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
return {
valid: true
};
}
};
var number_default = NumberCustomField;
// src/libs/custom-fields/fields/repeater.ts
var RepeaterCustomField = class extends custom_field_default {
type = "repeater";
column = null;
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary
},
config: {
isDisabled: this.props?.config?.isDisabled
},
fields: [],
validation: this.props?.validation
};
}
// Methods
responseValueFormat() {
return {
value: null,
meta: null
};
}
getInsertField() {
return null;
}
cfSpecificValidation() {
return {
valid: true
};
}
};
var repeater_default = RepeaterCustomField;
// src/libs/custom-fields/fields/select.ts
import z8 from "zod";
import merge2 from "lodash.merge";
var SelectCustomField = class extends custom_field_default {
type = "select";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
options: this.props?.options ?? [],
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
default: this.props?.config?.default ?? "",
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.text_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: props.item.value,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z8.string();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
if (this.config.options) {
const optionValues = this.config.options.map((option) => option.value);
if (!optionValues.includes(value)) {
return {
valid: false,
message: translations_default("please_ensure_a_valid_option_is_selected")
};
}
}
return { valid: true };
}
// Getters
get errors() {
return merge2(super.errors, {
required: {
message: translations_default("select_field_required")
}
});
}
};
var select_default = SelectCustomField;
// src/libs/custom-fields/fields/text.ts
import z9 from "zod";
var TextCustomField = class extends custom_field_default {
type = "text";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? true,
default: this.props?.config?.default ?? "",
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.text_value ?? this.config.config.default,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: props.item.value,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z9.string();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
return {
valid: true
};
}
};
var text_default = TextCustomField;
// src/libs/custom-fields/fields/textarea.ts
import z10 from "zod";
var TextareaCustomField = class extends custom_field_default {
type = "textarea";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? true,
default: this.props?.config?.default ?? "",
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.text_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: props.item.value,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z10.string();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
return {
valid: true
};
}
};
var textarea_default = TextareaCustomField;
// src/libs/custom-fields/fields/user.ts
import z11 from "zod";
var UserCustomField = class extends custom_field_default {
type = "user";
column = "user_id";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.user_id ?? null,
meta: {
email: props.data?.user_email ?? null,
username: props.data?.user_username ?? null,
firstName: props.data?.user_first_name ?? null,
lastName: props.data?.user_last_name ?? null
}
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: null,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: props.item.value
};
}
cfSpecificValidation(value, relationData) {
const valueSchema = z11.number();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
const findUser = relationData?.find((u) => u.id === value);
if (findUser === void 0) {
return {
valid: false,
message: translations_default("field_user_not_found")
};
}
return { valid: true };
}
};
var user_default = UserCustomField;
// src/libs/custom-fields/fields/wysiwyg.ts
import z12 from "zod";
import sanitizeHtml from "sanitize-html";
var WysiwygCustomField = class extends custom_field_default {
type = "wysiwyg";
column = "text_value";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary,
placeholder: this.props?.details?.placeholder
},
config: {
useTranslations: this.props?.config?.useTranslations ?? true,
default: this.props?.config?.default ?? "",
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
return {
value: props.data.text_value ?? this.config.config.default ?? null,
meta: null
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: props.item.value,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
userId: null
};
}
cfSpecificValidation(value) {
const valueSchema = z12.string();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
const sanitizedValue = sanitizeHtml(value);
if (this.config.validation?.zod) {
return zod_safe_parse_default(sanitizedValue, this.config.validation?.zod);
}
return { valid: true };
}
};
var wysiwyg_default = WysiwygCustomField;
// src/libs/custom-fields/fields/document.ts
import z13 from "zod";
var FieldsFormatter = formatters_default.get("collection-document-fields");
var DocumentCustomField = class extends custom_field_default {
type = "document";
column = "document_id";
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
collection: this.props.collection,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary
},
config: {
useTranslations: this.props?.config?.useTranslations ?? false,
isHidden: this.props?.config?.isHidden,
isDisabled: this.props?.config?.isDisabled
},
validation: this.props?.validation
};
}
// Methods
responseValueFormat(props) {
const CollectionBuilder2 = props.formatMeta.collections.find(
(c) => c.key === this.props.collection
);
if (!CollectionBuilder2) {
return {
value: props.data?.document_id ?? null,
meta: {
id: props.data.document_id ?? null,
fields: null
}
};
}
const documentFields = FieldsFormatter.objectifyFields(
FieldsFormatter.formatMultiple(
{
fields: props.data.document_fields || [],
groups: props.data.document_groups || []
},
{
builder: CollectionBuilder2,
collectionTranslations: CollectionBuilder2.getData.config.useTranslations,
localisation: props.formatMeta.localisation,
collections: props.formatMeta.collections,
host: props.formatMeta.host
}
)
);
return {
value: props.data?.document_id ?? null,
meta: {
id: props.data.document_id ?? null,
fields: Object.keys(documentFields).length > 0 ? documentFields : null
}
};
}
getInsertField(props) {
return {
key: this.config.key,
type: this.config.type,
localeCode: props.item.localeCode,
collectionBrickId: props.brickId,
groupId: props.groupId,
textValue: null,
intValue: null,
boolValue: null,
jsonValue: null,
mediaId: null,
documentId: props.item.value,
userId: null
};
}
cfSpecificValidation(value, relationData) {
const valueSchema = z13.number();
const valueValidate = zod_safe_parse_default(value, valueSchema);
if (!valueValidate.valid) return valueValidate;
const findDocument = relationData?.find((d) => d.id === value);
if (findDocument === void 0) {
return {
valid: false,
message: translations_default("field_document_not_found")
};
}
if (findDocument.collection_key !== this.config.collection) {
return {
valid: false,
message: translations_default("field_document_collection_key_mismatch", {
expected: this.config.collection,
received: findDocument.collection_key
})
};
}
return { valid: true };
}
};
var document_default = DocumentCustomField;
// src/libs/builders/field-builder/index.ts
var FieldBuilder = class {
fields = /* @__PURE__ */ new Map();
repeaterStack = [];
meta = {
fieldKeys: [],
repeaterDepth: {}
};
// Custom Fields
addRepeater(key, props) {
this.meta.repeaterDepth[key] = this.repeaterStack.length;
this.fields.set(key, new repeater_default(key, props));
this.repeaterStack.push(key);
return this;
}
addText(key, props) {
this.fields.set(key, new text_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addWysiwyg(key, props) {
this.fields.set(key, new wysiwyg_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addMedia(key, props) {
this.fields.set(key, new media_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addDocument(key, props) {
this.fields.set(key, new document_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addNumber(key, props) {
this.fields.set(key, new number_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addCheckbox(key, props) {
this.fields.set(key, new checkbox_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addSelect(key, props) {
this.fields.set(key, new select_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addTextarea(key, props) {
this.fields.set(key, new textarea_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addJSON(key, props) {
this.fields.set(key, new json_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addColour(key, props) {
this.fields.set(key, new colour_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addDateTime(key, props) {
this.fields.set(key, new datetime_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addLink(key, props) {
this.fields.set(key, new link_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
addUser(key, props) {
this.fields.set(key, new user_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
endRepeater() {
const key = this.repeaterStack.pop();
if (!key) return this;
const fields = Array.from(this.fields.values());
const selectedRepeaterIndex = fields.findIndex(
(field) => field.type === "repeater" && field.key === key
);
if (selectedRepeaterIndex === -1) return this;
const fieldsAfter = fields.slice(selectedRepeaterIndex + 1);
for (const field of fieldsAfter) {
if (field.type === "tab" || field.repeater) continue;
field.repeater = key;
}
return this;
}
// Private Methods
nestFields(excludeTabs) {
const fields = Array.from(this.fields.values()).filter((field) => {
if (excludeTabs) {
return field.type !== "tab";
}
return true;
});
const result = [];
let currentTab = null;
const repeaterStack = /* @__PURE__ */ new Map();
for (const field of fields) {
const config = JSON.parse(JSON.stringify(field.config));
if (field.type === "tab") {
if (currentTab) result.push(currentTab);
currentTab = config;
continue;
}
if (field.type === "repeater")
repeaterStack.set(field.key, config);
const targetPush = currentTab ? currentTab.fields : result;
if (field.repeater) {
const repeater = repeaterStack.get(field.repeater);
if (repeater)
repeater.fields.push(
config
);
} else {
targetPush.push(config);
}
}
if (currentTab) result.push(currentTab);
return result;
}
// Getters
get fieldTree() {
return this.nestFields(false);
}
get fieldTreeNoTab() {
return this.nestFields(true);
}
get flatFields() {
const config = [];
for (const [_, value] of this.fields) {
config.push(value.config);
}
return config;
}
};
var field_builder_default = FieldBuilder;
// src/libs/custom-fields/fields/tab.ts
var TabCustomField = class extends custom_field_default {
type = "tab";
column = null;
config;
key;
props;
constructor(key, props) {
super();
this.key = key;
this.props = props;
this.config = {
key: this.key,
type: this.type,
details: {
label: this.props?.details?.label ?? key_to_title_default(this.key),
summary: this.props?.details?.summary
},
fields: []
};
}
// Methods
responseValueFormat() {
return {
value: null,
meta: null
};
}
getInsertField() {
return null;
}
cfSpecificValidation() {
return {
valid: true
};
}
};
var tab_default = TabCustomField;
// src/libs/builders/brick-builder/index.ts
var BrickBuilder = class extends field_builder_default {
key;
config;
constructor(key, config) {
super();
this.key = key;
this.config = {
details: {
name: config?.details?.name || key,
summary: config?.details?.summary
},
preview: config?.preview || {}
};
}
// Builder methods
addFields(Builder) {
const fields = Array.from(Builder.fields.values());
for (const field of fields) {
this.fields.set(field.key, field);
this.meta.fieldKeys.push(field.key);
}
return this;
}
addTab(key, props) {
this.fields.set(key, new tab_default(key, props));
this.meta.fieldKeys.push(key);
return this;
}
};
var brick_builder_default = BrickBuilder;
// src/libs/builders/collection-builder/index.ts
var CollectionBuilder = class extends field_builder_default {
key;
config;
includeFieldKeys = [];
filterableFieldKeys = [];
constructor(key, config) {
super();
this.key = key;
this.config = config;
if (this.config.bricks?.fixed) {
this.config.bricks.fixed = this.#removeDuplicateBricks(
config.bricks?.fixed
);
}
if (this.config.bricks?.builder) {
this.config.bricks.builder = this.#removeDuplicateBricks(
config.bricks?.builder
);
}
}
// ------------------------------------
// Builder Methods
addText(key, props) {
this.#fieldCollectionHelper(key, "text", props?.collection);
super.addText(key, props);
return this;
}
addNumber(key, props) {
this.#fieldCollectionHelper(key, "number", props?.collection);
super.addNumber(key, props);
return this;
}
addCheckbox(key, props) {
this.#fieldCollectionHelper(key, "checkbox", props?.collection);
super.addCheckbox(key, props);
return this;
}
addSelect(key, props) {
this.#fieldCollectionHelper(key, "select", props?.collection);
super.addSelect(key, props);
return this;
}
addTextarea(key, props) {
this.#fieldCollectionHelper(key, "textarea", props?.collection);
super.addTextarea(key, props);
return this;
}
addDateTime(key, props) {
this.#fieldCollectionHelper(key, "datetime", props?.collection);
super.addDateTime(key, props);
return this;
}
addUser(key, props) {
this.#fieldCollectionHelper(key, "user", props?.collection);
super.addUser(key, props);
return this;
}
addMedia(key, props) {
this.#fieldCollectionHelper(key, "media", props?.collection);
super.addMedia(key, props);
return this;
}
// ------------------------------------
// Public Methods
documentFieldFilters(filters, allowAll) {
if (!filters) return [];
const fields = allowAll ? this.flatFields : this.filterableFieldKeys;
return fields.reduce((acc, field) => {
const filterValue = filters[field.key];
if (filterValue === void 0) return acc;
const fieldInstance = this.fields.get(field.key);
if (!fieldInstance) return acc;
acc.push({
key: field.key,
value: filterValue.value,
operator: filterValue.operator ?? "=",
column: fieldInstance.column
});
return acc;
}, []);
}
queryIncludeFields(all) {
if (all)
return this.flatFields.filter((f) => f.type !== "tab").map((f) => f.key);
const fieldKeys = Array.from(this.includeFieldKeys);
for (const field of this.filterableFieldKeys) {
if (fieldKeys.includes(field.key)) continue;
fieldKeys.push(field.key);
}
return fieldKeys;
}
// ------------------------------------
// Private Methods
#removeDuplicateBricks = (bricks) => {
if (!bricks) return void 0;
return bricks.filter(
(brick, index) => bricks.findIndex((b) => b.key === brick.key) === index
);
};
#fieldCollectionHelper = (key, type, config) => {
if (config?.column) this.includeFieldKeys.push(key);
if (config?.filterable)
this.filterableFieldKeys.push({
key,
type
});
};
// ------------------------------------
// Getters
get getData() {
return {
key: this.key,
mode: this.config.mode,
details: {
name: this.config.details.name,
singularName: this.config.details.singularName,
summary: this.config.details.summary ?? null
},
config: {
isLocked: this.config.config?.isLocked ?? constants_default.collectionBuilder.isLocked,
useDrafts: this.config.config?.useDrafts ?? constants_default.collectionBuilder.useDrafts,
useRevisions: this.config.config?.useRevisions ?? constants_default.collectionBuilder.useRevisions,
useTranslations: this.config.config?.useTranslations ?? constants_default.collectionBuilder.useTranslations,
fields: {
filter: this.filterableFieldKeys,
include: this.includeFieldKeys
}
}
};
}
get fixedBricks() {
return this.config.bricks?.fixed?.map((brick) => ({
key: brick.key,
details: brick.config.details,
preview: brick.config.preview,
fields: brick.fieldTree
})) ?? [];
}
get builderBricks() {
return this.config.bricks?.builder?.map((brick) => ({
key: brick.key,
details: brick.config.details,
preview: brick.config.preview,
fields: brick.fieldTree
})) ?? [];
}
get brickInstances() {
return (this.config.bricks?.builder || []).concat(
this.config.bricks?.fixed || []
);
}
};
var collection_builder_default = CollectionBuilder;
export {
brick_builder_default as BrickBuilder,
collection_builder_default as CollectionBuilder,
field_builder_default as FieldBuilder
};
//# sourceMappingURL=builders.js.map