@easy-cms/core 1.25.1 → 1.27.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-6CJMRQO4.js → chunk-3RZVRHBO.js} +252 -26
- package/dist/{chunk-RJGKAYUU.js → chunk-SYUQX2G6.js} +30 -1
- package/dist/{config-Bsp6rkuH.d.ts → config-BSIIyNMF.d.ts} +22 -4
- package/dist/{handler-Br9Pu6z9.d.ts → handler-DK6AcW-x.d.ts} +3 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/internal.d.ts +5 -3
- package/dist/internal.js +6 -3
- package/dist/{plugin-CUzEJN31.d.ts → plugin-B0_7iJ4s.d.ts} +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.js +1 -1
- package/package.json +1 -1
|
@@ -19,11 +19,13 @@ import {
|
|
|
19
19
|
UnauthorizedError,
|
|
20
20
|
ValidationError,
|
|
21
21
|
applyFieldTypes,
|
|
22
|
+
errorText,
|
|
22
23
|
expandMimeTypes,
|
|
23
24
|
fieldTypeModules,
|
|
24
25
|
hasRows,
|
|
25
26
|
imageDimensions,
|
|
26
27
|
isHasMany,
|
|
28
|
+
isPassingError,
|
|
27
29
|
isPrivateKey,
|
|
28
30
|
mimeAllowed,
|
|
29
31
|
mimeAllowedBy,
|
|
@@ -36,7 +38,7 @@ import {
|
|
|
36
38
|
warnDeprecated,
|
|
37
39
|
withCharset,
|
|
38
40
|
withPrivacy
|
|
39
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-SYUQX2G6.js";
|
|
40
42
|
|
|
41
43
|
// src/access.ts
|
|
42
44
|
var isSystemAdmin = (user) => user?.role === "admin" && !user.apiKey && user.scoped !== true;
|
|
@@ -2517,6 +2519,32 @@ var ADAPTER_API_VERSION = 1;
|
|
|
2517
2519
|
|
|
2518
2520
|
// src/document.ts
|
|
2519
2521
|
import { randomUUID } from "crypto";
|
|
2522
|
+
|
|
2523
|
+
// src/rich-text-links.ts
|
|
2524
|
+
function docLinkMarks(doc) {
|
|
2525
|
+
const found = [];
|
|
2526
|
+
const walk = (node, depth) => {
|
|
2527
|
+
if (!node || typeof node !== "object" || depth > 200) return;
|
|
2528
|
+
const { marks, content } = node;
|
|
2529
|
+
if (Array.isArray(marks))
|
|
2530
|
+
for (const mark of marks) {
|
|
2531
|
+
const m = mark;
|
|
2532
|
+
const attrs = m?.attrs;
|
|
2533
|
+
if (m?.type === "link" && attrs && attrs.doc !== void 0 && attrs.doc !== null)
|
|
2534
|
+
found.push(m);
|
|
2535
|
+
}
|
|
2536
|
+
if (Array.isArray(content)) for (const child of content) walk(child, depth + 1);
|
|
2537
|
+
};
|
|
2538
|
+
walk(doc, 0);
|
|
2539
|
+
return found;
|
|
2540
|
+
}
|
|
2541
|
+
function linkTarget(doc) {
|
|
2542
|
+
if (!doc || typeof doc !== "object") return void 0;
|
|
2543
|
+
const { relationTo, value } = doc;
|
|
2544
|
+
return typeof relationTo === "string" && relationTo !== "" && value !== void 0 && value !== null ? { relationTo, value } : void 0;
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
// src/document.ts
|
|
2520
2548
|
function isEmail(value) {
|
|
2521
2549
|
const at = value.indexOf("@");
|
|
2522
2550
|
return at > 0 && !value.includes("@", at + 1) && !/\s/.test(value) && value.slice(at + 2, -1).includes(".");
|
|
@@ -2754,10 +2782,26 @@ async function normalizeValue(field, raw, path, options, fail, errors, reference
|
|
|
2754
2782
|
} catch {
|
|
2755
2783
|
return fail("must be JSON-serializable");
|
|
2756
2784
|
}
|
|
2757
|
-
case "richText":
|
|
2785
|
+
case "richText": {
|
|
2758
2786
|
if (!isPlainObject(raw) || raw.type !== "doc")
|
|
2759
2787
|
return fail('must be a rich text document ({ type: "doc" })');
|
|
2760
|
-
|
|
2788
|
+
const marks = docLinkMarks(raw);
|
|
2789
|
+
if (marks.length === 0) return raw;
|
|
2790
|
+
const doc = structuredClone(raw);
|
|
2791
|
+
for (const mark of docLinkMarks(doc)) {
|
|
2792
|
+
const target = linkTarget(mark.attrs.doc);
|
|
2793
|
+
const id = target ? parseId(target.value) : void 0;
|
|
2794
|
+
if (!target || id === void 0)
|
|
2795
|
+
return fail("has a link to a document without { relationTo, value }");
|
|
2796
|
+
mark.attrs = {
|
|
2797
|
+
...mark.attrs,
|
|
2798
|
+
doc: { relationTo: target.relationTo, value: id },
|
|
2799
|
+
href: null
|
|
2800
|
+
};
|
|
2801
|
+
references2.push({ field: path, collection: target.relationTo, id, link: true });
|
|
2802
|
+
}
|
|
2803
|
+
return doc;
|
|
2804
|
+
}
|
|
2761
2805
|
case "upload":
|
|
2762
2806
|
case "relationship": {
|
|
2763
2807
|
const target = field.type === "upload" ? "media" : field.to;
|
|
@@ -3912,12 +3956,12 @@ function inScope(row, scope) {
|
|
|
3912
3956
|
// src/populate.ts
|
|
3913
3957
|
var DEFAULT_DEPTH = 1;
|
|
3914
3958
|
var MAX_DEPTH = 3;
|
|
3915
|
-
async function populate(load, collections, fields, docs, depth) {
|
|
3959
|
+
async function populate(load, collections, fields, docs, depth, linkURL) {
|
|
3916
3960
|
if (depth <= 0 || docs.length === 0) return docs;
|
|
3917
3961
|
const bySlug = new Map(collections.map((c) => [c.slug, c]));
|
|
3918
3962
|
const copies = docs.map((doc) => structuredClone(doc));
|
|
3919
3963
|
const slots = [];
|
|
3920
|
-
for (const doc of copies) collectSlots(fields, doc, bySlug, slots);
|
|
3964
|
+
for (const doc of copies) collectSlots(fields, doc, bySlug, slots, linkURL);
|
|
3921
3965
|
if (slots.length === 0) return copies;
|
|
3922
3966
|
const wanted = /* @__PURE__ */ new Map();
|
|
3923
3967
|
for (const slot of slots) {
|
|
@@ -3931,28 +3975,52 @@ async function populate(load, collections, fields, docs, depth) {
|
|
|
3931
3975
|
const collection2 = bySlug.get(slug2);
|
|
3932
3976
|
if (!collection2) return;
|
|
3933
3977
|
const raw = await load(collection2, [...ids]);
|
|
3934
|
-
const populated = await populate(
|
|
3978
|
+
const populated = await populate(
|
|
3979
|
+
load,
|
|
3980
|
+
collections,
|
|
3981
|
+
collection2.fields,
|
|
3982
|
+
raw,
|
|
3983
|
+
depth - 1,
|
|
3984
|
+
linkURL
|
|
3985
|
+
);
|
|
3935
3986
|
found.set(slug2, new Map(populated.map((d) => [d.id, d])));
|
|
3936
3987
|
})
|
|
3937
3988
|
);
|
|
3938
3989
|
for (const slot of slots) slot.assign(found.get(slot.collection) ?? /* @__PURE__ */ new Map());
|
|
3939
3990
|
return copies;
|
|
3940
3991
|
}
|
|
3941
|
-
function collectSlots(fields, data, bySlug, slots) {
|
|
3992
|
+
function collectSlots(fields, data, bySlug, slots, linkURL) {
|
|
3942
3993
|
for (const field of fields) {
|
|
3943
3994
|
if (field.name === "__proto__") continue;
|
|
3944
3995
|
const value = data[field.name];
|
|
3945
3996
|
if (value === null || value === void 0) continue;
|
|
3946
3997
|
if (field.type === "group") {
|
|
3947
|
-
if (typeof value === "object")
|
|
3998
|
+
if (typeof value === "object")
|
|
3999
|
+
collectSlots(field.fields, value, bySlug, slots, linkURL);
|
|
3948
4000
|
} else if (hasRows(field)) {
|
|
3949
4001
|
if (Array.isArray(value)) {
|
|
3950
4002
|
for (const row of value) {
|
|
3951
4003
|
const fields2 = rowFields(field, row);
|
|
3952
4004
|
if (fields2 && row && typeof row === "object")
|
|
3953
|
-
collectSlots(fields2, row, bySlug, slots);
|
|
4005
|
+
collectSlots(fields2, row, bySlug, slots, linkURL);
|
|
3954
4006
|
}
|
|
3955
4007
|
}
|
|
4008
|
+
} else if (field.type === "richText" && linkURL) {
|
|
4009
|
+
if (value.type !== "doc") continue;
|
|
4010
|
+
for (const mark of docLinkMarks(value)) {
|
|
4011
|
+
const target = linkTarget(mark.attrs.doc);
|
|
4012
|
+
const collection2 = target ? bySlug.get(target.relationTo) : void 0;
|
|
4013
|
+
if (!target || !collection2) continue;
|
|
4014
|
+
const id = target.value;
|
|
4015
|
+
slots.push({
|
|
4016
|
+
collection: target.relationTo,
|
|
4017
|
+
ids: [id],
|
|
4018
|
+
assign: (byId) => {
|
|
4019
|
+
const doc = byId.get(id);
|
|
4020
|
+
mark.attrs = { ...mark.attrs, href: doc ? linkURL(collection2, doc) : null };
|
|
4021
|
+
}
|
|
4022
|
+
});
|
|
4023
|
+
}
|
|
3956
4024
|
} else if (field.type === "relationship" || field.type === "upload") {
|
|
3957
4025
|
if (typeof value === "object" && !Array.isArray(value)) continue;
|
|
3958
4026
|
const collection2 = field.type === "upload" ? "media" : field.to;
|
|
@@ -7309,12 +7377,37 @@ function validateField(field, path, siblings, collectionSlugs, add) {
|
|
|
7309
7377
|
}
|
|
7310
7378
|
}
|
|
7311
7379
|
break;
|
|
7380
|
+
case "ui": {
|
|
7381
|
+
if (!field.admin?.component)
|
|
7382
|
+
add(
|
|
7383
|
+
`${path}.admin.component`,
|
|
7384
|
+
"is required on a ui field",
|
|
7385
|
+
"e.g. { name: 'estimate', type: 'ui', admin: { component: 'acme-estimate' } }"
|
|
7386
|
+
);
|
|
7387
|
+
const stored = [
|
|
7388
|
+
"required",
|
|
7389
|
+
"unique",
|
|
7390
|
+
"uniqueWithin",
|
|
7391
|
+
"index",
|
|
7392
|
+
"defaultValue",
|
|
7393
|
+
"validate",
|
|
7394
|
+
"access",
|
|
7395
|
+
"hidden",
|
|
7396
|
+
"localized"
|
|
7397
|
+
];
|
|
7398
|
+
for (const option of stored)
|
|
7399
|
+
if (field[option] !== void 0)
|
|
7400
|
+
add(`${path}.${option}`, "has no effect on a ui field, which stores nothing");
|
|
7401
|
+
break;
|
|
7402
|
+
}
|
|
7312
7403
|
case "array":
|
|
7313
7404
|
case "group":
|
|
7314
7405
|
if (!Array.isArray(field.fields) || field.fields.length === 0) {
|
|
7315
7406
|
add(`${path}.fields`, "must contain at least one field");
|
|
7316
7407
|
break;
|
|
7317
7408
|
}
|
|
7409
|
+
if (field.fields.every((f) => f?.type === "ui"))
|
|
7410
|
+
add(`${path}.fields`, "must contain a field that stores a value, not only ui fields");
|
|
7318
7411
|
if (field.type === "array")
|
|
7319
7412
|
checkRange(field.minRows, field.maxRows, "minRows", "maxRows", path, add);
|
|
7320
7413
|
validateFields2(field.fields, `${path}.fields`, /* @__PURE__ */ new Set(["id"]), collectionSlugs, add);
|
|
@@ -7734,8 +7827,59 @@ async function resolveConfig(input) {
|
|
|
7734
7827
|
),
|
|
7735
7828
|
fieldTypes: config.fieldTypes ?? []
|
|
7736
7829
|
};
|
|
7737
|
-
|
|
7738
|
-
|
|
7830
|
+
const final = withoutUiFields(result);
|
|
7831
|
+
resolved.add(final);
|
|
7832
|
+
return final;
|
|
7833
|
+
}
|
|
7834
|
+
var ADMIN_FIELDS = /* @__PURE__ */ Symbol("easy-cms.adminFields");
|
|
7835
|
+
function adminFieldsOf(container) {
|
|
7836
|
+
return container[ADMIN_FIELDS] ?? container.fields;
|
|
7837
|
+
}
|
|
7838
|
+
function withoutUiFields(config) {
|
|
7839
|
+
const strip = (fields) => {
|
|
7840
|
+
let changed = false;
|
|
7841
|
+
const admin = [];
|
|
7842
|
+
const data = [];
|
|
7843
|
+
for (const field of fields) {
|
|
7844
|
+
if (field.type === "ui") {
|
|
7845
|
+
changed = true;
|
|
7846
|
+
admin.push(field);
|
|
7847
|
+
continue;
|
|
7848
|
+
}
|
|
7849
|
+
let next = field;
|
|
7850
|
+
if (field.type === "group" || field.type === "array") {
|
|
7851
|
+
const inner = strip(field.fields);
|
|
7852
|
+
if (inner.changed) {
|
|
7853
|
+
changed = true;
|
|
7854
|
+
next = { ...field, fields: inner.data, [ADMIN_FIELDS]: inner.admin };
|
|
7855
|
+
}
|
|
7856
|
+
} else if (field.type === "blocks") {
|
|
7857
|
+
let blocksChanged = false;
|
|
7858
|
+
const blocks = field.blocks.map((block) => {
|
|
7859
|
+
const inner = strip(block.fields);
|
|
7860
|
+
if (!inner.changed) return block;
|
|
7861
|
+
blocksChanged = true;
|
|
7862
|
+
return { ...block, fields: inner.data, [ADMIN_FIELDS]: inner.admin };
|
|
7863
|
+
});
|
|
7864
|
+
if (blocksChanged) {
|
|
7865
|
+
changed = true;
|
|
7866
|
+
next = { ...field, blocks };
|
|
7867
|
+
}
|
|
7868
|
+
}
|
|
7869
|
+
admin.push(next);
|
|
7870
|
+
data.push(next);
|
|
7871
|
+
}
|
|
7872
|
+
return { data, admin, changed };
|
|
7873
|
+
};
|
|
7874
|
+
const apply2 = (container) => {
|
|
7875
|
+
const inner = strip(container.fields);
|
|
7876
|
+
return inner.changed ? { ...container, fields: inner.data, [ADMIN_FIELDS]: inner.admin } : container;
|
|
7877
|
+
};
|
|
7878
|
+
return {
|
|
7879
|
+
...config,
|
|
7880
|
+
collections: config.collections.map(apply2),
|
|
7881
|
+
globals: config.globals.map(apply2)
|
|
7882
|
+
};
|
|
7739
7883
|
}
|
|
7740
7884
|
function usesVersions(config) {
|
|
7741
7885
|
return [...config.collections ?? [], ...config.globals ?? []].some((c) => c.versions);
|
|
@@ -7788,7 +7932,7 @@ function cacheableResponse(request, body, status, headers, times, tags) {
|
|
|
7788
7932
|
}
|
|
7789
7933
|
|
|
7790
7934
|
// src/version.ts
|
|
7791
|
-
var VERSION = true ? "1.
|
|
7935
|
+
var VERSION = true ? "1.27.0" : "0.0.0-dev";
|
|
7792
7936
|
|
|
7793
7937
|
// src/telemetry.ts
|
|
7794
7938
|
var DB_CALLS = /* @__PURE__ */ new Set([
|
|
@@ -9871,7 +10015,7 @@ var EasyCMS = class {
|
|
|
9871
10015
|
if (!claimed) continue;
|
|
9872
10016
|
const parent = String(row.parent);
|
|
9873
10017
|
const action = row.action;
|
|
9874
|
-
|
|
10018
|
+
const run = async () => {
|
|
9875
10019
|
if (parent.startsWith("global:")) {
|
|
9876
10020
|
const { slug: slug2, scope } = splitGlobalKey(parent.slice("global:".length));
|
|
9877
10021
|
if (action === "publish")
|
|
@@ -9888,6 +10032,21 @@ var EasyCMS = class {
|
|
|
9888
10032
|
"unpublish"
|
|
9889
10033
|
);
|
|
9890
10034
|
}
|
|
10035
|
+
};
|
|
10036
|
+
try {
|
|
10037
|
+
for (let attempt = 0; ; attempt++) {
|
|
10038
|
+
try {
|
|
10039
|
+
await run();
|
|
10040
|
+
break;
|
|
10041
|
+
} catch (error) {
|
|
10042
|
+
const wait = SCHEDULED_RETRY_DELAYS[attempt];
|
|
10043
|
+
if (wait === void 0 || !isPassingError(error)) throw error;
|
|
10044
|
+
this.logger.warn(
|
|
10045
|
+
`Scheduled ${action} of ${parent} ${row.doc}: ${errorText(error)}; trying again`
|
|
10046
|
+
);
|
|
10047
|
+
await new Promise((resolve3) => setTimeout(resolve3, wait));
|
|
10048
|
+
}
|
|
10049
|
+
}
|
|
9891
10050
|
await this.db.update({
|
|
9892
10051
|
collection: SCHEDULED_JOBS,
|
|
9893
10052
|
id: row.id,
|
|
@@ -9896,7 +10055,7 @@ var EasyCMS = class {
|
|
|
9896
10055
|
ran++;
|
|
9897
10056
|
} catch (error) {
|
|
9898
10057
|
failed++;
|
|
9899
|
-
const message2 = error
|
|
10058
|
+
const message2 = errorText(error);
|
|
9900
10059
|
this.logger.error(`Scheduled ${action} of ${parent} ${row.doc} failed: ${message2}`, {
|
|
9901
10060
|
error
|
|
9902
10061
|
});
|
|
@@ -9906,7 +10065,7 @@ var EasyCMS = class {
|
|
|
9906
10065
|
data: {
|
|
9907
10066
|
...row,
|
|
9908
10067
|
state: "failed",
|
|
9909
|
-
error: message2
|
|
10068
|
+
error: message2,
|
|
9910
10069
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9911
10070
|
}
|
|
9912
10071
|
});
|
|
@@ -9914,6 +10073,22 @@ var EasyCMS = class {
|
|
|
9914
10073
|
}
|
|
9915
10074
|
return { ran, failed };
|
|
9916
10075
|
}
|
|
10076
|
+
/**
|
|
10077
|
+
* Puts a failed scheduled publish or unpublish back in the queue and runs what is due (#333).
|
|
10078
|
+
* Returns `false` when the job isn't a failed one.
|
|
10079
|
+
*/
|
|
10080
|
+
async retryScheduled(id) {
|
|
10081
|
+
const row = await this.db.findById({ collection: SCHEDULED_JOBS, id });
|
|
10082
|
+
if (!row || row.state !== "failed") return false;
|
|
10083
|
+
const claimed = await this.claim(
|
|
10084
|
+
SCHEDULED_JOBS,
|
|
10085
|
+
row,
|
|
10086
|
+
{ state: "pending", error: null, updatedAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
10087
|
+
{ state: { equals: "failed" } }
|
|
10088
|
+
);
|
|
10089
|
+
if (claimed) await this.runScheduled();
|
|
10090
|
+
return claimed;
|
|
10091
|
+
}
|
|
9917
10092
|
/** Schedules a publish or unpublish, replacing a pending job with the same action. */
|
|
9918
10093
|
async schedule(collection2, id, job, options = {}) {
|
|
9919
10094
|
const { parsed } = await this.scheduleTarget(collection2, id, options);
|
|
@@ -10341,7 +10516,16 @@ var EasyCMS = class {
|
|
|
10341
10516
|
};
|
|
10342
10517
|
const depth = Math.max(0, Math.min(MAX_DEPTH, Math.trunc(options.depth ?? DEFAULT_DEPTH)));
|
|
10343
10518
|
const localized = docs.map((d) => this.pick(config, d, options));
|
|
10344
|
-
const
|
|
10519
|
+
const locale = options.locale && options.locale !== "all" ? options.locale : this.config.localization?.defaultLocale ?? this.config.admin.locale;
|
|
10520
|
+
const linkURL = (target, doc) => target.preview?.({ doc, locale }) ?? null;
|
|
10521
|
+
const populated = await populate(
|
|
10522
|
+
load,
|
|
10523
|
+
this.config.collections,
|
|
10524
|
+
config.fields,
|
|
10525
|
+
localized,
|
|
10526
|
+
depth,
|
|
10527
|
+
linkURL
|
|
10528
|
+
);
|
|
10345
10529
|
return Promise.all(populated.map((d) => finish2(config, d)));
|
|
10346
10530
|
}
|
|
10347
10531
|
/** Creates a document: access, input filtering, hooks, validation, then afterChange. */
|
|
@@ -10882,11 +11066,26 @@ var EasyCMS = class {
|
|
|
10882
11066
|
}
|
|
10883
11067
|
async checkReferences(references2, guard) {
|
|
10884
11068
|
const byCollection = /* @__PURE__ */ new Map();
|
|
11069
|
+
const errors = [];
|
|
10885
11070
|
for (const ref of references2) {
|
|
10886
|
-
|
|
11071
|
+
const target = this.config.collections.find((c) => c.slug === ref.collection);
|
|
11072
|
+
if (ref.link && (!target || INTERNAL_COLLECTIONS.has(ref.collection))) {
|
|
11073
|
+
errors.push({
|
|
11074
|
+
field: ref.field,
|
|
11075
|
+
message: `links to "${ref.collection}", which is not a collection`
|
|
11076
|
+
});
|
|
11077
|
+
continue;
|
|
11078
|
+
}
|
|
11079
|
+
if (ref.link && typeof target?.preview !== "function") {
|
|
11080
|
+
errors.push({
|
|
11081
|
+
field: ref.field,
|
|
11082
|
+
message: `links to "${ref.collection}", whose documents have no URL (set its preview)`
|
|
11083
|
+
});
|
|
11084
|
+
continue;
|
|
11085
|
+
}
|
|
11086
|
+
if (!target) continue;
|
|
10887
11087
|
byCollection.set(ref.collection, [...byCollection.get(ref.collection) ?? [], ref]);
|
|
10888
11088
|
}
|
|
10889
|
-
const errors = [];
|
|
10890
11089
|
for (const [collection2, refs] of byCollection) {
|
|
10891
11090
|
const found = await this.db.findByIds({
|
|
10892
11091
|
collection: collection2,
|
|
@@ -11025,6 +11224,7 @@ function jobSchedule(job, row) {
|
|
|
11025
11224
|
var JOBS_RAN = "easy-cms:jobs-ran";
|
|
11026
11225
|
var LEGACY_JOB_RUNS = "easy-cms:jobs";
|
|
11027
11226
|
var JOB_LEASE = 10 * 6e4;
|
|
11227
|
+
var SCHEDULED_RETRY_DELAYS = [1e3, 3e3];
|
|
11028
11228
|
function durationSeconds(value) {
|
|
11029
11229
|
const match = typeof value === "string" ? /^(\d+)\s*([smhd])$/.exec(value.trim()) : null;
|
|
11030
11230
|
const seconds = typeof value === "number" ? value : match ? Number(match[1]) * { s: 1, m: 60, h: 3600, d: 86400 }[match[2]] : Number.NaN;
|
|
@@ -11162,6 +11362,15 @@ async function retryOutbox(cms, user, id) {
|
|
|
11162
11362
|
if (!await cms.retryOutbox(row.id))
|
|
11163
11363
|
throw new EasyCMSError("Only failed entries can be retried", 409);
|
|
11164
11364
|
}
|
|
11365
|
+
async function retryScheduled(cms, user, id) {
|
|
11366
|
+
if (!isSystemAdmin(user)) throw new ForbiddenError();
|
|
11367
|
+
if (!has(cms.config, SCHEDULED_JOBS)) throw new NotFoundError(SCHEDULED_JOBS, id);
|
|
11368
|
+
const parsed = parseId(id);
|
|
11369
|
+
const row = parsed === void 0 ? null : await cms.db.findById({ collection: SCHEDULED_JOBS, id: parsed });
|
|
11370
|
+
if (!row) throw new NotFoundError(SCHEDULED_JOBS, id);
|
|
11371
|
+
if (!await cms.retryScheduled(row.id))
|
|
11372
|
+
throw new EasyCMSError("Only failed jobs can be retried", 409);
|
|
11373
|
+
}
|
|
11165
11374
|
var TIME_OF_DAY2 = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
11166
11375
|
async function updateJob(cms, user, name, body) {
|
|
11167
11376
|
if (!isSystemAdmin(user)) throw new ForbiddenError();
|
|
@@ -12162,7 +12371,7 @@ async function serializeFields(fields, checks, localized, folderId, who) {
|
|
|
12162
12371
|
case "array":
|
|
12163
12372
|
if (field.minRows !== void 0) f.minRows = field.minRows;
|
|
12164
12373
|
if (field.maxRows !== void 0) f.maxRows = field.maxRows;
|
|
12165
|
-
f.fields = await serializeFields(field
|
|
12374
|
+
f.fields = await serializeFields(adminFieldsOf(field), checks, localized, folderId, who);
|
|
12166
12375
|
break;
|
|
12167
12376
|
case "blocks":
|
|
12168
12377
|
if (field.minRows !== void 0) f.minRows = field.minRows;
|
|
@@ -12171,12 +12380,16 @@ async function serializeFields(fields, checks, localized, folderId, who) {
|
|
|
12171
12380
|
field.blocks.map(async (block) => ({
|
|
12172
12381
|
slug: block.slug,
|
|
12173
12382
|
...block.labels ? { labels: block.labels } : {},
|
|
12174
|
-
fields: await serializeFields(block
|
|
12383
|
+
fields: await serializeFields(adminFieldsOf(block), checks, localized, folderId, who)
|
|
12175
12384
|
}))
|
|
12176
12385
|
);
|
|
12177
12386
|
break;
|
|
12178
12387
|
case "group":
|
|
12179
|
-
f.fields = await serializeFields(field
|
|
12388
|
+
f.fields = await serializeFields(adminFieldsOf(field), checks, localized, folderId, who);
|
|
12389
|
+
break;
|
|
12390
|
+
// A component alone: without a label of its own, none is shown.
|
|
12391
|
+
case "ui":
|
|
12392
|
+
if (field.label === void 0) f.label = "";
|
|
12180
12393
|
break;
|
|
12181
12394
|
}
|
|
12182
12395
|
out.push(f);
|
|
@@ -12196,7 +12409,7 @@ async function may(cms, access, user, target, operation, context) {
|
|
|
12196
12409
|
async function collection(cms, config, user, localized, roles, context) {
|
|
12197
12410
|
const target = { collection: config.slug };
|
|
12198
12411
|
const fields = await serializeFields(
|
|
12199
|
-
config
|
|
12412
|
+
adminFieldsOf(config),
|
|
12200
12413
|
await checkers(cms, user, context),
|
|
12201
12414
|
localized,
|
|
12202
12415
|
folderIds(cms, user, context),
|
|
@@ -12256,10 +12469,16 @@ async function global(cms, config, user, localized, context) {
|
|
|
12256
12469
|
versions: Boolean(config.versions),
|
|
12257
12470
|
preview: typeof config.preview === "function",
|
|
12258
12471
|
schedule: config.schedule === true,
|
|
12259
|
-
fields: await serializeFields(
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12472
|
+
fields: await serializeFields(
|
|
12473
|
+
adminFieldsOf(config),
|
|
12474
|
+
checks,
|
|
12475
|
+
localized,
|
|
12476
|
+
folderIds(cms, user, context),
|
|
12477
|
+
{
|
|
12478
|
+
user,
|
|
12479
|
+
context
|
|
12480
|
+
}
|
|
12481
|
+
),
|
|
12263
12482
|
permissions: {
|
|
12264
12483
|
read: await may(cms, config.access?.read, user, target, "read", context),
|
|
12265
12484
|
update: await may(cms, config.access?.update, user, target, "update", context),
|
|
@@ -13478,6 +13697,13 @@ async function route(cms, ctx, method, path, options) {
|
|
|
13478
13697
|
await cms.audit.record({ action: "jobs.outbox.retry", target: "jobs", detail: { id: id2 } });
|
|
13479
13698
|
return { body: await adminJobs(cms, ctx.user) };
|
|
13480
13699
|
}
|
|
13700
|
+
if (third === "scheduled" && segments.length === 4) {
|
|
13701
|
+
if (method !== "POST") throw methodNotAllowed(ctx, "POST");
|
|
13702
|
+
const id2 = segments[3];
|
|
13703
|
+
await retryScheduled(cms, ctx.user, id2);
|
|
13704
|
+
await cms.audit.record({ action: "jobs.scheduled.retry", target: "jobs", detail: { id: id2 } });
|
|
13705
|
+
return { body: await adminJobs(cms, ctx.user) };
|
|
13706
|
+
}
|
|
13481
13707
|
if (third !== void 0 && segments.length === 3) {
|
|
13482
13708
|
if (method !== "PATCH") throw methodNotAllowed(ctx, "PATCH");
|
|
13483
13709
|
const { action, detail } = await updateJob(
|
|
@@ -103,6 +103,32 @@ var PayloadTooLargeError = class extends EasyCMSError {
|
|
|
103
103
|
this.name = "PayloadTooLargeError";
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
|
+
function errorText(error, max = 500) {
|
|
107
|
+
const parts = [];
|
|
108
|
+
let current = error;
|
|
109
|
+
for (let depth = 0; current && depth < 5; depth++) {
|
|
110
|
+
const message = current instanceof Error ? current.message : typeof current === "string" ? current : "";
|
|
111
|
+
const code = current.code;
|
|
112
|
+
const text2 = [message, typeof code === "string" && !message.includes(code) ? code : ""].filter(Boolean).join(" ");
|
|
113
|
+
if (text2 && !parts.some((p) => p.includes(text2))) parts.push(text2);
|
|
114
|
+
current = current.cause;
|
|
115
|
+
}
|
|
116
|
+
const text = parts.join(" \u2014 ") || String(error);
|
|
117
|
+
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
|
118
|
+
}
|
|
119
|
+
var PASSING = /ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|EAI_AGAIN|ENOTFOUND|fetch failed|socket hang up|network|timed? ?out|SQLITE_BUSY|database is locked|too many (clients|connections)|connection (terminated|closed|reset|refused)|server closed|stream (expired|not found)|\b50[234]\b/i;
|
|
120
|
+
function isPassingError(error) {
|
|
121
|
+
if (error instanceof EasyCMSError) return false;
|
|
122
|
+
let current = error;
|
|
123
|
+
for (let depth = 0; current && depth < 5; depth++) {
|
|
124
|
+
const message = current instanceof Error ? current.message : String(current);
|
|
125
|
+
const code = current.code;
|
|
126
|
+
const checked = message.startsWith("Failed query") ? "" : message;
|
|
127
|
+
if (PASSING.test(checked) || typeof code === "string" && PASSING.test(code)) return true;
|
|
128
|
+
current = current.cause;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
106
132
|
|
|
107
133
|
// src/media.ts
|
|
108
134
|
var EXTENSIONS = {
|
|
@@ -329,7 +355,8 @@ var FIELD_TYPES = [
|
|
|
329
355
|
"relationship",
|
|
330
356
|
"array",
|
|
331
357
|
"group",
|
|
332
|
-
"blocks"
|
|
358
|
+
"blocks",
|
|
359
|
+
"ui"
|
|
333
360
|
];
|
|
334
361
|
|
|
335
362
|
// src/config.ts
|
|
@@ -547,6 +574,8 @@ export {
|
|
|
547
574
|
ForbiddenError,
|
|
548
575
|
TooManyRequestsError,
|
|
549
576
|
PayloadTooLargeError,
|
|
577
|
+
errorText,
|
|
578
|
+
isPassingError,
|
|
550
579
|
EXTENSIONS,
|
|
551
580
|
MIME_GROUPS,
|
|
552
581
|
expandMimeTypes,
|
|
@@ -993,14 +993,24 @@ declare function mimeAllowedBy(mimeType: string, patterns: readonly string[]): b
|
|
|
993
993
|
declare const hasRows: (field: Field) => field is ArrayField | BlocksField;
|
|
994
994
|
/** The fields of one row of an `array` or `blocks` field (`undefined` for an unknown block). */
|
|
995
995
|
declare function rowFields(field: ArrayField | BlocksField, row: unknown): readonly Field[] | undefined;
|
|
996
|
-
|
|
996
|
+
/**
|
|
997
|
+
* Stores nothing: a component in the edit form (`admin.component`), e.g. a calculator, a preview
|
|
998
|
+
* or a button. Placed like any field (layout, groups, conditions); not in the database, the API or
|
|
999
|
+
* the generated types.
|
|
1000
|
+
*/
|
|
1001
|
+
interface UiField extends BaseField<'ui', never> {
|
|
1002
|
+
readonly admin: FieldAdmin & {
|
|
1003
|
+
readonly component: AdminComponent;
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
type Field = CustomField | TextField | TextareaField | NumberField | BooleanField | DateField | EmailField | JsonField | SelectField | SlugField | RichTextField | UploadField | RelationshipField | ArrayField | GroupField | BlocksField | UiField;
|
|
997
1007
|
type FieldType = Field['type'];
|
|
998
1008
|
/**
|
|
999
1009
|
* The shortest `like` on a field with `index: 'trigram'`: trigrams are three characters, so a
|
|
1000
1010
|
* shorter search can't use the index and would read every row.
|
|
1001
1011
|
*/
|
|
1002
1012
|
declare const TRIGRAM_LIKE_MIN = 3;
|
|
1003
|
-
declare const FIELD_TYPES: readonly ["text", "textarea", "number", "boolean", "date", "email", "json", "select", "slug", "richText", "upload", "relationship", "array", "group", "blocks"];
|
|
1013
|
+
declare const FIELD_TYPES: readonly ["text", "textarea", "number", "boolean", "date", "email", "json", "select", "slug", "richText", "upload", "relationship", "array", "group", "blocks", "ui"];
|
|
1004
1014
|
|
|
1005
1015
|
type Simplify<T> = {
|
|
1006
1016
|
[K in keyof T]: T[K];
|
|
@@ -1259,8 +1269,11 @@ type BlockInput<B> = B extends {
|
|
|
1259
1269
|
id?: string;
|
|
1260
1270
|
blockType: S;
|
|
1261
1271
|
}> : never;
|
|
1272
|
+
/** The fields with a value: not `hidden`, and not `ui` fields (which store nothing). */
|
|
1262
1273
|
type Visible<Fs extends readonly Field[]> = Exclude<Fs[number], {
|
|
1263
1274
|
readonly hidden: true;
|
|
1275
|
+
} | {
|
|
1276
|
+
readonly type: 'ui';
|
|
1264
1277
|
}>;
|
|
1265
1278
|
/** Always set when read: required fields, and lists and groups (empty `[]` / `{}` otherwise). */
|
|
1266
1279
|
type Present = {
|
|
@@ -2237,6 +2250,11 @@ declare class EasyCMS<C extends Config = Config> {
|
|
|
2237
2250
|
ran: number;
|
|
2238
2251
|
failed: number;
|
|
2239
2252
|
}>;
|
|
2253
|
+
/**
|
|
2254
|
+
* Puts a failed scheduled publish or unpublish back in the queue and runs what is due (#333).
|
|
2255
|
+
* Returns `false` when the job isn't a failed one.
|
|
2256
|
+
*/
|
|
2257
|
+
retryScheduled(id: ID): Promise<boolean>;
|
|
2240
2258
|
/** Schedules a publish or unpublish, replacing a pending job with the same action. */
|
|
2241
2259
|
schedule<S extends Slug<C>>(collection: S, id: ID, job: {
|
|
2242
2260
|
action: 'publish' | 'unpublish';
|
|
@@ -3803,5 +3821,5 @@ interface ResolvedConfig extends Omit<Config, 'cors' | 'localization' | 'routes'
|
|
|
3803
3821
|
*/
|
|
3804
3822
|
declare function defineConfig<const TConfig extends Config>(config: TConfig): TConfig;
|
|
3805
3823
|
|
|
3806
|
-
export { ADAPTER_API_VERSION as A, EasyCMS as E, AuditLog as S, Auth as V, EasyCMSError as aE, FIELD_TYPES as aL, ConfigError as am, SchemaError as b$, ForbiddenError as b3, PLUGIN_API_VERSION as bC, PayloadTooLargeError as bH, QueryError as bN, ROLE_OPERATIONS as bO, Roles as bY, NotFoundError as bw,
|
|
3807
|
-
export type { AuthUser as $, AfterDeleteHook as B, Config as C, AfterReadHook as D, Field as F, ApiKeyContext as G, ApiKeyGlobalOperation as H, ID as I, ApiKeyOperation as J, ApiKeyPermissions as K, LocalizationConfig as L, ArrayField as M, AuditChange as N, AuditConfig as O, PaginatedDocs as P, AuditEntry as Q, ResolvedConfig as R, AuditPage as T, AuditVerification as U, WebhookPayload as W, AuthConfig as X, AuthProvider as Y, AuthProviderProfile as Z, AuthProviderRequest as _, FieldError as a, FindArgs as a$, BackupsConfig as a0, BeforeChangeHook as a1, BeforeDeleteHook as a2, BeforeValidateHook as a3, Block as a4, BlocksField as a5, BooleanField as a6, BuiltinApiKeysCollection as a7, BuiltinMediaCollection as a8, BuiltinMediaFoldersCollection as a9, DepthOptions as aA, DirectUpload as aB, DiskStorageOptions as aC, DocumentOf as aD, EmailAdapter as aF, EmailField as aG, EmailMessage as aH, Endpoint as aI, EndpointRequest as aJ, ErrorCode as aK, FieldAccess as aM, FieldAccessFn as aN, FieldAdmin as aO, FieldRule as aP, FieldType as aQ, FieldTypeBase as aR, FieldTypeDefinition as aS, FieldTypeValidateContext as aT, FieldValidate as aU, FieldValidateContext as aV, FieldValue as aW, FieldsInput as aX, FieldsValue as aY, FilterOptionsArgs as aZ, FindAfterArgs as a_, BuiltinUsersCollection as aa, BundleHints as ab, CliCommand as ac, CollectionAccess as ad, CollectionAdmin as ae, CollectionCalendarAdmin as af, CollectionConfig as ag, CollectionDocument as ah, CollectionHooks as ai, CollectionListAdmin as aj, CollectionSearch as ak, CollectionSlug as al, ConfigIssue as an, ContainerAdmin as ao, CreateInput as ap, CreateMigrationResult as aq, CursorDocs as ar, CustomField as as, CustomFieldTypes as at, DashboardWidget as au, Database as av, DatabaseAdapter as aw, DatabaseInitArgs as ax, DatabaseTransfer as ay, DateField as az, FilterOptions as b, FindOptions as b0, FolderLevel as b1, FolderPermissions as b2, GlobalAccess as b4, GlobalConfig as b5, GlobalDocument as b6, GlobalHooks as b7, GlobalInput as b8, GlobalSlug as b9, Operation as bA, OutboxRow as bB, PasswordEmail as bD, PasswordEmailArgs as bE, PasswordEmailFn as bF, PasswordLinkOptions as bG, Plugin as bI, PluginInfo as bJ, PluginTypes as bK, PreviewTarget as bL, PreviewURL as bM, RawDocument as bP, ReadOptions as bQ, RelationshipField as bR, RequestContext as bS, RichTextDocument as bT, RichTextField as bU, Role as bV, RoleOperation as bW, RolePermissions as bX, RoutesConfig as bZ, ScheduledPublish as b_, GroupField as ba, ImageSize as bb, IncrementOptions as bc, InferCollection as bd, InferGlobal as be, JobConfig as bf, JsonField as bg, KeysetPage as bh, Label as bi, LayoutNode as bj, LivePreview as bk, LocaleOf as bl, LogDetails as bm, Logger as bn, LoginArgs as bo, LogsConfig as bp, MediaDocument as bq, MediaSize as br, MembersConfig as bs, MembersSignup as bt, MigrationInfo as bu, NavGroup as bv, NumberField as bx, OnRequest as by, OnRequestArgs as bz, CreateEasyCMSOptions as c, SchemaMode as c0, SearchAdapter as c1, SearchEntry as c2, SearchHits as c3, SearchOptions as c4, SearchQuery as c5, SearchResults as c6, SearchSetting as c7, SelectField as c8, SelectOption as c9, Version as
|
|
3824
|
+
export { ADAPTER_API_VERSION as A, EasyCMS as E, AuditLog as S, Auth as V, EasyCMSError as aE, FIELD_TYPES as aL, ConfigError as am, SchemaError as b$, ForbiddenError as b3, PLUGIN_API_VERSION as bC, PayloadTooLargeError as bH, QueryError as bN, ROLE_OPERATIONS as bO, Roles as bY, NotFoundError as bw, silentLogger as c$, ValidationError as cA, WEBHOOK_EVENTS as cE, anyone as cJ, consoleEmail as cK, consoleLogger as cL, createEasyCMS as cM, defineConfig as cN, defineFieldType as cO, definePlugin as cP, diskStorage as cQ, hasRows as cR, isAdmin as cS, isHasMany as cT, isSignedIn as cU, isStaff as cV, isSystemAdmin as cW, jsonLogger as cX, memorySearch as cY, mimeAllowedBy as cZ, rowFields as c_, SingleSignOn as ce, TRIGRAM_LIKE_MIN as cl, TooManyRequestsError as cp, UnauthorizedError as cs, uniqueWithinOf as d0, API_KEYS as d1, API_KEY_GLOBAL_OPERATIONS as d2, API_KEY_OPERATIONS as d3, DEFAULT_MAX_VERSIONS as d4, DEFAULT_PASSWORD_EMAILS as d5, FIELD_TYPE_BASES as d6, FOLDER_LEVELS as d7, MediaFolders as d8, SSO_COOKIE as d9, codeOfStatus as db, isJsonLogger as dc, keyAllows as dd, logFormat as de, secretsOf as df, ADMIN_ICONS as e };
|
|
3825
|
+
export type { AuthUser as $, AfterDeleteHook as B, Config as C, AfterReadHook as D, Field as F, ApiKeyContext as G, ApiKeyGlobalOperation as H, ID as I, ApiKeyOperation as J, ApiKeyPermissions as K, LocalizationConfig as L, ArrayField as M, AuditChange as N, AuditConfig as O, PaginatedDocs as P, AuditEntry as Q, ResolvedConfig as R, AuditPage as T, AuditVerification as U, WebhookPayload as W, AuthConfig as X, AuthProvider as Y, AuthProviderProfile as Z, AuthProviderRequest as _, FieldError as a, FindArgs as a$, BackupsConfig as a0, BeforeChangeHook as a1, BeforeDeleteHook as a2, BeforeValidateHook as a3, Block as a4, BlocksField as a5, BooleanField as a6, BuiltinApiKeysCollection as a7, BuiltinMediaCollection as a8, BuiltinMediaFoldersCollection as a9, DepthOptions as aA, DirectUpload as aB, DiskStorageOptions as aC, DocumentOf as aD, EmailAdapter as aF, EmailField as aG, EmailMessage as aH, Endpoint as aI, EndpointRequest as aJ, ErrorCode as aK, FieldAccess as aM, FieldAccessFn as aN, FieldAdmin as aO, FieldRule as aP, FieldType as aQ, FieldTypeBase as aR, FieldTypeDefinition as aS, FieldTypeValidateContext as aT, FieldValidate as aU, FieldValidateContext as aV, FieldValue as aW, FieldsInput as aX, FieldsValue as aY, FilterOptionsArgs as aZ, FindAfterArgs as a_, BuiltinUsersCollection as aa, BundleHints as ab, CliCommand as ac, CollectionAccess as ad, CollectionAdmin as ae, CollectionCalendarAdmin as af, CollectionConfig as ag, CollectionDocument as ah, CollectionHooks as ai, CollectionListAdmin as aj, CollectionSearch as ak, CollectionSlug as al, ConfigIssue as an, ContainerAdmin as ao, CreateInput as ap, CreateMigrationResult as aq, CursorDocs as ar, CustomField as as, CustomFieldTypes as at, DashboardWidget as au, Database as av, DatabaseAdapter as aw, DatabaseInitArgs as ax, DatabaseTransfer as ay, DateField as az, FilterOptions as b, FindOptions as b0, FolderLevel as b1, FolderPermissions as b2, GlobalAccess as b4, GlobalConfig as b5, GlobalDocument as b6, GlobalHooks as b7, GlobalInput as b8, GlobalSlug as b9, Operation as bA, OutboxRow as bB, PasswordEmail as bD, PasswordEmailArgs as bE, PasswordEmailFn as bF, PasswordLinkOptions as bG, Plugin as bI, PluginInfo as bJ, PluginTypes as bK, PreviewTarget as bL, PreviewURL as bM, RawDocument as bP, ReadOptions as bQ, RelationshipField as bR, RequestContext as bS, RichTextDocument as bT, RichTextField as bU, Role as bV, RoleOperation as bW, RolePermissions as bX, RoutesConfig as bZ, ScheduledPublish as b_, GroupField as ba, ImageSize as bb, IncrementOptions as bc, InferCollection as bd, InferGlobal as be, JobConfig as bf, JsonField as bg, KeysetPage as bh, Label as bi, LayoutNode as bj, LivePreview as bk, LocaleOf as bl, LogDetails as bm, Logger as bn, LoginArgs as bo, LogsConfig as bp, MediaDocument as bq, MediaSize as br, MembersConfig as bs, MembersSignup as bt, MigrationInfo as bu, NavGroup as bv, NumberField as bx, OnRequest as by, OnRequestArgs as bz, CreateEasyCMSOptions as c, SchemaMode as c0, SearchAdapter as c1, SearchEntry as c2, SearchHits as c3, SearchOptions as c4, SearchQuery as c5, SearchResults as c6, SearchSetting as c7, SelectField as c8, SelectOption as c9, Version as cB, VersionSummary as cC, VersionsConfig as cD, WebhookConfig as cF, WebhookEvent as cG, Where as cH, WhereOperators as cI, Session as ca, SidebarPanel as cb, SignupArgs as cc, SignupResult as cd, SlugField as cf, SlugOf as cg, SsoOutcome as ch, SsoProviderRef as ci, StorageAdapter as cj, StoredFile as ck, TelemetryConfig as cm, TextField as cn, TextareaField as co, TypedPlugin as cq, UiField as cr, UncountedDocs as ct, UpdateInput as cu, UpdateOptions as cv, UploadConfig as cw, UploadField as cx, UploadFromURLConfig as cy, UserIdentity as cz, EmailSetting as d, Secrets as da, Access as f, AccessArgs as g, AccessOptions as h, AdminBrand as i, AdminCommand as j, AdminComponent as k, AdminConfig as l, AdminFieldArgs as m, AdminIcon as n, AdminLocale as o, AdminPage as p, AdminRole as q, AdminRoleChange as r, AdminRoleField as s, AdminRoleTarget as t, AdminRoleView as u, AdminRoles as v, AdminSso as w, AdminSwitcher as x, AdminViewAccess as y, AfterChangeHook as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as ID, C as Config, E as EasyCMS, L as LocalizationConfig, F as Field, a as FieldError, b as FilterOptions, c as CreateEasyCMSOptions, R as ResolvedConfig } from './config-
|
|
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-BSIIyNMF.js';
|
|
2
2
|
|
|
3
3
|
/** Decrypts a file from `encryptBackup`; throws for another key or a changed file. */
|
|
4
4
|
declare function decryptBackup(data: Uint8Array, encryptionKey: string): Uint8Array;
|
|
@@ -79,6 +79,8 @@ interface Reference {
|
|
|
79
79
|
readonly mimeTypes?: readonly string[];
|
|
80
80
|
/** The upload's `folder` with `folderOnly`: the file must be in it, checked when saving. */
|
|
81
81
|
readonly folderOnly?: string;
|
|
82
|
+
/** A link in rich text (#326): its collection must exist and have a URL (`preview`). */
|
|
83
|
+
readonly link?: true;
|
|
82
84
|
}
|
|
83
85
|
interface ValidateOptions {
|
|
84
86
|
readonly operation: 'create' | 'update';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-
|
|
2
|
-
export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as CollectionCalendarAdmin, ag as CollectionConfig, ah as CollectionDocument, ai as CollectionHooks, aj as CollectionListAdmin, ak as CollectionSearch, al as CollectionSlug, C as Config, am as ConfigError, an as ConfigIssue, ao as ContainerAdmin, c as CreateEasyCMSOptions, ap as CreateInput, aq as CreateMigrationResult, ar as CursorDocs, as as CustomField, at as CustomFieldTypes, au as DashboardWidget, av as Database, aw as DatabaseAdapter, ax as DatabaseInitArgs, ay as DatabaseTransfer, az as DateField, aA as DepthOptions, aB as DirectUpload, aC as DiskStorageOptions, aD as DocumentOf, E as EasyCMS, aE as EasyCMSError, aF as EmailAdapter, aG as EmailField, aH as EmailMessage, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, aL as FIELD_TYPES, F as Field, aM as FieldAccess, aN as FieldAccessFn, aO as FieldAdmin, a as FieldError, aP as FieldRule, aQ as FieldType, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, aU as FieldValidate, aV as FieldValidateContext, aW as FieldValue, aX as FieldsInput, aY as FieldsValue, b as FilterOptions, aZ as FilterOptionsArgs, a_ as FindAfterArgs, a$ as FindArgs, b0 as FindOptions, b1 as FolderLevel, b2 as FolderPermissions, b3 as ForbiddenError, b4 as GlobalAccess, b5 as GlobalConfig, b6 as GlobalDocument, b7 as GlobalHooks, b8 as GlobalInput, b9 as GlobalSlug, ba as GroupField, bb as ImageSize, bc as IncrementOptions, bd as InferCollection, be as InferGlobal, bf as JobConfig, bg as JsonField, bh as KeysetPage, bi as Label, bj as LayoutNode, bk as LivePreview, bl as LocaleOf, L as LocalizationConfig, bm as LogDetails, bn as Logger, bo as LoginArgs, bp as LogsConfig, bq as MediaDocument, br as MediaSize, bs as MembersConfig, bt as MembersSignup, bu as MigrationInfo, bv as NavGroup, bw as NotFoundError, bx as NumberField, by as OnRequest, bz as OnRequestArgs, bA as Operation, bB as OutboxRow, bC as PLUGIN_API_VERSION, bD as PasswordEmail, bE as PasswordEmailArgs, bF as PasswordEmailFn, bG as PasswordLinkOptions, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bL as PreviewTarget, bM as PreviewURL, bN as QueryError, bO as ROLE_OPERATIONS, bP as RawDocument, bQ as ReadOptions, bR as RelationshipField, bS as RequestContext, R as ResolvedConfig, bT as RichTextDocument, bU as RichTextField, bV as Role, bW as RoleOperation, bX as RolePermissions, bY as Roles, bZ as RoutesConfig, b_ as ScheduledPublish, b$ as SchemaError, c0 as SchemaMode, c1 as SearchAdapter, c2 as SearchEntry, c3 as SearchHits, c4 as SearchOptions, c5 as SearchQuery, c6 as SearchResults, c7 as SearchSetting, c8 as SelectField, c9 as SelectOption, ca as Session, cb as SidebarPanel, cc as SignupArgs, cd as SignupResult, ce as SingleSignOn, cf as SlugField, cg as SlugOf, ch as SsoOutcome, ci as SsoProviderRef, cj as StorageAdapter, ck as StoredFile, cl as TRIGRAM_LIKE_MIN, cm as TelemetryConfig, cn as TextField, co as TextareaField, cp as TooManyRequestsError, cq as TypedPlugin, cr as
|
|
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-BSIIyNMF.js';
|
|
2
|
+
export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as CollectionCalendarAdmin, ag as CollectionConfig, ah as CollectionDocument, ai as CollectionHooks, aj as CollectionListAdmin, ak as CollectionSearch, al as CollectionSlug, C as Config, am as ConfigError, an as ConfigIssue, ao as ContainerAdmin, c as CreateEasyCMSOptions, ap as CreateInput, aq as CreateMigrationResult, ar as CursorDocs, as as CustomField, at as CustomFieldTypes, au as DashboardWidget, av as Database, aw as DatabaseAdapter, ax as DatabaseInitArgs, ay as DatabaseTransfer, az as DateField, aA as DepthOptions, aB as DirectUpload, aC as DiskStorageOptions, aD as DocumentOf, E as EasyCMS, aE as EasyCMSError, aF as EmailAdapter, aG as EmailField, aH as EmailMessage, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, aL as FIELD_TYPES, F as Field, aM as FieldAccess, aN as FieldAccessFn, aO as FieldAdmin, a as FieldError, aP as FieldRule, aQ as FieldType, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, aU as FieldValidate, aV as FieldValidateContext, aW as FieldValue, aX as FieldsInput, aY as FieldsValue, b as FilterOptions, aZ as FilterOptionsArgs, a_ as FindAfterArgs, a$ as FindArgs, b0 as FindOptions, b1 as FolderLevel, b2 as FolderPermissions, b3 as ForbiddenError, b4 as GlobalAccess, b5 as GlobalConfig, b6 as GlobalDocument, b7 as GlobalHooks, b8 as GlobalInput, b9 as GlobalSlug, ba as GroupField, bb as ImageSize, bc as IncrementOptions, bd as InferCollection, be as InferGlobal, bf as JobConfig, bg as JsonField, bh as KeysetPage, bi as Label, bj as LayoutNode, bk as LivePreview, bl as LocaleOf, L as LocalizationConfig, bm as LogDetails, bn as Logger, bo as LoginArgs, bp as LogsConfig, bq as MediaDocument, br as MediaSize, bs as MembersConfig, bt as MembersSignup, bu as MigrationInfo, bv as NavGroup, bw as NotFoundError, bx as NumberField, by as OnRequest, bz as OnRequestArgs, bA as Operation, bB as OutboxRow, bC as PLUGIN_API_VERSION, bD as PasswordEmail, bE as PasswordEmailArgs, bF as PasswordEmailFn, bG as PasswordLinkOptions, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bL as PreviewTarget, bM as PreviewURL, bN as QueryError, bO as ROLE_OPERATIONS, bP as RawDocument, bQ as ReadOptions, bR as RelationshipField, bS as RequestContext, R as ResolvedConfig, bT as RichTextDocument, bU as RichTextField, bV as Role, bW as RoleOperation, bX as RolePermissions, bY as Roles, bZ as RoutesConfig, b_ as ScheduledPublish, b$ as SchemaError, c0 as SchemaMode, c1 as SearchAdapter, c2 as SearchEntry, c3 as SearchHits, c4 as SearchOptions, c5 as SearchQuery, c6 as SearchResults, c7 as SearchSetting, c8 as SelectField, c9 as SelectOption, ca as Session, cb as SidebarPanel, cc as SignupArgs, cd as SignupResult, ce as SingleSignOn, cf as SlugField, cg as SlugOf, ch as SsoOutcome, ci as SsoProviderRef, cj as StorageAdapter, ck as StoredFile, cl as TRIGRAM_LIKE_MIN, cm as TelemetryConfig, cn as TextField, co as TextareaField, cp as TooManyRequestsError, cq as TypedPlugin, cr as UiField, cs as UnauthorizedError, ct as UncountedDocs, cu as UpdateInput, cv as UpdateOptions, cw as UploadConfig, cx as UploadField, cy as UploadFromURLConfig, cz as UserIdentity, cA as ValidationError, cB as Version, cC as VersionSummary, cD as VersionsConfig, cE as WEBHOOK_EVENTS, cF as WebhookConfig, cG as WebhookEvent, cH as Where, cI as WhereOperators, cJ as anyone, cK as consoleEmail, cL as consoleLogger, cM as createEasyCMS, cN as defineConfig, cO as defineFieldType, cP as definePlugin, cQ as diskStorage, cR as hasRows, cS as isAdmin, cT as isHasMany, cU as isSignedIn, cV as isStaff, cW as isSystemAdmin, cX as jsonLogger, cY as memorySearch, cZ as mimeAllowedBy, c_ as rowFields, c$ as silentLogger, d0 as uniqueWithinOf } from './config-BSIIyNMF.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-B0_7iJ4s.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-DK6AcW-x.js';
|
|
5
5
|
export { FieldCondition, matchesCondition } from './conditions.js';
|
|
6
6
|
|
|
7
7
|
type DeliveryKind = 'webhook' | 'email';
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
silentLogger,
|
|
29
29
|
slugify,
|
|
30
30
|
verifyWebhook
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-3RZVRHBO.js";
|
|
32
32
|
import {
|
|
33
33
|
matchesCondition
|
|
34
34
|
} from "./chunk-U266LV4M.js";
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
defineFieldType,
|
|
54
54
|
definePlugin,
|
|
55
55
|
warnDeprecated
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-SYUQX2G6.js";
|
|
57
57
|
export {
|
|
58
58
|
ADAPTER_API_VERSION,
|
|
59
59
|
ADMIN_API_VERSION,
|
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 {
|
|
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 { d1 as API_KEYS, d2 as API_KEY_GLOBAL_OPERATIONS, d3 as API_KEY_OPERATIONS, d4 as DEFAULT_MAX_VERSIONS, d5 as DEFAULT_PASSWORD_EMAILS, d6 as FIELD_TYPE_BASES, d7 as FOLDER_LEVELS, d8 as MediaFolders, d9 as SSO_COOKIE, da as Secrets, cl as TRIGRAM_LIKE_MIN, db as codeOfStatus, cR as hasRows, cT as isHasMany, dc as isJsonLogger, dd as keyAllows, de as logFormat, cZ as mimeAllowedBy, c_ as rowFields, df as secretsOf, d0 as uniqueWithinOf } from './config-BSIIyNMF.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-DK6AcW-x.js';
|
|
4
4
|
export { conditionIssues } from './conditions.js';
|
|
5
5
|
|
|
6
6
|
/** The session cookie the REST API sets at login. */
|
|
@@ -92,12 +92,14 @@ declare const DEFAULT_DEPTH = 1;
|
|
|
92
92
|
declare const MAX_DEPTH = 3;
|
|
93
93
|
/** Loads the documents of one collection that the caller may see. */
|
|
94
94
|
type Loader = (collection: CollectionConfig, ids: readonly ID[]) => Promise<RawDocument[]>;
|
|
95
|
+
/** A linked document's URL, for links in rich text (#326); `null` when it has none. */
|
|
96
|
+
type LinkURL = (collection: CollectionConfig, doc: RawDocument) => string | null;
|
|
95
97
|
/**
|
|
96
98
|
* Replaces relationship and upload ids with documents, `depth` levels deep.
|
|
97
99
|
* Missing (or unreadable) documents become `null` (single) or are dropped (hasMany).
|
|
98
100
|
* Returns new objects; the input is not modified.
|
|
99
101
|
*/
|
|
100
|
-
declare function populate(load: Loader, collections: readonly CollectionConfig[], fields: readonly Field[], docs: RawDocument[], depth: number): Promise<RawDocument[]>;
|
|
102
|
+
declare function populate(load: Loader, collections: readonly CollectionConfig[], fields: readonly Field[], docs: RawDocument[], depth: number, linkURL?: LinkURL): Promise<RawDocument[]>;
|
|
101
103
|
|
|
102
104
|
/**
|
|
103
105
|
* Finds the file of an admin module (`admin.modules`): a package export or a path relative to
|
package/dist/internal.js
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
verifyPassword,
|
|
59
59
|
verifyTurnstile,
|
|
60
60
|
writeBackupFile
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-3RZVRHBO.js";
|
|
62
62
|
import {
|
|
63
63
|
conditionIssues
|
|
64
64
|
} from "./chunk-U266LV4M.js";
|
|
@@ -77,7 +77,7 @@ import {
|
|
|
77
77
|
rowFields,
|
|
78
78
|
sniffMimeType,
|
|
79
79
|
uniqueWithinOf
|
|
80
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-SYUQX2G6.js";
|
|
81
81
|
|
|
82
82
|
// src/typegen.ts
|
|
83
83
|
var pascal = (name) => name.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -160,12 +160,15 @@ ${indent}}`
|
|
|
160
160
|
);
|
|
161
161
|
return `(${kinds.join(" | ")})[]`;
|
|
162
162
|
}
|
|
163
|
+
// Stores nothing (and is gone from a resolved config).
|
|
164
|
+
case "ui":
|
|
165
|
+
return "never";
|
|
163
166
|
}
|
|
164
167
|
}
|
|
165
168
|
function fieldLines(fields, n, indent) {
|
|
166
169
|
const lines = [];
|
|
167
170
|
for (const field of fields) {
|
|
168
|
-
if (field.hidden) continue;
|
|
171
|
+
if (field.hidden || field.type === "ui") continue;
|
|
169
172
|
const type = fieldType(field, n, indent);
|
|
170
173
|
const alwaysPresent = field.type === "array" || field.type === "blocks" || field.type === "group" || isHasMany(field);
|
|
171
174
|
if (field.required || alwaysPresent) lines.push(`${indent}${key(field.name)}: ${type}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bi as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ci as SsoProviderRef } from './config-
|
|
1
|
+
import { bi as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ci as SsoProviderRef } from './config-BSIIyNMF.js';
|
|
2
2
|
import { FieldCondition } from './conditions.js';
|
|
3
3
|
|
|
4
4
|
/** A Web Component from an admin module, with its `props` (plain JSON). */
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, ag as CollectionConfig, C as Config, am as ConfigError, au as DashboardWidget, aE as EasyCMSError, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, F as Field, aM as FieldAccess, a as FieldError, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, b3 as ForbiddenError, b5 as GlobalConfig, I as ID, bf as JobConfig, bi as Label, bv as NavGroup, bw as NotFoundError, by as OnRequest, bz as OnRequestArgs, bC as PLUGIN_API_VERSION, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bN as QueryError, bS as RequestContext, cp as TooManyRequestsError, cq as TypedPlugin,
|
|
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, ag as CollectionConfig, C as Config, am as ConfigError, au as DashboardWidget, aE as EasyCMSError, aI as Endpoint, aJ as EndpointRequest, aK as ErrorCode, F as Field, aM as FieldAccess, a as FieldError, aR as FieldTypeBase, aS as FieldTypeDefinition, aT as FieldTypeValidateContext, b3 as ForbiddenError, b5 as GlobalConfig, I as ID, bf as JobConfig, bi as Label, bv as NavGroup, bw as NotFoundError, by as OnRequest, bz as OnRequestArgs, bC as PLUGIN_API_VERSION, bH as PayloadTooLargeError, bI as Plugin, bJ as PluginInfo, bK as PluginTypes, bN as QueryError, bS as RequestContext, cp as TooManyRequestsError, cq as TypedPlugin, cs as UnauthorizedError, cA as ValidationError, cH as Where, cO as defineFieldType, cP as definePlugin } from './config-BSIIyNMF.js';
|
|
2
|
+
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-B0_7iJ4s.js';
|
|
3
3
|
import './conditions.js';
|
package/dist/plugin.js
CHANGED