@easy-cms/core 1.25.0 → 1.26.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.
@@ -36,7 +36,7 @@ import {
36
36
  warnDeprecated,
37
37
  withCharset,
38
38
  withPrivacy
39
- } from "./chunk-RJGKAYUU.js";
39
+ } from "./chunk-J6E6QMDG.js";
40
40
 
41
41
  // src/access.ts
42
42
  var isSystemAdmin = (user) => user?.role === "admin" && !user.apiKey && user.scoped !== true;
@@ -2517,6 +2517,32 @@ var ADAPTER_API_VERSION = 1;
2517
2517
 
2518
2518
  // src/document.ts
2519
2519
  import { randomUUID } from "crypto";
2520
+
2521
+ // src/rich-text-links.ts
2522
+ function docLinkMarks(doc) {
2523
+ const found = [];
2524
+ const walk = (node, depth) => {
2525
+ if (!node || typeof node !== "object" || depth > 200) return;
2526
+ const { marks, content } = node;
2527
+ if (Array.isArray(marks))
2528
+ for (const mark of marks) {
2529
+ const m = mark;
2530
+ const attrs = m?.attrs;
2531
+ if (m?.type === "link" && attrs && attrs.doc !== void 0 && attrs.doc !== null)
2532
+ found.push(m);
2533
+ }
2534
+ if (Array.isArray(content)) for (const child of content) walk(child, depth + 1);
2535
+ };
2536
+ walk(doc, 0);
2537
+ return found;
2538
+ }
2539
+ function linkTarget(doc) {
2540
+ if (!doc || typeof doc !== "object") return void 0;
2541
+ const { relationTo, value } = doc;
2542
+ return typeof relationTo === "string" && relationTo !== "" && value !== void 0 && value !== null ? { relationTo, value } : void 0;
2543
+ }
2544
+
2545
+ // src/document.ts
2520
2546
  function isEmail(value) {
2521
2547
  const at = value.indexOf("@");
2522
2548
  return at > 0 && !value.includes("@", at + 1) && !/\s/.test(value) && value.slice(at + 2, -1).includes(".");
@@ -2754,10 +2780,26 @@ async function normalizeValue(field, raw, path, options, fail, errors, reference
2754
2780
  } catch {
2755
2781
  return fail("must be JSON-serializable");
2756
2782
  }
2757
- case "richText":
2783
+ case "richText": {
2758
2784
  if (!isPlainObject(raw) || raw.type !== "doc")
2759
2785
  return fail('must be a rich text document ({ type: "doc" })');
2760
- return raw;
2786
+ const marks = docLinkMarks(raw);
2787
+ if (marks.length === 0) return raw;
2788
+ const doc = structuredClone(raw);
2789
+ for (const mark of docLinkMarks(doc)) {
2790
+ const target = linkTarget(mark.attrs.doc);
2791
+ const id = target ? parseId(target.value) : void 0;
2792
+ if (!target || id === void 0)
2793
+ return fail("has a link to a document without { relationTo, value }");
2794
+ mark.attrs = {
2795
+ ...mark.attrs,
2796
+ doc: { relationTo: target.relationTo, value: id },
2797
+ href: null
2798
+ };
2799
+ references2.push({ field: path, collection: target.relationTo, id, link: true });
2800
+ }
2801
+ return doc;
2802
+ }
2761
2803
  case "upload":
2762
2804
  case "relationship": {
2763
2805
  const target = field.type === "upload" ? "media" : field.to;
@@ -3912,12 +3954,12 @@ function inScope(row, scope) {
3912
3954
  // src/populate.ts
3913
3955
  var DEFAULT_DEPTH = 1;
3914
3956
  var MAX_DEPTH = 3;
3915
- async function populate(load, collections, fields, docs, depth) {
3957
+ async function populate(load, collections, fields, docs, depth, linkURL) {
3916
3958
  if (depth <= 0 || docs.length === 0) return docs;
3917
3959
  const bySlug = new Map(collections.map((c) => [c.slug, c]));
3918
3960
  const copies = docs.map((doc) => structuredClone(doc));
3919
3961
  const slots = [];
3920
- for (const doc of copies) collectSlots(fields, doc, bySlug, slots);
3962
+ for (const doc of copies) collectSlots(fields, doc, bySlug, slots, linkURL);
3921
3963
  if (slots.length === 0) return copies;
3922
3964
  const wanted = /* @__PURE__ */ new Map();
3923
3965
  for (const slot of slots) {
@@ -3931,28 +3973,52 @@ async function populate(load, collections, fields, docs, depth) {
3931
3973
  const collection2 = bySlug.get(slug2);
3932
3974
  if (!collection2) return;
3933
3975
  const raw = await load(collection2, [...ids]);
3934
- const populated = await populate(load, collections, collection2.fields, raw, depth - 1);
3976
+ const populated = await populate(
3977
+ load,
3978
+ collections,
3979
+ collection2.fields,
3980
+ raw,
3981
+ depth - 1,
3982
+ linkURL
3983
+ );
3935
3984
  found.set(slug2, new Map(populated.map((d) => [d.id, d])));
3936
3985
  })
3937
3986
  );
3938
3987
  for (const slot of slots) slot.assign(found.get(slot.collection) ?? /* @__PURE__ */ new Map());
3939
3988
  return copies;
3940
3989
  }
3941
- function collectSlots(fields, data, bySlug, slots) {
3990
+ function collectSlots(fields, data, bySlug, slots, linkURL) {
3942
3991
  for (const field of fields) {
3943
3992
  if (field.name === "__proto__") continue;
3944
3993
  const value = data[field.name];
3945
3994
  if (value === null || value === void 0) continue;
3946
3995
  if (field.type === "group") {
3947
- if (typeof value === "object") collectSlots(field.fields, value, bySlug, slots);
3996
+ if (typeof value === "object")
3997
+ collectSlots(field.fields, value, bySlug, slots, linkURL);
3948
3998
  } else if (hasRows(field)) {
3949
3999
  if (Array.isArray(value)) {
3950
4000
  for (const row of value) {
3951
4001
  const fields2 = rowFields(field, row);
3952
4002
  if (fields2 && row && typeof row === "object")
3953
- collectSlots(fields2, row, bySlug, slots);
4003
+ collectSlots(fields2, row, bySlug, slots, linkURL);
3954
4004
  }
3955
4005
  }
4006
+ } else if (field.type === "richText" && linkURL) {
4007
+ if (value.type !== "doc") continue;
4008
+ for (const mark of docLinkMarks(value)) {
4009
+ const target = linkTarget(mark.attrs.doc);
4010
+ const collection2 = target ? bySlug.get(target.relationTo) : void 0;
4011
+ if (!target || !collection2) continue;
4012
+ const id = target.value;
4013
+ slots.push({
4014
+ collection: target.relationTo,
4015
+ ids: [id],
4016
+ assign: (byId) => {
4017
+ const doc = byId.get(id);
4018
+ mark.attrs = { ...mark.attrs, href: doc ? linkURL(collection2, doc) : null };
4019
+ }
4020
+ });
4021
+ }
3956
4022
  } else if (field.type === "relationship" || field.type === "upload") {
3957
4023
  if (typeof value === "object" && !Array.isArray(value)) continue;
3958
4024
  const collection2 = field.type === "upload" ? "media" : field.to;
@@ -7309,12 +7375,37 @@ function validateField(field, path, siblings, collectionSlugs, add) {
7309
7375
  }
7310
7376
  }
7311
7377
  break;
7378
+ case "ui": {
7379
+ if (!field.admin?.component)
7380
+ add(
7381
+ `${path}.admin.component`,
7382
+ "is required on a ui field",
7383
+ "e.g. { name: 'estimate', type: 'ui', admin: { component: 'acme-estimate' } }"
7384
+ );
7385
+ const stored = [
7386
+ "required",
7387
+ "unique",
7388
+ "uniqueWithin",
7389
+ "index",
7390
+ "defaultValue",
7391
+ "validate",
7392
+ "access",
7393
+ "hidden",
7394
+ "localized"
7395
+ ];
7396
+ for (const option of stored)
7397
+ if (field[option] !== void 0)
7398
+ add(`${path}.${option}`, "has no effect on a ui field, which stores nothing");
7399
+ break;
7400
+ }
7312
7401
  case "array":
7313
7402
  case "group":
7314
7403
  if (!Array.isArray(field.fields) || field.fields.length === 0) {
7315
7404
  add(`${path}.fields`, "must contain at least one field");
7316
7405
  break;
7317
7406
  }
7407
+ if (field.fields.every((f) => f?.type === "ui"))
7408
+ add(`${path}.fields`, "must contain a field that stores a value, not only ui fields");
7318
7409
  if (field.type === "array")
7319
7410
  checkRange(field.minRows, field.maxRows, "minRows", "maxRows", path, add);
7320
7411
  validateFields2(field.fields, `${path}.fields`, /* @__PURE__ */ new Set(["id"]), collectionSlugs, add);
@@ -7734,8 +7825,59 @@ async function resolveConfig(input) {
7734
7825
  ),
7735
7826
  fieldTypes: config.fieldTypes ?? []
7736
7827
  };
7737
- resolved.add(result);
7738
- return result;
7828
+ const final = withoutUiFields(result);
7829
+ resolved.add(final);
7830
+ return final;
7831
+ }
7832
+ var ADMIN_FIELDS = /* @__PURE__ */ Symbol("easy-cms.adminFields");
7833
+ function adminFieldsOf(container) {
7834
+ return container[ADMIN_FIELDS] ?? container.fields;
7835
+ }
7836
+ function withoutUiFields(config) {
7837
+ const strip = (fields) => {
7838
+ let changed = false;
7839
+ const admin = [];
7840
+ const data = [];
7841
+ for (const field of fields) {
7842
+ if (field.type === "ui") {
7843
+ changed = true;
7844
+ admin.push(field);
7845
+ continue;
7846
+ }
7847
+ let next = field;
7848
+ if (field.type === "group" || field.type === "array") {
7849
+ const inner = strip(field.fields);
7850
+ if (inner.changed) {
7851
+ changed = true;
7852
+ next = { ...field, fields: inner.data, [ADMIN_FIELDS]: inner.admin };
7853
+ }
7854
+ } else if (field.type === "blocks") {
7855
+ let blocksChanged = false;
7856
+ const blocks = field.blocks.map((block) => {
7857
+ const inner = strip(block.fields);
7858
+ if (!inner.changed) return block;
7859
+ blocksChanged = true;
7860
+ return { ...block, fields: inner.data, [ADMIN_FIELDS]: inner.admin };
7861
+ });
7862
+ if (blocksChanged) {
7863
+ changed = true;
7864
+ next = { ...field, blocks };
7865
+ }
7866
+ }
7867
+ admin.push(next);
7868
+ data.push(next);
7869
+ }
7870
+ return { data, admin, changed };
7871
+ };
7872
+ const apply2 = (container) => {
7873
+ const inner = strip(container.fields);
7874
+ return inner.changed ? { ...container, fields: inner.data, [ADMIN_FIELDS]: inner.admin } : container;
7875
+ };
7876
+ return {
7877
+ ...config,
7878
+ collections: config.collections.map(apply2),
7879
+ globals: config.globals.map(apply2)
7880
+ };
7739
7881
  }
7740
7882
  function usesVersions(config) {
7741
7883
  return [...config.collections ?? [], ...config.globals ?? []].some((c) => c.versions);
@@ -7788,7 +7930,7 @@ function cacheableResponse(request, body, status, headers, times, tags) {
7788
7930
  }
7789
7931
 
7790
7932
  // src/version.ts
7791
- var VERSION = true ? "1.25.0" : "0.0.0-dev";
7933
+ var VERSION = true ? "1.26.0" : "0.0.0-dev";
7792
7934
 
7793
7935
  // src/telemetry.ts
7794
7936
  var DB_CALLS = /* @__PURE__ */ new Set([
@@ -10341,7 +10483,16 @@ var EasyCMS = class {
10341
10483
  };
10342
10484
  const depth = Math.max(0, Math.min(MAX_DEPTH, Math.trunc(options.depth ?? DEFAULT_DEPTH)));
10343
10485
  const localized = docs.map((d) => this.pick(config, d, options));
10344
- const populated = await populate(load, this.config.collections, config.fields, localized, depth);
10486
+ const locale = options.locale && options.locale !== "all" ? options.locale : this.config.localization?.defaultLocale ?? this.config.admin.locale;
10487
+ const linkURL = (target, doc) => target.preview?.({ doc, locale }) ?? null;
10488
+ const populated = await populate(
10489
+ load,
10490
+ this.config.collections,
10491
+ config.fields,
10492
+ localized,
10493
+ depth,
10494
+ linkURL
10495
+ );
10345
10496
  return Promise.all(populated.map((d) => finish2(config, d)));
10346
10497
  }
10347
10498
  /** Creates a document: access, input filtering, hooks, validation, then afterChange. */
@@ -10882,11 +11033,26 @@ var EasyCMS = class {
10882
11033
  }
10883
11034
  async checkReferences(references2, guard) {
10884
11035
  const byCollection = /* @__PURE__ */ new Map();
11036
+ const errors = [];
10885
11037
  for (const ref of references2) {
10886
- if (!this.config.collections.some((c) => c.slug === ref.collection)) continue;
11038
+ const target = this.config.collections.find((c) => c.slug === ref.collection);
11039
+ if (ref.link && (!target || INTERNAL_COLLECTIONS.has(ref.collection))) {
11040
+ errors.push({
11041
+ field: ref.field,
11042
+ message: `links to "${ref.collection}", which is not a collection`
11043
+ });
11044
+ continue;
11045
+ }
11046
+ if (ref.link && typeof target?.preview !== "function") {
11047
+ errors.push({
11048
+ field: ref.field,
11049
+ message: `links to "${ref.collection}", whose documents have no URL (set its preview)`
11050
+ });
11051
+ continue;
11052
+ }
11053
+ if (!target) continue;
10887
11054
  byCollection.set(ref.collection, [...byCollection.get(ref.collection) ?? [], ref]);
10888
11055
  }
10889
- const errors = [];
10890
11056
  for (const [collection2, refs] of byCollection) {
10891
11057
  const found = await this.db.findByIds({
10892
11058
  collection: collection2,
@@ -12162,7 +12328,7 @@ async function serializeFields(fields, checks, localized, folderId, who) {
12162
12328
  case "array":
12163
12329
  if (field.minRows !== void 0) f.minRows = field.minRows;
12164
12330
  if (field.maxRows !== void 0) f.maxRows = field.maxRows;
12165
- f.fields = await serializeFields(field.fields, checks, localized, folderId, who);
12331
+ f.fields = await serializeFields(adminFieldsOf(field), checks, localized, folderId, who);
12166
12332
  break;
12167
12333
  case "blocks":
12168
12334
  if (field.minRows !== void 0) f.minRows = field.minRows;
@@ -12171,12 +12337,16 @@ async function serializeFields(fields, checks, localized, folderId, who) {
12171
12337
  field.blocks.map(async (block) => ({
12172
12338
  slug: block.slug,
12173
12339
  ...block.labels ? { labels: block.labels } : {},
12174
- fields: await serializeFields(block.fields, checks, localized, folderId, who)
12340
+ fields: await serializeFields(adminFieldsOf(block), checks, localized, folderId, who)
12175
12341
  }))
12176
12342
  );
12177
12343
  break;
12178
12344
  case "group":
12179
- f.fields = await serializeFields(field.fields, checks, localized, folderId, who);
12345
+ f.fields = await serializeFields(adminFieldsOf(field), checks, localized, folderId, who);
12346
+ break;
12347
+ // A component alone: without a label of its own, none is shown.
12348
+ case "ui":
12349
+ if (field.label === void 0) f.label = "";
12180
12350
  break;
12181
12351
  }
12182
12352
  out.push(f);
@@ -12196,7 +12366,7 @@ async function may(cms, access, user, target, operation, context) {
12196
12366
  async function collection(cms, config, user, localized, roles, context) {
12197
12367
  const target = { collection: config.slug };
12198
12368
  const fields = await serializeFields(
12199
- config.fields,
12369
+ adminFieldsOf(config),
12200
12370
  await checkers(cms, user, context),
12201
12371
  localized,
12202
12372
  folderIds(cms, user, context),
@@ -12256,10 +12426,16 @@ async function global(cms, config, user, localized, context) {
12256
12426
  versions: Boolean(config.versions),
12257
12427
  preview: typeof config.preview === "function",
12258
12428
  schedule: config.schedule === true,
12259
- fields: await serializeFields(config.fields, checks, localized, folderIds(cms, user, context), {
12260
- user,
12261
- context
12262
- }),
12429
+ fields: await serializeFields(
12430
+ adminFieldsOf(config),
12431
+ checks,
12432
+ localized,
12433
+ folderIds(cms, user, context),
12434
+ {
12435
+ user,
12436
+ context
12437
+ }
12438
+ ),
12263
12439
  permissions: {
12264
12440
  read: await may(cms, config.access?.read, user, target, "read", context),
12265
12441
  update: await may(cms, config.access?.update, user, target, "update", context),
@@ -329,7 +329,8 @@ var FIELD_TYPES = [
329
329
  "relationship",
330
330
  "array",
331
331
  "group",
332
- "blocks"
332
+ "blocks",
333
+ "ui"
333
334
  ];
334
335
 
335
336
  // src/config.ts
@@ -993,14 +993,24 @@ declare function mimeAllowedBy(mimeType: string, patterns: readonly string[]): b
993
993
  declare const hasRows: (field: Field) => field is ArrayField | BlocksField;
994
994
  /** The fields of one row of an `array` or `blocks` field (`undefined` for an unknown block). */
995
995
  declare function rowFields(field: ArrayField | BlocksField, row: unknown): readonly Field[] | undefined;
996
- type Field = CustomField | TextField | TextareaField | NumberField | BooleanField | DateField | EmailField | JsonField | SelectField | SlugField | RichTextField | UploadField | RelationshipField | ArrayField | GroupField | BlocksField;
996
+ /**
997
+ * Stores nothing: a component in the edit form (`admin.component`), e.g. a calculator, a preview
998
+ * or a button. Placed like any field (layout, groups, conditions); not in the database, the API or
999
+ * the generated types.
1000
+ */
1001
+ interface UiField extends BaseField<'ui', never> {
1002
+ readonly admin: FieldAdmin & {
1003
+ readonly component: AdminComponent;
1004
+ };
1005
+ }
1006
+ type Field = CustomField | TextField | TextareaField | NumberField | BooleanField | DateField | EmailField | JsonField | SelectField | SlugField | RichTextField | UploadField | RelationshipField | ArrayField | GroupField | BlocksField | UiField;
997
1007
  type FieldType = Field['type'];
998
1008
  /**
999
1009
  * The shortest `like` on a field with `index: 'trigram'`: trigrams are three characters, so a
1000
1010
  * shorter search can't use the index and would read every row.
1001
1011
  */
1002
1012
  declare const TRIGRAM_LIKE_MIN = 3;
1003
- declare const FIELD_TYPES: readonly ["text", "textarea", "number", "boolean", "date", "email", "json", "select", "slug", "richText", "upload", "relationship", "array", "group", "blocks"];
1013
+ declare const FIELD_TYPES: readonly ["text", "textarea", "number", "boolean", "date", "email", "json", "select", "slug", "richText", "upload", "relationship", "array", "group", "blocks", "ui"];
1004
1014
 
1005
1015
  type Simplify<T> = {
1006
1016
  [K in keyof T]: T[K];
@@ -1259,8 +1269,11 @@ type BlockInput<B> = B extends {
1259
1269
  id?: string;
1260
1270
  blockType: S;
1261
1271
  }> : never;
1272
+ /** The fields with a value: not `hidden`, and not `ui` fields (which store nothing). */
1262
1273
  type Visible<Fs extends readonly Field[]> = Exclude<Fs[number], {
1263
1274
  readonly hidden: true;
1275
+ } | {
1276
+ readonly type: 'ui';
1264
1277
  }>;
1265
1278
  /** Always set when read: required fields, and lists and groups (empty `[]` / `{}` otherwise). */
1266
1279
  type Present = {
@@ -3803,5 +3816,5 @@ interface ResolvedConfig extends Omit<Config, 'cors' | 'localization' | 'routes'
3803
3816
  */
3804
3817
  declare function defineConfig<const TConfig extends Config>(config: TConfig): TConfig;
3805
3818
 
3806
- export { ADAPTER_API_VERSION as A, EasyCMS as E, AuditLog as S, Auth as V, EasyCMSError as aE, FIELD_TYPES as aL, ConfigError as am, SchemaError as b$, ForbiddenError as b3, PLUGIN_API_VERSION as bC, PayloadTooLargeError as bH, QueryError as bN, ROLE_OPERATIONS as bO, Roles as bY, NotFoundError as bw, uniqueWithinOf as c$, WEBHOOK_EVENTS as cD, anyone as cI, consoleEmail as cJ, consoleLogger as cK, createEasyCMS as cL, defineConfig as cM, defineFieldType as cN, definePlugin as cO, diskStorage as cP, hasRows as cQ, isAdmin as cR, isHasMany as cS, isSignedIn as cT, isStaff as cU, isSystemAdmin as cV, jsonLogger as cW, memorySearch as cX, mimeAllowedBy as cY, rowFields as cZ, silentLogger as c_, SingleSignOn as ce, TRIGRAM_LIKE_MIN as cl, TooManyRequestsError as cp, UnauthorizedError as cr, ValidationError as cz, API_KEYS as d0, API_KEY_GLOBAL_OPERATIONS as d1, API_KEY_OPERATIONS as d2, DEFAULT_MAX_VERSIONS as d3, DEFAULT_PASSWORD_EMAILS as d4, FIELD_TYPE_BASES as d5, FOLDER_LEVELS as d6, MediaFolders as d7, SSO_COOKIE as d8, codeOfStatus as da, isJsonLogger as db, keyAllows as dc, logFormat as dd, secretsOf as de, ADMIN_ICONS as e };
3807
- export type { AuthUser as $, AfterDeleteHook as B, Config as C, AfterReadHook as D, Field as F, ApiKeyContext as G, ApiKeyGlobalOperation as H, ID as I, ApiKeyOperation as J, ApiKeyPermissions as K, LocalizationConfig as L, ArrayField as M, AuditChange as N, AuditConfig as O, PaginatedDocs as P, AuditEntry as Q, ResolvedConfig as R, AuditPage as T, AuditVerification as U, WebhookPayload as W, AuthConfig as X, AuthProvider as Y, AuthProviderProfile as Z, AuthProviderRequest as _, FieldError as a, FindArgs as a$, BackupsConfig as a0, BeforeChangeHook as a1, BeforeDeleteHook as a2, BeforeValidateHook as a3, Block as a4, BlocksField as a5, BooleanField as a6, BuiltinApiKeysCollection as a7, BuiltinMediaCollection as a8, BuiltinMediaFoldersCollection as a9, DepthOptions as aA, DirectUpload as aB, DiskStorageOptions as aC, DocumentOf as aD, EmailAdapter as aF, EmailField as aG, EmailMessage as aH, Endpoint as aI, EndpointRequest as aJ, ErrorCode as aK, FieldAccess as aM, FieldAccessFn as aN, FieldAdmin as aO, FieldRule as aP, FieldType as aQ, FieldTypeBase as aR, FieldTypeDefinition as aS, FieldTypeValidateContext as aT, FieldValidate as aU, FieldValidateContext as aV, FieldValue as aW, FieldsInput as aX, FieldsValue as aY, FilterOptionsArgs as aZ, FindAfterArgs as a_, BuiltinUsersCollection as aa, BundleHints as ab, CliCommand as ac, CollectionAccess as ad, CollectionAdmin as ae, CollectionCalendarAdmin as af, CollectionConfig as ag, CollectionDocument as ah, CollectionHooks as ai, CollectionListAdmin as aj, CollectionSearch as ak, CollectionSlug as al, ConfigIssue as an, ContainerAdmin as ao, CreateInput as ap, CreateMigrationResult as aq, CursorDocs as ar, CustomField as as, CustomFieldTypes as at, DashboardWidget as au, Database as av, DatabaseAdapter as aw, DatabaseInitArgs as ax, DatabaseTransfer as ay, DateField as az, FilterOptions as b, FindOptions as b0, FolderLevel as b1, FolderPermissions as b2, GlobalAccess as b4, GlobalConfig as b5, GlobalDocument as b6, GlobalHooks as b7, GlobalInput as b8, GlobalSlug as b9, Operation as bA, OutboxRow as bB, PasswordEmail as bD, PasswordEmailArgs as bE, PasswordEmailFn as bF, PasswordLinkOptions as bG, Plugin as bI, PluginInfo as bJ, PluginTypes as bK, PreviewTarget as bL, PreviewURL as bM, RawDocument as bP, ReadOptions as bQ, RelationshipField as bR, RequestContext as bS, RichTextDocument as bT, RichTextField as bU, Role as bV, RoleOperation as bW, RolePermissions as bX, RoutesConfig as bZ, ScheduledPublish as b_, GroupField as ba, ImageSize as bb, IncrementOptions as bc, InferCollection as bd, InferGlobal as be, JobConfig as bf, JsonField as bg, KeysetPage as bh, Label as bi, LayoutNode as bj, LivePreview as bk, LocaleOf as bl, LogDetails as bm, Logger as bn, LoginArgs as bo, LogsConfig as bp, MediaDocument as bq, MediaSize as br, MembersConfig as bs, MembersSignup as bt, MigrationInfo as bu, NavGroup as bv, NumberField as bx, OnRequest as by, OnRequestArgs as bz, CreateEasyCMSOptions as c, SchemaMode as c0, SearchAdapter as c1, SearchEntry as c2, SearchHits as c3, SearchOptions as c4, SearchQuery as c5, SearchResults as c6, SearchSetting as c7, SelectField as c8, SelectOption as c9, Version as cA, VersionSummary as cB, VersionsConfig as cC, WebhookConfig as cE, WebhookEvent as cF, Where as cG, WhereOperators as cH, Session as ca, SidebarPanel as cb, SignupArgs as cc, SignupResult as cd, SlugField as cf, SlugOf as cg, SsoOutcome as ch, SsoProviderRef as ci, StorageAdapter as cj, StoredFile as ck, TelemetryConfig as cm, TextField as cn, TextareaField as co, TypedPlugin as cq, UncountedDocs as cs, UpdateInput as ct, UpdateOptions as cu, UploadConfig as cv, UploadField as cw, UploadFromURLConfig as cx, UserIdentity as cy, EmailSetting as d, Secrets as d9, Access as f, AccessArgs as g, AccessOptions as h, AdminBrand as i, AdminCommand as j, AdminComponent as k, AdminConfig as l, AdminFieldArgs as m, AdminIcon as n, AdminLocale as o, AdminPage as p, AdminRole as q, AdminRoleChange as r, AdminRoleField as s, AdminRoleTarget as t, AdminRoleView as u, AdminRoles as v, AdminSso as w, AdminSwitcher as x, AdminViewAccess as y, AfterChangeHook as z };
3819
+ export { ADAPTER_API_VERSION as A, EasyCMS as E, AuditLog as S, Auth as V, EasyCMSError as aE, FIELD_TYPES as aL, ConfigError as am, SchemaError as b$, ForbiddenError as b3, PLUGIN_API_VERSION as bC, PayloadTooLargeError as bH, QueryError as bN, ROLE_OPERATIONS as bO, Roles as bY, NotFoundError as bw, silentLogger as c$, ValidationError as cA, WEBHOOK_EVENTS as cE, anyone as cJ, consoleEmail as cK, consoleLogger as cL, createEasyCMS as cM, defineConfig as cN, defineFieldType as cO, definePlugin as cP, diskStorage as cQ, hasRows as cR, isAdmin as cS, isHasMany as cT, isSignedIn as cU, isStaff as cV, isSystemAdmin as cW, jsonLogger as cX, memorySearch as cY, mimeAllowedBy as cZ, rowFields as c_, SingleSignOn as ce, TRIGRAM_LIKE_MIN as cl, TooManyRequestsError as cp, UnauthorizedError as cs, uniqueWithinOf as d0, API_KEYS as d1, API_KEY_GLOBAL_OPERATIONS as d2, API_KEY_OPERATIONS as d3, DEFAULT_MAX_VERSIONS as d4, DEFAULT_PASSWORD_EMAILS as d5, FIELD_TYPE_BASES as d6, FOLDER_LEVELS as d7, MediaFolders as d8, SSO_COOKIE as d9, codeOfStatus as db, isJsonLogger as dc, keyAllows as dd, logFormat as de, secretsOf as df, ADMIN_ICONS as e };
3820
+ export type { AuthUser as $, AfterDeleteHook as B, Config as C, AfterReadHook as D, Field as F, ApiKeyContext as G, ApiKeyGlobalOperation as H, ID as I, ApiKeyOperation as J, ApiKeyPermissions as K, LocalizationConfig as L, ArrayField as M, AuditChange as N, AuditConfig as O, PaginatedDocs as P, AuditEntry as Q, ResolvedConfig as R, AuditPage as T, AuditVerification as U, WebhookPayload as W, AuthConfig as X, AuthProvider as Y, AuthProviderProfile as Z, AuthProviderRequest as _, FieldError as a, FindArgs as a$, BackupsConfig as a0, BeforeChangeHook as a1, BeforeDeleteHook as a2, BeforeValidateHook as a3, Block as a4, BlocksField as a5, BooleanField as a6, BuiltinApiKeysCollection as a7, BuiltinMediaCollection as a8, BuiltinMediaFoldersCollection as a9, DepthOptions as aA, DirectUpload as aB, DiskStorageOptions as aC, DocumentOf as aD, EmailAdapter as aF, EmailField as aG, EmailMessage as aH, Endpoint as aI, EndpointRequest as aJ, ErrorCode as aK, FieldAccess as aM, FieldAccessFn as aN, FieldAdmin as aO, FieldRule as aP, FieldType as aQ, FieldTypeBase as aR, FieldTypeDefinition as aS, FieldTypeValidateContext as aT, FieldValidate as aU, FieldValidateContext as aV, FieldValue as aW, FieldsInput as aX, FieldsValue as aY, FilterOptionsArgs as aZ, FindAfterArgs as a_, BuiltinUsersCollection as aa, BundleHints as ab, CliCommand as ac, CollectionAccess as ad, CollectionAdmin as ae, CollectionCalendarAdmin as af, CollectionConfig as ag, CollectionDocument as ah, CollectionHooks as ai, CollectionListAdmin as aj, CollectionSearch as ak, CollectionSlug as al, ConfigIssue as an, ContainerAdmin as ao, CreateInput as ap, CreateMigrationResult as aq, CursorDocs as ar, CustomField as as, CustomFieldTypes as at, DashboardWidget as au, Database as av, DatabaseAdapter as aw, DatabaseInitArgs as ax, DatabaseTransfer as ay, DateField as az, FilterOptions as b, FindOptions as b0, FolderLevel as b1, FolderPermissions as b2, GlobalAccess as b4, GlobalConfig as b5, GlobalDocument as b6, GlobalHooks as b7, GlobalInput as b8, GlobalSlug as b9, Operation as bA, OutboxRow as bB, PasswordEmail as bD, PasswordEmailArgs as bE, PasswordEmailFn as bF, PasswordLinkOptions as bG, Plugin as bI, PluginInfo as bJ, PluginTypes as bK, PreviewTarget as bL, PreviewURL as bM, RawDocument as bP, ReadOptions as bQ, RelationshipField as bR, RequestContext as bS, RichTextDocument as bT, RichTextField as bU, Role as bV, RoleOperation as bW, RolePermissions as bX, RoutesConfig as bZ, ScheduledPublish as b_, GroupField as ba, ImageSize as bb, IncrementOptions as bc, InferCollection as bd, InferGlobal as be, JobConfig as bf, JsonField as bg, KeysetPage as bh, Label as bi, LayoutNode as bj, LivePreview as bk, LocaleOf as bl, LogDetails as bm, Logger as bn, LoginArgs as bo, LogsConfig as bp, MediaDocument as bq, MediaSize as br, MembersConfig as bs, MembersSignup as bt, MigrationInfo as bu, NavGroup as bv, NumberField as bx, OnRequest as by, OnRequestArgs as bz, CreateEasyCMSOptions as c, SchemaMode as c0, SearchAdapter as c1, SearchEntry as c2, SearchHits as c3, SearchOptions as c4, SearchQuery as c5, SearchResults as c6, SearchSetting as c7, SelectField as c8, SelectOption as c9, Version as cB, VersionSummary as cC, VersionsConfig as cD, WebhookConfig as cF, WebhookEvent as cG, Where as cH, WhereOperators as cI, Session as ca, SidebarPanel as cb, SignupArgs as cc, SignupResult as cd, SlugField as cf, SlugOf as cg, SsoOutcome as ch, SsoProviderRef as ci, StorageAdapter as cj, StoredFile as ck, TelemetryConfig as cm, TextField as cn, TextareaField as co, TypedPlugin as cq, UiField as cr, UncountedDocs as ct, UpdateInput as cu, UpdateOptions as cv, UploadConfig as cw, UploadField as cx, UploadFromURLConfig as cy, UserIdentity as cz, EmailSetting as d, Secrets as da, Access as f, AccessArgs as g, AccessOptions as h, AdminBrand as i, AdminCommand as j, AdminComponent as k, AdminConfig as l, AdminFieldArgs as m, AdminIcon as n, AdminLocale as o, AdminPage as p, AdminRole as q, AdminRoleChange as r, AdminRoleField as s, AdminRoleTarget as t, AdminRoleView as u, AdminRoles as v, AdminSso as w, AdminSwitcher as x, AdminViewAccess as y, AfterChangeHook as z };
@@ -1,4 +1,4 @@
1
- import { I as ID, C as Config, E as EasyCMS, L as LocalizationConfig, F as Field, a as FieldError, b as FilterOptions, c as CreateEasyCMSOptions, R as ResolvedConfig } from './config-Bsp6rkuH.js';
1
+ import { I as ID, C as Config, E as EasyCMS, L as LocalizationConfig, F as Field, a as FieldError, b as FilterOptions, c as CreateEasyCMSOptions, R as ResolvedConfig } from './config-BpKdXA32.js';
2
2
 
3
3
  /** Decrypts a file from `encryptBackup`; throws for another key or a changed file. */
4
4
  declare function decryptBackup(data: Uint8Array, encryptionKey: string): Uint8Array;
@@ -79,6 +79,8 @@ interface Reference {
79
79
  readonly mimeTypes?: readonly string[];
80
80
  /** The upload's `folder` with `folderOnly`: the file must be in it, checked when saving. */
81
81
  readonly folderOnly?: string;
82
+ /** A link in rich text (#326): its collection must exist and have a URL (`preview`). */
83
+ readonly link?: true;
82
84
  }
83
85
  interface ValidateOptions {
84
86
  readonly operation: 'create' | 'update';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-Bsp6rkuH.js';
2
- export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as CollectionCalendarAdmin, ag as CollectionConfig, ah as CollectionDocument, ai as CollectionHooks, aj as CollectionListAdmin, ak as CollectionSearch, al as CollectionSlug, C as Config, am as ConfigError, an as ConfigIssue, ao as ContainerAdmin, c as CreateEasyCMSOptions, ap as CreateInput, aq as CreateMigrationResult, ar as CursorDocs, as as CustomField, at as CustomFieldTypes, au as DashboardWidget, av as Database, aw as DatabaseAdapter, ax as DatabaseInitArgs, ay as DatabaseTransfer, az as DateField, aA as DepthOptions, aB as DirectUpload, aC as DiskStorageOptions, aD as DocumentOf, E as EasyCMS, aE as EasyCMSError, aF as EmailAdapter, aG as EmailField, aH as EmailMessage, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, aL as FIELD_TYPES, F as Field, aM as FieldAccess, aN as FieldAccessFn, aO as FieldAdmin, a as FieldError, aP as FieldRule, aQ as FieldType, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, aU as FieldValidate, aV as FieldValidateContext, aW as FieldValue, aX as FieldsInput, aY as FieldsValue, b as FilterOptions, aZ as FilterOptionsArgs, a_ as FindAfterArgs, a$ as FindArgs, b0 as FindOptions, b1 as FolderLevel, b2 as FolderPermissions, b3 as ForbiddenError, b4 as GlobalAccess, b5 as GlobalConfig, b6 as GlobalDocument, b7 as GlobalHooks, b8 as GlobalInput, b9 as GlobalSlug, ba as GroupField, bb as ImageSize, bc as IncrementOptions, bd as InferCollection, be as InferGlobal, bf as JobConfig, bg as JsonField, bh as KeysetPage, bi as Label, bj as LayoutNode, bk as LivePreview, bl as LocaleOf, L as LocalizationConfig, bm as LogDetails, bn as Logger, bo as LoginArgs, bp as LogsConfig, bq as MediaDocument, br as MediaSize, bs as MembersConfig, bt as MembersSignup, bu as MigrationInfo, bv as NavGroup, bw as NotFoundError, bx as NumberField, by as OnRequest, bz as OnRequestArgs, bA as Operation, bB as OutboxRow, bC as PLUGIN_API_VERSION, bD as PasswordEmail, bE as PasswordEmailArgs, bF as PasswordEmailFn, bG as PasswordLinkOptions, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bL as PreviewTarget, bM as PreviewURL, bN as QueryError, bO as ROLE_OPERATIONS, bP as RawDocument, bQ as ReadOptions, bR as RelationshipField, bS as RequestContext, R as ResolvedConfig, bT as RichTextDocument, bU as RichTextField, bV as Role, bW as RoleOperation, bX as RolePermissions, bY as Roles, bZ as RoutesConfig, b_ as ScheduledPublish, b$ as SchemaError, c0 as SchemaMode, c1 as SearchAdapter, c2 as SearchEntry, c3 as SearchHits, c4 as SearchOptions, c5 as SearchQuery, c6 as SearchResults, c7 as SearchSetting, c8 as SelectField, c9 as SelectOption, ca as Session, cb as SidebarPanel, cc as SignupArgs, cd as SignupResult, ce as SingleSignOn, cf as SlugField, cg as SlugOf, ch as SsoOutcome, ci as SsoProviderRef, cj as StorageAdapter, ck as StoredFile, cl as TRIGRAM_LIKE_MIN, cm as TelemetryConfig, cn as TextField, co as TextareaField, cp as TooManyRequestsError, cq as TypedPlugin, cr as UnauthorizedError, cs as UncountedDocs, ct as UpdateInput, cu as UpdateOptions, cv as UploadConfig, cw as UploadField, cx as UploadFromURLConfig, cy as UserIdentity, cz as ValidationError, cA as Version, cB as VersionSummary, cC as VersionsConfig, cD as WEBHOOK_EVENTS, cE as WebhookConfig, cF as WebhookEvent, cG as Where, cH as WhereOperators, cI as anyone, cJ as consoleEmail, cK as consoleLogger, cL as createEasyCMS, cM as defineConfig, cN as defineFieldType, cO as definePlugin, cP as diskStorage, cQ as hasRows, cR as isAdmin, cS as isHasMany, cT as isSignedIn, cU as isStaff, cV as isSystemAdmin, cW as jsonLogger, cX as memorySearch, cY as mimeAllowedBy, cZ as rowFields, c_ as silentLogger, c$ as uniqueWithinOf } from './config-Bsp6rkuH.js';
3
- export { A as ADMIN_API_VERSION, a as AdminCollection, b as AdminComponentRef, c as AdminElementProps, d as AdminField, e as AdminGlobal, f as AdminLayoutNode, g as AdminNavGroup, h as AdminNavItem, i as AdminNavNode, j as AdminPageRef, k as AdminPageRoute, l as AdminSchema, m as AdminWidgetRef, S as SetFieldDetail, w as warnDeprecated } from './plugin-CUzEJN31.js';
4
- export { A as AdminBackup, a as AdminBackups, b as ApiHandlerOptions, B as BackupState, L as LoadConfigOptions, R as RestHandler, c as RestHandlerOptions, d as createApiHandler, e as createRestHandler, l as loadConfig, r as resolveConfig, s as sharedEasyCMS, f as slugify } from './handler-Br9Pu6z9.js';
1
+ import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-BpKdXA32.js';
2
+ export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as CollectionCalendarAdmin, ag as CollectionConfig, ah as CollectionDocument, ai as CollectionHooks, aj as CollectionListAdmin, ak as CollectionSearch, al as CollectionSlug, C as Config, am as ConfigError, an as ConfigIssue, ao as ContainerAdmin, c as CreateEasyCMSOptions, ap as CreateInput, aq as CreateMigrationResult, ar as CursorDocs, as as CustomField, at as CustomFieldTypes, au as DashboardWidget, av as Database, aw as DatabaseAdapter, ax as DatabaseInitArgs, ay as DatabaseTransfer, az as DateField, aA as DepthOptions, aB as DirectUpload, aC as DiskStorageOptions, aD as DocumentOf, E as EasyCMS, aE as EasyCMSError, aF as EmailAdapter, aG as EmailField, aH as EmailMessage, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, aL as FIELD_TYPES, F as Field, aM as FieldAccess, aN as FieldAccessFn, aO as FieldAdmin, a as FieldError, aP as FieldRule, aQ as FieldType, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, aU as FieldValidate, aV as FieldValidateContext, aW as FieldValue, aX as FieldsInput, aY as FieldsValue, b as FilterOptions, aZ as FilterOptionsArgs, a_ as FindAfterArgs, a$ as FindArgs, b0 as FindOptions, b1 as FolderLevel, b2 as FolderPermissions, b3 as ForbiddenError, b4 as GlobalAccess, b5 as GlobalConfig, b6 as GlobalDocument, b7 as GlobalHooks, b8 as GlobalInput, b9 as GlobalSlug, ba as GroupField, bb as ImageSize, bc as IncrementOptions, bd as InferCollection, be as InferGlobal, bf as JobConfig, bg as JsonField, bh as KeysetPage, bi as Label, bj as LayoutNode, bk as LivePreview, bl as LocaleOf, L as LocalizationConfig, bm as LogDetails, bn as Logger, bo as LoginArgs, bp as LogsConfig, bq as MediaDocument, br as MediaSize, bs as MembersConfig, bt as MembersSignup, bu as MigrationInfo, bv as NavGroup, bw as NotFoundError, bx as NumberField, by as OnRequest, bz as OnRequestArgs, bA as Operation, bB as OutboxRow, bC as PLUGIN_API_VERSION, bD as PasswordEmail, bE as PasswordEmailArgs, bF as PasswordEmailFn, bG as PasswordLinkOptions, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bL as PreviewTarget, bM as PreviewURL, bN as QueryError, bO as ROLE_OPERATIONS, bP as RawDocument, bQ as ReadOptions, bR as RelationshipField, bS as RequestContext, R as ResolvedConfig, bT as RichTextDocument, bU as RichTextField, bV as Role, bW as RoleOperation, bX as RolePermissions, bY as Roles, bZ as RoutesConfig, b_ as ScheduledPublish, b$ as SchemaError, c0 as SchemaMode, c1 as SearchAdapter, c2 as SearchEntry, c3 as SearchHits, c4 as SearchOptions, c5 as SearchQuery, c6 as SearchResults, c7 as SearchSetting, c8 as SelectField, c9 as SelectOption, ca as Session, cb as SidebarPanel, cc as SignupArgs, cd as SignupResult, ce as SingleSignOn, cf as SlugField, cg as SlugOf, ch as SsoOutcome, ci as SsoProviderRef, cj as StorageAdapter, ck as StoredFile, cl as TRIGRAM_LIKE_MIN, cm as TelemetryConfig, cn as TextField, co as TextareaField, cp as TooManyRequestsError, cq as TypedPlugin, cr as UiField, cs as UnauthorizedError, ct as UncountedDocs, cu as UpdateInput, cv as UpdateOptions, cw as UploadConfig, cx as UploadField, cy as UploadFromURLConfig, cz as UserIdentity, cA as ValidationError, cB as Version, cC as VersionSummary, cD as VersionsConfig, cE as WEBHOOK_EVENTS, cF as WebhookConfig, cG as WebhookEvent, cH as Where, cI as WhereOperators, cJ as anyone, cK as consoleEmail, cL as consoleLogger, cM as createEasyCMS, cN as defineConfig, cO as defineFieldType, cP as definePlugin, cQ as diskStorage, cR as hasRows, cS as isAdmin, cT as isHasMany, cU as isSignedIn, cV as isStaff, cW as isSystemAdmin, cX as jsonLogger, cY as memorySearch, cZ as mimeAllowedBy, c_ as rowFields, c$ as silentLogger, d0 as uniqueWithinOf } from './config-BpKdXA32.js';
3
+ export { A as ADMIN_API_VERSION, a as AdminCollection, b as AdminComponentRef, c as AdminElementProps, d as AdminField, e as AdminGlobal, f as AdminLayoutNode, g as AdminNavGroup, h as AdminNavItem, i as AdminNavNode, j as AdminPageRef, k as AdminPageRoute, l as AdminSchema, m as AdminWidgetRef, S as SetFieldDetail, w as warnDeprecated } from './plugin-AYwNCGrB.js';
4
+ export { A as AdminBackup, a as AdminBackups, b as ApiHandlerOptions, B as BackupState, L as LoadConfigOptions, R as RestHandler, c as RestHandlerOptions, d as createApiHandler, e as createRestHandler, l as loadConfig, r as resolveConfig, s as sharedEasyCMS, f as slugify } from './handler-BokoUN1I.js';
5
5
  export { FieldCondition, matchesCondition } from './conditions.js';
6
6
 
7
7
  type DeliveryKind = 'webhook' | 'email';
package/dist/index.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  silentLogger,
29
29
  slugify,
30
30
  verifyWebhook
31
- } from "./chunk-AAZ35NPQ.js";
31
+ } from "./chunk-5L544S33.js";
32
32
  import {
33
33
  matchesCondition
34
34
  } from "./chunk-U266LV4M.js";
@@ -53,7 +53,7 @@ import {
53
53
  defineFieldType,
54
54
  definePlugin,
55
55
  warnDeprecated
56
- } from "./chunk-RJGKAYUU.js";
56
+ } from "./chunk-J6E6QMDG.js";
57
57
  export {
58
58
  ADAPTER_API_VERSION,
59
59
  ADMIN_API_VERSION,
@@ -1,6 +1,6 @@
1
1
  import { Config, Database, EasyCMS, NavGroup, CollectionConfig, ID, RawDocument, Field, ResolvedConfig, ConfigIssue } from './index.js';
2
- export { d0 as API_KEYS, d1 as API_KEY_GLOBAL_OPERATIONS, d2 as API_KEY_OPERATIONS, d3 as DEFAULT_MAX_VERSIONS, d4 as DEFAULT_PASSWORD_EMAILS, d5 as FIELD_TYPE_BASES, d6 as FOLDER_LEVELS, d7 as MediaFolders, d8 as SSO_COOKIE, d9 as Secrets, cl as TRIGRAM_LIKE_MIN, da as codeOfStatus, cQ as hasRows, cS as isHasMany, db as isJsonLogger, dc as keyAllows, dd as logFormat, cY as mimeAllowedBy, cZ as rowFields, de as secretsOf, c$ as uniqueWithinOf } from './config-Bsp6rkuH.js';
3
- export { C as CONFIG_FILE_NAMES, g as CSRF_COOKIE, h as CSRF_HEADER, D as DEFAULT_ADMIN_PATH, i as DEFAULT_API_PATH, j as DEFAULT_MAX_FILE_SIZE, k as DEFAULT_TOKEN_EXPIRATION, m as applyDefaults, n as applyPlugins, o as createRootEndpointHandler, p as decryptBackup, q as fillMissing, t as findConfigFile, u as forwardedClientIp, v as generateSlugs, w as importConfig, x as isEmail, y as mergeForUpdate, z as parseId, E as platformClientIp, F as readCookie, G as validateFields, H as writeBackupFile } from './handler-Br9Pu6z9.js';
2
+ export { d1 as API_KEYS, d2 as API_KEY_GLOBAL_OPERATIONS, d3 as API_KEY_OPERATIONS, d4 as DEFAULT_MAX_VERSIONS, d5 as DEFAULT_PASSWORD_EMAILS, d6 as FIELD_TYPE_BASES, d7 as FOLDER_LEVELS, d8 as MediaFolders, d9 as SSO_COOKIE, da as Secrets, cl as TRIGRAM_LIKE_MIN, db as codeOfStatus, cR as hasRows, cT as isHasMany, dc as isJsonLogger, dd as keyAllows, de as logFormat, cZ as mimeAllowedBy, c_ as rowFields, df as secretsOf, d0 as uniqueWithinOf } from './config-BpKdXA32.js';
3
+ export { C as CONFIG_FILE_NAMES, g as CSRF_COOKIE, h as CSRF_HEADER, D as DEFAULT_ADMIN_PATH, i as DEFAULT_API_PATH, j as DEFAULT_MAX_FILE_SIZE, k as DEFAULT_TOKEN_EXPIRATION, m as applyDefaults, n as applyPlugins, o as createRootEndpointHandler, p as decryptBackup, q as fillMissing, t as findConfigFile, u as forwardedClientIp, v as generateSlugs, w as importConfig, x as isEmail, y as mergeForUpdate, z as parseId, E as platformClientIp, F as readCookie, G as validateFields, H as writeBackupFile } from './handler-BokoUN1I.js';
4
4
  export { conditionIssues } from './conditions.js';
5
5
 
6
6
  /** The session cookie the REST API sets at login. */
@@ -92,12 +92,14 @@ declare const DEFAULT_DEPTH = 1;
92
92
  declare const MAX_DEPTH = 3;
93
93
  /** Loads the documents of one collection that the caller may see. */
94
94
  type Loader = (collection: CollectionConfig, ids: readonly ID[]) => Promise<RawDocument[]>;
95
+ /** A linked document's URL, for links in rich text (#326); `null` when it has none. */
96
+ type LinkURL = (collection: CollectionConfig, doc: RawDocument) => string | null;
95
97
  /**
96
98
  * Replaces relationship and upload ids with documents, `depth` levels deep.
97
99
  * Missing (or unreadable) documents become `null` (single) or are dropped (hasMany).
98
100
  * Returns new objects; the input is not modified.
99
101
  */
100
- declare function populate(load: Loader, collections: readonly CollectionConfig[], fields: readonly Field[], docs: RawDocument[], depth: number): Promise<RawDocument[]>;
102
+ declare function populate(load: Loader, collections: readonly CollectionConfig[], fields: readonly Field[], docs: RawDocument[], depth: number, linkURL?: LinkURL): Promise<RawDocument[]>;
101
103
 
102
104
  /**
103
105
  * Finds the file of an admin module (`admin.modules`): a package export or a path relative to
package/dist/internal.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  verifyPassword,
59
59
  verifyTurnstile,
60
60
  writeBackupFile
61
- } from "./chunk-AAZ35NPQ.js";
61
+ } from "./chunk-5L544S33.js";
62
62
  import {
63
63
  conditionIssues
64
64
  } from "./chunk-U266LV4M.js";
@@ -77,7 +77,7 @@ import {
77
77
  rowFields,
78
78
  sniffMimeType,
79
79
  uniqueWithinOf
80
- } from "./chunk-RJGKAYUU.js";
80
+ } from "./chunk-J6E6QMDG.js";
81
81
 
82
82
  // src/typegen.ts
83
83
  var pascal = (name) => name.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
@@ -160,12 +160,15 @@ ${indent}}`
160
160
  );
161
161
  return `(${kinds.join(" | ")})[]`;
162
162
  }
163
+ // Stores nothing (and is gone from a resolved config).
164
+ case "ui":
165
+ return "never";
163
166
  }
164
167
  }
165
168
  function fieldLines(fields, n, indent) {
166
169
  const lines = [];
167
170
  for (const field of fields) {
168
- if (field.hidden) continue;
171
+ if (field.hidden || field.type === "ui") continue;
169
172
  const type = fieldType(field, n, indent);
170
173
  const alwaysPresent = field.type === "array" || field.type === "blocks" || field.type === "group" || isHasMany(field);
171
174
  if (field.required || alwaysPresent) lines.push(`${indent}${key(field.name)}: ${type}`);
@@ -1,4 +1,4 @@
1
- import { bi as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ci as SsoProviderRef } from './config-Bsp6rkuH.js';
1
+ import { bi as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ci as SsoProviderRef } from './config-BpKdXA32.js';
2
2
  import { FieldCondition } from './conditions.js';
3
3
 
4
4
  /** A Web Component from an admin module, with its `props` (plain JSON). */
package/dist/plugin.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, ag as CollectionConfig, C as Config, am as ConfigError, au as DashboardWidget, aE as EasyCMSError, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, F as Field, aM as FieldAccess, a as FieldError, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, b3 as ForbiddenError, b5 as GlobalConfig, I as ID, bf as JobConfig, bi as Label, bv as NavGroup, bw as NotFoundError, by as OnRequest, bz as OnRequestArgs, bC as PLUGIN_API_VERSION, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bN as QueryError, bS as RequestContext, cp as TooManyRequestsError, cq as TypedPlugin, cr as UnauthorizedError, cz as ValidationError, cG as Where, cN as defineFieldType, cO as definePlugin } from './config-Bsp6rkuH.js';
2
- export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-CUzEJN31.js';
1
+ export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, ag as CollectionConfig, C as Config, am as ConfigError, au as DashboardWidget, aE as EasyCMSError, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, F as Field, aM as FieldAccess, a as FieldError, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, b3 as ForbiddenError, b5 as GlobalConfig, I as ID, bf as JobConfig, bi as Label, bv as NavGroup, bw as NotFoundError, by as OnRequest, bz as OnRequestArgs, bC as PLUGIN_API_VERSION, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bN as QueryError, bS as RequestContext, cp as TooManyRequestsError, cq as TypedPlugin, cs as UnauthorizedError, cA as ValidationError, cH as Where, cO as defineFieldType, cP as definePlugin } from './config-BpKdXA32.js';
2
+ export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-AYwNCGrB.js';
3
3
  import './conditions.js';
package/dist/plugin.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  defineFieldType,
17
17
  definePlugin,
18
18
  warnDeprecated
19
- } from "./chunk-RJGKAYUU.js";
19
+ } from "./chunk-J6E6QMDG.js";
20
20
  export {
21
21
  ADMIN_API_VERSION,
22
22
  ADMIN_ICONS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easy-cms/core",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "description": "Embedded, code-first headless CMS for Nuxt and Next.js",
5
5
  "license": "MIT",
6
6
  "type": "module",