@easy-cms/core 0.62.0 → 0.63.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.
@@ -1169,11 +1169,13 @@ function safeEqual(a, b) {
1169
1169
  const right = Buffer.from(b);
1170
1170
  return left.length === right.length && timingSafeEqual4(left, right);
1171
1171
  }
1172
- function signPreviewToken(secret, target, expiresAt) {
1172
+ function signPreviewToken(secret, target, expiresAt, user) {
1173
1173
  const payload = Buffer.from(
1174
- JSON.stringify(
1175
- "global" in target ? { g: target.global, e: expiresAt } : { c: target.collection, i: target.id, e: expiresAt }
1176
- )
1174
+ JSON.stringify({
1175
+ ..."global" in target ? { g: target.global } : { c: target.collection, i: target.id },
1176
+ e: expiresAt,
1177
+ ...user !== void 0 ? { u: user } : {}
1178
+ })
1177
1179
  ).toString("base64url");
1178
1180
  return `${payload}.${hmac(secret, `preview:${payload}`)}`;
1179
1181
  }
@@ -1185,9 +1187,10 @@ function verifyPreviewToken(secret, token, now = Date.now()) {
1185
1187
  try {
1186
1188
  const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
1187
1189
  if (typeof data.e !== "number" || data.e <= now) return null;
1188
- if (typeof data.g === "string") return { global: data.g, expiresAt: data.e };
1190
+ const user = typeof data.u === "string" ? { user: data.u } : {};
1191
+ if (typeof data.g === "string") return { global: data.g, expiresAt: data.e, ...user };
1189
1192
  if (typeof data.c === "string" && typeof data.i === "string")
1190
- return { collection: data.c, id: data.i, expiresAt: data.e };
1193
+ return { collection: data.c, id: data.i, expiresAt: data.e, ...user };
1191
1194
  return null;
1192
1195
  } catch {
1193
1196
  return null;
@@ -1934,6 +1937,12 @@ var Auth = class {
1934
1937
  if (!user || user.active === false) return null;
1935
1938
  return this.toAuthUser(user);
1936
1939
  }
1940
+ /** An active user by id, as requests see them; `null` when deleted or deactivated. @internal */
1941
+ async activeUser(id) {
1942
+ const user = await this.db.findById({ collection: USERS, id });
1943
+ if (!user || user.active === false) return null;
1944
+ return this.toAuthUser(user);
1945
+ }
1937
1946
  /** The CSRF token clients must echo for a signed session token. @internal */
1938
1947
  csrfFor(signedToken) {
1939
1948
  const token = unsignToken(this.config.secret, signedToken);
@@ -7119,18 +7128,23 @@ var EasyCMS = class {
7119
7128
  }
7120
7129
  /**
7121
7130
  * How many documents use any of these files in a top-level upload field (rich text and fields
7122
- * inside groups, arrays and blocks are not counted). Drafts count too.
7131
+ * inside groups, arrays and blocks are not counted). Drafts count too. With
7132
+ * `overrideAccess: false`, only documents the user may read.
7123
7133
  */
7124
- async mediaUsage(ids) {
7134
+ async mediaUsage(ids, options = {}) {
7125
7135
  if (ids.length === 0) return 0;
7126
7136
  let count = 0;
7127
7137
  for (const config of this.config.collections) {
7128
7138
  if (INTERNAL_COLLECTIONS.has(config.slug)) continue;
7129
7139
  for (const field of config.fields) {
7130
7140
  if (field.type !== "upload") continue;
7131
- count += await this.db.count({
7132
- collection: config.slug,
7133
- where: { [field.name]: { in: [...ids] } }
7141
+ count += await this.count(config.slug, {
7142
+ ...options,
7143
+ where: { [field.name]: { in: [...ids] } },
7144
+ draft: true
7145
+ }).catch((error) => {
7146
+ if (error instanceof ForbiddenError || error instanceof UnauthorizedError) return 0;
7147
+ throw error;
7134
7148
  });
7135
7149
  }
7136
7150
  }
@@ -7381,12 +7395,15 @@ var EasyCMS = class {
7381
7395
  /**
7382
7396
  * A token that lets a page read one document's current draft for a while (default one hour),
7383
7397
  * without a login: `GET /api/cms/:collection/:id?preview=<token>`. The admin adds one to the
7384
- * preview URL as `easy-cms-preview`, for sites on another origin.
7398
+ * preview URL as `easy-cms-preview`, for sites on another origin. With `user`, the page reads
7399
+ * it with that user's access (fields they can't read are left out; a deactivated user's token
7400
+ * stops working); without, with full access.
7385
7401
  */
7386
7402
  createPreviewToken(target, options = {}) {
7387
7403
  const seconds = options.expiresIn ?? 60 * 60;
7388
7404
  const normalized = "global" in target ? target : { collection: target.collection, id: String(target.id) };
7389
- return signPreviewToken(this.config.secret, normalized, Date.now() + seconds * 1e3);
7405
+ const user = options.user ? String(options.user.id) : void 0;
7406
+ return signPreviewToken(this.config.secret, normalized, Date.now() + seconds * 1e3, user);
7390
7407
  }
7391
7408
  /** What a preview token opens, or `null` when it is invalid or expired. */
7392
7409
  verifyPreviewToken(token) {
@@ -7846,7 +7863,8 @@ var EasyCMS = class {
7846
7863
  const check3 = (operation) => this.checkDocumentAccess(config, operation, guard, parsed, void 0).then(
7847
7864
  () => true,
7848
7865
  (error) => {
7849
- if (error instanceof ForbiddenError || error instanceof UnauthorizedError) return false;
7866
+ if (error instanceof ForbiddenError || error instanceof UnauthorizedError || error instanceof NotFoundError)
7867
+ return false;
7850
7868
  throw error;
7851
7869
  }
7852
7870
  );
@@ -8315,7 +8333,38 @@ var EasyCMS = class {
8315
8333
  await this.checkQueryFields(config, guard, where);
8316
8334
  return andWhere(andWhere(where, access), own);
8317
8335
  }
8336
+ /**
8337
+ * Throws unless the caller may update or delete this document. A user who may not even read
8338
+ * it gets `NotFoundError`, as for an id that doesn't exist: a 403 would tell it does.
8339
+ */
8318
8340
  async checkDocumentAccess(config, operation, guard, id, data) {
8341
+ await this.hidingDenied(
8342
+ config.slug,
8343
+ guard,
8344
+ id,
8345
+ () => this.documentAccess(config, operation, guard, id, data)
8346
+ );
8347
+ }
8348
+ /** Runs a check; a `ForbiddenError` for a document the user can't read becomes a 404. */
8349
+ async hidingDenied(collection2, guard, id, check3) {
8350
+ try {
8351
+ await check3();
8352
+ } catch (error) {
8353
+ if (error instanceof ForbiddenError && !await this.mayRead(collection2, guard, id))
8354
+ throw new NotFoundError(collection2, String(id));
8355
+ throw error;
8356
+ }
8357
+ }
8358
+ async mayRead(collection2, guard, id) {
8359
+ const config = this.collection(collection2);
8360
+ try {
8361
+ const where = await this.readWhere(config, guard, { id: { equals: id } });
8362
+ return await this.db.count({ collection: collection2, where }) > 0;
8363
+ } catch {
8364
+ return false;
8365
+ }
8366
+ }
8367
+ async documentAccess(config, operation, guard, id, data) {
8319
8368
  if (!guard.enforce) return;
8320
8369
  const own = await this.checkGrant(guard, { collection: config.slug }, operation);
8321
8370
  const allowed2 = await evaluateAccess(config.access?.[operation], {
@@ -8382,13 +8431,15 @@ var EasyCMS = class {
8382
8431
  }
8383
8432
  /** `checkGrant` for one document: a role limited to its own documents must own it. */
8384
8433
  async checkDocumentGrant(guard, collection2, operation, id) {
8385
- const own = await this.checkGrant(guard, { collection: collection2 }, operation);
8386
- if (own === true) return;
8387
- const matches2 = await this.db.count({
8388
- collection: collection2,
8389
- where: andWhere(own, { id: { equals: id } })
8434
+ await this.hidingDenied(collection2, guard, id, async () => {
8435
+ const own = await this.checkGrant(guard, { collection: collection2 }, operation);
8436
+ if (own === true) return;
8437
+ const matches2 = await this.db.count({
8438
+ collection: collection2,
8439
+ where: andWhere(own, { id: { equals: id } })
8440
+ });
8441
+ if (matches2 === 0) throw deny(guard.user);
8390
8442
  });
8391
- if (matches2 === 0) throw deny(guard.user);
8392
8443
  }
8393
8444
  /** Runs afterRead hooks, populates relationships and removes what the caller may not see. */
8394
8445
  async output(config, docs, guard, options) {
@@ -9042,7 +9093,7 @@ async function readAdminModule(cms, index) {
9042
9093
  }
9043
9094
 
9044
9095
  // src/version.ts
9045
- var VERSION = true ? "0.62.0" : "0.0.0-dev";
9096
+ var VERSION = true ? "0.63.0" : "0.0.0-dev";
9046
9097
 
9047
9098
  // src/rest/admin-deliveries.ts
9048
9099
  var PER_PAGE = 50;
@@ -10406,7 +10457,12 @@ async function route(cms, ctx, method, path, options) {
10406
10457
  if (!ctx.user || ctx.user.apiKey) throw new UnauthorizedError();
10407
10458
  if (method !== "GET") throw methodNotAllowed(ctx, "GET");
10408
10459
  const ids = (ctx.url.searchParams.get("ids") ?? "").split(",").map((id2) => parseId(id2)).filter((id2) => id2 !== void 0);
10409
- return { body: { count: await cms.mediaUsage(ids) } };
10460
+ const count = await cms.mediaUsage(ids, {
10461
+ overrideAccess: false,
10462
+ user: ctx.user,
10463
+ context: ctx.context
10464
+ });
10465
+ return { body: { count } };
10410
10466
  }
10411
10467
  if (first === "admin" && second === "roles") {
10412
10468
  if (!ctx.user) throw new UnauthorizedError();
@@ -10551,9 +10607,10 @@ async function route(cms, ctx, method, path, options) {
10551
10607
  if (third !== void 0) return globalAction(cms, ctx, method, second, segments.slice(2));
10552
10608
  if (method === "GET") {
10553
10609
  if (ctx.url.searchParams.has("preview")) {
10554
- requirePreview(cms, ctx, { global: second });
10610
+ const as = await requirePreview(cms, ctx, { global: second });
10555
10611
  return {
10556
10612
  body: await cms.findGlobal(second, {
10613
+ ...as,
10557
10614
  ...parseDepth(ctx.url),
10558
10615
  ...parseLocale(ctx.url),
10559
10616
  draft: true
@@ -10662,8 +10719,9 @@ async function route(cms, ctx, method, path, options) {
10662
10719
  }
10663
10720
  const id = second;
10664
10721
  if (method === "GET" && ctx.url.searchParams.has("preview")) {
10665
- requirePreview(cms, ctx, { collection: collection2, id });
10722
+ const as = await requirePreview(cms, ctx, { collection: collection2, id });
10666
10723
  const doc = await cms.findById(collection2, id, {
10724
+ ...as,
10667
10725
  ...parseDepth(ctx.url),
10668
10726
  ...parseLocale(ctx.url),
10669
10727
  draft: true
@@ -10742,7 +10800,7 @@ async function documentAction(cms, ctx, method, collection2, id, path) {
10742
10800
  if (method !== "POST") throw methodNotAllowed(ctx, "POST");
10743
10801
  const body = await readJson(ctx.request);
10744
10802
  const result = await cms.preview(collection2, id, body, { ...access, ...depth });
10745
- const token = cms.createPreviewToken({ collection: collection2, id });
10803
+ const token = cms.createPreviewToken({ collection: collection2, id }, { user: ctx.user });
10746
10804
  return { body: { ...result, url: result.url && withPreviewToken(result.url, token) } };
10747
10805
  }
10748
10806
  if (path.length === 1 && (action === "unpublish" || action === "discard-draft")) {
@@ -10792,7 +10850,7 @@ async function globalAction(cms, ctx, method, slug2, path) {
10792
10850
  if (method !== "POST") throw methodNotAllowed(ctx, "POST");
10793
10851
  const body = await readJson(ctx.request);
10794
10852
  const result = await cms.previewGlobal(slug2, body, { ...access, ...depth });
10795
- const token = cms.createPreviewToken({ global: slug2 });
10853
+ const token = cms.createPreviewToken({ global: slug2 }, { user: ctx.user });
10796
10854
  return { body: { ...result, url: result.url && withPreviewToken(result.url, token) } };
10797
10855
  }
10798
10856
  if (path.length === 1 && (action === "unpublish" || action === "discard-draft")) {
@@ -10831,10 +10889,16 @@ function withPreviewToken(url, token) {
10831
10889
  const separator = base.includes("?") ? "&" : "?";
10832
10890
  return `${base}${separator}${PREVIEW_PARAM}=${encodeURIComponent(token)}${fragment}`;
10833
10891
  }
10834
- function requirePreview(cms, ctx, target) {
10892
+ async function requirePreview(cms, ctx, target) {
10835
10893
  const opened = cms.verifyPreviewToken(ctx.url.searchParams.get("preview"));
10836
10894
  const matches2 = opened !== null && ("global" in target ? "global" in opened && opened.global === target.global : "collection" in opened && opened.collection === target.collection && opened.id === target.id);
10837
10895
  if (!matches2) throw new UnauthorizedError("Invalid or expired preview token");
10896
+ if (opened.user === void 0) return {};
10897
+ const id = parseId(opened.user);
10898
+ const issuer = id === void 0 ? null : await cms.auth.activeUser(id);
10899
+ if (!issuer) throw new UnauthorizedError("Invalid or expired preview token");
10900
+ const { user, context } = await cms.applyOnRequest(ctx.request.headers, ctx.url, issuer);
10901
+ return { overrideAccess: false, user, context };
10838
10902
  }
10839
10903
  function parsePage(url) {
10840
10904
  const { page, limit } = parseListQuery(url);
@@ -1746,9 +1746,10 @@ declare class EasyCMS<C extends Config = Config> {
1746
1746
  private mediaSignature;
1747
1747
  /**
1748
1748
  * How many documents use any of these files in a top-level upload field (rich text and fields
1749
- * inside groups, arrays and blocks are not counted). Drafts count too.
1749
+ * inside groups, arrays and blocks are not counted). Drafts count too. With
1750
+ * `overrideAccess: false`, only documents the user may read.
1750
1751
  */
1751
- mediaUsage(ids: readonly ID[]): Promise<number>;
1752
+ mediaUsage(ids: readonly ID[], options?: AccessOptions): Promise<number>;
1752
1753
  /** The storage for public files, or for private ones. */
1753
1754
  storageFor(isPrivate: boolean): StorageAdapter;
1754
1755
  /**
@@ -1811,7 +1812,9 @@ declare class EasyCMS<C extends Config = Config> {
1811
1812
  /**
1812
1813
  * A token that lets a page read one document's current draft for a while (default one hour),
1813
1814
  * without a login: `GET /api/cms/:collection/:id?preview=<token>`. The admin adds one to the
1814
- * preview URL as `easy-cms-preview`, for sites on another origin.
1815
+ * preview URL as `easy-cms-preview`, for sites on another origin. With `user`, the page reads
1816
+ * it with that user's access (fields they can't read are left out; a deactivated user's token
1817
+ * stops working); without, with full access.
1815
1818
  */
1816
1819
  createPreviewToken(target: {
1817
1820
  collection: string;
@@ -1820,10 +1823,12 @@ declare class EasyCMS<C extends Config = Config> {
1820
1823
  global: string;
1821
1824
  }, options?: {
1822
1825
  expiresIn?: number;
1826
+ user?: AuthUser | null;
1823
1827
  }): string;
1824
1828
  /** What a preview token opens, or `null` when it is invalid or expired. */
1825
1829
  verifyPreviewToken(token: string | null | undefined): (PreviewTarget & {
1826
1830
  expiresAt: number;
1831
+ user?: string;
1827
1832
  }) | null;
1828
1833
  /** Live preview of a global. See `preview`. */
1829
1834
  previewGlobal<S extends GSlug<C>>(slug: S, data: Record<string, unknown>, options?: DepthOptions): Promise<LivePreview<GDoc<C, S>>>;
@@ -1992,7 +1997,15 @@ declare class EasyCMS<C extends Config = Config> {
1992
1997
  private checkGrant;
1993
1998
  /** The query constraint read access adds, or `undefined` when there is none. Throws when denied. */
1994
1999
  private readWhere;
2000
+ /**
2001
+ * Throws unless the caller may update or delete this document. A user who may not even read
2002
+ * it gets `NotFoundError`, as for an id that doesn't exist: a 403 would tell it does.
2003
+ */
1995
2004
  private checkDocumentAccess;
2005
+ /** Runs a check; a `ForbiddenError` for a document the user can't read becomes a 404. */
2006
+ private hidingDenied;
2007
+ private mayRead;
2008
+ private documentAccess;
1996
2009
  private checkGlobalAccess;
1997
2010
  private fieldChecker;
1998
2011
  /**
@@ -1,4 +1,4 @@
1
- import { I as ID, ab as Config, au as EasyCMS, bd as LocalizationConfig, aD as Field, aH as FieldError, aS as FilterOptions, af as CreateEasyCMSOptions, bI as ResolvedConfig } from './config-jzFGsNL6.js';
1
+ import { I as ID, ab as Config, au as EasyCMS, bd as LocalizationConfig, aD as Field, aH as FieldError, aS as FilterOptions, af as CreateEasyCMSOptions, bI as ResolvedConfig } from './config-Dgs6FE0S.js';
2
2
 
3
3
  type BackupState = 'pending' | 'running' | 'done' | 'failed';
4
4
  /** One backup as the admin shows it (`GET <api>/admin/backups`). */
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as PaginatedDocs, I as ID, E as EmailSetting } from './config-jzFGsNL6.js';
2
- export { A as ADAPTER_API_VERSION, a as ADMIN_ICONS, b as Access, c as AccessArgs, d as AccessOptions, e as AdminBrand, f as AdminCommand, g as AdminComponent, h as AdminConfig, i as AdminFieldArgs, j as AdminIcon, k as AdminLocale, l as AdminPage, m as AdminRole, n as AdminRoleChange, o as AdminRoleField, p as AdminRoleTarget, q as AdminRoleView, r as AdminRoles, s as AdminSso, t as AdminSwitcher, u as AdminViewAccess, v as AfterChangeHook, w as AfterDeleteHook, x as AfterReadHook, y as ApiKeyContext, z as ApiKeyGlobalOperation, B as ApiKeyOperation, C as ApiKeyPermissions, D as ArrayField, F as AuditChange, G as AuditConfig, H as AuditEntry, J as AuditLog, K as AuditPage, L as AuditVerification, M as Auth, N as AuthConfig, O as AuthProvider, Q as AuthProviderProfile, R as AuthProviderRequest, S as AuthUser, T as BackupsConfig, U as BeforeChangeHook, V as BeforeDeleteHook, W as BeforeValidateHook, X as Block, Y as BlocksField, Z as BooleanField, _ as BuiltinApiKeysCollection, $ as BuiltinMediaCollection, a0 as BuiltinMediaFoldersCollection, a1 as BuiltinUsersCollection, a2 as BundleHints, a3 as CliCommand, a4 as CollectionAccess, a5 as CollectionAdmin, a6 as CollectionConfig, a7 as CollectionDocument, a8 as CollectionHooks, a9 as CollectionListAdmin, aa as CollectionSlug, ab as Config, ac as ConfigError, ad as ConfigIssue, ae as ContainerAdmin, af as CreateEasyCMSOptions, ag as CreateInput, ah as CreateMigrationResult, ai as CustomField, aj as CustomFieldTypes, ak as DashboardWidget, al as Database, am as DatabaseAdapter, an as DatabaseInitArgs, ao as DatabaseTransfer, ap as DateField, aq as DepthOptions, ar as DirectUpload, as as DiskStorageOptions, at as DocumentOf, au as EasyCMS, av as EasyCMSError, aw as EmailAdapter, ax as EmailField, ay as EmailMessage, az as Endpoint, aA as EndpointRequest, aB as ErrorCode, aC as FIELD_TYPES, aD as Field, aE as FieldAccess, aF as FieldAccessFn, aG as FieldAdmin, aH as FieldError, aI as FieldRule, aJ as FieldType, aK as FieldTypeBase, aL as FieldTypeDefinition, aM as FieldTypeValidateContext, aN as FieldValidate, aO as FieldValidateContext, aP as FieldValue, aQ as FieldsInput, aR as FieldsValue, aS as FilterOptions, aT as FilterOptionsArgs, aU as FindArgs, aV as FindOptions, aW as FolderLevel, aX as FolderPermissions, aY as ForbiddenError, aZ as GlobalAccess, a_ as GlobalConfig, a$ as GlobalDocument, b0 as GlobalHooks, b1 as GlobalInput, b2 as GlobalSlug, b3 as GroupField, b4 as ImageSize, b5 as IncrementOptions, b6 as InferCollection, b7 as InferGlobal, b8 as JobConfig, b9 as JsonField, ba as Label, bb as LayoutNode, bc as LivePreview, bd as LocalizationConfig, be as Logger, bf as LoginArgs, bg as MediaDocument, bh as MediaSize, bi as MembersConfig, bj as MembersSignup, bk as MigrationInfo, bl as NavGroup, bm as NotFoundError, bn as NumberField, bo as OnRequest, bp as OnRequestArgs, bq as Operation, br as PLUGIN_API_VERSION, bs as PasswordEmail, bt as PasswordEmailArgs, bu as PasswordEmailFn, bv as PasswordLinkOptions, bw as PayloadTooLargeError, bx as Plugin, by as PluginInfo, bz as PluginTypes, bA as PreviewTarget, bB as PreviewURL, bC as QueryError, bD as ROLE_OPERATIONS, bE as RawDocument, bF as ReadOptions, bG as RelationshipField, bH as RequestContext, bI as ResolvedConfig, bJ as RichTextDocument, bK as RichTextField, bL as Role, bM as RoleOperation, bN as RolePermissions, bO as Roles, bP as RoutesConfig, bQ as ScheduledPublish, bR as SchemaError, bS as SchemaMode, bT as SelectField, bU as SelectOption, bV as Session, bW as SidebarPanel, bX as SignupArgs, bY as SignupResult, bZ as SingleSignOn, b_ as SlugField, b$ as SlugOf, c0 as SsoOutcome, c1 as SsoProviderRef, c2 as StorageAdapter, c3 as StoredFile, c4 as TextField, c5 as TextareaField, c6 as TooManyRequestsError, c7 as TypedPlugin, c8 as UnauthorizedError, c9 as UpdateInput, ca as UpdateOptions, cb as UploadConfig, cc as UploadField, cd as UploadFromURLConfig, ce as UserIdentity, cf as ValidationError, cg as Version, ch as VersionSummary, ci as VersionsConfig, cj as WEBHOOK_EVENTS, ck as WebhookConfig, cl as WebhookEvent, cm as WebhookPayload, cn as Where, co as WhereOperators, cp as anyone, cq as consoleEmail, cr as consoleLogger, cs as createEasyCMS, ct as defineConfig, cu as defineFieldType, cv as definePlugin, cw as diskStorage, cx as hasRows, cy as isAdmin, cz as isHasMany, cA as isSignedIn, cB as isStaff, cC as isSystemAdmin, cD as mimeAllowedBy, cE as rowFields, cF as silentLogger, cG as uniqueWithinOf } from './config-jzFGsNL6.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-C19Bt8ux.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-CMA1LIq7.js';
1
+ import { P as PaginatedDocs, I as ID, E as EmailSetting } from './config-Dgs6FE0S.js';
2
+ export { A as ADAPTER_API_VERSION, a as ADMIN_ICONS, b as Access, c as AccessArgs, d as AccessOptions, e as AdminBrand, f as AdminCommand, g as AdminComponent, h as AdminConfig, i as AdminFieldArgs, j as AdminIcon, k as AdminLocale, l as AdminPage, m as AdminRole, n as AdminRoleChange, o as AdminRoleField, p as AdminRoleTarget, q as AdminRoleView, r as AdminRoles, s as AdminSso, t as AdminSwitcher, u as AdminViewAccess, v as AfterChangeHook, w as AfterDeleteHook, x as AfterReadHook, y as ApiKeyContext, z as ApiKeyGlobalOperation, B as ApiKeyOperation, C as ApiKeyPermissions, D as ArrayField, F as AuditChange, G as AuditConfig, H as AuditEntry, J as AuditLog, K as AuditPage, L as AuditVerification, M as Auth, N as AuthConfig, O as AuthProvider, Q as AuthProviderProfile, R as AuthProviderRequest, S as AuthUser, T as BackupsConfig, U as BeforeChangeHook, V as BeforeDeleteHook, W as BeforeValidateHook, X as Block, Y as BlocksField, Z as BooleanField, _ as BuiltinApiKeysCollection, $ as BuiltinMediaCollection, a0 as BuiltinMediaFoldersCollection, a1 as BuiltinUsersCollection, a2 as BundleHints, a3 as CliCommand, a4 as CollectionAccess, a5 as CollectionAdmin, a6 as CollectionConfig, a7 as CollectionDocument, a8 as CollectionHooks, a9 as CollectionListAdmin, aa as CollectionSlug, ab as Config, ac as ConfigError, ad as ConfigIssue, ae as ContainerAdmin, af as CreateEasyCMSOptions, ag as CreateInput, ah as CreateMigrationResult, ai as CustomField, aj as CustomFieldTypes, ak as DashboardWidget, al as Database, am as DatabaseAdapter, an as DatabaseInitArgs, ao as DatabaseTransfer, ap as DateField, aq as DepthOptions, ar as DirectUpload, as as DiskStorageOptions, at as DocumentOf, au as EasyCMS, av as EasyCMSError, aw as EmailAdapter, ax as EmailField, ay as EmailMessage, az as Endpoint, aA as EndpointRequest, aB as ErrorCode, aC as FIELD_TYPES, aD as Field, aE as FieldAccess, aF as FieldAccessFn, aG as FieldAdmin, aH as FieldError, aI as FieldRule, aJ as FieldType, aK as FieldTypeBase, aL as FieldTypeDefinition, aM as FieldTypeValidateContext, aN as FieldValidate, aO as FieldValidateContext, aP as FieldValue, aQ as FieldsInput, aR as FieldsValue, aS as FilterOptions, aT as FilterOptionsArgs, aU as FindArgs, aV as FindOptions, aW as FolderLevel, aX as FolderPermissions, aY as ForbiddenError, aZ as GlobalAccess, a_ as GlobalConfig, a$ as GlobalDocument, b0 as GlobalHooks, b1 as GlobalInput, b2 as GlobalSlug, b3 as GroupField, b4 as ImageSize, b5 as IncrementOptions, b6 as InferCollection, b7 as InferGlobal, b8 as JobConfig, b9 as JsonField, ba as Label, bb as LayoutNode, bc as LivePreview, bd as LocalizationConfig, be as Logger, bf as LoginArgs, bg as MediaDocument, bh as MediaSize, bi as MembersConfig, bj as MembersSignup, bk as MigrationInfo, bl as NavGroup, bm as NotFoundError, bn as NumberField, bo as OnRequest, bp as OnRequestArgs, bq as Operation, br as PLUGIN_API_VERSION, bs as PasswordEmail, bt as PasswordEmailArgs, bu as PasswordEmailFn, bv as PasswordLinkOptions, bw as PayloadTooLargeError, bx as Plugin, by as PluginInfo, bz as PluginTypes, bA as PreviewTarget, bB as PreviewURL, bC as QueryError, bD as ROLE_OPERATIONS, bE as RawDocument, bF as ReadOptions, bG as RelationshipField, bH as RequestContext, bI as ResolvedConfig, bJ as RichTextDocument, bK as RichTextField, bL as Role, bM as RoleOperation, bN as RolePermissions, bO as Roles, bP as RoutesConfig, bQ as ScheduledPublish, bR as SchemaError, bS as SchemaMode, bT as SelectField, bU as SelectOption, bV as Session, bW as SidebarPanel, bX as SignupArgs, bY as SignupResult, bZ as SingleSignOn, b_ as SlugField, b$ as SlugOf, c0 as SsoOutcome, c1 as SsoProviderRef, c2 as StorageAdapter, c3 as StoredFile, c4 as TextField, c5 as TextareaField, c6 as TooManyRequestsError, c7 as TypedPlugin, c8 as UnauthorizedError, c9 as UpdateInput, ca as UpdateOptions, cb as UploadConfig, cc as UploadField, cd as UploadFromURLConfig, ce as UserIdentity, cf as ValidationError, cg as Version, ch as VersionSummary, ci as VersionsConfig, cj as WEBHOOK_EVENTS, ck as WebhookConfig, cl as WebhookEvent, cm as WebhookPayload, cn as Where, co as WhereOperators, cp as anyone, cq as consoleEmail, cr as consoleLogger, cs as createEasyCMS, ct as defineConfig, cu as defineFieldType, cv as definePlugin, cw as diskStorage, cx as hasRows, cy as isAdmin, cz as isHasMany, cA as isSignedIn, cB as isStaff, cC as isSystemAdmin, cD as mimeAllowedBy, cE as rowFields, cF as silentLogger, cG as uniqueWithinOf } from './config-Dgs6FE0S.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-8hrkYMuR.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-CcQjkj5Q.js';
5
5
  export { FieldCondition, matchesCondition } from './conditions.js';
6
6
 
7
7
  type DeliveryKind = 'webhook' | 'email';
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  sharedEasyCMS,
24
24
  silentLogger,
25
25
  slugify
26
- } from "./chunk-CX7R6QBJ.js";
26
+ } from "./chunk-LN4M4BUP.js";
27
27
  import {
28
28
  matchesCondition
29
29
  } from "./chunk-U266LV4M.js";
@@ -1,6 +1,6 @@
1
- import { ab as Config, al as Database, bl as NavGroup, a6 as CollectionConfig, I as ID, bE as RawDocument, aD as Field, bI as ResolvedConfig, ad as ConfigIssue } from './config-jzFGsNL6.js';
2
- export { cH as API_KEYS, cI as API_KEY_GLOBAL_OPERATIONS, cJ as API_KEY_OPERATIONS, cK as DEFAULT_MAX_VERSIONS, cL as DEFAULT_PASSWORD_EMAILS, cM as FIELD_TYPE_BASES, cN as FOLDER_LEVELS, cO as MediaFolders, cP as SSO_COOKIE, cQ as codeOfStatus, cx as hasRows, cz as isHasMany, cR as keyAllows, cD as mimeAllowedBy, cE as rowFields, cG as uniqueWithinOf } from './config-jzFGsNL6.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 fillMissing, q as findConfigFile, t as forwardedClientIp, u as generateSlugs, v as importConfig, w as mergeForUpdate, x as parseId, y as platformClientIp, z as readCookie, E as validateFields, F as writeBackupFile } from './handler-CMA1LIq7.js';
1
+ import { ab as Config, al as Database, bl as NavGroup, a6 as CollectionConfig, I as ID, bE as RawDocument, aD as Field, bI as ResolvedConfig, ad as ConfigIssue } from './config-Dgs6FE0S.js';
2
+ export { cH as API_KEYS, cI as API_KEY_GLOBAL_OPERATIONS, cJ as API_KEY_OPERATIONS, cK as DEFAULT_MAX_VERSIONS, cL as DEFAULT_PASSWORD_EMAILS, cM as FIELD_TYPE_BASES, cN as FOLDER_LEVELS, cO as MediaFolders, cP as SSO_COOKIE, cQ as codeOfStatus, cx as hasRows, cz as isHasMany, cR as keyAllows, cD as mimeAllowedBy, cE as rowFields, cG as uniqueWithinOf } from './config-Dgs6FE0S.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 fillMissing, q as findConfigFile, t as forwardedClientIp, u as generateSlugs, v as importConfig, w as mergeForUpdate, x as parseId, y as platformClientIp, z as readCookie, E as validateFields, F as writeBackupFile } from './handler-CcQjkj5Q.js';
4
4
  export { conditionIssues } from './conditions.js';
5
5
 
6
6
  /** The session cookie the REST API sets at login. */
package/dist/internal.js CHANGED
@@ -52,7 +52,7 @@ import {
52
52
  verifyPassword,
53
53
  verifyTurnstile,
54
54
  writeBackupFile
55
- } from "./chunk-CX7R6QBJ.js";
55
+ } from "./chunk-LN4M4BUP.js";
56
56
  import {
57
57
  conditionIssues
58
58
  } from "./chunk-U266LV4M.js";
@@ -1,4 +1,4 @@
1
- import { ba as Label, aD as Field, I as ID, k as AdminLocale, t as AdminSwitcher, c1 as SsoProviderRef } from './config-jzFGsNL6.js';
1
+ import { ba as Label, aD as Field, I as ID, k as AdminLocale, t as AdminSwitcher, c1 as SsoProviderRef } from './config-Dgs6FE0S.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 { a as ADMIN_ICONS, g as AdminComponent, j as AdminIcon, S as AuthUser, a3 as CliCommand, a4 as CollectionAccess, a6 as CollectionConfig, ab as Config, ac as ConfigError, ak as DashboardWidget, av as EasyCMSError, az as Endpoint, aA as EndpointRequest, aB as ErrorCode, aD as Field, aE as FieldAccess, aH as FieldError, aK as FieldTypeBase, aL as FieldTypeDefinition, aM as FieldTypeValidateContext, aY as ForbiddenError, a_ as GlobalConfig, I as ID, b8 as JobConfig, ba as Label, bl as NavGroup, bm as NotFoundError, bo as OnRequest, bp as OnRequestArgs, br as PLUGIN_API_VERSION, bw as PayloadTooLargeError, bx as Plugin, by as PluginInfo, bz as PluginTypes, bC as QueryError, bH as RequestContext, c6 as TooManyRequestsError, c7 as TypedPlugin, c8 as UnauthorizedError, cf as ValidationError, cn as Where, cu as defineFieldType, cv as definePlugin } from './config-jzFGsNL6.js';
2
- export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-C19Bt8ux.js';
1
+ export { a as ADMIN_ICONS, g as AdminComponent, j as AdminIcon, S as AuthUser, a3 as CliCommand, a4 as CollectionAccess, a6 as CollectionConfig, ab as Config, ac as ConfigError, ak as DashboardWidget, av as EasyCMSError, az as Endpoint, aA as EndpointRequest, aB as ErrorCode, aD as Field, aE as FieldAccess, aH as FieldError, aK as FieldTypeBase, aL as FieldTypeDefinition, aM as FieldTypeValidateContext, aY as ForbiddenError, a_ as GlobalConfig, I as ID, b8 as JobConfig, ba as Label, bl as NavGroup, bm as NotFoundError, bo as OnRequest, bp as OnRequestArgs, br as PLUGIN_API_VERSION, bw as PayloadTooLargeError, bx as Plugin, by as PluginInfo, bz as PluginTypes, bC as QueryError, bH as RequestContext, c6 as TooManyRequestsError, c7 as TypedPlugin, c8 as UnauthorizedError, cf as ValidationError, cn as Where, cu as defineFieldType, cv as definePlugin } from './config-Dgs6FE0S.js';
2
+ export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-8hrkYMuR.js';
3
3
  import './conditions.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easy-cms/core",
3
- "version": "0.62.0",
3
+ "version": "0.63.0",
4
4
  "description": "Embedded, code-first headless CMS for Nuxt and Next.js",
5
5
  "license": "MIT",
6
6
  "type": "module",