@easy-cms/core 0.22.2 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +31 -4
- package/dist/index.js +63 -10
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -415,7 +415,9 @@ type FieldValue<F extends Field, C extends Config = Config> = F extends {
|
|
|
415
415
|
readonly type: 'richText';
|
|
416
416
|
} ? RichTextDocument : F extends {
|
|
417
417
|
readonly type: 'upload';
|
|
418
|
-
} ?
|
|
418
|
+
} ? F extends {
|
|
419
|
+
readonly hasMany: true;
|
|
420
|
+
} ? (ID | MediaDocument)[] : ID | MediaDocument : F extends {
|
|
419
421
|
readonly type: 'relationship';
|
|
420
422
|
readonly to: infer S;
|
|
421
423
|
} ? F extends {
|
|
@@ -504,7 +506,9 @@ type InputValue<F extends Field> = F extends {
|
|
|
504
506
|
readonly hasMany: true;
|
|
505
507
|
} ? Readonly<SelectValue<F>> : F extends {
|
|
506
508
|
readonly type: 'upload';
|
|
507
|
-
} ?
|
|
509
|
+
} ? F extends {
|
|
510
|
+
readonly hasMany: true;
|
|
511
|
+
} ? readonly ID[] : ID : F extends {
|
|
508
512
|
readonly type: 'date';
|
|
509
513
|
} ? string | Date : F extends {
|
|
510
514
|
readonly type: 'array';
|
|
@@ -1037,8 +1041,19 @@ interface RichTextDocument {
|
|
|
1037
1041
|
}
|
|
1038
1042
|
interface RichTextField extends BaseField<'richText', RichTextDocument> {
|
|
1039
1043
|
}
|
|
1040
|
-
/** References a document in the built-in `media` collection. */
|
|
1044
|
+
/** References a document in the built-in `media` collection: a file or an image. */
|
|
1041
1045
|
interface UploadField extends BaseField<'upload', never> {
|
|
1046
|
+
/** Several files, e.g. a gallery: the value is a list, in the order editors arrange. */
|
|
1047
|
+
readonly hasMany?: boolean;
|
|
1048
|
+
/** With `hasMany`: the fewest files. */
|
|
1049
|
+
readonly minRows?: number;
|
|
1050
|
+
/** With `hasMany`: the most files. */
|
|
1051
|
+
readonly maxRows?: number;
|
|
1052
|
+
/**
|
|
1053
|
+
* The file types allowed, e.g. `['image/*']` or `['image/*', 'application/pdf']`. The admin
|
|
1054
|
+
* offers only these, and saving refuses others.
|
|
1055
|
+
*/
|
|
1056
|
+
readonly mimeTypes?: readonly string[];
|
|
1042
1057
|
}
|
|
1043
1058
|
interface FilterOptionsArgs {
|
|
1044
1059
|
/** The document being edited; `undefined` while it is being created. */
|
|
@@ -1055,6 +1070,10 @@ interface RelationshipField extends BaseField<'relationship', never> {
|
|
|
1055
1070
|
/** Slug of the target collection. */
|
|
1056
1071
|
readonly to: string;
|
|
1057
1072
|
readonly hasMany?: boolean;
|
|
1073
|
+
/** With `hasMany`: the fewest documents. */
|
|
1074
|
+
readonly minRows?: number;
|
|
1075
|
+
/** With `hasMany`: the most documents. */
|
|
1076
|
+
readonly maxRows?: number;
|
|
1058
1077
|
readonly filterOptions?: FilterOptions;
|
|
1059
1078
|
}
|
|
1060
1079
|
interface ArrayField extends BaseField<'array', never> {
|
|
@@ -1084,6 +1103,10 @@ interface BlocksField extends BaseField<'blocks', never> {
|
|
|
1084
1103
|
readonly minRows?: number;
|
|
1085
1104
|
readonly maxRows?: number;
|
|
1086
1105
|
}
|
|
1106
|
+
/** Fields with `hasMany`: their value is a list of options, documents or files. */
|
|
1107
|
+
declare const isHasMany: (field: Field) => boolean;
|
|
1108
|
+
/** Whether a MIME type is one of `patterns` (`image/*` matches every image). */
|
|
1109
|
+
declare function mimeAllowedBy(mimeType: string, patterns: readonly string[]): boolean;
|
|
1087
1110
|
/** Fields whose value is a list of rows: `array` and `blocks`. */
|
|
1088
1111
|
declare const hasRows: (field: Field) => field is ArrayField | BlocksField;
|
|
1089
1112
|
/** The fields of one row of an `array` or `blocks` field (`undefined` for an unknown block). */
|
|
@@ -1623,6 +1646,8 @@ interface Reference {
|
|
|
1623
1646
|
readonly id: ID;
|
|
1624
1647
|
/** The relationship's `filterOptions`, checked when saving. */
|
|
1625
1648
|
readonly filterOptions?: FilterOptions;
|
|
1649
|
+
/** The upload's `mimeTypes`, checked when saving. */
|
|
1650
|
+
readonly mimeTypes?: readonly string[];
|
|
1626
1651
|
}
|
|
1627
1652
|
interface ValidateOptions {
|
|
1628
1653
|
readonly operation: 'create' | 'update';
|
|
@@ -1732,6 +1757,8 @@ interface AdminField {
|
|
|
1732
1757
|
}[];
|
|
1733
1758
|
hasMany?: boolean;
|
|
1734
1759
|
to?: string;
|
|
1760
|
+
/** An upload's allowed file types, e.g. `image/*`. */
|
|
1761
|
+
mimeTypes?: string[];
|
|
1735
1762
|
/** A relationship with `filterOptions`: the picker asks the server which documents fit. */
|
|
1736
1763
|
filtered?: boolean;
|
|
1737
1764
|
from?: string;
|
|
@@ -1859,4 +1886,4 @@ declare const BUILTIN_COLLECTIONS: readonly ["users", "media"];
|
|
|
1859
1886
|
/** Checks a config and returns every problem found. An empty array means it is valid. */
|
|
1860
1887
|
declare function validateConfig(config: Config): ConfigIssue[];
|
|
1861
1888
|
|
|
1862
|
-
export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminField, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminSchema, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, Auth, type AuthConfig, type AuthUser, BUILTIN_COLLECTIONS, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinUsersCollection, type BundleHints, CONFIG_FILE_NAMES, CSRF_COOKIE, CSRF_HEADER, type CliCommand, type CollectionAccess, type CollectionAdmin, type CollectionConfig, type CollectionDocument, type CollectionHooks, type CollectionListAdmin, type CollectionSlug, type Config, ConfigError, type ConfigIssue, type ContainerAdmin, type CopyProgress, type CopyResult, type CreateEasyCMSOptions, type CreateInput, type CreateMigrationResult, DEFAULT_ADMIN_PATH, DEFAULT_API_PATH, DEFAULT_DEPTH, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_VERSIONS, DEFAULT_TOKEN_EXPIRATION, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DepthOptions, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailField, type EmailMessage, type Endpoint, type EndpointRequest, FIELD_TYPES, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldType, type FieldValidate, type FieldValidateContext, type FieldValue, type FieldsInput, type FieldsValue, type FilterOptions, type FilterOptionsArgs, type FindArgs, type FindOptions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type InferCollection, type InferGlobal, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type Operation, type PaginatedDocs, PayloadTooLargeError, type Plugin, type PreviewTarget, type PreviewURL, QueryError, type RawDocument, type ReadOptions, type RelationshipField, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoutesConfig, SESSION_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, configSignature, consoleEmail, consoleLogger, copyDatabase, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isLoggedIn, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, silentLogger, singularize, slugify, sniffMimeType, validateConfig, validateFields, verifyPassword };
|
|
1889
|
+
export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminField, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminSchema, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, Auth, type AuthConfig, type AuthUser, BUILTIN_COLLECTIONS, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinUsersCollection, type BundleHints, CONFIG_FILE_NAMES, CSRF_COOKIE, CSRF_HEADER, type CliCommand, type CollectionAccess, type CollectionAdmin, type CollectionConfig, type CollectionDocument, type CollectionHooks, type CollectionListAdmin, type CollectionSlug, type Config, ConfigError, type ConfigIssue, type ContainerAdmin, type CopyProgress, type CopyResult, type CreateEasyCMSOptions, type CreateInput, type CreateMigrationResult, DEFAULT_ADMIN_PATH, DEFAULT_API_PATH, DEFAULT_DEPTH, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_VERSIONS, DEFAULT_TOKEN_EXPIRATION, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DepthOptions, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailField, type EmailMessage, type Endpoint, type EndpointRequest, FIELD_TYPES, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldType, type FieldValidate, type FieldValidateContext, type FieldValue, type FieldsInput, type FieldsValue, type FilterOptions, type FilterOptionsArgs, type FindArgs, type FindOptions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type InferCollection, type InferGlobal, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type Operation, type PaginatedDocs, PayloadTooLargeError, type Plugin, type PreviewTarget, type PreviewURL, QueryError, type RawDocument, type ReadOptions, type RelationshipField, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoutesConfig, SESSION_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, configSignature, consoleEmail, consoleLogger, copyDatabase, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, silentLogger, singularize, slugify, sniffMimeType, validateConfig, validateFields, verifyPassword };
|
package/dist/index.js
CHANGED
|
@@ -209,6 +209,14 @@ var PayloadTooLargeError = class extends EasyCMSError {
|
|
|
209
209
|
};
|
|
210
210
|
|
|
211
211
|
// src/fields.ts
|
|
212
|
+
var isHasMany = (field) => (field.type === "select" || field.type === "relationship" || field.type === "upload") && field.hasMany === true;
|
|
213
|
+
function mimeAllowedBy(mimeType, patterns) {
|
|
214
|
+
const type = mimeType.toLowerCase();
|
|
215
|
+
return patterns.some((pattern) => {
|
|
216
|
+
const p = pattern.toLowerCase();
|
|
217
|
+
return p.endsWith("/*") ? type.startsWith(p.slice(0, -1)) : type === p;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
212
220
|
var hasRows = (field) => field.type === "array" || field.type === "blocks";
|
|
213
221
|
function rowFields(field, row) {
|
|
214
222
|
if (field.type === "array") return field.fields;
|
|
@@ -997,6 +1005,10 @@ async function copyDatabase(source, target, options = {}) {
|
|
|
997
1005
|
import { randomUUID } from "crypto";
|
|
998
1006
|
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
999
1007
|
var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1008
|
+
function itemsOf(field, n) {
|
|
1009
|
+
const unit = field.type === "upload" ? "file" : field.type === "relationship" ? "document" : "row";
|
|
1010
|
+
return `${n} ${unit}${n === 1 ? "" : "s"}`;
|
|
1011
|
+
}
|
|
1000
1012
|
var isEmpty = (value) => value === void 0 || value === null || value === "";
|
|
1001
1013
|
function slugify(text) {
|
|
1002
1014
|
return text.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/^-+|-+$/g, "");
|
|
@@ -1162,6 +1174,8 @@ async function validateFields(fields, input, options, prefix = "") {
|
|
|
1162
1174
|
}
|
|
1163
1175
|
if (isEmpty(raw) || Array.isArray(raw) && raw.length === 0) {
|
|
1164
1176
|
if (field.required && !options.skipRequired) fail("is required");
|
|
1177
|
+
else if (!options.skipRequired && "minRows" in field && field.minRows)
|
|
1178
|
+
fail(`must have at least ${itemsOf(field, field.minRows)}`);
|
|
1165
1179
|
data[field.name] = hasRows(field) || isHasMany(field) ? [] : null;
|
|
1166
1180
|
if (!field.required) await runCustom(field, null, options, fail);
|
|
1167
1181
|
continue;
|
|
@@ -1173,9 +1187,6 @@ async function validateFields(fields, input, options, prefix = "") {
|
|
|
1173
1187
|
}
|
|
1174
1188
|
return { data, errors, references };
|
|
1175
1189
|
}
|
|
1176
|
-
function isHasMany(field) {
|
|
1177
|
-
return (field.type === "select" || field.type === "relationship") && field.hasMany === true;
|
|
1178
|
-
}
|
|
1179
1190
|
async function runCustom(field, value, options, fail) {
|
|
1180
1191
|
if (!field.validate) return;
|
|
1181
1192
|
const validate = field.validate;
|
|
@@ -1231,9 +1242,13 @@ async function normalizeValue(field, raw, path, options, fail, errors, reference
|
|
|
1231
1242
|
case "upload":
|
|
1232
1243
|
case "relationship": {
|
|
1233
1244
|
const target = field.type === "upload" ? "media" : field.to;
|
|
1234
|
-
const many = field.
|
|
1245
|
+
const many = field.hasMany === true;
|
|
1235
1246
|
const values = many ? raw : [raw];
|
|
1236
1247
|
if (!Array.isArray(values)) return fail("must be an array of ids");
|
|
1248
|
+
if (many && field.minRows !== void 0 && values.length < field.minRows)
|
|
1249
|
+
return fail(`must have at least ${itemsOf(field, field.minRows)}`);
|
|
1250
|
+
if (many && field.maxRows !== void 0 && values.length > field.maxRows)
|
|
1251
|
+
return fail(`must have at most ${itemsOf(field, field.maxRows)}`);
|
|
1237
1252
|
const ids = [];
|
|
1238
1253
|
for (const item of values) {
|
|
1239
1254
|
const id = parseId(isPlainObject(item) ? item.id : item);
|
|
@@ -1244,7 +1259,8 @@ async function normalizeValue(field, raw, path, options, fail, errors, reference
|
|
|
1244
1259
|
field: path,
|
|
1245
1260
|
collection: target,
|
|
1246
1261
|
id,
|
|
1247
|
-
...field.type === "relationship" && field.filterOptions ? { filterOptions: field.filterOptions } : {}
|
|
1262
|
+
...field.type === "relationship" && field.filterOptions ? { filterOptions: field.filterOptions } : {},
|
|
1263
|
+
...field.type === "upload" && field.mimeTypes ? { mimeTypes: field.mimeTypes } : {}
|
|
1248
1264
|
});
|
|
1249
1265
|
}
|
|
1250
1266
|
return many ? ids : ids[0];
|
|
@@ -2060,6 +2076,13 @@ function validateList(list, container, path, add) {
|
|
|
2060
2076
|
);
|
|
2061
2077
|
}
|
|
2062
2078
|
}
|
|
2079
|
+
function validateManyRange(field, path, add) {
|
|
2080
|
+
if ((field.minRows !== void 0 || field.maxRows !== void 0) && !field.hasMany) {
|
|
2081
|
+
add(path, "minRows and maxRows need hasMany: true");
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
checkRange(field.minRows, field.maxRows, "minRows", "maxRows", path, add);
|
|
2085
|
+
}
|
|
2063
2086
|
function validateField(field, path, siblings, collectionSlugs, add) {
|
|
2064
2087
|
const position = field.position;
|
|
2065
2088
|
if (position !== void 0 && position !== "sidebar") {
|
|
@@ -2115,6 +2138,16 @@ function validateField(field, path, siblings, collectionSlugs, add) {
|
|
|
2115
2138
|
`use one of: ${[...collectionSlugs].join(", ")}`
|
|
2116
2139
|
);
|
|
2117
2140
|
}
|
|
2141
|
+
validateManyRange(field, path, add);
|
|
2142
|
+
break;
|
|
2143
|
+
case "upload":
|
|
2144
|
+
validateManyRange(field, path, add);
|
|
2145
|
+
if (field.mimeTypes !== void 0) {
|
|
2146
|
+
const types = field.mimeTypes;
|
|
2147
|
+
if (!Array.isArray(types) || types.length === 0 || !types.every((t) => typeof t === "string" && /^[\w.+-]+\/(\*|[\w.+-]+)$/.test(t))) {
|
|
2148
|
+
add(`${path}.mimeTypes`, "must be a list of MIME types", "e.g. mimeTypes: ['image/*']");
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2118
2151
|
break;
|
|
2119
2152
|
case "array":
|
|
2120
2153
|
case "group":
|
|
@@ -4343,10 +4376,20 @@ var EasyCMS = class {
|
|
|
4343
4376
|
collection: collection2,
|
|
4344
4377
|
ids: [...new Set(refs.map((r) => r.id))]
|
|
4345
4378
|
});
|
|
4346
|
-
const
|
|
4379
|
+
const byId = new Map(found.map((d) => [d.id, d]));
|
|
4347
4380
|
for (const ref of refs) {
|
|
4348
|
-
|
|
4381
|
+
const doc = byId.get(ref.id);
|
|
4382
|
+
if (!doc) {
|
|
4349
4383
|
errors.push({ field: ref.field, message: `${collection2} ${ref.id} does not exist` });
|
|
4384
|
+
continue;
|
|
4385
|
+
}
|
|
4386
|
+
const type = typeof doc.mimeType === "string" ? doc.mimeType : "";
|
|
4387
|
+
if (ref.mimeTypes && !mimeAllowedBy(type, ref.mimeTypes)) {
|
|
4388
|
+
const images = ref.mimeTypes.every((t) => t.toLowerCase() === "image/*");
|
|
4389
|
+
errors.push({
|
|
4390
|
+
field: ref.field,
|
|
4391
|
+
message: images ? `must be an image (${doc.filename ?? ref.id} is ${type || "not one"})` : `must be ${ref.mimeTypes.join(", ")} (${doc.filename ?? ref.id} is ${type || "unknown"})`
|
|
4392
|
+
});
|
|
4350
4393
|
}
|
|
4351
4394
|
}
|
|
4352
4395
|
}
|
|
@@ -4492,10 +4535,16 @@ async function serializeFields(fields, update, localized) {
|
|
|
4492
4535
|
case "relationship":
|
|
4493
4536
|
f.to = field.to;
|
|
4494
4537
|
if (field.hasMany) f.hasMany = true;
|
|
4538
|
+
if (field.minRows !== void 0) f.minRows = field.minRows;
|
|
4539
|
+
if (field.maxRows !== void 0) f.maxRows = field.maxRows;
|
|
4495
4540
|
if (field.filterOptions) f.filtered = true;
|
|
4496
4541
|
break;
|
|
4497
4542
|
case "upload":
|
|
4498
4543
|
f.to = "media";
|
|
4544
|
+
if (field.hasMany) f.hasMany = true;
|
|
4545
|
+
if (field.minRows !== void 0) f.minRows = field.minRows;
|
|
4546
|
+
if (field.maxRows !== void 0) f.maxRows = field.maxRows;
|
|
4547
|
+
if (field.mimeTypes) f.mimeTypes = [...field.mimeTypes];
|
|
4499
4548
|
break;
|
|
4500
4549
|
case "array":
|
|
4501
4550
|
if (field.minRows !== void 0) f.minRows = field.minRows;
|
|
@@ -5370,8 +5419,10 @@ function fieldType(field, n, indent) {
|
|
|
5370
5419
|
const union = field.options.map((o) => quote(typeof o === "string" ? o : o.value)).join(" | ") || "string";
|
|
5371
5420
|
return field.hasMany ? `(${union})[]` : union;
|
|
5372
5421
|
}
|
|
5373
|
-
case "upload":
|
|
5374
|
-
|
|
5422
|
+
case "upload": {
|
|
5423
|
+
const one = `ID | ${n.collections.get(MEDIA) ?? "Record<string, unknown>"}`;
|
|
5424
|
+
return field.hasMany ? `(${one})[]` : one;
|
|
5425
|
+
}
|
|
5375
5426
|
case "relationship": {
|
|
5376
5427
|
const target = n.collections.get(field.to);
|
|
5377
5428
|
const one = target ? `ID | ${target}` : "ID";
|
|
@@ -5403,7 +5454,7 @@ function fieldLines(fields, n, indent) {
|
|
|
5403
5454
|
for (const field of fields) {
|
|
5404
5455
|
if (field.hidden) continue;
|
|
5405
5456
|
const type = fieldType(field, n, indent);
|
|
5406
|
-
const alwaysPresent = field.type === "array" || field.type === "blocks" || field.type === "group" || (field
|
|
5457
|
+
const alwaysPresent = field.type === "array" || field.type === "blocks" || field.type === "group" || isHasMany(field);
|
|
5407
5458
|
if (field.required || alwaysPresent) lines.push(`${indent}${key(field.name)}: ${type}`);
|
|
5408
5459
|
else lines.push(`${indent}${key(field.name)}?: ${type} | null`);
|
|
5409
5460
|
}
|
|
@@ -5536,12 +5587,14 @@ export {
|
|
|
5536
5587
|
imageDimensions,
|
|
5537
5588
|
importConfig,
|
|
5538
5589
|
isAdmin,
|
|
5590
|
+
isHasMany,
|
|
5539
5591
|
isLoggedIn,
|
|
5540
5592
|
keyAllows,
|
|
5541
5593
|
loadConfig,
|
|
5542
5594
|
localStorage,
|
|
5543
5595
|
mergeForUpdate,
|
|
5544
5596
|
mimeAllowed,
|
|
5597
|
+
mimeAllowedBy,
|
|
5545
5598
|
parseId,
|
|
5546
5599
|
populate,
|
|
5547
5600
|
readCookie,
|