@easy-cms/core 0.62.0 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-CX7R6QBJ.js → chunk-JZW6G6XI.js} +137 -53
- package/dist/{chunk-FPFWLQB5.js → chunk-RTKWMVAC.js} +7 -0
- package/dist/{config-jzFGsNL6.d.ts → config-Dgs6FE0S.d.ts} +16 -3
- package/dist/{handler-CMA1LIq7.d.ts → handler-CcmsrLs8.d.ts} +7 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +2 -2
- package/dist/{plugin-C19Bt8ux.d.ts → plugin-8hrkYMuR.d.ts} +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.js +1 -1
- package/package.json +1 -1
|
@@ -33,8 +33,9 @@ import {
|
|
|
33
33
|
typeFromName,
|
|
34
34
|
uniqueWithinOf,
|
|
35
35
|
warnDeprecated,
|
|
36
|
+
withCharset,
|
|
36
37
|
withPrivacy
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-RTKWMVAC.js";
|
|
38
39
|
|
|
39
40
|
// src/access.ts
|
|
40
41
|
var isSystemAdmin = (user) => user?.role === "admin" && !user.apiKey && user.scoped !== true;
|
|
@@ -1015,6 +1016,21 @@ async function verifyTurnstile(secretKey, response, ip, fetcher = fetch) {
|
|
|
1015
1016
|
|
|
1016
1017
|
// src/auth/cookie.ts
|
|
1017
1018
|
var SESSION_COOKIE = "ecms-session";
|
|
1019
|
+
var hostCookie = (name) => `__Host-${name}`;
|
|
1020
|
+
function cookieValue(header, name) {
|
|
1021
|
+
if (!header) return void 0;
|
|
1022
|
+
let plain;
|
|
1023
|
+
for (const part of header.split(";")) {
|
|
1024
|
+
const eq = part.indexOf("=");
|
|
1025
|
+
if (eq <= 0) continue;
|
|
1026
|
+
const key = part.slice(0, eq).trim();
|
|
1027
|
+
if (key !== name && key !== hostCookie(name)) continue;
|
|
1028
|
+
const value = decodeURIComponent(part.slice(eq + 1).trim());
|
|
1029
|
+
if (key !== name) return value;
|
|
1030
|
+
plain ??= value;
|
|
1031
|
+
}
|
|
1032
|
+
return plain;
|
|
1033
|
+
}
|
|
1018
1034
|
|
|
1019
1035
|
// src/auth/emails.ts
|
|
1020
1036
|
var esc = (value) => value.replace(
|
|
@@ -1169,11 +1185,13 @@ function safeEqual(a, b) {
|
|
|
1169
1185
|
const right = Buffer.from(b);
|
|
1170
1186
|
return left.length === right.length && timingSafeEqual4(left, right);
|
|
1171
1187
|
}
|
|
1172
|
-
function signPreviewToken(secret, target, expiresAt) {
|
|
1188
|
+
function signPreviewToken(secret, target, expiresAt, user) {
|
|
1173
1189
|
const payload = Buffer.from(
|
|
1174
|
-
JSON.stringify(
|
|
1175
|
-
"global" in target ? { g: target.global
|
|
1176
|
-
|
|
1190
|
+
JSON.stringify({
|
|
1191
|
+
..."global" in target ? { g: target.global } : { c: target.collection, i: target.id },
|
|
1192
|
+
e: expiresAt,
|
|
1193
|
+
...user !== void 0 ? { u: user } : {}
|
|
1194
|
+
})
|
|
1177
1195
|
).toString("base64url");
|
|
1178
1196
|
return `${payload}.${hmac(secret, `preview:${payload}`)}`;
|
|
1179
1197
|
}
|
|
@@ -1185,9 +1203,10 @@ function verifyPreviewToken(secret, token, now = Date.now()) {
|
|
|
1185
1203
|
try {
|
|
1186
1204
|
const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
1187
1205
|
if (typeof data.e !== "number" || data.e <= now) return null;
|
|
1188
|
-
|
|
1206
|
+
const user = typeof data.u === "string" ? { user: data.u } : {};
|
|
1207
|
+
if (typeof data.g === "string") return { global: data.g, expiresAt: data.e, ...user };
|
|
1189
1208
|
if (typeof data.c === "string" && typeof data.i === "string")
|
|
1190
|
-
return { collection: data.c, id: data.i, expiresAt: data.e };
|
|
1209
|
+
return { collection: data.c, id: data.i, expiresAt: data.e, ...user };
|
|
1191
1210
|
return null;
|
|
1192
1211
|
} catch {
|
|
1193
1212
|
return null;
|
|
@@ -1908,12 +1927,8 @@ var Auth = class {
|
|
|
1908
1927
|
async userFromHeaders(headers) {
|
|
1909
1928
|
const authorization = headers.get("authorization");
|
|
1910
1929
|
if (authorization?.startsWith("Bearer ")) return this.verify(authorization.slice(7).trim());
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
if (eq > 0 && part.slice(0, eq).trim() === SESSION_COOKIE)
|
|
1914
|
-
return this.verify(decodeURIComponent(part.slice(eq + 1).trim()));
|
|
1915
|
-
}
|
|
1916
|
-
return null;
|
|
1930
|
+
const cookie2 = cookieValue(headers.get("cookie"), SESSION_COOKIE);
|
|
1931
|
+
return cookie2 ? this.verify(cookie2) : null;
|
|
1917
1932
|
}
|
|
1918
1933
|
/**
|
|
1919
1934
|
* Returns the user for a signed session token, or for an API key (`ecms_…`, with `apiKey` set
|
|
@@ -1934,6 +1949,12 @@ var Auth = class {
|
|
|
1934
1949
|
if (!user || user.active === false) return null;
|
|
1935
1950
|
return this.toAuthUser(user);
|
|
1936
1951
|
}
|
|
1952
|
+
/** An active user by id, as requests see them; `null` when deleted or deactivated. @internal */
|
|
1953
|
+
async activeUser(id) {
|
|
1954
|
+
const user = await this.db.findById({ collection: USERS, id });
|
|
1955
|
+
if (!user || user.active === false) return null;
|
|
1956
|
+
return this.toAuthUser(user);
|
|
1957
|
+
}
|
|
1937
1958
|
/** The CSRF token clients must echo for a signed session token. @internal */
|
|
1938
1959
|
csrfFor(signedToken) {
|
|
1939
1960
|
const token = unsignToken(this.config.secret, signedToken);
|
|
@@ -6818,7 +6839,7 @@ var EasyCMS = class {
|
|
|
6818
6839
|
const filename = withPrivacy(storageKey(file.name, mimeType, random2), isPrivate);
|
|
6819
6840
|
const stored = [];
|
|
6820
6841
|
try {
|
|
6821
|
-
await storage.put(filename, file.data, { contentType: mimeType });
|
|
6842
|
+
await storage.put(filename, file.data, { contentType: withCharset(mimeType) });
|
|
6822
6843
|
stored.push(filename);
|
|
6823
6844
|
const dimensions = imageDimensions(file.data, mimeType);
|
|
6824
6845
|
const sizes = await this.resizeImage(
|
|
@@ -7119,18 +7140,23 @@ var EasyCMS = class {
|
|
|
7119
7140
|
}
|
|
7120
7141
|
/**
|
|
7121
7142
|
* 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.
|
|
7143
|
+
* inside groups, arrays and blocks are not counted). Drafts count too. With
|
|
7144
|
+
* `overrideAccess: false`, only documents the user may read.
|
|
7123
7145
|
*/
|
|
7124
|
-
async mediaUsage(ids) {
|
|
7146
|
+
async mediaUsage(ids, options = {}) {
|
|
7125
7147
|
if (ids.length === 0) return 0;
|
|
7126
7148
|
let count = 0;
|
|
7127
7149
|
for (const config of this.config.collections) {
|
|
7128
7150
|
if (INTERNAL_COLLECTIONS.has(config.slug)) continue;
|
|
7129
7151
|
for (const field of config.fields) {
|
|
7130
7152
|
if (field.type !== "upload") continue;
|
|
7131
|
-
count += await this.
|
|
7132
|
-
|
|
7133
|
-
where: { [field.name]: { in: [...ids] } }
|
|
7153
|
+
count += await this.count(config.slug, {
|
|
7154
|
+
...options,
|
|
7155
|
+
where: { [field.name]: { in: [...ids] } },
|
|
7156
|
+
draft: true
|
|
7157
|
+
}).catch((error) => {
|
|
7158
|
+
if (error instanceof ForbiddenError || error instanceof UnauthorizedError) return 0;
|
|
7159
|
+
throw error;
|
|
7134
7160
|
});
|
|
7135
7161
|
}
|
|
7136
7162
|
}
|
|
@@ -7159,7 +7185,7 @@ var EasyCMS = class {
|
|
|
7159
7185
|
const old = [String(doc.filename)];
|
|
7160
7186
|
const copy = async (source, target) => {
|
|
7161
7187
|
const file = await from.get(source);
|
|
7162
|
-
if (file) await to.put(target, file.body, { contentType });
|
|
7188
|
+
if (file) await to.put(target, file.body, { contentType: withCharset(contentType) });
|
|
7163
7189
|
};
|
|
7164
7190
|
await copy(String(doc.filename), filename);
|
|
7165
7191
|
const sizes = {};
|
|
@@ -7381,12 +7407,15 @@ var EasyCMS = class {
|
|
|
7381
7407
|
/**
|
|
7382
7408
|
* A token that lets a page read one document's current draft for a while (default one hour),
|
|
7383
7409
|
* 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.
|
|
7410
|
+
* preview URL as `easy-cms-preview`, for sites on another origin. With `user`, the page reads
|
|
7411
|
+
* it with that user's access (fields they can't read are left out; a deactivated user's token
|
|
7412
|
+
* stops working); without, with full access.
|
|
7385
7413
|
*/
|
|
7386
7414
|
createPreviewToken(target, options = {}) {
|
|
7387
7415
|
const seconds = options.expiresIn ?? 60 * 60;
|
|
7388
7416
|
const normalized = "global" in target ? target : { collection: target.collection, id: String(target.id) };
|
|
7389
|
-
|
|
7417
|
+
const user = options.user ? String(options.user.id) : void 0;
|
|
7418
|
+
return signPreviewToken(this.config.secret, normalized, Date.now() + seconds * 1e3, user);
|
|
7390
7419
|
}
|
|
7391
7420
|
/** What a preview token opens, or `null` when it is invalid or expired. */
|
|
7392
7421
|
verifyPreviewToken(token) {
|
|
@@ -7846,7 +7875,8 @@ var EasyCMS = class {
|
|
|
7846
7875
|
const check3 = (operation) => this.checkDocumentAccess(config, operation, guard, parsed, void 0).then(
|
|
7847
7876
|
() => true,
|
|
7848
7877
|
(error) => {
|
|
7849
|
-
if (error instanceof ForbiddenError || error instanceof UnauthorizedError
|
|
7878
|
+
if (error instanceof ForbiddenError || error instanceof UnauthorizedError || error instanceof NotFoundError)
|
|
7879
|
+
return false;
|
|
7850
7880
|
throw error;
|
|
7851
7881
|
}
|
|
7852
7882
|
);
|
|
@@ -8315,7 +8345,38 @@ var EasyCMS = class {
|
|
|
8315
8345
|
await this.checkQueryFields(config, guard, where);
|
|
8316
8346
|
return andWhere(andWhere(where, access), own);
|
|
8317
8347
|
}
|
|
8348
|
+
/**
|
|
8349
|
+
* Throws unless the caller may update or delete this document. A user who may not even read
|
|
8350
|
+
* it gets `NotFoundError`, as for an id that doesn't exist: a 403 would tell it does.
|
|
8351
|
+
*/
|
|
8318
8352
|
async checkDocumentAccess(config, operation, guard, id, data) {
|
|
8353
|
+
await this.hidingDenied(
|
|
8354
|
+
config.slug,
|
|
8355
|
+
guard,
|
|
8356
|
+
id,
|
|
8357
|
+
() => this.documentAccess(config, operation, guard, id, data)
|
|
8358
|
+
);
|
|
8359
|
+
}
|
|
8360
|
+
/** Runs a check; a `ForbiddenError` for a document the user can't read becomes a 404. */
|
|
8361
|
+
async hidingDenied(collection2, guard, id, check3) {
|
|
8362
|
+
try {
|
|
8363
|
+
await check3();
|
|
8364
|
+
} catch (error) {
|
|
8365
|
+
if (error instanceof ForbiddenError && !await this.mayRead(collection2, guard, id))
|
|
8366
|
+
throw new NotFoundError(collection2, String(id));
|
|
8367
|
+
throw error;
|
|
8368
|
+
}
|
|
8369
|
+
}
|
|
8370
|
+
async mayRead(collection2, guard, id) {
|
|
8371
|
+
const config = this.collection(collection2);
|
|
8372
|
+
try {
|
|
8373
|
+
const where = await this.readWhere(config, guard, { id: { equals: id } });
|
|
8374
|
+
return await this.db.count({ collection: collection2, where }) > 0;
|
|
8375
|
+
} catch {
|
|
8376
|
+
return false;
|
|
8377
|
+
}
|
|
8378
|
+
}
|
|
8379
|
+
async documentAccess(config, operation, guard, id, data) {
|
|
8319
8380
|
if (!guard.enforce) return;
|
|
8320
8381
|
const own = await this.checkGrant(guard, { collection: config.slug }, operation);
|
|
8321
8382
|
const allowed2 = await evaluateAccess(config.access?.[operation], {
|
|
@@ -8382,13 +8443,15 @@ var EasyCMS = class {
|
|
|
8382
8443
|
}
|
|
8383
8444
|
/** `checkGrant` for one document: a role limited to its own documents must own it. */
|
|
8384
8445
|
async checkDocumentGrant(guard, collection2, operation, id) {
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8446
|
+
await this.hidingDenied(collection2, guard, id, async () => {
|
|
8447
|
+
const own = await this.checkGrant(guard, { collection: collection2 }, operation);
|
|
8448
|
+
if (own === true) return;
|
|
8449
|
+
const matches2 = await this.db.count({
|
|
8450
|
+
collection: collection2,
|
|
8451
|
+
where: andWhere(own, { id: { equals: id } })
|
|
8452
|
+
});
|
|
8453
|
+
if (matches2 === 0) throw deny(guard.user);
|
|
8390
8454
|
});
|
|
8391
|
-
if (matches2 === 0) throw deny(guard.user);
|
|
8392
8455
|
}
|
|
8393
8456
|
/** Runs afterRead hooks, populates relationships and removes what the caller may not see. */
|
|
8394
8457
|
async output(config, docs, guard, options) {
|
|
@@ -9042,7 +9105,7 @@ async function readAdminModule(cms, index) {
|
|
|
9042
9105
|
}
|
|
9043
9106
|
|
|
9044
9107
|
// src/version.ts
|
|
9045
|
-
var VERSION = true ? "0.
|
|
9108
|
+
var VERSION = true ? "0.64.0" : "0.0.0-dev";
|
|
9046
9109
|
|
|
9047
9110
|
// src/rest/admin-deliveries.ts
|
|
9048
9111
|
var PER_PAGE = 50;
|
|
@@ -9978,7 +10041,8 @@ async function respond(cms, request, url, path, root, options, production) {
|
|
|
9978
10041
|
const headers = new Headers({
|
|
9979
10042
|
"content-type": "application/json; charset=utf-8",
|
|
9980
10043
|
"cache-control": "no-store",
|
|
9981
|
-
"x-content-type-options": "nosniff"
|
|
10044
|
+
"x-content-type-options": "nosniff",
|
|
10045
|
+
...production ? { "strict-transport-security": "max-age=31536000" } : {}
|
|
9982
10046
|
});
|
|
9983
10047
|
try {
|
|
9984
10048
|
if (path === null) throw new HttpError("Not found", 404);
|
|
@@ -9995,7 +10059,8 @@ async function respond(cms, request, url, path, root, options, production) {
|
|
|
9995
10059
|
context,
|
|
9996
10060
|
via: signedIn ? via : null,
|
|
9997
10061
|
token,
|
|
9998
|
-
headers
|
|
10062
|
+
headers,
|
|
10063
|
+
trustProxy: options.trustProxy === true
|
|
9999
10064
|
};
|
|
10000
10065
|
const method = request.method.toUpperCase();
|
|
10001
10066
|
if (method !== "GET" && method !== "HEAD") checkCsrf(cms, ctx);
|
|
@@ -10171,6 +10236,7 @@ async function route(cms, ctx, method, path, options) {
|
|
|
10171
10236
|
case "POST logout": {
|
|
10172
10237
|
if (ctx.token) await cms.auth.logout(ctx.token);
|
|
10173
10238
|
clearSessionCookies(ctx);
|
|
10239
|
+
ctx.headers.set("clear-site-data", '"cache"');
|
|
10174
10240
|
return { body: { message: "Logged out" } };
|
|
10175
10241
|
}
|
|
10176
10242
|
case "GET me": {
|
|
@@ -10406,7 +10472,12 @@ async function route(cms, ctx, method, path, options) {
|
|
|
10406
10472
|
if (!ctx.user || ctx.user.apiKey) throw new UnauthorizedError();
|
|
10407
10473
|
if (method !== "GET") throw methodNotAllowed(ctx, "GET");
|
|
10408
10474
|
const ids = (ctx.url.searchParams.get("ids") ?? "").split(",").map((id2) => parseId(id2)).filter((id2) => id2 !== void 0);
|
|
10409
|
-
|
|
10475
|
+
const count = await cms.mediaUsage(ids, {
|
|
10476
|
+
overrideAccess: false,
|
|
10477
|
+
user: ctx.user,
|
|
10478
|
+
context: ctx.context
|
|
10479
|
+
});
|
|
10480
|
+
return { body: { count } };
|
|
10410
10481
|
}
|
|
10411
10482
|
if (first === "admin" && second === "roles") {
|
|
10412
10483
|
if (!ctx.user) throw new UnauthorizedError();
|
|
@@ -10551,9 +10622,10 @@ async function route(cms, ctx, method, path, options) {
|
|
|
10551
10622
|
if (third !== void 0) return globalAction(cms, ctx, method, second, segments.slice(2));
|
|
10552
10623
|
if (method === "GET") {
|
|
10553
10624
|
if (ctx.url.searchParams.has("preview")) {
|
|
10554
|
-
requirePreview(cms, ctx, { global: second });
|
|
10625
|
+
const as = await requirePreview(cms, ctx, { global: second });
|
|
10555
10626
|
return {
|
|
10556
10627
|
body: await cms.findGlobal(second, {
|
|
10628
|
+
...as,
|
|
10557
10629
|
...parseDepth(ctx.url),
|
|
10558
10630
|
...parseLocale(ctx.url),
|
|
10559
10631
|
draft: true
|
|
@@ -10662,8 +10734,9 @@ async function route(cms, ctx, method, path, options) {
|
|
|
10662
10734
|
}
|
|
10663
10735
|
const id = second;
|
|
10664
10736
|
if (method === "GET" && ctx.url.searchParams.has("preview")) {
|
|
10665
|
-
requirePreview(cms, ctx, { collection: collection2, id });
|
|
10737
|
+
const as = await requirePreview(cms, ctx, { collection: collection2, id });
|
|
10666
10738
|
const doc = await cms.findById(collection2, id, {
|
|
10739
|
+
...as,
|
|
10667
10740
|
...parseDepth(ctx.url),
|
|
10668
10741
|
...parseLocale(ctx.url),
|
|
10669
10742
|
draft: true
|
|
@@ -10742,7 +10815,7 @@ async function documentAction(cms, ctx, method, collection2, id, path) {
|
|
|
10742
10815
|
if (method !== "POST") throw methodNotAllowed(ctx, "POST");
|
|
10743
10816
|
const body = await readJson(ctx.request);
|
|
10744
10817
|
const result = await cms.preview(collection2, id, body, { ...access, ...depth });
|
|
10745
|
-
const token = cms.createPreviewToken({ collection: collection2, id });
|
|
10818
|
+
const token = cms.createPreviewToken({ collection: collection2, id }, { user: ctx.user });
|
|
10746
10819
|
return { body: { ...result, url: result.url && withPreviewToken(result.url, token) } };
|
|
10747
10820
|
}
|
|
10748
10821
|
if (path.length === 1 && (action === "unpublish" || action === "discard-draft")) {
|
|
@@ -10792,7 +10865,7 @@ async function globalAction(cms, ctx, method, slug2, path) {
|
|
|
10792
10865
|
if (method !== "POST") throw methodNotAllowed(ctx, "POST");
|
|
10793
10866
|
const body = await readJson(ctx.request);
|
|
10794
10867
|
const result = await cms.previewGlobal(slug2, body, { ...access, ...depth });
|
|
10795
|
-
const token = cms.createPreviewToken({ global: slug2 });
|
|
10868
|
+
const token = cms.createPreviewToken({ global: slug2 }, { user: ctx.user });
|
|
10796
10869
|
return { body: { ...result, url: result.url && withPreviewToken(result.url, token) } };
|
|
10797
10870
|
}
|
|
10798
10871
|
if (path.length === 1 && (action === "unpublish" || action === "discard-draft")) {
|
|
@@ -10831,10 +10904,16 @@ function withPreviewToken(url, token) {
|
|
|
10831
10904
|
const separator = base.includes("?") ? "&" : "?";
|
|
10832
10905
|
return `${base}${separator}${PREVIEW_PARAM}=${encodeURIComponent(token)}${fragment}`;
|
|
10833
10906
|
}
|
|
10834
|
-
function requirePreview(cms, ctx, target) {
|
|
10907
|
+
async function requirePreview(cms, ctx, target) {
|
|
10835
10908
|
const opened = cms.verifyPreviewToken(ctx.url.searchParams.get("preview"));
|
|
10836
10909
|
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
10910
|
if (!matches2) throw new UnauthorizedError("Invalid or expired preview token");
|
|
10911
|
+
if (opened.user === void 0) return {};
|
|
10912
|
+
const id = parseId(opened.user);
|
|
10913
|
+
const issuer = id === void 0 ? null : await cms.auth.activeUser(id);
|
|
10914
|
+
if (!issuer) throw new UnauthorizedError("Invalid or expired preview token");
|
|
10915
|
+
const { user, context } = await cms.applyOnRequest(ctx.request.headers, ctx.url, issuer);
|
|
10916
|
+
return { overrideAccess: false, user, context };
|
|
10838
10917
|
}
|
|
10839
10918
|
function parsePage(url) {
|
|
10840
10919
|
const { page, limit } = parseListQuery(url);
|
|
@@ -10852,23 +10931,17 @@ function readToken(request) {
|
|
|
10852
10931
|
return { token, via: token ? "cookie" : null };
|
|
10853
10932
|
}
|
|
10854
10933
|
function readCookie(request, name) {
|
|
10855
|
-
|
|
10856
|
-
if (!header) return void 0;
|
|
10857
|
-
for (const part of header.split(";")) {
|
|
10858
|
-
const eq = part.indexOf("=");
|
|
10859
|
-
if (eq > 0 && part.slice(0, eq).trim() === name)
|
|
10860
|
-
return decodeURIComponent(part.slice(eq + 1).trim());
|
|
10861
|
-
}
|
|
10862
|
-
return void 0;
|
|
10934
|
+
return cookieValue(request.headers.get("cookie"), name);
|
|
10863
10935
|
}
|
|
10864
|
-
function sameHost(origin, request) {
|
|
10936
|
+
function sameHost(origin, request, trustProxy) {
|
|
10865
10937
|
let host;
|
|
10866
10938
|
try {
|
|
10867
10939
|
host = new URL(origin).host;
|
|
10868
10940
|
} catch {
|
|
10869
10941
|
return false;
|
|
10870
10942
|
}
|
|
10871
|
-
const
|
|
10943
|
+
const trusted = trustProxy || !!process.env.VERCEL || !!process.env.NETLIFY;
|
|
10944
|
+
const forwarded = trusted ? request.headers.get("x-forwarded-host")?.split(",")[0]?.trim() : void 0;
|
|
10872
10945
|
return host === (forwarded || request.headers.get("host"));
|
|
10873
10946
|
}
|
|
10874
10947
|
function checkCsrf(cms, ctx) {
|
|
@@ -10876,7 +10949,7 @@ function checkCsrf(cms, ctx) {
|
|
|
10876
10949
|
const fetchSite = ctx.request.headers.get("sec-fetch-site");
|
|
10877
10950
|
const cookie2 = ctx.via === "cookie" && ctx.token !== void 0;
|
|
10878
10951
|
const { cors } = cms.config;
|
|
10879
|
-
const trusted = origin !== null && (origin === ctx.url.origin || sameHost(origin, ctx.request) || cms.config.auth.trustedOrigins.includes(origin) || !cookie2 && (cors === "*" || cors.includes(origin)));
|
|
10952
|
+
const trusted = origin !== null && (origin === ctx.url.origin || sameHost(origin, ctx.request, ctx.trustProxy) || cms.config.auth.trustedOrigins.includes(origin) || !cookie2 && (cors === "*" || cors.includes(origin)));
|
|
10880
10953
|
if (origin !== null && !trusted) throw new ForbiddenError("CSRF check failed: untrusted origin");
|
|
10881
10954
|
if (origin === null && fetchSite === "cross-site")
|
|
10882
10955
|
throw new ForbiddenError("CSRF check failed: cross-site request");
|
|
@@ -10898,7 +10971,7 @@ async function serveFile(cms, key, head) {
|
|
|
10898
10971
|
const file = await cms.storage.get(key);
|
|
10899
10972
|
if (!file) throw new HttpError("Not found", 404);
|
|
10900
10973
|
const extension = key.slice(key.lastIndexOf(".") + 1);
|
|
10901
|
-
const type = TYPE_BY_EXTENSION[extension] ?? "application/octet-stream";
|
|
10974
|
+
const type = withCharset(TYPE_BY_EXTENSION[extension] ?? "application/octet-stream");
|
|
10902
10975
|
return new Response(
|
|
10903
10976
|
head ? null : file.body,
|
|
10904
10977
|
{
|
|
@@ -10941,7 +11014,9 @@ async function servePrivateFile(cms, ctx, key, head) {
|
|
|
10941
11014
|
}
|
|
10942
11015
|
const file = await cms.privateStorage.get(key);
|
|
10943
11016
|
if (!file) throw new HttpError("Not found", 404);
|
|
10944
|
-
const type =
|
|
11017
|
+
const type = withCharset(
|
|
11018
|
+
TYPE_BY_EXTENSION[key.slice(key.lastIndexOf(".") + 1)] ?? "application/octet-stream"
|
|
11019
|
+
);
|
|
10945
11020
|
return new Response(
|
|
10946
11021
|
head ? null : file.body,
|
|
10947
11022
|
{
|
|
@@ -11052,9 +11127,14 @@ function isSecure(ctx) {
|
|
|
11052
11127
|
return ctx.url.protocol === "https:" || process.env.NODE_ENV === "production";
|
|
11053
11128
|
}
|
|
11054
11129
|
function cookie(ctx, name, value, opts) {
|
|
11055
|
-
const
|
|
11130
|
+
const secure = isSecure(ctx);
|
|
11131
|
+
const parts = [
|
|
11132
|
+
`${secure ? hostCookie(name) : name}=${encodeURIComponent(value)}`,
|
|
11133
|
+
"Path=/",
|
|
11134
|
+
"SameSite=Lax"
|
|
11135
|
+
];
|
|
11056
11136
|
if (opts.httpOnly) parts.push("HttpOnly");
|
|
11057
|
-
if (
|
|
11137
|
+
if (secure) parts.push("Secure");
|
|
11058
11138
|
if (opts.maxAge !== void 0) parts.push(`Max-Age=${opts.maxAge}`);
|
|
11059
11139
|
return parts.join("; ");
|
|
11060
11140
|
}
|
|
@@ -11133,6 +11213,9 @@ function setSessionCookies(cms, ctx, session) {
|
|
|
11133
11213
|
function clearSessionCookies(ctx) {
|
|
11134
11214
|
ctx.headers.append("set-cookie", cookie(ctx, SESSION_COOKIE, "", { httpOnly: true, maxAge: 0 }));
|
|
11135
11215
|
ctx.headers.append("set-cookie", cookie(ctx, CSRF_COOKIE, "", { httpOnly: false, maxAge: 0 }));
|
|
11216
|
+
if (isSecure(ctx))
|
|
11217
|
+
for (const name of [SESSION_COOKIE, CSRF_COOKIE])
|
|
11218
|
+
ctx.headers.append("set-cookie", `${name}=; Path=/; Max-Age=0; Secure; SameSite=Lax`);
|
|
11136
11219
|
}
|
|
11137
11220
|
function errorResponse(cms, error, headers, production) {
|
|
11138
11221
|
if (error instanceof EasyCMSError) {
|
|
@@ -11198,6 +11281,7 @@ function createApiHandler(config, options = {}) {
|
|
|
11198
11281
|
if (!handler) {
|
|
11199
11282
|
handler = createRestHandler(cms, {
|
|
11200
11283
|
getClientIp,
|
|
11284
|
+
trustProxy: options.trustProxy === true,
|
|
11201
11285
|
...options.basePath ? { basePath: options.basePath } : {}
|
|
11202
11286
|
});
|
|
11203
11287
|
handlers.set(cms, handler);
|
|
@@ -271,6 +271,12 @@ function sizeKey(filename, size) {
|
|
|
271
271
|
return filename.replace(/\.([^.]+)$/, `-${size}.$1`);
|
|
272
272
|
}
|
|
273
273
|
var PRIVATE_KEY = /^[\p{L}\p{M}\p{N}-]+\.private(-[\p{L}\p{N}_-]+)?\.[a-z0-9]+$/u;
|
|
274
|
+
function withCharset(type) {
|
|
275
|
+
if (/;\s*charset=/i.test(type)) return type;
|
|
276
|
+
const base = type.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
277
|
+
const text = base.startsWith("text/") || /^application\/(json|xml|javascript|ecmascript)$/.test(base) || /\+(json|xml)$/.test(base);
|
|
278
|
+
return text ? `${type}; charset=utf-8` : type;
|
|
279
|
+
}
|
|
274
280
|
|
|
275
281
|
// src/fields.ts
|
|
276
282
|
var uniqueWithinOf = (field) => field.uniqueWithin === void 0 ? [] : [field.uniqueWithin].flat();
|
|
@@ -534,6 +540,7 @@ export {
|
|
|
534
540
|
withPrivacy,
|
|
535
541
|
sizeKey,
|
|
536
542
|
PRIVATE_KEY,
|
|
543
|
+
withCharset,
|
|
537
544
|
uniqueWithinOf,
|
|
538
545
|
isHasMany,
|
|
539
546
|
mimeAllowedBy,
|
|
@@ -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-
|
|
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`). */
|
|
@@ -172,6 +172,11 @@ interface RestHandlerOptions {
|
|
|
172
172
|
readonly basePath?: string;
|
|
173
173
|
/** Client IP, used with the email to rate-limit logins. Adapters provide it. */
|
|
174
174
|
readonly getClientIp?: (request: Request) => string | undefined;
|
|
175
|
+
/**
|
|
176
|
+
* Behind a reverse proxy you control: its `X-Forwarded-Host` names the public host (for the
|
|
177
|
+
* CSRF check of a request's Origin). Vercel and Netlify are recognized without it.
|
|
178
|
+
*/
|
|
179
|
+
readonly trustProxy?: boolean;
|
|
175
180
|
}
|
|
176
181
|
type RestHandler = (request: Request) => Promise<Response>;
|
|
177
182
|
/** Creates the REST API as a Web-standard `(Request) => Response` handler. */
|
|
@@ -183,6 +188,7 @@ declare function createRestHandler<C extends Config>(instance: EasyCMS<C>, optio
|
|
|
183
188
|
* use it; the standalone server does.
|
|
184
189
|
*/
|
|
185
190
|
declare function createRootEndpointHandler<C extends Config>(instance: EasyCMS<C>, options?: Pick<RestHandlerOptions, 'getClientIp'>): (request: Request) => Promise<Response | undefined>;
|
|
191
|
+
/** A cookie of the request; the `__Host-` one (set over HTTPS) first. */
|
|
186
192
|
declare function readCookie(request: Request, name: string): string | undefined;
|
|
187
193
|
|
|
188
194
|
export { type AdminBackup as A, type BackupState as B, CONFIG_FILE_NAMES as C, DEFAULT_ADMIN_PATH as D, validateFields as E, writeBackupFile as F, type LoadConfigOptions as L, type RestHandler as R, type AdminBackups as a, type ApiHandlerOptions as b, type RestHandlerOptions as c, createApiHandler as d, createRestHandler as e, slugify as f, CSRF_COOKIE as g, CSRF_HEADER as h, DEFAULT_API_PATH as i, DEFAULT_MAX_FILE_SIZE as j, DEFAULT_TOKEN_EXPIRATION as k, loadConfig as l, applyDefaults as m, applyPlugins as n, createRootEndpointHandler as o, fillMissing as p, findConfigFile as q, resolveConfig as r, sharedEasyCMS as s, forwardedClientIp as t, generateSlugs as u, importConfig as v, mergeForUpdate as w, parseId as x, platformClientIp as y, readCookie as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PaginatedDocs, I as ID, E as EmailSetting } from './config-
|
|
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-
|
|
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, 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-CcmsrLs8.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-
|
|
26
|
+
} from "./chunk-JZW6G6XI.js";
|
|
27
27
|
import {
|
|
28
28
|
matchesCondition
|
|
29
29
|
} from "./chunk-U266LV4M.js";
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
defineFieldType,
|
|
49
49
|
definePlugin,
|
|
50
50
|
warnDeprecated
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-RTKWMVAC.js";
|
|
52
52
|
export {
|
|
53
53
|
ADAPTER_API_VERSION,
|
|
54
54
|
ADMIN_API_VERSION,
|
package/dist/internal.d.ts
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-CcmsrLs8.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-
|
|
55
|
+
} from "./chunk-JZW6G6XI.js";
|
|
56
56
|
import {
|
|
57
57
|
conditionIssues
|
|
58
58
|
} from "./chunk-U266LV4M.js";
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
rowFields,
|
|
71
71
|
sniffMimeType,
|
|
72
72
|
uniqueWithinOf
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-RTKWMVAC.js";
|
|
74
74
|
|
|
75
75
|
// src/typegen.ts
|
|
76
76
|
var pascal = (name) => name.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -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-
|
|
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-
|
|
2
|
-
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-
|
|
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/dist/plugin.js
CHANGED