@easy-cms/core 1.19.0 → 1.20.1
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/{chunk-FZCQXH5M.js → chunk-R2YJ2K56.js} +156 -16
- package/dist/{config-U1mRwD4t.d.ts → config-BuKlngv6.d.ts} +36 -7
- package/dist/{handler-D2y4WSSM.d.ts → handler-DuOjJu_X.d.ts} +1 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +1 -1
- package/dist/{plugin-DRV5HA4a.d.ts → plugin-zOdLJ1oh.d.ts} +7 -1
- package/dist/plugin.d.ts +2 -2
- package/package.json +1 -1
|
@@ -972,7 +972,10 @@ var AuditLog = class {
|
|
|
972
972
|
}
|
|
973
973
|
await auditContext.run({ via: "scheduler", user: null }, () => this.verify());
|
|
974
974
|
}
|
|
975
|
-
/**
|
|
975
|
+
/**
|
|
976
|
+
* What the dashboard warns about: many failed logins, sign-ins of break-glass accounts in the
|
|
977
|
+
* last day, entries not written, a failed check.
|
|
978
|
+
*/
|
|
976
979
|
async attention(now = /* @__PURE__ */ new Date()) {
|
|
977
980
|
if (!this.enabled) return [];
|
|
978
981
|
const out = [];
|
|
@@ -984,6 +987,20 @@ var AuditLog = class {
|
|
|
984
987
|
}
|
|
985
988
|
});
|
|
986
989
|
if (failed >= this.settings.failedLogins) out.push({ id: "failed-logins", count: failed });
|
|
990
|
+
const day = new Date(now.getTime() - 864e5).toISOString();
|
|
991
|
+
const breakGlass = await this.cms.db.find({
|
|
992
|
+
collection: AUDIT_LOGS,
|
|
993
|
+
where: { and: [{ action: { equals: "login.breakGlass" } }, { createdAt: { gte: day } }] },
|
|
994
|
+
sort: ["-id"],
|
|
995
|
+
limit: 0,
|
|
996
|
+
page: 1
|
|
997
|
+
});
|
|
998
|
+
if (breakGlass.docs.length > 0)
|
|
999
|
+
out.push({
|
|
1000
|
+
id: "break-glass",
|
|
1001
|
+
count: breakGlass.docs.length,
|
|
1002
|
+
emails: [...new Set(breakGlass.docs.map((row) => String(row.actorEmail ?? "")))]
|
|
1003
|
+
});
|
|
987
1004
|
if (this.failures > 0) out.push({ id: "audit-failures", count: this.failures });
|
|
988
1005
|
const last = await this.lastVerification();
|
|
989
1006
|
if (last && last.invalid > 0)
|
|
@@ -1394,6 +1411,9 @@ function unseal(secrets, value) {
|
|
|
1394
1411
|
return null;
|
|
1395
1412
|
}
|
|
1396
1413
|
}
|
|
1414
|
+
function passwordFor(policy) {
|
|
1415
|
+
return policy === true ? "everyone" : policy === false ? "admins" : "breakGlass";
|
|
1416
|
+
}
|
|
1397
1417
|
var SingleSignOn = class {
|
|
1398
1418
|
constructor(cms) {
|
|
1399
1419
|
this.cms = cms;
|
|
@@ -1412,9 +1432,19 @@ var SingleSignOn = class {
|
|
|
1412
1432
|
icon: p.icon ?? "key"
|
|
1413
1433
|
}));
|
|
1414
1434
|
}
|
|
1415
|
-
/**
|
|
1435
|
+
/**
|
|
1436
|
+
* Whether a user may sign in with a password: everyone, only admins (`auth.password: false`), or
|
|
1437
|
+
* only break-glass accounts (`{ breakGlass }`).
|
|
1438
|
+
*/
|
|
1416
1439
|
passwordAllowed(user) {
|
|
1417
|
-
|
|
1440
|
+
const policy = this.config.auth.password;
|
|
1441
|
+
if (policy === true) return true;
|
|
1442
|
+
if (policy === false) return user.role === "admin";
|
|
1443
|
+
return typeof user.email === "string" && policy.breakGlass.includes(user.email.toLowerCase());
|
|
1444
|
+
}
|
|
1445
|
+
/** Whether a user signs in with a password only as a break-glass account. */
|
|
1446
|
+
isBreakGlass(user) {
|
|
1447
|
+
return typeof this.config.auth.password === "object" && this.passwordAllowed(user);
|
|
1418
1448
|
}
|
|
1419
1449
|
/** `<serverURL><api>/auth/<id>/callback`, or `null` without `serverURL` in production. */
|
|
1420
1450
|
callbackURL(provider, origin) {
|
|
@@ -1607,7 +1637,8 @@ var SingleSignOn = class {
|
|
|
1607
1637
|
callbackURL: this.callbackURL(p.id, origin),
|
|
1608
1638
|
details: { ...p.describe?.() ?? {} }
|
|
1609
1639
|
})),
|
|
1610
|
-
password: this.config.auth.password
|
|
1640
|
+
password: passwordFor(this.config.auth.password),
|
|
1641
|
+
...typeof this.config.auth.password === "object" ? { breakGlass: [...this.config.auth.password.breakGlass] } : {},
|
|
1611
1642
|
signUp: providerSignUp.domains.length > 0 ? {
|
|
1612
1643
|
domains: [...providerSignUp.domains],
|
|
1613
1644
|
role: providerSignUp.role ?? this.defaultRole()
|
|
@@ -1845,7 +1876,11 @@ var Auth = class {
|
|
|
1845
1876
|
}
|
|
1846
1877
|
await this.deleteExpiredSessions(user.id);
|
|
1847
1878
|
const session = await this.startSession(user);
|
|
1848
|
-
await this.cms.audit.record({
|
|
1879
|
+
await this.cms.audit.record({
|
|
1880
|
+
action: this.sso.isBreakGlass(user) ? "login.breakGlass" : "login",
|
|
1881
|
+
target: "auth",
|
|
1882
|
+
user: session.user
|
|
1883
|
+
});
|
|
1849
1884
|
return session;
|
|
1850
1885
|
}
|
|
1851
1886
|
/**
|
|
@@ -2019,6 +2054,58 @@ var Auth = class {
|
|
|
2019
2054
|
const path = target ?? `${this.config.admin.path}/${page === "verifyEmail" ? "verify-email" : "reset-password"}`;
|
|
2020
2055
|
return `${base}${path.startsWith("/") ? "" : "/"}${path}${path.includes("?") ? "&" : "?"}${query}`;
|
|
2021
2056
|
}
|
|
2057
|
+
/**
|
|
2058
|
+
* At start: when `auth.password` differs from the last start, records the change and ends the
|
|
2059
|
+
* sessions of accounts that may no longer use a password (single sign-on users sign in once
|
|
2060
|
+
* more). With break-glass accounts, warns when none of them can sign in with a password.
|
|
2061
|
+
* @internal
|
|
2062
|
+
*/
|
|
2063
|
+
async applyPasswordPolicy() {
|
|
2064
|
+
const policy = passwordPolicyName(this.config.auth.password);
|
|
2065
|
+
const stored = await this.db.findGlobal({ slug: PASSWORD_POLICY });
|
|
2066
|
+
const before = typeof stored?.policy === "string" ? stored.policy : "everyone";
|
|
2067
|
+
if (before !== policy) {
|
|
2068
|
+
let ended = 0;
|
|
2069
|
+
if (policy !== "everyone") {
|
|
2070
|
+
const users = /* @__PURE__ */ new Map();
|
|
2071
|
+
const { docs } = await this.db.find({ collection: SESSIONS, sort: [], limit: 0, page: 1 });
|
|
2072
|
+
for (const session of docs) {
|
|
2073
|
+
const id = String(session.user);
|
|
2074
|
+
if (!users.has(id))
|
|
2075
|
+
users.set(id, await this.db.findById({ collection: USERS, id: session.user }));
|
|
2076
|
+
const user = users.get(id);
|
|
2077
|
+
if (user && this.sso.passwordAllowed(user)) continue;
|
|
2078
|
+
await this.db.delete({ collection: SESSIONS, id: session.id });
|
|
2079
|
+
ended++;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2083
|
+
await this.db.updateGlobal({ slug: PASSWORD_POLICY, data: { policy, updatedAt: at } });
|
|
2084
|
+
await this.cms.audit.record({
|
|
2085
|
+
action: "auth.password.policy",
|
|
2086
|
+
target: "auth",
|
|
2087
|
+
user: null,
|
|
2088
|
+
detail: { from: before, to: policy, sessionsEnded: ended }
|
|
2089
|
+
});
|
|
2090
|
+
this.cms.logger.info(
|
|
2091
|
+
`Password sign-in: ${before} \u2192 ${policy}${ended ? `; ${ended} session(s) ended` : ""}.`
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
const password = this.config.auth.password;
|
|
2095
|
+
if (typeof password === "object" && await this.hasUsers()) {
|
|
2096
|
+
const { docs } = await this.db.find({
|
|
2097
|
+
collection: USERS,
|
|
2098
|
+
where: { email: { in: [...password.breakGlass] } },
|
|
2099
|
+
sort: [],
|
|
2100
|
+
limit: 0,
|
|
2101
|
+
page: 1
|
|
2102
|
+
});
|
|
2103
|
+
if (!docs.some((user) => user.passwordHash && user.active !== false))
|
|
2104
|
+
this.cms.logger.warn(
|
|
2105
|
+
"auth.password.breakGlass: none of these accounts exists with a password, so nobody can sign in if the provider is down. Create one with `easy-cms admin:create`."
|
|
2106
|
+
);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2022
2109
|
async hasUsers() {
|
|
2023
2110
|
return await this.db.count({ collection: USERS }) > 0;
|
|
2024
2111
|
}
|
|
@@ -2388,6 +2475,12 @@ var Auth = class {
|
|
|
2388
2475
|
await this.db.delete({ collection: LOGIN_ATTEMPTS, id: attempt.id });
|
|
2389
2476
|
}
|
|
2390
2477
|
};
|
|
2478
|
+
var PASSWORD_POLICY = "easy-cms:password-policy";
|
|
2479
|
+
function passwordPolicyName(policy) {
|
|
2480
|
+
if (policy === true) return "everyone";
|
|
2481
|
+
if (policy === false) return "admins";
|
|
2482
|
+
return `breakGlass:${[...policy.breakGlass].sort().join(",")}`;
|
|
2483
|
+
}
|
|
2391
2484
|
|
|
2392
2485
|
// src/database.ts
|
|
2393
2486
|
var ADAPTER_API_VERSION = 1;
|
|
@@ -5960,8 +6053,16 @@ function validateAuth(config, add) {
|
|
|
5960
6053
|
if (auth === void 0) return;
|
|
5961
6054
|
if (auth.rbac !== void 0 && typeof auth.rbac !== "boolean")
|
|
5962
6055
|
add("auth.rbac", "must be true or false");
|
|
5963
|
-
if (auth.password
|
|
5964
|
-
|
|
6056
|
+
if (typeof auth.password === "object" && auth.password !== null) {
|
|
6057
|
+
const { breakGlass } = auth.password;
|
|
6058
|
+
if (!Array.isArray(breakGlass) || breakGlass.length === 0 || breakGlass.some((email2) => typeof email2 !== "string" || !email2.includes("@")))
|
|
6059
|
+
add(
|
|
6060
|
+
"auth.password.breakGlass",
|
|
6061
|
+
"must list the emails of the accounts that may still use a password",
|
|
6062
|
+
"e.g. { breakGlass: ['emergency@example.com'] }"
|
|
6063
|
+
);
|
|
6064
|
+
} else if (auth.password !== void 0 && typeof auth.password !== "boolean")
|
|
6065
|
+
add("auth.password", "must be true, false or { breakGlass: [emails] }");
|
|
5965
6066
|
if (auth.setupCode !== void 0 && typeof auth.setupCode !== "string")
|
|
5966
6067
|
add("auth.setupCode", "must be a string");
|
|
5967
6068
|
const providers = auth.providers;
|
|
@@ -6012,8 +6113,12 @@ function validateAuth(config, add) {
|
|
|
6012
6113
|
if (!Array.isArray(providers) || providers.length === 0)
|
|
6013
6114
|
add("auth.providerSignUp", "needs auth.providers");
|
|
6014
6115
|
}
|
|
6015
|
-
if (auth.password
|
|
6016
|
-
add(
|
|
6116
|
+
if (auth.password !== void 0 && auth.password !== true && (!Array.isArray(providers) || providers.length === 0))
|
|
6117
|
+
add(
|
|
6118
|
+
"auth.password",
|
|
6119
|
+
"turning passwords off needs auth.providers",
|
|
6120
|
+
"otherwise nobody else could sign in"
|
|
6121
|
+
);
|
|
6017
6122
|
if (auth.roles !== void 0) {
|
|
6018
6123
|
const roles = auth.roles;
|
|
6019
6124
|
if (!Array.isArray(roles) || roles.some((r) => typeof r !== "string" || r === "")) {
|
|
@@ -7223,7 +7328,7 @@ async function resolveConfig(input) {
|
|
|
7223
7328
|
rbac: config.auth?.rbac === true,
|
|
7224
7329
|
providers: config.auth?.providers ?? [],
|
|
7225
7330
|
providerSignUp: config.auth?.providerSignUp ?? { domains: [] },
|
|
7226
|
-
password: config.auth?.password !== false,
|
|
7331
|
+
password: typeof config.auth?.password === "object" ? { breakGlass: config.auth.password.breakGlass.map((email2) => email2.toLowerCase()) } : config.auth?.password !== false,
|
|
7227
7332
|
setupCode: config.auth?.setupCode ?? process.env.EASY_CMS_SETUP_CODE ?? "",
|
|
7228
7333
|
tokenExpiration: config.auth?.tokenExpiration ?? DEFAULT_TOKEN_EXPIRATION,
|
|
7229
7334
|
maxLoginAttempts: config.auth?.maxLoginAttempts ?? 5,
|
|
@@ -7317,7 +7422,7 @@ function cacheableResponse(request, body, status, headers, times, tags) {
|
|
|
7317
7422
|
}
|
|
7318
7423
|
|
|
7319
7424
|
// src/version.ts
|
|
7320
|
-
var VERSION = true ? "1.
|
|
7425
|
+
var VERSION = true ? "1.20.1" : "0.0.0-dev";
|
|
7321
7426
|
|
|
7322
7427
|
// src/telemetry.ts
|
|
7323
7428
|
var DB_CALLS = /* @__PURE__ */ new Set([
|
|
@@ -7551,6 +7656,10 @@ async function createEasyCMS(config, options = {}) {
|
|
|
7551
7656
|
if (options.scheduler !== false) cms.startSearch();
|
|
7552
7657
|
const scheduling = [...resolved3.collections, ...resolved3.globals].some((c) => c.schedule) || (resolved3.webhooks?.length ?? 0) > 0 || resolved3.email !== void 0 || resolved3.jobs.length > 0 || resolved3.outbox === true;
|
|
7553
7658
|
if (scheduling && options.scheduler !== false) cms.startScheduler();
|
|
7659
|
+
if (options.schema !== "skip")
|
|
7660
|
+
await cms.auth.applyPasswordPolicy().catch(
|
|
7661
|
+
(error) => logger.error(`Password sign-in policy: ${error.message}`, { error })
|
|
7662
|
+
);
|
|
7554
7663
|
if (process.env.NODE_ENV === "production" && !resolved3.auth.setupCode && await cms.auth.hasUsers().catch(() => true) === false)
|
|
7555
7664
|
logger.warn(
|
|
7556
7665
|
"No admin exists yet and no setup code is set: whoever opens the admin first becomes the admin. Set EASY_CMS_SETUP_CODE, or create the admin with `easy-cms admin:create`."
|
|
@@ -8556,7 +8665,10 @@ var EasyCMS = class {
|
|
|
8556
8665
|
return out2;
|
|
8557
8666
|
}
|
|
8558
8667
|
if (config.slug === USERS) await this.guardLastAdmin(parsed, existing, prepared);
|
|
8559
|
-
if (password !== void 0)
|
|
8668
|
+
if (password !== void 0) {
|
|
8669
|
+
await this.guardPassword({ ...existing, ...prepared });
|
|
8670
|
+
prepared.passwordHash = await hashPassword(password);
|
|
8671
|
+
}
|
|
8560
8672
|
if (collection2 === MEDIA_FOLDERS) {
|
|
8561
8673
|
await this.validateFolder(prepared, parsed);
|
|
8562
8674
|
if (prepared.private !== existing.private || String(prepared.parent ?? null) !== String(existing.parent ?? null))
|
|
@@ -9895,7 +10007,10 @@ var EasyCMS = class {
|
|
|
9895
10007
|
{ ...base, operation: "create" },
|
|
9896
10008
|
prepared
|
|
9897
10009
|
);
|
|
9898
|
-
if (password !== void 0)
|
|
10010
|
+
if (password !== void 0) {
|
|
10011
|
+
await this.guardPassword(prepared);
|
|
10012
|
+
prepared.passwordHash = await hashPassword(password);
|
|
10013
|
+
}
|
|
9899
10014
|
if (collection2 === MEDIA_FOLDERS) await this.validateFolder(prepared, void 0);
|
|
9900
10015
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9901
10016
|
const row = { ...prepared, createdAt: now, updatedAt: now };
|
|
@@ -10215,6 +10330,20 @@ var EasyCMS = class {
|
|
|
10215
10330
|
return clean2;
|
|
10216
10331
|
}
|
|
10217
10332
|
/** Refuses changes that would leave no active admin (and lock everyone out). */
|
|
10333
|
+
/**
|
|
10334
|
+
* With break-glass accounts (`auth.password: { breakGlass }`), other accounts get no password:
|
|
10335
|
+
* they couldn't use it. The first account, made before anyone can sign in with a provider, may.
|
|
10336
|
+
*/
|
|
10337
|
+
async guardPassword(user) {
|
|
10338
|
+
if (typeof this.config.auth.password !== "object" || this.auth.sso.passwordAllowed(user)) return;
|
|
10339
|
+
if (!await this.auth.hasUsers()) return;
|
|
10340
|
+
throw new ValidationError(USERS, [
|
|
10341
|
+
{
|
|
10342
|
+
field: "password",
|
|
10343
|
+
message: "passwords are off: this account signs in with single sign-on"
|
|
10344
|
+
}
|
|
10345
|
+
]);
|
|
10346
|
+
}
|
|
10218
10347
|
async guardLastAdmin(id, before, after) {
|
|
10219
10348
|
const wasAdmin = before.role === "admin" && before.active !== false;
|
|
10220
10349
|
const staysAdmin = after.role === "admin" && after.active !== false;
|
|
@@ -11777,6 +11906,8 @@ async function adminSchema(cms, user, origin, context = {}) {
|
|
|
11777
11906
|
locale: cms.config.admin.locale,
|
|
11778
11907
|
switcher: cms.config.admin.switcher || null,
|
|
11779
11908
|
passwordLinks: cms.auth.canSendPasswordLinks(origin),
|
|
11909
|
+
passwordFor: passwordFor(cms.config.auth.password),
|
|
11910
|
+
...typeof cms.config.auth.password === "object" && isSystemAdmin(user) ? { breakGlass: [...cms.config.auth.password.breakGlass] } : {},
|
|
11780
11911
|
nav: buildNav(cms, adminCollections, adminGlobals, adminPages, views),
|
|
11781
11912
|
commands: cms.config.admin.commands.map((c) => JSON.parse(JSON.stringify(c))),
|
|
11782
11913
|
localization: localization ? { locales: [...localization.locales], defaultLocale: localization.defaultLocale } : null,
|
|
@@ -12593,7 +12724,14 @@ async function route(cms, ctx, method, path, options) {
|
|
|
12593
12724
|
const csrfToken2 = ctx.via === "cookie" && ctx.token ? cms.auth.csrfFor(ctx.token) : void 0;
|
|
12594
12725
|
if (csrfToken2)
|
|
12595
12726
|
ctx.headers.append("set-cookie", cookie(ctx, CSRF_COOKIE, csrfToken2, { httpOnly: false }));
|
|
12596
|
-
return {
|
|
12727
|
+
return {
|
|
12728
|
+
body: {
|
|
12729
|
+
user: ctx.user,
|
|
12730
|
+
// Whether this user may set and use a password (`auth.password`).
|
|
12731
|
+
...ctx.user ? { password: cms.auth.sso.passwordAllowed(ctx.user) } : {},
|
|
12732
|
+
...csrfToken2 ? { csrfToken: csrfToken2 } : {}
|
|
12733
|
+
}
|
|
12734
|
+
};
|
|
12597
12735
|
}
|
|
12598
12736
|
case "GET init":
|
|
12599
12737
|
return {
|
|
@@ -12601,9 +12739,11 @@ async function route(cms, ctx, method, path, options) {
|
|
|
12601
12739
|
hasUsers: await cms.auth.hasUsers(),
|
|
12602
12740
|
// The login page offers "Forgot password?" only when the email can be sent.
|
|
12603
12741
|
passwordReset: cms.auth.canSendPasswordLinks(ctx.url.origin),
|
|
12604
|
-
// Buttons to sign in with outside accounts; `password: false`: only
|
|
12742
|
+
// Buttons to sign in with outside accounts; `password: false`: only some use one
|
|
12743
|
+
// (`passwordFor`: admins, or break-glass accounts), behind a folded form.
|
|
12605
12744
|
providers: cms.auth.sso.providers(),
|
|
12606
|
-
password: cms.config.auth.password,
|
|
12745
|
+
password: cms.config.auth.password === true,
|
|
12746
|
+
passwordFor: passwordFor(cms.config.auth.password),
|
|
12607
12747
|
// The first admin needs the setup code (`EASY_CMS_SETUP_CODE`).
|
|
12608
12748
|
setupCode: cms.config.auth.setupCode !== ""
|
|
12609
12749
|
}
|
|
@@ -432,8 +432,10 @@ interface AdminSso {
|
|
|
432
432
|
callbackURL: string | null;
|
|
433
433
|
details: Record<string, string>;
|
|
434
434
|
})[];
|
|
435
|
-
/** Who may sign in with a password: everyone, or only
|
|
436
|
-
password: 'everyone' | 'admins';
|
|
435
|
+
/** Who may sign in with a password: everyone, only admins, or only break-glass accounts. */
|
|
436
|
+
password: 'everyone' | 'admins' | 'breakGlass';
|
|
437
|
+
/** The accounts that may still use a password (`auth.password: { breakGlass }`). */
|
|
438
|
+
breakGlass?: string[];
|
|
437
439
|
/** Email domains whose people get an account when they first sign in. */
|
|
438
440
|
signUp: {
|
|
439
441
|
domains: string[];
|
|
@@ -461,10 +463,17 @@ declare class SingleSignOn {
|
|
|
461
463
|
private get config();
|
|
462
464
|
get enabled(): boolean;
|
|
463
465
|
providers(): SsoProviderRef[];
|
|
464
|
-
/**
|
|
466
|
+
/**
|
|
467
|
+
* Whether a user may sign in with a password: everyone, only admins (`auth.password: false`), or
|
|
468
|
+
* only break-glass accounts (`{ breakGlass }`).
|
|
469
|
+
*/
|
|
465
470
|
passwordAllowed(user: {
|
|
466
471
|
readonly [key: string]: unknown;
|
|
467
472
|
}): boolean;
|
|
473
|
+
/** Whether a user signs in with a password only as a break-glass account. */
|
|
474
|
+
isBreakGlass(user: {
|
|
475
|
+
readonly [key: string]: unknown;
|
|
476
|
+
}): boolean;
|
|
468
477
|
/** `<serverURL><api>/auth/<id>/callback`, or `null` without `serverURL` in production. */
|
|
469
478
|
callbackURL(provider: string, origin?: string): string | null;
|
|
470
479
|
/**
|
|
@@ -2331,6 +2340,11 @@ declare class EasyCMS<C extends Config = Config> {
|
|
|
2331
2340
|
/** Validates, checks uniqueness and references. Returns clean data or throws `ValidationError`. */
|
|
2332
2341
|
private prepare;
|
|
2333
2342
|
/** Refuses changes that would leave no active admin (and lock everyone out). */
|
|
2343
|
+
/**
|
|
2344
|
+
* With break-glass accounts (`auth.password: { breakGlass }`), other accounts get no password:
|
|
2345
|
+
* they couldn't use it. The first account, made before anyone can sign in with a provider, may.
|
|
2346
|
+
*/
|
|
2347
|
+
private guardPassword;
|
|
2334
2348
|
private guardLastAdmin;
|
|
2335
2349
|
private makeSlugsUnique;
|
|
2336
2350
|
private checkUnique;
|
|
@@ -2484,10 +2498,17 @@ declare class AuditLog {
|
|
|
2484
2498
|
resigned: number;
|
|
2485
2499
|
invalid: ID[];
|
|
2486
2500
|
}>;
|
|
2487
|
-
/**
|
|
2501
|
+
/**
|
|
2502
|
+
* What the dashboard warns about: many failed logins, sign-ins of break-glass accounts in the
|
|
2503
|
+
* last day, entries not written, a failed check.
|
|
2504
|
+
*/
|
|
2488
2505
|
attention(now?: Date): Promise<({
|
|
2489
2506
|
id: 'failed-logins';
|
|
2490
2507
|
count: number;
|
|
2508
|
+
} | {
|
|
2509
|
+
id: 'break-glass';
|
|
2510
|
+
count: number;
|
|
2511
|
+
emails: string[];
|
|
2491
2512
|
} | {
|
|
2492
2513
|
id: 'audit-failures';
|
|
2493
2514
|
count: number;
|
|
@@ -3344,10 +3365,13 @@ interface AuthConfig {
|
|
|
3344
3365
|
readonly role?: string;
|
|
3345
3366
|
};
|
|
3346
3367
|
/**
|
|
3347
|
-
*
|
|
3348
|
-
* everyone
|
|
3368
|
+
* Who may sign in with a password; everyone else signs in with `providers`. Default `true`:
|
|
3369
|
+
* everyone. `false`: only admins (a way in when the provider is down). `{ breakGlass: [emails] }`:
|
|
3370
|
+
* only those accounts, for organisations that require single sign-on (and its MFA) for every
|
|
3371
|
+
* other account, admins included. A change ends the sessions of accounts that may no longer use a
|
|
3372
|
+
* password, and is recorded in the audit log, as is each sign-in of a break-glass account.
|
|
3349
3373
|
*/
|
|
3350
|
-
readonly password?: boolean;
|
|
3374
|
+
readonly password?: boolean | PasswordPolicy;
|
|
3351
3375
|
/**
|
|
3352
3376
|
* A code the first admin must enter to create their account, so nobody else can claim a
|
|
3353
3377
|
* freshly deployed site. Default: the `EASY_CMS_SETUP_CODE` environment variable; without it,
|
|
@@ -3366,6 +3390,11 @@ interface AuthConfig {
|
|
|
3366
3390
|
readonly passwordChanged?: PasswordEmailFn;
|
|
3367
3391
|
};
|
|
3368
3392
|
}
|
|
3393
|
+
/** `auth.password` with break-glass accounts: the only ones that sign in with a password. */
|
|
3394
|
+
interface PasswordPolicy {
|
|
3395
|
+
/** Emails of the accounts that may still use a password, e.g. one kept for when the provider is down. */
|
|
3396
|
+
readonly breakGlass: readonly string[];
|
|
3397
|
+
}
|
|
3369
3398
|
interface RateLimitConfig {
|
|
3370
3399
|
/** Seconds each count lasts. Default 60. */
|
|
3371
3400
|
readonly window?: number;
|
|
@@ -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-
|
|
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-BuKlngv6.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;
|
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-
|
|
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 CollectionConfig, ag as CollectionDocument, ah as CollectionHooks, ai as CollectionListAdmin, aj as CollectionSearch, ak as CollectionSlug, C as Config, al as ConfigError, am as ConfigIssue, an as ContainerAdmin, c as CreateEasyCMSOptions, ao as CreateInput, ap as CreateMigrationResult, aq as CursorDocs, ar as CustomField, as as CustomFieldTypes, at as DashboardWidget, au as Database, av as DatabaseAdapter, aw as DatabaseInitArgs, ax as DatabaseTransfer, ay as DateField, az as DepthOptions, aA as DirectUpload, aB as DiskStorageOptions, aC as DocumentOf, E as EasyCMS, aD as EasyCMSError, aE as EmailAdapter, aF as EmailField, aG as EmailMessage, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, aK as FIELD_TYPES, F as Field, aL as FieldAccess, aM as FieldAccessFn, aN as FieldAdmin, a as FieldError, aO as FieldRule, aP as FieldType, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, aT as FieldValidate, aU as FieldValidateContext, aV as FieldValue, aW as FieldsInput, aX as FieldsValue, b as FilterOptions, aY as FilterOptionsArgs, aZ as FindAfterArgs, a_ as FindArgs, a$ as FindOptions, b0 as FolderLevel, b1 as FolderPermissions, b2 as ForbiddenError, b3 as GlobalAccess, b4 as GlobalConfig, b5 as GlobalDocument, b6 as GlobalHooks, b7 as GlobalInput, b8 as GlobalSlug, b9 as GroupField, ba as ImageSize, bb as IncrementOptions, bc as InferCollection, bd as InferGlobal, be as JobConfig, bf as JsonField, bg as KeysetPage, bh as Label, bi as LayoutNode, bj as LivePreview, bk as LocaleOf, L as LocalizationConfig, bl as LogDetails, bm as Logger, bn as LoginArgs, bo as LogsConfig, bp as MediaDocument, bq as MediaSize, br as MembersConfig, bs as MembersSignup, bt as MigrationInfo, bu as NavGroup, bv as NotFoundError, bw as NumberField, bx as OnRequest, by as OnRequestArgs, bz as Operation, bA as OutboxRow, bB as PLUGIN_API_VERSION, bC as PasswordEmail, bD as PasswordEmailArgs, bE as PasswordEmailFn, bF as PasswordLinkOptions, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bK as PreviewTarget, bL as PreviewURL, bM as QueryError, bN as ROLE_OPERATIONS, bO as RawDocument, bP as ReadOptions, bQ as RelationshipField, bR as RequestContext, R as ResolvedConfig, bS as RichTextDocument, bT as RichTextField, bU as Role, bV as RoleOperation, bW as RolePermissions, bX as Roles, bY as RoutesConfig, bZ as ScheduledPublish, b_ as SchemaError, b$ as SchemaMode, c0 as SearchAdapter, c1 as SearchEntry, c2 as SearchHits, c3 as SearchOptions, c4 as SearchQuery, c5 as SearchResults, c6 as SearchSetting, c7 as SelectField, c8 as SelectOption, c9 as Session, ca as SidebarPanel, cb as SignupArgs, cc as SignupResult, cd as SingleSignOn, ce as SlugField, cf as SlugOf, cg as SsoOutcome, ch as SsoProviderRef, ci as StorageAdapter, cj as StoredFile, ck as TRIGRAM_LIKE_MIN, cl as TelemetryConfig, cm as TextField, cn as TextareaField, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cr as UncountedDocs, cs as UpdateInput, ct as UpdateOptions, cu as UploadConfig, cv as UploadField, cw as UploadFromURLConfig, cx as UserIdentity, cy as ValidationError, cz as Version, cA as VersionSummary, cB as VersionsConfig, cC as WEBHOOK_EVENTS, cD as WebhookConfig, cE as WebhookEvent, cF as Where, cG as WhereOperators, cH as anyone, cI as consoleEmail, cJ as consoleLogger, cK as createEasyCMS, cL as defineConfig, cM as defineFieldType, cN as definePlugin, cO as diskStorage, cP as hasRows, cQ as isAdmin, cR as isHasMany, cS as isSignedIn, cT as isStaff, cU as isSystemAdmin, cV as jsonLogger, cW as memorySearch, cX as mimeAllowedBy, cY as rowFields, cZ as silentLogger, c_ as uniqueWithinOf } from './config-
|
|
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-
|
|
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-
|
|
1
|
+
import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-BuKlngv6.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 CollectionConfig, ag as CollectionDocument, ah as CollectionHooks, ai as CollectionListAdmin, aj as CollectionSearch, ak as CollectionSlug, C as Config, al as ConfigError, am as ConfigIssue, an as ContainerAdmin, c as CreateEasyCMSOptions, ao as CreateInput, ap as CreateMigrationResult, aq as CursorDocs, ar as CustomField, as as CustomFieldTypes, at as DashboardWidget, au as Database, av as DatabaseAdapter, aw as DatabaseInitArgs, ax as DatabaseTransfer, ay as DateField, az as DepthOptions, aA as DirectUpload, aB as DiskStorageOptions, aC as DocumentOf, E as EasyCMS, aD as EasyCMSError, aE as EmailAdapter, aF as EmailField, aG as EmailMessage, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, aK as FIELD_TYPES, F as Field, aL as FieldAccess, aM as FieldAccessFn, aN as FieldAdmin, a as FieldError, aO as FieldRule, aP as FieldType, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, aT as FieldValidate, aU as FieldValidateContext, aV as FieldValue, aW as FieldsInput, aX as FieldsValue, b as FilterOptions, aY as FilterOptionsArgs, aZ as FindAfterArgs, a_ as FindArgs, a$ as FindOptions, b0 as FolderLevel, b1 as FolderPermissions, b2 as ForbiddenError, b3 as GlobalAccess, b4 as GlobalConfig, b5 as GlobalDocument, b6 as GlobalHooks, b7 as GlobalInput, b8 as GlobalSlug, b9 as GroupField, ba as ImageSize, bb as IncrementOptions, bc as InferCollection, bd as InferGlobal, be as JobConfig, bf as JsonField, bg as KeysetPage, bh as Label, bi as LayoutNode, bj as LivePreview, bk as LocaleOf, L as LocalizationConfig, bl as LogDetails, bm as Logger, bn as LoginArgs, bo as LogsConfig, bp as MediaDocument, bq as MediaSize, br as MembersConfig, bs as MembersSignup, bt as MigrationInfo, bu as NavGroup, bv as NotFoundError, bw as NumberField, bx as OnRequest, by as OnRequestArgs, bz as Operation, bA as OutboxRow, bB as PLUGIN_API_VERSION, bC as PasswordEmail, bD as PasswordEmailArgs, bE as PasswordEmailFn, bF as PasswordLinkOptions, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bK as PreviewTarget, bL as PreviewURL, bM as QueryError, bN as ROLE_OPERATIONS, bO as RawDocument, bP as ReadOptions, bQ as RelationshipField, bR as RequestContext, R as ResolvedConfig, bS as RichTextDocument, bT as RichTextField, bU as Role, bV as RoleOperation, bW as RolePermissions, bX as Roles, bY as RoutesConfig, bZ as ScheduledPublish, b_ as SchemaError, b$ as SchemaMode, c0 as SearchAdapter, c1 as SearchEntry, c2 as SearchHits, c3 as SearchOptions, c4 as SearchQuery, c5 as SearchResults, c6 as SearchSetting, c7 as SelectField, c8 as SelectOption, c9 as Session, ca as SidebarPanel, cb as SignupArgs, cc as SignupResult, cd as SingleSignOn, ce as SlugField, cf as SlugOf, cg as SsoOutcome, ch as SsoProviderRef, ci as StorageAdapter, cj as StoredFile, ck as TRIGRAM_LIKE_MIN, cl as TelemetryConfig, cm as TextField, cn as TextareaField, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cr as UncountedDocs, cs as UpdateInput, ct as UpdateOptions, cu as UploadConfig, cv as UploadField, cw as UploadFromURLConfig, cx as UserIdentity, cy as ValidationError, cz as Version, cA as VersionSummary, cB as VersionsConfig, cC as WEBHOOK_EVENTS, cD as WebhookConfig, cE as WebhookEvent, cF as Where, cG as WhereOperators, cH as anyone, cI as consoleEmail, cJ as consoleLogger, cK as createEasyCMS, cL as defineConfig, cM as defineFieldType, cN as definePlugin, cO as diskStorage, cP as hasRows, cQ as isAdmin, cR as isHasMany, cS as isSignedIn, cT as isStaff, cU as isSystemAdmin, cV as jsonLogger, cW as memorySearch, cX as mimeAllowedBy, cY as rowFields, cZ as silentLogger, c_ as uniqueWithinOf } from './config-BuKlngv6.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-zOdLJ1oh.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-DuOjJu_X.js';
|
|
5
5
|
export { FieldCondition, matchesCondition } from './conditions.js';
|
|
6
6
|
|
|
7
7
|
type DeliveryKind = 'webhook' | 'email';
|
|
@@ -196,6 +196,12 @@ type AdminAttention =
|
|
|
196
196
|
id: 'failed-logins';
|
|
197
197
|
count: number;
|
|
198
198
|
}
|
|
199
|
+
/** Break-glass accounts signed in with a password in the last day (`auth.password`). */
|
|
200
|
+
| {
|
|
201
|
+
id: 'break-glass';
|
|
202
|
+
count: number;
|
|
203
|
+
emails: string[];
|
|
204
|
+
}
|
|
199
205
|
/** Audit log entries that could not be written since the server started. */
|
|
200
206
|
| {
|
|
201
207
|
id: 'audit-failures';
|
package/dist/index.js
CHANGED
package/dist/internal.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Config, Database, EasyCMS, NavGroup, CollectionConfig, ID, RawDocument, Field, ResolvedConfig, ConfigIssue } from './index.js';
|
|
2
|
-
export { c$ as API_KEYS, d0 as API_KEY_GLOBAL_OPERATIONS, d1 as API_KEY_OPERATIONS, d2 as DEFAULT_MAX_VERSIONS, d3 as DEFAULT_PASSWORD_EMAILS, d4 as FIELD_TYPE_BASES, d5 as FOLDER_LEVELS, d6 as MediaFolders, d7 as SSO_COOKIE, d8 as Secrets, ck as TRIGRAM_LIKE_MIN, d9 as codeOfStatus, cP as hasRows, cR as isHasMany, da as isJsonLogger, db as keyAllows, dc as logFormat, cX as mimeAllowedBy, cY as rowFields, dd as secretsOf, c_ as uniqueWithinOf } from './config-
|
|
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-
|
|
2
|
+
export { c$ as API_KEYS, d0 as API_KEY_GLOBAL_OPERATIONS, d1 as API_KEY_OPERATIONS, d2 as DEFAULT_MAX_VERSIONS, d3 as DEFAULT_PASSWORD_EMAILS, d4 as FIELD_TYPE_BASES, d5 as FOLDER_LEVELS, d6 as MediaFolders, d7 as SSO_COOKIE, d8 as Secrets, ck as TRIGRAM_LIKE_MIN, d9 as codeOfStatus, cP as hasRows, cR as isHasMany, da as isJsonLogger, db as keyAllows, dc as logFormat, cX as mimeAllowedBy, cY as rowFields, dd as secretsOf, c_ as uniqueWithinOf } from './config-BuKlngv6.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-DuOjJu_X.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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bh as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ch as SsoProviderRef } from './config-
|
|
1
|
+
import { bh as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ch as SsoProviderRef } from './config-BuKlngv6.js';
|
|
2
2
|
import { FieldCondition } from './conditions.js';
|
|
3
3
|
|
|
4
4
|
/** A Web Component from an admin module, with its `props` (plain JSON). */
|
|
@@ -211,6 +211,12 @@ interface AdminSchema {
|
|
|
211
211
|
switcher: AdminSwitcher | null;
|
|
212
212
|
/** Admins can email users links to set their password (needs `email` and `serverURL`). */
|
|
213
213
|
passwordLinks: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Who may have a password (`auth.password`); with `breakGlass`, the accounts, for admins of the
|
|
216
|
+
* whole system: others get no password field.
|
|
217
|
+
*/
|
|
218
|
+
passwordFor: 'everyone' | 'admins' | 'breakGlass';
|
|
219
|
+
breakGlass?: string[];
|
|
214
220
|
/** The menu: groups and what this user may open in them, in order. */
|
|
215
221
|
nav: AdminNavNode[];
|
|
216
222
|
/** More entries of the command palette (`admin.commands`). */
|
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, af as CollectionConfig, C as Config, al as ConfigError, at as DashboardWidget, aD as EasyCMSError, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, F as Field, aL as FieldAccess, a as FieldError, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, b2 as ForbiddenError, b4 as GlobalConfig, I as ID, be as JobConfig, bh as Label, bu as NavGroup, bv as NotFoundError, bx as OnRequest, by as OnRequestArgs, bB as PLUGIN_API_VERSION, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bM as QueryError, bR as RequestContext, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cy as ValidationError, cF as Where, cM as defineFieldType, cN as definePlugin } from './config-
|
|
2
|
-
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-
|
|
1
|
+
export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, af as CollectionConfig, C as Config, al as ConfigError, at as DashboardWidget, aD as EasyCMSError, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, F as Field, aL as FieldAccess, a as FieldError, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, b2 as ForbiddenError, b4 as GlobalConfig, I as ID, be as JobConfig, bh as Label, bu as NavGroup, bv as NotFoundError, bx as OnRequest, by as OnRequestArgs, bB as PLUGIN_API_VERSION, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bM as QueryError, bR as RequestContext, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cy as ValidationError, cF as Where, cM as defineFieldType, cN as definePlugin } from './config-BuKlngv6.js';
|
|
2
|
+
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-zOdLJ1oh.js';
|
|
3
3
|
import './conditions.js';
|