@easy-cms/core 1.1.0 → 1.3.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-SGAAJMGL.js → chunk-4NRYIE5Z.js} +227 -26
- package/dist/{config-BK8lrNcJ.d.ts → config-BhTVeJg4.d.ts} +18 -3
- package/dist/{handler-Bx_3ilqI.d.ts → handler-D7FaZRW-.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +1 -1
- package/dist/{plugin-aVtmn8t4.d.ts → plugin-dt85uDgT.d.ts} +1 -1
- package/dist/plugin.d.ts +2 -2
- package/package.json +1 -1
|
@@ -55,6 +55,7 @@ var SCHEDULED_JOBS = "scheduled-jobs";
|
|
|
55
55
|
var WEBHOOK_DELIVERIES = "webhook-deliveries";
|
|
56
56
|
var EMAIL_DELIVERIES = "email-deliveries";
|
|
57
57
|
var DATABASE_BACKUPS = "database-backups";
|
|
58
|
+
var JOB_RUNS = "job-runs";
|
|
58
59
|
var ROLES = "user-roles";
|
|
59
60
|
var USER_IDENTITIES = "user-identities";
|
|
60
61
|
var AUDIT_LOGS = "audit-logs";
|
|
@@ -66,6 +67,7 @@ var INTERNAL_COLLECTIONS = /* @__PURE__ */ new Set([
|
|
|
66
67
|
WEBHOOK_DELIVERIES,
|
|
67
68
|
EMAIL_DELIVERIES,
|
|
68
69
|
DATABASE_BACKUPS,
|
|
70
|
+
JOB_RUNS,
|
|
69
71
|
ROLES,
|
|
70
72
|
USER_IDENTITIES,
|
|
71
73
|
AUDIT_LOGS
|
|
@@ -497,6 +499,26 @@ var auditLogsCollection = {
|
|
|
497
499
|
{ name: "scope", type: "text", index: true }
|
|
498
500
|
]
|
|
499
501
|
};
|
|
502
|
+
var jobRunsCollection = {
|
|
503
|
+
slug: JOB_RUNS,
|
|
504
|
+
access: { read: nobody, create: nobody, update: nobody, delete: nobody },
|
|
505
|
+
fields: [
|
|
506
|
+
{ name: "name", type: "text", required: true, unique: true },
|
|
507
|
+
{ name: "lastRunAt", type: "text", required: true },
|
|
508
|
+
// running | ok | failed; empty until it first runs here.
|
|
509
|
+
{ name: "lastStatus", type: "text" },
|
|
510
|
+
{ name: "lastError", type: "text" },
|
|
511
|
+
{ name: "lastDurationMs", type: "number" },
|
|
512
|
+
// Set from Settings → Jobs by an admin: paused, or a schedule in place of the code's (only
|
|
513
|
+
// for jobs with `adminSchedule`). Empty: as the code says.
|
|
514
|
+
{ name: "pausedAt", type: "text" },
|
|
515
|
+
{ name: "pausedBy", type: "text" },
|
|
516
|
+
{ name: "everyOverride", type: "number" },
|
|
517
|
+
{ name: "atOverride", type: "text" },
|
|
518
|
+
{ name: "changedBy", type: "text" },
|
|
519
|
+
{ name: "changedAt", type: "text" }
|
|
520
|
+
]
|
|
521
|
+
};
|
|
500
522
|
var emailDeliveriesCollection = {
|
|
501
523
|
slug: EMAIL_DELIVERIES,
|
|
502
524
|
access: { read: nobody, create: nobody, update: nobody, delete: nobody },
|
|
@@ -2671,7 +2693,12 @@ var Mailer = class {
|
|
|
2671
2693
|
let failed = 0;
|
|
2672
2694
|
for (const { id, ...queued } of await this.queue.due(now, 50)) {
|
|
2673
2695
|
const attempts = queued.attempts + 1;
|
|
2674
|
-
await this.queue.
|
|
2696
|
+
const claimed = await this.queue.claim(id, queued, {
|
|
2697
|
+
...queued,
|
|
2698
|
+
attempts,
|
|
2699
|
+
nextAttemptAt: later(now, CLAIM)
|
|
2700
|
+
});
|
|
2701
|
+
if (!claimed) continue;
|
|
2675
2702
|
const error = await this.attempt(JSON.parse(queued.message));
|
|
2676
2703
|
if (!error) {
|
|
2677
2704
|
await this.queue.remove(id);
|
|
@@ -3015,7 +3042,16 @@ async function startBackup(cms, trigger, author) {
|
|
|
3015
3042
|
}
|
|
3016
3043
|
async function runBackup(cms, record) {
|
|
3017
3044
|
const started = /* @__PURE__ */ new Date();
|
|
3018
|
-
|
|
3045
|
+
const { id, ...rest } = record;
|
|
3046
|
+
const changes = { state: "running", startedAt: started.toISOString() };
|
|
3047
|
+
const claimed = await cms.db.update({
|
|
3048
|
+
collection: DATABASE_BACKUPS,
|
|
3049
|
+
id,
|
|
3050
|
+
data: { ...rest, ...changes, updatedAt: started.toISOString() },
|
|
3051
|
+
where: { state: { equals: "pending" } }
|
|
3052
|
+
});
|
|
3053
|
+
if (!claimed) return;
|
|
3054
|
+
let row = { ...record, ...changes };
|
|
3019
3055
|
const dir = await mkdtemp(join2(tmpdir(), "easy-cms-backup-"));
|
|
3020
3056
|
try {
|
|
3021
3057
|
const file = join2(dir, "backup.db");
|
|
@@ -4539,7 +4575,12 @@ var Webhooks = class {
|
|
|
4539
4575
|
continue;
|
|
4540
4576
|
}
|
|
4541
4577
|
const attempts = queued.attempts + 1;
|
|
4542
|
-
await this.queue.
|
|
4578
|
+
const claimed = await this.queue.claim(id, queued, {
|
|
4579
|
+
...queued,
|
|
4580
|
+
attempts,
|
|
4581
|
+
nextAttemptAt: later2(now, CLAIM2)
|
|
4582
|
+
});
|
|
4583
|
+
if (!claimed) continue;
|
|
4543
4584
|
const result = await this.attempt(hook, queued.event, queued.body, queued.delivery);
|
|
4544
4585
|
if (result.ok) {
|
|
4545
4586
|
await this.queue.remove(id);
|
|
@@ -6137,6 +6178,7 @@ async function resolveConfig(input) {
|
|
|
6137
6178
|
...(config.webhooks?.length ?? 0) > 0 ? [webhookDeliveriesCollection] : [],
|
|
6138
6179
|
...config.apiKeys ? [apiKeysCollection] : [],
|
|
6139
6180
|
...config.email ? [emailDeliveriesCollection] : [],
|
|
6181
|
+
...(config.jobs?.length ?? 0) > 0 ? [jobRunsCollection] : [],
|
|
6140
6182
|
databaseBackupsCollection,
|
|
6141
6183
|
...config.auth?.rbac ? [rolesCollection] : [],
|
|
6142
6184
|
...(config.auth?.providers?.length ?? 0) > 0 ? [userIdentitiesCollection] : [],
|
|
@@ -8022,6 +8064,16 @@ var EasyCMS = class {
|
|
|
8022
8064
|
data: toRow(email2, current?.createdAt)
|
|
8023
8065
|
});
|
|
8024
8066
|
},
|
|
8067
|
+
claim: async (id, current, next) => {
|
|
8068
|
+
const row = await this.db.findById({ collection: collection2, id });
|
|
8069
|
+
if (!row) return false;
|
|
8070
|
+
return this.claim(collection2, row, toRow(next, row.createdAt), {
|
|
8071
|
+
and: [
|
|
8072
|
+
{ state: { equals: current.state } },
|
|
8073
|
+
{ nextAttemptAt: { equals: current.nextAttemptAt } }
|
|
8074
|
+
]
|
|
8075
|
+
});
|
|
8076
|
+
},
|
|
8025
8077
|
remove: async (id) => {
|
|
8026
8078
|
await this.db.delete({ collection: collection2, id });
|
|
8027
8079
|
},
|
|
@@ -8053,10 +8105,8 @@ var EasyCMS = class {
|
|
|
8053
8105
|
startScheduler(interval = 6e4) {
|
|
8054
8106
|
if (this.schedulerTimer) return;
|
|
8055
8107
|
this.schedulerTimer = setInterval(() => {
|
|
8056
|
-
|
|
8057
|
-
() => this.
|
|
8058
|
-
(error) => this.logger.error(`Scheduled jobs failed: ${error.message}`)
|
|
8059
|
-
)
|
|
8108
|
+
void this.runJobs().catch(
|
|
8109
|
+
(error) => this.logger.error(`Scheduled jobs failed: ${error.message}`)
|
|
8060
8110
|
);
|
|
8061
8111
|
}, interval);
|
|
8062
8112
|
this.schedulerTimer.unref?.();
|
|
@@ -8065,7 +8115,13 @@ var EasyCMS = class {
|
|
|
8065
8115
|
* Runs due scheduled publishes and unpublishes, and retries failed webhook deliveries. What the
|
|
8066
8116
|
* scheduler and the cron endpoint (`GET <api>/jobs/run`) call.
|
|
8067
8117
|
*/
|
|
8068
|
-
|
|
8118
|
+
runJobs(now = /* @__PURE__ */ new Date()) {
|
|
8119
|
+
const run = this.running.then(() => this.runJobsNow(now));
|
|
8120
|
+
this.running = run.catch(() => {
|
|
8121
|
+
});
|
|
8122
|
+
return run;
|
|
8123
|
+
}
|
|
8124
|
+
runJobsNow(now) {
|
|
8069
8125
|
return auditContext.run({ via: "scheduler", user: null }, async () => {
|
|
8070
8126
|
const scheduled = await this.runScheduled(now);
|
|
8071
8127
|
await this.pruneFailedDeliveries(now);
|
|
@@ -8081,31 +8137,91 @@ var EasyCMS = class {
|
|
|
8081
8137
|
};
|
|
8082
8138
|
});
|
|
8083
8139
|
}
|
|
8084
|
-
/**
|
|
8140
|
+
/**
|
|
8141
|
+
* `jobs` of the config that are due. When each last ran is a row of `job-runs`; an instance
|
|
8142
|
+
* claims a run by moving `lastRunAt` from the value it read, so each run happens once however
|
|
8143
|
+
* many instances run jobs.
|
|
8144
|
+
*/
|
|
8085
8145
|
async runConfigJobs(now) {
|
|
8086
8146
|
const { jobs } = this.config;
|
|
8087
8147
|
if (jobs.length === 0) return { ran: 0, failed: 0 };
|
|
8088
|
-
const
|
|
8089
|
-
const
|
|
8090
|
-
|
|
8148
|
+
const { docs } = await this.db.find({ collection: JOB_RUNS, sort: ["name"], limit: 0, page: 1 });
|
|
8149
|
+
const rows = new Map(docs.map((row) => [String(row.name), row]));
|
|
8150
|
+
let legacy;
|
|
8151
|
+
const stamp = now.toISOString();
|
|
8091
8152
|
let ran = 0;
|
|
8092
8153
|
let failed = 0;
|
|
8093
8154
|
for (const job of jobs) {
|
|
8094
|
-
const
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8155
|
+
const due = (previous) => job.every === void 0 || typeof previous !== "string" || now.getTime() - Date.parse(previous) >= job.every * 1e3;
|
|
8156
|
+
const row = rows.get(job.name);
|
|
8157
|
+
let claimed;
|
|
8158
|
+
if (row) {
|
|
8159
|
+
if (!due(row.lastRunAt)) continue;
|
|
8160
|
+
claimed = await this.claim(
|
|
8161
|
+
JOB_RUNS,
|
|
8162
|
+
row,
|
|
8163
|
+
{ lastRunAt: stamp, lastStatus: "running", updatedAt: stamp },
|
|
8164
|
+
{ lastRunAt: { equals: String(row.lastRunAt) } }
|
|
8165
|
+
);
|
|
8166
|
+
} else {
|
|
8167
|
+
legacy ??= await this.db.findGlobal({ slug: LEGACY_JOB_RUNS }) ?? {};
|
|
8168
|
+
const previous = legacy[job.name];
|
|
8169
|
+
const run = due(previous);
|
|
8170
|
+
claimed = await this.db.create({
|
|
8171
|
+
collection: JOB_RUNS,
|
|
8172
|
+
data: {
|
|
8173
|
+
name: job.name,
|
|
8174
|
+
lastRunAt: run ? stamp : String(previous),
|
|
8175
|
+
lastStatus: run ? "running" : null,
|
|
8176
|
+
lastError: null,
|
|
8177
|
+
lastDurationMs: null,
|
|
8178
|
+
createdAt: stamp,
|
|
8179
|
+
updatedAt: stamp
|
|
8180
|
+
}
|
|
8181
|
+
}).then(
|
|
8182
|
+
() => run,
|
|
8183
|
+
() => false
|
|
8184
|
+
);
|
|
8185
|
+
}
|
|
8186
|
+
if (!claimed) continue;
|
|
8187
|
+
const started = Date.now();
|
|
8188
|
+
let error = null;
|
|
8098
8189
|
try {
|
|
8099
8190
|
await job.run({ cms: this, now });
|
|
8100
8191
|
ran++;
|
|
8101
|
-
} catch (
|
|
8192
|
+
} catch (caught) {
|
|
8102
8193
|
failed++;
|
|
8103
|
-
|
|
8194
|
+
error = (caught.message || String(caught)).slice(0, 500);
|
|
8195
|
+
this.logger.error(`Job ${job.name} failed: ${error}`);
|
|
8104
8196
|
}
|
|
8197
|
+
await this.recordJobRun(job.name, stamp, error, Date.now() - started).catch(
|
|
8198
|
+
(caught) => this.logger.error(`Job ${job.name}: ${caught.message}`)
|
|
8199
|
+
);
|
|
8105
8200
|
}
|
|
8106
|
-
await this.db.updateGlobal({ slug: JOB_RUNS, data: { ...runs, updatedAt: now.toISOString() } });
|
|
8107
8201
|
return { ran, failed };
|
|
8108
8202
|
}
|
|
8203
|
+
async recordJobRun(name, at, error, ms) {
|
|
8204
|
+
const { docs } = await this.db.find({
|
|
8205
|
+
collection: JOB_RUNS,
|
|
8206
|
+
where: { name: { equals: name } },
|
|
8207
|
+
sort: ["name"],
|
|
8208
|
+
limit: 1,
|
|
8209
|
+
page: 1
|
|
8210
|
+
});
|
|
8211
|
+
const row = docs[0];
|
|
8212
|
+
if (!row || row.lastRunAt !== at) return;
|
|
8213
|
+
await this.claim(
|
|
8214
|
+
JOB_RUNS,
|
|
8215
|
+
row,
|
|
8216
|
+
{
|
|
8217
|
+
lastStatus: error ? "failed" : "ok",
|
|
8218
|
+
lastError: error,
|
|
8219
|
+
lastDurationMs: ms,
|
|
8220
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8221
|
+
},
|
|
8222
|
+
{ lastRunAt: { equals: at } }
|
|
8223
|
+
);
|
|
8224
|
+
}
|
|
8109
8225
|
/**
|
|
8110
8226
|
* Sends an event of the app or a plugin (`events` in the config, e.g. `order.paid`) to the
|
|
8111
8227
|
* webhooks that list it. Returns at once; deliveries are queued and retried like content changes.
|
|
@@ -8139,6 +8255,16 @@ var EasyCMS = class {
|
|
|
8139
8255
|
data: toRow(delivery, current?.createdAt)
|
|
8140
8256
|
});
|
|
8141
8257
|
},
|
|
8258
|
+
claim: async (id, current, next) => {
|
|
8259
|
+
const row = await this.db.findById({ collection: collection2, id });
|
|
8260
|
+
if (!row) return false;
|
|
8261
|
+
return this.claim(collection2, row, toRow(next, row.createdAt), {
|
|
8262
|
+
and: [
|
|
8263
|
+
{ state: { equals: current.state } },
|
|
8264
|
+
{ nextAttemptAt: { equals: current.nextAttemptAt } }
|
|
8265
|
+
]
|
|
8266
|
+
});
|
|
8267
|
+
},
|
|
8142
8268
|
remove: async (id) => {
|
|
8143
8269
|
await this.db.delete({ collection: collection2, id });
|
|
8144
8270
|
},
|
|
@@ -8156,13 +8282,37 @@ var EasyCMS = class {
|
|
|
8156
8282
|
}
|
|
8157
8283
|
};
|
|
8158
8284
|
}
|
|
8285
|
+
/**
|
|
8286
|
+
* Takes a queued row for this process by writing `changes`, only if it still matches `expect`
|
|
8287
|
+
* (compare and set): `false` when another process changed it first.
|
|
8288
|
+
*/
|
|
8289
|
+
async claim(collection2, row, changes, expect) {
|
|
8290
|
+
const { id, ...data } = row;
|
|
8291
|
+
return await this.db.update({ collection: collection2, id, data: { ...data, ...changes }, where: expect }) !== null;
|
|
8292
|
+
}
|
|
8159
8293
|
/**
|
|
8160
8294
|
* Publishes or unpublishes documents whose scheduled time has come. Safe to call often, e.g.
|
|
8161
|
-
* from a cron job (`GET <api>/jobs/run`) where no process keeps running
|
|
8295
|
+
* from a cron job (`GET <api>/jobs/run`) where no process keeps running, and from several
|
|
8296
|
+
* processes at once: each job is claimed before it runs.
|
|
8162
8297
|
*/
|
|
8163
8298
|
async runScheduled(now = /* @__PURE__ */ new Date()) {
|
|
8164
8299
|
if (!this.config.collections.some((c) => c.slug === SCHEDULED_JOBS))
|
|
8165
8300
|
return { ran: 0, failed: 0 };
|
|
8301
|
+
const expired = new Date(now.getTime() - JOB_LEASE).toISOString();
|
|
8302
|
+
const stuck = await this.db.find({
|
|
8303
|
+
collection: SCHEDULED_JOBS,
|
|
8304
|
+
where: { and: [{ state: { equals: "running" } }, { updatedAt: { lt: expired } }] },
|
|
8305
|
+
sort: ["updatedAt"],
|
|
8306
|
+
limit: 100,
|
|
8307
|
+
page: 1
|
|
8308
|
+
});
|
|
8309
|
+
for (const row of stuck.docs)
|
|
8310
|
+
await this.claim(
|
|
8311
|
+
SCHEDULED_JOBS,
|
|
8312
|
+
row,
|
|
8313
|
+
{ state: "pending", updatedAt: now.toISOString() },
|
|
8314
|
+
{ and: [{ state: { equals: "running" } }, { updatedAt: { lt: expired } }] }
|
|
8315
|
+
);
|
|
8166
8316
|
const due = await this.db.find({
|
|
8167
8317
|
collection: SCHEDULED_JOBS,
|
|
8168
8318
|
where: {
|
|
@@ -8172,8 +8322,16 @@ var EasyCMS = class {
|
|
|
8172
8322
|
limit: 100,
|
|
8173
8323
|
page: 1
|
|
8174
8324
|
});
|
|
8325
|
+
let ran = 0;
|
|
8175
8326
|
let failed = 0;
|
|
8176
8327
|
for (const row of due.docs) {
|
|
8328
|
+
const claimed = await this.claim(
|
|
8329
|
+
SCHEDULED_JOBS,
|
|
8330
|
+
row,
|
|
8331
|
+
{ state: "running", updatedAt: now.toISOString() },
|
|
8332
|
+
{ state: { equals: "pending" } }
|
|
8333
|
+
);
|
|
8334
|
+
if (!claimed) continue;
|
|
8177
8335
|
const parent = String(row.parent);
|
|
8178
8336
|
const action = row.action;
|
|
8179
8337
|
try {
|
|
@@ -8196,8 +8354,9 @@ var EasyCMS = class {
|
|
|
8196
8354
|
await this.db.update({
|
|
8197
8355
|
collection: SCHEDULED_JOBS,
|
|
8198
8356
|
id: row.id,
|
|
8199
|
-
data: { ...row, state: "done" }
|
|
8357
|
+
data: { ...row, state: "done", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
8200
8358
|
});
|
|
8359
|
+
ran++;
|
|
8201
8360
|
} catch (error) {
|
|
8202
8361
|
failed++;
|
|
8203
8362
|
const message2 = error.message;
|
|
@@ -8205,11 +8364,16 @@ var EasyCMS = class {
|
|
|
8205
8364
|
await this.db.update({
|
|
8206
8365
|
collection: SCHEDULED_JOBS,
|
|
8207
8366
|
id: row.id,
|
|
8208
|
-
data: {
|
|
8367
|
+
data: {
|
|
8368
|
+
...row,
|
|
8369
|
+
state: "failed",
|
|
8370
|
+
error: message2.slice(0, 500),
|
|
8371
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8372
|
+
}
|
|
8209
8373
|
});
|
|
8210
8374
|
}
|
|
8211
8375
|
}
|
|
8212
|
-
return { ran
|
|
8376
|
+
return { ran, failed };
|
|
8213
8377
|
}
|
|
8214
8378
|
/** Schedules a publish or unpublish, replacing a pending job with the same action. */
|
|
8215
8379
|
async schedule(collection2, id, job, options = {}) {
|
|
@@ -8369,6 +8533,20 @@ var EasyCMS = class {
|
|
|
8369
8533
|
const collection2 = kind === "webhook" ? WEBHOOK_DELIVERIES : EMAIL_DELIVERIES;
|
|
8370
8534
|
const row = await this.db.findById({ collection: collection2, id });
|
|
8371
8535
|
if (!row) throw new NotFoundError(collection2, id);
|
|
8536
|
+
const busy = { ok: false, error: "it is being sent right now; try again in a minute" };
|
|
8537
|
+
if (row.state !== "pending" && row.state !== "failed") return busy;
|
|
8538
|
+
const claimed = await this.claim(
|
|
8539
|
+
collection2,
|
|
8540
|
+
row,
|
|
8541
|
+
{ state: "sending", updatedAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
8542
|
+
{
|
|
8543
|
+
and: [
|
|
8544
|
+
{ state: { equals: row.state } },
|
|
8545
|
+
{ nextAttemptAt: { equals: String(row.nextAttemptAt) } }
|
|
8546
|
+
]
|
|
8547
|
+
}
|
|
8548
|
+
);
|
|
8549
|
+
if (!claimed) return busy;
|
|
8372
8550
|
const error = kind === "webhook" ? await this.webhooks.sendNow(row).then((result) => result.ok ? void 0 : result.error) : await this.mailer.sendNow(String(row.message));
|
|
8373
8551
|
if (error === void 0) {
|
|
8374
8552
|
await this.db.delete({ collection: collection2, id });
|
|
@@ -8388,11 +8566,33 @@ var EasyCMS = class {
|
|
|
8388
8566
|
});
|
|
8389
8567
|
return { ok: false, error };
|
|
8390
8568
|
}
|
|
8391
|
-
/**
|
|
8569
|
+
/**
|
|
8570
|
+
* Removes webhook deliveries and emails that failed more than 30 days ago, and marks as failed
|
|
8571
|
+
* the ones an admin's Retry left `sending` because its instance stopped.
|
|
8572
|
+
*/
|
|
8392
8573
|
async pruneFailedDeliveries(now) {
|
|
8393
8574
|
const before = new Date(now.getTime() - 30 * 864e5).toISOString();
|
|
8575
|
+
const stuck = new Date(now.getTime() - 5 * 6e4).toISOString();
|
|
8394
8576
|
for (const collection2 of [WEBHOOK_DELIVERIES, EMAIL_DELIVERIES]) {
|
|
8395
8577
|
if (!this.config.collections.some((c) => c.slug === collection2)) continue;
|
|
8578
|
+
const sending = await this.db.find({
|
|
8579
|
+
collection: collection2,
|
|
8580
|
+
where: { and: [{ state: { equals: "sending" } }, { updatedAt: { lt: stuck } }] },
|
|
8581
|
+
sort: ["updatedAt"],
|
|
8582
|
+
limit: 100,
|
|
8583
|
+
page: 1
|
|
8584
|
+
});
|
|
8585
|
+
for (const row of sending.docs)
|
|
8586
|
+
await this.claim(
|
|
8587
|
+
collection2,
|
|
8588
|
+
row,
|
|
8589
|
+
{
|
|
8590
|
+
state: "failed",
|
|
8591
|
+
error: "Interrupted: the server stopped while sending",
|
|
8592
|
+
updatedAt: now.toISOString()
|
|
8593
|
+
},
|
|
8594
|
+
{ and: [{ state: { equals: "sending" } }, { updatedAt: { lt: stuck } }] }
|
|
8595
|
+
);
|
|
8396
8596
|
for (; ; ) {
|
|
8397
8597
|
const { docs } = await this.db.find({
|
|
8398
8598
|
collection: collection2,
|
|
@@ -9152,7 +9352,8 @@ var UPLOAD_URL_SECONDS = 15 * 60;
|
|
|
9152
9352
|
var UPLOAD_TICKET_SECONDS = 24 * 60 * 60;
|
|
9153
9353
|
var SNIFF_BYTES = 64 * 1024;
|
|
9154
9354
|
var MAX_FILES_TO_MOVE = 200;
|
|
9155
|
-
var
|
|
9355
|
+
var LEGACY_JOB_RUNS = "easy-cms:jobs";
|
|
9356
|
+
var JOB_LEASE = 10 * 6e4;
|
|
9156
9357
|
function durationSeconds(value) {
|
|
9157
9358
|
const match = typeof value === "string" ? /^(\d+)\s*([smhd])$/.exec(value.trim()) : null;
|
|
9158
9359
|
const seconds = typeof value === "number" ? value : match ? Number(match[1]) * { s: 1, m: 60, h: 3600, d: 86400 }[match[2]] : Number.NaN;
|
|
@@ -9208,7 +9409,7 @@ async function readAdminModule(cms, index) {
|
|
|
9208
9409
|
}
|
|
9209
9410
|
|
|
9210
9411
|
// src/version.ts
|
|
9211
|
-
var VERSION = true ? "1.
|
|
9412
|
+
var VERSION = true ? "1.3.0" : "0.0.0-dev";
|
|
9212
9413
|
|
|
9213
9414
|
// src/rest/admin-deliveries.ts
|
|
9214
9415
|
var PER_PAGE = 50;
|
|
@@ -1934,8 +1934,14 @@ declare class EasyCMS<C extends Config = Config> {
|
|
|
1934
1934
|
failed: number;
|
|
1935
1935
|
};
|
|
1936
1936
|
}>;
|
|
1937
|
-
|
|
1937
|
+
private runJobsNow;
|
|
1938
|
+
/**
|
|
1939
|
+
* `jobs` of the config that are due. When each last ran is a row of `job-runs`; an instance
|
|
1940
|
+
* claims a run by moving `lastRunAt` from the value it read, so each run happens once however
|
|
1941
|
+
* many instances run jobs.
|
|
1942
|
+
*/
|
|
1938
1943
|
private runConfigJobs;
|
|
1944
|
+
private recordJobRun;
|
|
1939
1945
|
/**
|
|
1940
1946
|
* Sends an event of the app or a plugin (`events` in the config, e.g. `order.paid`) to the
|
|
1941
1947
|
* webhooks that list it. Returns at once; deliveries are queued and retried like content changes.
|
|
@@ -1954,9 +1960,15 @@ declare class EasyCMS<C extends Config = Config> {
|
|
|
1954
1960
|
}>;
|
|
1955
1961
|
/** Webhook deliveries until they succeed, stored in `webhook-deliveries`. */
|
|
1956
1962
|
private webhookQueue;
|
|
1963
|
+
/**
|
|
1964
|
+
* Takes a queued row for this process by writing `changes`, only if it still matches `expect`
|
|
1965
|
+
* (compare and set): `false` when another process changed it first.
|
|
1966
|
+
*/
|
|
1967
|
+
private claim;
|
|
1957
1968
|
/**
|
|
1958
1969
|
* Publishes or unpublishes documents whose scheduled time has come. Safe to call often, e.g.
|
|
1959
|
-
* from a cron job (`GET <api>/jobs/run`) where no process keeps running
|
|
1970
|
+
* from a cron job (`GET <api>/jobs/run`) where no process keeps running, and from several
|
|
1971
|
+
* processes at once: each job is claimed before it runs.
|
|
1960
1972
|
*/
|
|
1961
1973
|
runScheduled(now?: Date): Promise<{
|
|
1962
1974
|
ran: number;
|
|
@@ -1992,7 +2004,10 @@ declare class EasyCMS<C extends Config = Config> {
|
|
|
1992
2004
|
})[]>;
|
|
1993
2005
|
private pendingJobs;
|
|
1994
2006
|
private removeJob;
|
|
1995
|
-
/**
|
|
2007
|
+
/**
|
|
2008
|
+
* Removes webhook deliveries and emails that failed more than 30 days ago, and marks as failed
|
|
2009
|
+
* the ones an admin's Retry left `sending` because its instance stopped.
|
|
2010
|
+
*/
|
|
1996
2011
|
private pruneFailedDeliveries;
|
|
1997
2012
|
private global;
|
|
1998
2013
|
/**
|
|
@@ -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-BhTVeJg4.js';
|
|
2
2
|
|
|
3
3
|
/** Decrypts a file from `encryptBackup`; throws for another key or a changed file. */
|
|
4
4
|
declare function decryptBackup(data: Uint8Array, encryptionKey: string): Uint8Array;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PaginatedDocs, I as ID, 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-BhTVeJg4.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-BhTVeJg4.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-dt85uDgT.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-D7FaZRW-.js';
|
|
5
5
|
export { FieldCondition, matchesCondition } from './conditions.js';
|
|
6
6
|
|
|
7
7
|
type DeliveryKind = 'webhook' | 'email';
|
package/dist/index.js
CHANGED
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 decryptBackup, q as fillMissing, t as findConfigFile, u as forwardedClientIp, v as generateSlugs, w as importConfig, x as mergeForUpdate, y as parseId, z as platformClientIp, E as readCookie, F as validateFields, G 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-BhTVeJg4.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-BhTVeJg4.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 mergeForUpdate, y as parseId, z as platformClientIp, E as readCookie, F as validateFields, G as writeBackupFile } from './handler-D7FaZRW-.js';
|
|
4
4
|
export { conditionIssues } from './conditions.js';
|
|
5
5
|
|
|
6
6
|
/** The session cookie the REST API sets at login. */
|
package/dist/internal.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { 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-BhTVeJg4.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-BhTVeJg4.js';
|
|
2
|
+
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-dt85uDgT.js';
|
|
3
3
|
import './conditions.js';
|