@easy-cms/core 1.24.0 → 1.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-V3SGXMJ6.js → chunk-6CJMRQO4.js} +416 -41
- package/dist/{config-kFcSdrV9.d.ts → config-Bsp6rkuH.d.ts} +4 -0
- package/dist/{handler-D-RXQhlD.d.ts → handler-Br9Pu6z9.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +1 -1
- package/dist/{plugin-uKrb_7kI.d.ts → plugin-CUzEJN31.d.ts} +1 -1
- package/dist/plugin.d.ts +2 -2
- package/package.json +1 -1
|
@@ -155,6 +155,7 @@ var USER_IDENTITIES = "user-identities";
|
|
|
155
155
|
var AUDIT_LOGS = "audit-logs";
|
|
156
156
|
var OUTBOX = "outbox";
|
|
157
157
|
var RATE_LIMITS = "rate-limits";
|
|
158
|
+
var BULK_OPERATIONS = "bulk-operations";
|
|
158
159
|
var INTERNAL_COLLECTIONS = /* @__PURE__ */ new Set([
|
|
159
160
|
SESSIONS,
|
|
160
161
|
LOGIN_ATTEMPTS,
|
|
@@ -168,7 +169,8 @@ var INTERNAL_COLLECTIONS = /* @__PURE__ */ new Set([
|
|
|
168
169
|
USER_IDENTITIES,
|
|
169
170
|
AUDIT_LOGS,
|
|
170
171
|
OUTBOX,
|
|
171
|
-
RATE_LIMITS
|
|
172
|
+
RATE_LIMITS,
|
|
173
|
+
BULK_OPERATIONS
|
|
172
174
|
]);
|
|
173
175
|
var DEFAULT_ROLES = ["admin", "editor"];
|
|
174
176
|
var CREATED_BY_FIELD = {
|
|
@@ -528,6 +530,34 @@ var scheduledJobsCollection = {
|
|
|
528
530
|
{ name: "author", type: "number" }
|
|
529
531
|
]
|
|
530
532
|
};
|
|
533
|
+
var bulkOperationsCollection = {
|
|
534
|
+
slug: BULK_OPERATIONS,
|
|
535
|
+
access: { read: nobody, create: nobody, update: nobody, delete: nobody },
|
|
536
|
+
fields: [
|
|
537
|
+
{ name: "collection", type: "text", required: true },
|
|
538
|
+
// publish | unpublish | delete | move
|
|
539
|
+
{ name: "action", type: "text", required: true },
|
|
540
|
+
// The list's `where`, and for `move` the folder (`null`: the top).
|
|
541
|
+
{ name: "query", type: "json" },
|
|
542
|
+
{ name: "folder", type: "text" },
|
|
543
|
+
{ name: "transferTo", type: "text" },
|
|
544
|
+
{ name: "user", type: "text", required: true, index: true },
|
|
545
|
+
// pending | running | cancelling | done | cancelled | failed
|
|
546
|
+
{ name: "state", type: "text", required: true, index: true },
|
|
547
|
+
{ name: "total", type: "number", required: true },
|
|
548
|
+
{ name: "done", type: "number", required: true },
|
|
549
|
+
{ name: "skipped", type: "number", required: true },
|
|
550
|
+
{ name: "failed", type: "number", required: true },
|
|
551
|
+
// The last id handled: the next step continues after it, in id order.
|
|
552
|
+
{ name: "after", type: "json" },
|
|
553
|
+
// The first documents skipped or failed, with why: `{ id, reason, message? }`.
|
|
554
|
+
{ name: "problems", type: "json" },
|
|
555
|
+
{ name: "error", type: "text" },
|
|
556
|
+
// A step holds the operation until then; a process that stopped lets it go.
|
|
557
|
+
{ name: "leaseUntil", type: "text" },
|
|
558
|
+
{ name: "finishedAt", type: "text" }
|
|
559
|
+
]
|
|
560
|
+
};
|
|
531
561
|
var webhookDeliveriesCollection = {
|
|
532
562
|
slug: WEBHOOK_DELIVERIES,
|
|
533
563
|
access: { read: nobody, create: nobody, update: nobody, delete: nobody },
|
|
@@ -3000,9 +3030,9 @@ async function pendingMigrations(cms) {
|
|
|
3000
3030
|
if (pending === 0) migrated.add(cms);
|
|
3001
3031
|
return pending;
|
|
3002
3032
|
}
|
|
3003
|
-
async function healthResponse(
|
|
3033
|
+
async function healthResponse(check4, instance) {
|
|
3004
3034
|
const cms = instance;
|
|
3005
|
-
if (
|
|
3035
|
+
if (check4 === "healthz") return new Response("ok", { headers: { "cache-control": "no-store" } });
|
|
3006
3036
|
if (!cms) {
|
|
3007
3037
|
return Response.json(
|
|
3008
3038
|
{ status: "error", checks: { startup: "error" } },
|
|
@@ -4300,6 +4330,306 @@ zzzzzzzz
|
|
|
4300
4330
|
`;
|
|
4301
4331
|
var COMMON_PASSWORDS = new Set(LIST.split(/\s+/).filter(Boolean));
|
|
4302
4332
|
|
|
4333
|
+
// src/bulk.ts
|
|
4334
|
+
var BULK_ACTIONS = ["publish", "unpublish", "delete", "move"];
|
|
4335
|
+
var BULK_STEP = 100;
|
|
4336
|
+
var BULK_MAX = 1e4;
|
|
4337
|
+
var LEASE_MS = 6e4;
|
|
4338
|
+
var PROBLEMS_KEPT = 50;
|
|
4339
|
+
var FINISHED_KEPT = 10;
|
|
4340
|
+
var ACTIVE = ["pending", "running", "cancelling"];
|
|
4341
|
+
function check(cms, collection2, action, options) {
|
|
4342
|
+
if (!BULK_ACTIONS.includes(action))
|
|
4343
|
+
throw new QueryError(`action must be one of ${BULK_ACTIONS.join(", ")}`);
|
|
4344
|
+
const config = cms.collection(collection2);
|
|
4345
|
+
if ((action === "publish" || action === "unpublish") && !config.drafts)
|
|
4346
|
+
throw new QueryError(`"${collection2}" has no drafts to publish`);
|
|
4347
|
+
if (action === "move" && collection2 !== MEDIA)
|
|
4348
|
+
throw new QueryError("Only media files move to folders");
|
|
4349
|
+
if (action === "move" && options.folder === void 0)
|
|
4350
|
+
throw new QueryError("folder is required to move files");
|
|
4351
|
+
}
|
|
4352
|
+
async function apply(cms, collection2, action, id, options) {
|
|
4353
|
+
const access = {
|
|
4354
|
+
overrideAccess: false,
|
|
4355
|
+
user: options.user,
|
|
4356
|
+
...options.context ? { context: options.context } : {},
|
|
4357
|
+
depth: 0
|
|
4358
|
+
};
|
|
4359
|
+
const slug2 = collection2;
|
|
4360
|
+
try {
|
|
4361
|
+
if (action === "publish") await cms.update(slug2, id, { status: "published" }, access);
|
|
4362
|
+
else if (action === "unpublish") await cms.unpublish(slug2, id, access);
|
|
4363
|
+
else if (action === "move")
|
|
4364
|
+
await cms.update(slug2, id, { folder: options.folder ?? null }, access);
|
|
4365
|
+
else
|
|
4366
|
+
await cms.delete(slug2, id, {
|
|
4367
|
+
...access,
|
|
4368
|
+
...options.transferTo !== void 0 ? { transferTo: options.transferTo } : {}
|
|
4369
|
+
});
|
|
4370
|
+
return null;
|
|
4371
|
+
} catch (error) {
|
|
4372
|
+
if (error instanceof ForbiddenError) return { id, reason: "forbidden" };
|
|
4373
|
+
if (error instanceof NotFoundError) return { id, reason: "not-found" };
|
|
4374
|
+
return { id, reason: "error", message: error.message };
|
|
4375
|
+
}
|
|
4376
|
+
}
|
|
4377
|
+
async function bulkIds(cms, collection2, action, ids, options) {
|
|
4378
|
+
check(cms, collection2, action, options);
|
|
4379
|
+
if (ids.length > BULK_STEP) throw new QueryError(`ids: at most ${BULK_STEP} at a time`);
|
|
4380
|
+
const result = { done: 0, skipped: [], failed: [] };
|
|
4381
|
+
for (const id of new Set(ids)) {
|
|
4382
|
+
const problem = await apply(cms, collection2, action, id, options);
|
|
4383
|
+
if (!problem) result.done++;
|
|
4384
|
+
else if (problem.reason === "error") result.failed.push(problem);
|
|
4385
|
+
else result.skipped.push(problem);
|
|
4386
|
+
}
|
|
4387
|
+
return result;
|
|
4388
|
+
}
|
|
4389
|
+
async function startBulk(cms, collection2, action, where, options) {
|
|
4390
|
+
check(cms, collection2, action, options);
|
|
4391
|
+
const total = await cms.count(collection2, {
|
|
4392
|
+
...where ? { where } : {},
|
|
4393
|
+
draft: true,
|
|
4394
|
+
overrideAccess: false,
|
|
4395
|
+
user: options.user,
|
|
4396
|
+
...options.context ? { context: options.context } : {},
|
|
4397
|
+
max: BULK_MAX
|
|
4398
|
+
});
|
|
4399
|
+
if (total > BULK_MAX)
|
|
4400
|
+
throw new QueryError(
|
|
4401
|
+
`More than ${BULK_MAX.toLocaleString("en")} documents match: filter the list further`
|
|
4402
|
+
);
|
|
4403
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4404
|
+
const row = await cms.db.create({
|
|
4405
|
+
collection: BULK_OPERATIONS,
|
|
4406
|
+
data: {
|
|
4407
|
+
collection: collection2,
|
|
4408
|
+
action,
|
|
4409
|
+
query: where ?? null,
|
|
4410
|
+
folder: options.folder === void 0 ? null : JSON.stringify(options.folder),
|
|
4411
|
+
transferTo: options.transferTo === void 0 ? null : JSON.stringify(options.transferTo),
|
|
4412
|
+
user: String(options.user.id),
|
|
4413
|
+
state: total === 0 ? "done" : "pending",
|
|
4414
|
+
total,
|
|
4415
|
+
done: 0,
|
|
4416
|
+
skipped: 0,
|
|
4417
|
+
failed: 0,
|
|
4418
|
+
after: null,
|
|
4419
|
+
problems: [],
|
|
4420
|
+
error: null,
|
|
4421
|
+
leaseUntil: null,
|
|
4422
|
+
finishedAt: total === 0 ? now : null,
|
|
4423
|
+
createdAt: now,
|
|
4424
|
+
updatedAt: now
|
|
4425
|
+
}
|
|
4426
|
+
});
|
|
4427
|
+
await cms.audit.record({
|
|
4428
|
+
action: `bulk.${action}`,
|
|
4429
|
+
target: collection2,
|
|
4430
|
+
detail: { total, operation: String(row.id) }
|
|
4431
|
+
});
|
|
4432
|
+
await pruneFinished(cms, String(options.user.id));
|
|
4433
|
+
if (total > 0) void runBulk(cms, row.id).catch(() => {
|
|
4434
|
+
});
|
|
4435
|
+
return toOperation(row);
|
|
4436
|
+
}
|
|
4437
|
+
async function runBulk(cms, id) {
|
|
4438
|
+
while (await stepBulk(cms, id)) {
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
async function stepBulk(cms, id, now = /* @__PURE__ */ new Date()) {
|
|
4442
|
+
const row = await cms.db.findById({ collection: BULK_OPERATIONS, id });
|
|
4443
|
+
if (!row || !ACTIVE.includes(String(row.state))) return false;
|
|
4444
|
+
const lease = row.leaseUntil ? Date.parse(String(row.leaseUntil)) : 0;
|
|
4445
|
+
if (lease > now.getTime()) return false;
|
|
4446
|
+
const claimedAt = new Date(Math.max(now.getTime(), Date.parse(String(row.updatedAt)) + 1));
|
|
4447
|
+
const claimed = await save(cms, row, {
|
|
4448
|
+
state: row.state === "pending" ? "running" : row.state,
|
|
4449
|
+
leaseUntil: new Date(now.getTime() + LEASE_MS).toISOString(),
|
|
4450
|
+
updatedAt: claimedAt.toISOString()
|
|
4451
|
+
});
|
|
4452
|
+
if (!claimed) return false;
|
|
4453
|
+
if (claimed.state === "cancelling") {
|
|
4454
|
+
await finish(cms, claimed, "cancelled");
|
|
4455
|
+
return false;
|
|
4456
|
+
}
|
|
4457
|
+
const user = await cms.auth.activeUser(String(claimed.user));
|
|
4458
|
+
if (!user) {
|
|
4459
|
+
await finish(cms, claimed, "failed", "The user who started it is no longer active");
|
|
4460
|
+
return false;
|
|
4461
|
+
}
|
|
4462
|
+
const collection2 = String(claimed.collection);
|
|
4463
|
+
const action = claimed.action;
|
|
4464
|
+
const options = {
|
|
4465
|
+
user,
|
|
4466
|
+
...claimed.folder !== null && claimed.folder !== void 0 ? { folder: JSON.parse(String(claimed.folder)) } : {},
|
|
4467
|
+
...claimed.transferTo !== null && claimed.transferTo !== void 0 ? { transferTo: JSON.parse(String(claimed.transferTo)) } : {}
|
|
4468
|
+
};
|
|
4469
|
+
const handled = Number(claimed.done) + Number(claimed.skipped) + Number(claimed.failed);
|
|
4470
|
+
const query = claimed.query ?? void 0;
|
|
4471
|
+
const after = claimed.after;
|
|
4472
|
+
const conditions = [query, after === null ? void 0 : { id: { gt: after } }].filter(
|
|
4473
|
+
(w) => w !== void 0
|
|
4474
|
+
);
|
|
4475
|
+
let found;
|
|
4476
|
+
try {
|
|
4477
|
+
found = await cms.find(collection2, {
|
|
4478
|
+
...conditions.length ? { where: { and: conditions } } : {},
|
|
4479
|
+
sort: "id",
|
|
4480
|
+
limit: Math.min(BULK_STEP, BULK_MAX - handled),
|
|
4481
|
+
depth: 0,
|
|
4482
|
+
draft: true,
|
|
4483
|
+
count: false,
|
|
4484
|
+
overrideAccess: false,
|
|
4485
|
+
user
|
|
4486
|
+
});
|
|
4487
|
+
} catch (error) {
|
|
4488
|
+
await finish(cms, claimed, "failed", error.message);
|
|
4489
|
+
return false;
|
|
4490
|
+
}
|
|
4491
|
+
const changes = {
|
|
4492
|
+
done: Number(claimed.done),
|
|
4493
|
+
skipped: Number(claimed.skipped),
|
|
4494
|
+
failed: Number(claimed.failed),
|
|
4495
|
+
problems: [...claimed.problems ?? []],
|
|
4496
|
+
after
|
|
4497
|
+
};
|
|
4498
|
+
await auditContext.run({ user }, async () => {
|
|
4499
|
+
for (const doc of found.docs) {
|
|
4500
|
+
const problem = await apply(cms, collection2, action, doc.id, options);
|
|
4501
|
+
if (!problem) changes.done++;
|
|
4502
|
+
else {
|
|
4503
|
+
if (problem.reason === "error") changes.failed++;
|
|
4504
|
+
else changes.skipped++;
|
|
4505
|
+
if (changes.problems.length < PROBLEMS_KEPT) changes.problems.push(problem);
|
|
4506
|
+
}
|
|
4507
|
+
changes.after = doc.id;
|
|
4508
|
+
}
|
|
4509
|
+
});
|
|
4510
|
+
const finished = !found.hasNextPage || found.docs.length === 0 || changes.done + changes.skipped + changes.failed >= BULK_MAX;
|
|
4511
|
+
const at = /* @__PURE__ */ new Date();
|
|
4512
|
+
const saved = await save(cms, claimed, {
|
|
4513
|
+
...changes,
|
|
4514
|
+
state: finished ? "done" : "running",
|
|
4515
|
+
leaseUntil: null,
|
|
4516
|
+
finishedAt: finished ? at.toISOString() : null,
|
|
4517
|
+
updatedAt: later2(at, claimed).toISOString()
|
|
4518
|
+
});
|
|
4519
|
+
if (saved) return !finished;
|
|
4520
|
+
const current = await cms.db.findById({ collection: BULK_OPERATIONS, id });
|
|
4521
|
+
if (current?.state === "cancelling") await finish(cms, { ...current, ...changes }, "cancelled");
|
|
4522
|
+
else if (current) await save(cms, current, { ...changes, leaseUntil: null });
|
|
4523
|
+
return false;
|
|
4524
|
+
}
|
|
4525
|
+
function later2(at, row) {
|
|
4526
|
+
return new Date(Math.max(at.getTime(), Date.parse(String(row.updatedAt)) + 1));
|
|
4527
|
+
}
|
|
4528
|
+
async function save(cms, row, changes) {
|
|
4529
|
+
const { id, ...data } = row;
|
|
4530
|
+
const next = { ...data, ...changes };
|
|
4531
|
+
const saved = await cms.db.update({
|
|
4532
|
+
collection: BULK_OPERATIONS,
|
|
4533
|
+
id,
|
|
4534
|
+
data: next,
|
|
4535
|
+
where: { updatedAt: { equals: row.updatedAt } }
|
|
4536
|
+
});
|
|
4537
|
+
return saved ? { ...row, ...changes } : null;
|
|
4538
|
+
}
|
|
4539
|
+
async function finish(cms, row, state, error) {
|
|
4540
|
+
const at = /* @__PURE__ */ new Date();
|
|
4541
|
+
await save(cms, row, {
|
|
4542
|
+
state,
|
|
4543
|
+
leaseUntil: null,
|
|
4544
|
+
finishedAt: at.toISOString(),
|
|
4545
|
+
updatedAt: later2(at, row).toISOString(),
|
|
4546
|
+
...error ? { error } : {}
|
|
4547
|
+
});
|
|
4548
|
+
}
|
|
4549
|
+
async function runBulkOperations(cms, now = /* @__PURE__ */ new Date(), budgetMs = 2e4) {
|
|
4550
|
+
const { docs } = await cms.db.find({
|
|
4551
|
+
collection: BULK_OPERATIONS,
|
|
4552
|
+
where: { state: { in: ACTIVE } },
|
|
4553
|
+
sort: ["createdAt"],
|
|
4554
|
+
limit: 20,
|
|
4555
|
+
page: 1
|
|
4556
|
+
});
|
|
4557
|
+
const until = Date.now() + budgetMs;
|
|
4558
|
+
let steps = 0;
|
|
4559
|
+
for (const row of docs) {
|
|
4560
|
+
while (Date.now() < until) {
|
|
4561
|
+
const more = await stepBulk(cms, row.id, now).catch((error) => {
|
|
4562
|
+
cms.logger.error(`Bulk operation ${row.id}: ${error.message}`, { error });
|
|
4563
|
+
return false;
|
|
4564
|
+
});
|
|
4565
|
+
steps++;
|
|
4566
|
+
if (!more) break;
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
return { steps };
|
|
4570
|
+
}
|
|
4571
|
+
async function bulkProgress(cms, id, user) {
|
|
4572
|
+
const row = await mine(cms, id, user);
|
|
4573
|
+
if (ACTIVE.includes(String(row.state))) await stepBulk(cms, row.id);
|
|
4574
|
+
return toOperation(await cms.db.findById({ collection: BULK_OPERATIONS, id: row.id }) ?? row);
|
|
4575
|
+
}
|
|
4576
|
+
async function bulkOperations(cms, user) {
|
|
4577
|
+
const { docs } = await cms.db.find({
|
|
4578
|
+
collection: BULK_OPERATIONS,
|
|
4579
|
+
where: { user: { equals: String(user.id) } },
|
|
4580
|
+
sort: ["-createdAt"],
|
|
4581
|
+
limit: FINISHED_KEPT + 20,
|
|
4582
|
+
page: 1
|
|
4583
|
+
});
|
|
4584
|
+
return docs.map(toOperation);
|
|
4585
|
+
}
|
|
4586
|
+
async function cancelBulk(cms, id, user) {
|
|
4587
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
4588
|
+
const row = await mine(cms, id, user);
|
|
4589
|
+
if (!ACTIVE.includes(String(row.state))) return toOperation(row);
|
|
4590
|
+
const at = /* @__PURE__ */ new Date();
|
|
4591
|
+
const saved = row.leaseUntil ? await save(cms, row, { state: "cancelling", updatedAt: later2(at, row).toISOString() }) : await save(cms, row, {
|
|
4592
|
+
state: "cancelled",
|
|
4593
|
+
finishedAt: at.toISOString(),
|
|
4594
|
+
updatedAt: later2(at, row).toISOString()
|
|
4595
|
+
});
|
|
4596
|
+
if (saved) return toOperation(saved);
|
|
4597
|
+
}
|
|
4598
|
+
return toOperation(await mine(cms, id, user));
|
|
4599
|
+
}
|
|
4600
|
+
async function mine(cms, id, user) {
|
|
4601
|
+
const row = await cms.db.findById({ collection: BULK_OPERATIONS, id });
|
|
4602
|
+
if (!row || String(row.user) !== String(user.id)) throw new NotFoundError(BULK_OPERATIONS, id);
|
|
4603
|
+
return row;
|
|
4604
|
+
}
|
|
4605
|
+
async function pruneFinished(cms, user) {
|
|
4606
|
+
const { docs } = await cms.db.find({
|
|
4607
|
+
collection: BULK_OPERATIONS,
|
|
4608
|
+
where: { and: [{ user: { equals: user } }, { state: { not_in: ACTIVE } }] },
|
|
4609
|
+
sort: ["-createdAt"],
|
|
4610
|
+
limit: 100,
|
|
4611
|
+
page: 1
|
|
4612
|
+
});
|
|
4613
|
+
for (const old of docs.slice(FINISHED_KEPT))
|
|
4614
|
+
await cms.db.delete({ collection: BULK_OPERATIONS, id: old.id });
|
|
4615
|
+
}
|
|
4616
|
+
function toOperation(row) {
|
|
4617
|
+
return {
|
|
4618
|
+
id: row.id,
|
|
4619
|
+
collection: String(row.collection),
|
|
4620
|
+
action: row.action,
|
|
4621
|
+
state: row.state,
|
|
4622
|
+
total: Number(row.total),
|
|
4623
|
+
done: Number(row.done),
|
|
4624
|
+
skipped: Number(row.skipped),
|
|
4625
|
+
failed: Number(row.failed),
|
|
4626
|
+
problems: row.problems ?? [],
|
|
4627
|
+
error: row.error ?? null,
|
|
4628
|
+
createdAt: String(row.createdAt),
|
|
4629
|
+
finishedAt: row.finishedAt ?? null
|
|
4630
|
+
};
|
|
4631
|
+
}
|
|
4632
|
+
|
|
4303
4633
|
// src/localization.ts
|
|
4304
4634
|
var ALL_LOCALES = "all";
|
|
4305
4635
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -4400,7 +4730,7 @@ function localizeSort(fields, sort, locale, locales = []) {
|
|
|
4400
4730
|
var DELAYS = [6e4, 5 * 6e4, 30 * 6e4, 2 * 36e5, 12 * 36e5];
|
|
4401
4731
|
var LEASE = 5 * 6e4;
|
|
4402
4732
|
var BATCH2 = 50;
|
|
4403
|
-
var
|
|
4733
|
+
var later3 = (from, ms) => new Date(from.getTime() + ms).toISOString();
|
|
4404
4734
|
var json = (value) => value === void 0 ? null : JSON.stringify(value);
|
|
4405
4735
|
var parse2 = (value) => typeof value === "string" ? JSON.parse(value) : void 0;
|
|
4406
4736
|
function withoutHash(value) {
|
|
@@ -4520,7 +4850,7 @@ var Outbox = class {
|
|
|
4520
4850
|
...data,
|
|
4521
4851
|
state: "running",
|
|
4522
4852
|
attempts,
|
|
4523
|
-
nextAttemptAt:
|
|
4853
|
+
nextAttemptAt: later3(now, LEASE),
|
|
4524
4854
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4525
4855
|
};
|
|
4526
4856
|
const claimed = await this.db.update({
|
|
@@ -4553,7 +4883,7 @@ var Outbox = class {
|
|
|
4553
4883
|
data: {
|
|
4554
4884
|
...current,
|
|
4555
4885
|
state: delay === void 0 ? "failed" : "pending",
|
|
4556
|
-
nextAttemptAt:
|
|
4886
|
+
nextAttemptAt: later3(now, delay ?? 0),
|
|
4557
4887
|
error: message2,
|
|
4558
4888
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4559
4889
|
}
|
|
@@ -4855,7 +5185,7 @@ async function fetchRemoteFile(link, options) {
|
|
|
4855
5185
|
const deadline = Date.now() + (options.timeout ?? 15e3);
|
|
4856
5186
|
const maxRedirects = options.maxRedirects ?? 3;
|
|
4857
5187
|
for (let redirects = 0; ; redirects++) {
|
|
4858
|
-
|
|
5188
|
+
check2(url, options);
|
|
4859
5189
|
const response = await get(url, options, deadline);
|
|
4860
5190
|
const status = response.statusCode ?? 0;
|
|
4861
5191
|
if (status >= 300 && status < 400 && response.headers.location) {
|
|
@@ -4877,7 +5207,7 @@ async function fetchRemoteFile(link, options) {
|
|
|
4877
5207
|
};
|
|
4878
5208
|
}
|
|
4879
5209
|
}
|
|
4880
|
-
function
|
|
5210
|
+
function check2(url, options) {
|
|
4881
5211
|
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
4882
5212
|
throw new RemoteFileError("must be an http(s) link");
|
|
4883
5213
|
if (url.username || url.password) throw new RemoteFileError("must not contain a password");
|
|
@@ -5043,7 +5373,7 @@ function distance(a, b) {
|
|
|
5043
5373
|
}
|
|
5044
5374
|
return row[b.length];
|
|
5045
5375
|
}
|
|
5046
|
-
function
|
|
5376
|
+
function check3(value, path, scope, known, add) {
|
|
5047
5377
|
if (!isObject(value)) return;
|
|
5048
5378
|
for (const key of Object.keys(value)) {
|
|
5049
5379
|
if (known.has(key)) continue;
|
|
@@ -5066,8 +5396,8 @@ function checkFields(fields, path, add) {
|
|
|
5066
5396
|
if (!isObject(field)) continue;
|
|
5067
5397
|
const at = `${path}.${typeof field.name === "string" ? field.name : `[${i}]`}`;
|
|
5068
5398
|
const known = typeof field.type === "string" ? FIELD[field.type] : void 0;
|
|
5069
|
-
if (known && field.customType === void 0)
|
|
5070
|
-
|
|
5399
|
+
if (known && field.customType === void 0) check3(field, at, "field", known, add);
|
|
5400
|
+
check3(field.admin, `${at}.admin`, "fieldAdmin", FIELD_ADMIN, add);
|
|
5071
5401
|
checkFields(field.fields, `${at}.fields`, add);
|
|
5072
5402
|
if (Array.isArray(field.blocks)) {
|
|
5073
5403
|
for (const block of field.blocks)
|
|
@@ -5077,21 +5407,21 @@ function checkFields(fields, path, add) {
|
|
|
5077
5407
|
}
|
|
5078
5408
|
function checkConfigKeys(config, add) {
|
|
5079
5409
|
const c = config;
|
|
5080
|
-
|
|
5081
|
-
|
|
5410
|
+
check3(c, "", "config", CONFIG, add);
|
|
5411
|
+
check3(c.admin, "admin", "admin", ADMIN, add);
|
|
5082
5412
|
const admin = isObject(c.admin) ? c.admin : {};
|
|
5083
5413
|
if (Array.isArray(admin.commands)) {
|
|
5084
5414
|
for (const [i, command] of admin.commands.entries())
|
|
5085
5415
|
if (isObject(command) && "to" in command)
|
|
5086
5416
|
add({ path: `admin.commands[${i}].to`, message: "is now `href`" });
|
|
5087
5417
|
}
|
|
5088
|
-
|
|
5089
|
-
if (isObject(c.auth))
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
if (isObject(c.audit))
|
|
5093
|
-
if (isObject(c.rateLimit))
|
|
5094
|
-
|
|
5418
|
+
check3(c.auth, "auth", "auth", AUTH, add);
|
|
5419
|
+
if (isObject(c.auth)) check3(c.auth.members, "auth.members", "members", MEMBERS, add);
|
|
5420
|
+
check3(c.upload, "upload", "upload", UPLOAD, add);
|
|
5421
|
+
check3(c.backups, "backups", "backups", BACKUPS, add);
|
|
5422
|
+
if (isObject(c.audit)) check3(c.audit, "audit", "audit", AUDIT, add);
|
|
5423
|
+
if (isObject(c.rateLimit)) check3(c.rateLimit, "rateLimit", "rateLimit", RATE_LIMIT, add);
|
|
5424
|
+
check3(c.logs, "logs", "logs", LOGS, add);
|
|
5095
5425
|
for (const [kind, list] of [
|
|
5096
5426
|
["collections", c.collections],
|
|
5097
5427
|
["globals", c.globals]
|
|
@@ -5101,8 +5431,8 @@ function checkConfigKeys(config, add) {
|
|
|
5101
5431
|
for (const [i, item] of list.entries()) {
|
|
5102
5432
|
if (!isObject(item)) continue;
|
|
5103
5433
|
const at = `${kind}.${typeof item.slug === "string" ? item.slug : `[${i}]`}`;
|
|
5104
|
-
|
|
5105
|
-
|
|
5434
|
+
check3(item, at, collection2 ? "collection" : "global", collection2 ? COLLECTION : GLOBAL, add);
|
|
5435
|
+
check3(
|
|
5106
5436
|
item.admin,
|
|
5107
5437
|
`${at}.admin`,
|
|
5108
5438
|
"admin-of",
|
|
@@ -5110,9 +5440,9 @@ function checkConfigKeys(config, add) {
|
|
|
5110
5440
|
add
|
|
5111
5441
|
);
|
|
5112
5442
|
if (collection2 && isObject(item.admin) && isObject(item.admin.calendar))
|
|
5113
|
-
|
|
5443
|
+
check3(item.admin.calendar, `${at}.admin.calendar`, "calendar", keys("start end color"), add);
|
|
5114
5444
|
if (isObject(item.versions))
|
|
5115
|
-
|
|
5445
|
+
check3(item.versions, `${at}.versions`, "versions", keys("keep"), add);
|
|
5116
5446
|
checkFields(item.fields, `${at}.fields`, add);
|
|
5117
5447
|
}
|
|
5118
5448
|
}
|
|
@@ -5561,7 +5891,7 @@ var Webhooks = class {
|
|
|
5561
5891
|
const claimed = await this.queue.claim(id, queued, {
|
|
5562
5892
|
...queued,
|
|
5563
5893
|
attempts,
|
|
5564
|
-
nextAttemptAt:
|
|
5894
|
+
nextAttemptAt: later4(now, CLAIM2)
|
|
5565
5895
|
});
|
|
5566
5896
|
if (!claimed) continue;
|
|
5567
5897
|
const result = await this.attempt(hook, queued.event, queued.body, queued.delivery);
|
|
@@ -5575,7 +5905,7 @@ var Webhooks = class {
|
|
|
5575
5905
|
await this.queue.update(id, {
|
|
5576
5906
|
...queued,
|
|
5577
5907
|
attempts,
|
|
5578
|
-
nextAttemptAt:
|
|
5908
|
+
nextAttemptAt: later4(now, delay ?? 0),
|
|
5579
5909
|
state: delay === void 0 ? "failed" : "pending",
|
|
5580
5910
|
error: result.error
|
|
5581
5911
|
});
|
|
@@ -5613,7 +5943,7 @@ var Webhooks = class {
|
|
|
5613
5943
|
error
|
|
5614
5944
|
});
|
|
5615
5945
|
const { queue } = this;
|
|
5616
|
-
const saved = queue ? this.saving.then(() => queue.add(entry(0,
|
|
5946
|
+
const saved = queue ? this.saving.then(() => queue.add(entry(0, later4(/* @__PURE__ */ new Date(), CLAIM2), null))) : Promise.resolve(void 0);
|
|
5617
5947
|
this.saving = saved.catch(() => {
|
|
5618
5948
|
});
|
|
5619
5949
|
let queued;
|
|
@@ -5634,7 +5964,7 @@ var Webhooks = class {
|
|
|
5634
5964
|
if (delay === void 0) {
|
|
5635
5965
|
if (queued === void 0 || !this.queue)
|
|
5636
5966
|
return this.giveUp(hook, event, result.error, attempt + 1);
|
|
5637
|
-
const next =
|
|
5967
|
+
const next = later4(/* @__PURE__ */ new Date(), QUEUE_DELAYS2[0]);
|
|
5638
5968
|
await this.queue.update(queued, entry(attempt + 1, next, result.error));
|
|
5639
5969
|
this.logger.warn(
|
|
5640
5970
|
`Webhook ${hook.url} failed for ${event} (${result.error}); will retry later`
|
|
@@ -5682,7 +6012,7 @@ var Webhooks = class {
|
|
|
5682
6012
|
);
|
|
5683
6013
|
}
|
|
5684
6014
|
};
|
|
5685
|
-
var
|
|
6015
|
+
var later4 = (from, ms) => new Date(from.getTime() + ms).toISOString();
|
|
5686
6016
|
var isContentEvent = (event) => WEBHOOK_EVENTS.includes(event);
|
|
5687
6017
|
function matches(hook, payload) {
|
|
5688
6018
|
if (!isContentEvent(payload.event)) return hook.events?.includes(payload.event) === true;
|
|
@@ -6593,7 +6923,7 @@ function validateNav(config, add) {
|
|
|
6593
6923
|
add("admin.nav", "must be a list of groups", "e.g. nav: [{ id: 'shop', label: 'Shop' }]");
|
|
6594
6924
|
else
|
|
6595
6925
|
nav.forEach((group, i) => {
|
|
6596
|
-
const
|
|
6926
|
+
const check4 = (g, path, child) => {
|
|
6597
6927
|
const { id, label, children, order } = g ?? {};
|
|
6598
6928
|
if (typeof id !== "string" || !NAV_ID.test(id))
|
|
6599
6929
|
add(`${path}.id`, "must be lowercase letters, digits and -", "e.g. 'shop'");
|
|
@@ -6606,11 +6936,11 @@ function validateNav(config, add) {
|
|
|
6606
6936
|
else if (!Array.isArray(children)) add(`${path}.children`, "must be a list of groups");
|
|
6607
6937
|
else
|
|
6608
6938
|
children.forEach((c, j) => {
|
|
6609
|
-
|
|
6939
|
+
check4(c, `${path}.children[${j}]`, true);
|
|
6610
6940
|
});
|
|
6611
6941
|
}
|
|
6612
6942
|
};
|
|
6613
|
-
|
|
6943
|
+
check4(group, `admin.nav[${i}]`, false);
|
|
6614
6944
|
});
|
|
6615
6945
|
}
|
|
6616
6946
|
const commands = config.admin?.commands;
|
|
@@ -7388,6 +7718,7 @@ async function resolveConfig(input) {
|
|
|
7388
7718
|
...config.outbox ? [outboxCollection] : [],
|
|
7389
7719
|
...config.rateLimit ? [rateLimitsCollection] : [],
|
|
7390
7720
|
databaseBackupsCollection,
|
|
7721
|
+
bulkOperationsCollection,
|
|
7391
7722
|
...config.auth?.rbac ? [rolesCollection] : [],
|
|
7392
7723
|
...(config.auth?.providers?.length ?? 0) > 0 ? [userIdentitiesCollection] : [],
|
|
7393
7724
|
...config.audit ? [auditLogsCollection] : []
|
|
@@ -7457,7 +7788,7 @@ function cacheableResponse(request, body, status, headers, times, tags) {
|
|
|
7457
7788
|
}
|
|
7458
7789
|
|
|
7459
7790
|
// src/version.ts
|
|
7460
|
-
var VERSION = true ? "1.
|
|
7791
|
+
var VERSION = true ? "1.25.1" : "0.0.0-dev";
|
|
7461
7792
|
|
|
7462
7793
|
// src/telemetry.ts
|
|
7463
7794
|
var DB_CALLS = /* @__PURE__ */ new Set([
|
|
@@ -9052,7 +9383,7 @@ var EasyCMS = class {
|
|
|
9052
9383
|
const parsed = parseId(id);
|
|
9053
9384
|
if (parsed === void 0) return { update: false, delete: false };
|
|
9054
9385
|
const guard = { enforce: true, user, context };
|
|
9055
|
-
const
|
|
9386
|
+
const check4 = (operation) => this.checkDocumentAccess(config, operation, guard, parsed, void 0).then(
|
|
9056
9387
|
() => true,
|
|
9057
9388
|
(error) => {
|
|
9058
9389
|
if (error instanceof ForbiddenError || error instanceof UnauthorizedError || error instanceof NotFoundError)
|
|
@@ -9060,7 +9391,7 @@ var EasyCMS = class {
|
|
|
9060
9391
|
throw error;
|
|
9061
9392
|
}
|
|
9062
9393
|
);
|
|
9063
|
-
return { update: await
|
|
9394
|
+
return { update: await check4("update"), delete: await check4("delete") };
|
|
9064
9395
|
}
|
|
9065
9396
|
/** Closes the database connection. */
|
|
9066
9397
|
/**
|
|
@@ -9287,7 +9618,11 @@ var EasyCMS = class {
|
|
|
9287
9618
|
webhooks: await this.retryWebhooks(now),
|
|
9288
9619
|
emails: await this.mailer.retry(now),
|
|
9289
9620
|
jobs: await this.runConfigJobs(now),
|
|
9290
|
-
outbox: await this.outbox?.run(now) ?? { ran: 0, failed: 0 }
|
|
9621
|
+
outbox: await this.outbox?.run(now) ?? { ran: 0, failed: 0 },
|
|
9622
|
+
bulk: await runBulkOperations(this, now).catch((error) => {
|
|
9623
|
+
this.logger.error(`Bulk actions: ${error.message}`, { error });
|
|
9624
|
+
return { steps: 0 };
|
|
9625
|
+
})
|
|
9291
9626
|
};
|
|
9292
9627
|
if (this.telemetry?.measuresQueues)
|
|
9293
9628
|
await this.countQueues(now).catch(
|
|
@@ -9878,9 +10213,9 @@ var EasyCMS = class {
|
|
|
9878
10213
|
);
|
|
9879
10214
|
}
|
|
9880
10215
|
/** Runs a check; a `ForbiddenError` for a document the user can't read becomes a 404. */
|
|
9881
|
-
async hidingDenied(collection2, guard, id,
|
|
10216
|
+
async hidingDenied(collection2, guard, id, check4) {
|
|
9882
10217
|
try {
|
|
9883
|
-
await
|
|
10218
|
+
await check4();
|
|
9884
10219
|
} catch (error) {
|
|
9885
10220
|
if (error instanceof ForbiddenError && !await this.mayRead(collection2, guard, id))
|
|
9886
10221
|
throw new NotFoundError(collection2, String(id));
|
|
@@ -9976,7 +10311,7 @@ var EasyCMS = class {
|
|
|
9976
10311
|
/** Runs afterRead hooks, populates relationships and removes what the caller may not see. */
|
|
9977
10312
|
async output(config, docs, guard, options) {
|
|
9978
10313
|
const read2 = await this.fieldChecker("read", guard, void 0, void 0);
|
|
9979
|
-
const
|
|
10314
|
+
const finish2 = async (target, doc) => {
|
|
9980
10315
|
const hooked = await this.transform(
|
|
9981
10316
|
target.hooks?.afterRead,
|
|
9982
10317
|
"doc",
|
|
@@ -10001,13 +10336,13 @@ var EasyCMS = class {
|
|
|
10001
10336
|
});
|
|
10002
10337
|
const docs2 = drafts ? await this.withDrafts(target, found.docs) : found.docs;
|
|
10003
10338
|
return Promise.all(
|
|
10004
|
-
docs2.map((d) =>
|
|
10339
|
+
docs2.map((d) => finish2(target, this.pick(target, d, options)))
|
|
10005
10340
|
);
|
|
10006
10341
|
};
|
|
10007
10342
|
const depth = Math.max(0, Math.min(MAX_DEPTH, Math.trunc(options.depth ?? DEFAULT_DEPTH)));
|
|
10008
10343
|
const localized = docs.map((d) => this.pick(config, d, options));
|
|
10009
10344
|
const populated = await populate(load, this.config.collections, config.fields, localized, depth);
|
|
10010
|
-
return Promise.all(populated.map((d) =>
|
|
10345
|
+
return Promise.all(populated.map((d) => finish2(config, d)));
|
|
10011
10346
|
}
|
|
10012
10347
|
/** Creates a document: access, input filtering, hooks, validation, then afterChange. */
|
|
10013
10348
|
async createDocument(config, raw, options, hookGuard) {
|
|
@@ -12646,6 +12981,7 @@ var ADMIN_UI_ROUTES = /* @__PURE__ */ new Set([
|
|
|
12646
12981
|
"modules",
|
|
12647
12982
|
"scheduled",
|
|
12648
12983
|
"access",
|
|
12984
|
+
"bulk",
|
|
12649
12985
|
"total",
|
|
12650
12986
|
"media-usage",
|
|
12651
12987
|
"owned",
|
|
@@ -13233,6 +13569,8 @@ async function route(cms, ctx, method, path, options) {
|
|
|
13233
13569
|
body: { total: Math.min(total, LIST_TOTAL_MAX), more: total > LIST_TOTAL_MAX }
|
|
13234
13570
|
};
|
|
13235
13571
|
}
|
|
13572
|
+
if (second === "bulk" && third === void 0)
|
|
13573
|
+
return { body: { docs: await bulkOperations(cms, ctx.user) } };
|
|
13236
13574
|
const [, , collection3, id2, extra] = segments;
|
|
13237
13575
|
if (second === "access" && collection3 && id2 && extra === void 0) {
|
|
13238
13576
|
if (INTERNAL_COLLECTIONS.has(collection3) || !cms.config.collections.some((c) => c.slug === collection3)) {
|
|
@@ -13350,6 +13688,7 @@ async function route(cms, ctx, method, path, options) {
|
|
|
13350
13688
|
if (INTERNAL_COLLECTIONS.has(collection2) || !cms.config.collections.some((c) => c.slug === collection2)) {
|
|
13351
13689
|
throw new HttpError(`Unknown collection "${collection2}"`, 404);
|
|
13352
13690
|
}
|
|
13691
|
+
if (second === "bulk") return bulkRoute(cms, ctx, method, collection2, segments.slice(2), access);
|
|
13353
13692
|
if (second !== void 0 && third !== void 0) {
|
|
13354
13693
|
return documentAction(cms, ctx, method, collection2, second, segments.slice(2));
|
|
13355
13694
|
}
|
|
@@ -13487,6 +13826,42 @@ async function documentAction(cms, ctx, method, collection2, id, path) {
|
|
|
13487
13826
|
}
|
|
13488
13827
|
throw new HttpError("Not found", 404);
|
|
13489
13828
|
}
|
|
13829
|
+
async function bulkRoute(cms, ctx, method, collection2, path, access) {
|
|
13830
|
+
const user = ctx.user;
|
|
13831
|
+
if (!user) throw new UnauthorizedError();
|
|
13832
|
+
const [raw, action, extra] = path;
|
|
13833
|
+
if (raw === void 0) {
|
|
13834
|
+
if (method !== "POST") throw methodNotAllowed(ctx, "POST");
|
|
13835
|
+
const body = await readJson(ctx.request);
|
|
13836
|
+
const options = {
|
|
13837
|
+
user,
|
|
13838
|
+
...access.context ? { context: access.context } : {},
|
|
13839
|
+
...body.folder !== void 0 ? { folder: body.folder } : {},
|
|
13840
|
+
...body.transferTo !== void 0 ? { transferTo: body.transferTo } : {}
|
|
13841
|
+
};
|
|
13842
|
+
const name = String(body.action ?? "");
|
|
13843
|
+
if (Array.isArray(body.ids))
|
|
13844
|
+
return { body: await bulkIds(cms, collection2, name, body.ids, options) };
|
|
13845
|
+
const where = body.where;
|
|
13846
|
+
if (where !== void 0 && (typeof where !== "object" || where === null || Array.isArray(where)))
|
|
13847
|
+
throw new QueryError("where must be an object");
|
|
13848
|
+
return {
|
|
13849
|
+
status: 202,
|
|
13850
|
+
body: await startBulk(cms, collection2, name, where, options)
|
|
13851
|
+
};
|
|
13852
|
+
}
|
|
13853
|
+
const id = parseId(raw);
|
|
13854
|
+
if (id === void 0) throw new HttpError("Not found", 404);
|
|
13855
|
+
if (action === void 0) {
|
|
13856
|
+
if (method !== "GET") throw methodNotAllowed(ctx, "GET");
|
|
13857
|
+
return { body: await bulkProgress(cms, id, user) };
|
|
13858
|
+
}
|
|
13859
|
+
if (action === "cancel" && extra === void 0) {
|
|
13860
|
+
if (method !== "POST") throw methodNotAllowed(ctx, "POST");
|
|
13861
|
+
return { body: await cancelBulk(cms, id, user) };
|
|
13862
|
+
}
|
|
13863
|
+
throw new HttpError("Not found", 404);
|
|
13864
|
+
}
|
|
13490
13865
|
async function globalAction(cms, ctx, method, slug2, path) {
|
|
13491
13866
|
const access = {
|
|
13492
13867
|
overrideAccess: false,
|
|
@@ -2190,6 +2190,10 @@ declare class EasyCMS<C extends Config = Config> {
|
|
|
2190
2190
|
ran: number;
|
|
2191
2191
|
failed: number;
|
|
2192
2192
|
};
|
|
2193
|
+
/** Steps of bulk actions on a list's matches (100 documents each). */
|
|
2194
|
+
bulk: {
|
|
2195
|
+
steps: number;
|
|
2196
|
+
};
|
|
2193
2197
|
}>;
|
|
2194
2198
|
private runJobsNow;
|
|
2195
2199
|
/**
|
|
@@ -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-Bsp6rkuH.js';
|
|
2
2
|
|
|
3
3
|
/** Decrypts a file from `encryptBackup`; throws for another key or a changed file. */
|
|
4
4
|
declare function decryptBackup(data: Uint8Array, encryptionKey: string): Uint8Array;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-
|
|
2
|
-
export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as 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 UnauthorizedError, cs as UncountedDocs, ct as UpdateInput, cu as UpdateOptions, cv as UploadConfig, cw as UploadField, cx as UploadFromURLConfig, cy as UserIdentity, cz as ValidationError, cA as Version, cB as VersionSummary, cC as VersionsConfig, cD as WEBHOOK_EVENTS, cE as WebhookConfig, cF as WebhookEvent, cG as Where, cH as WhereOperators, cI as anyone, cJ as consoleEmail, cK as consoleLogger, cL as createEasyCMS, cM as defineConfig, cN as defineFieldType, cO as definePlugin, cP as diskStorage, cQ as hasRows, cR as isAdmin, cS as isHasMany, cT as isSignedIn, cU as isStaff, cV as isSystemAdmin, cW as jsonLogger, cX as memorySearch, cY as mimeAllowedBy, cZ as rowFields, c_ as silentLogger, c$ as uniqueWithinOf } from './config-
|
|
3
|
-
export { A as ADMIN_API_VERSION, a as AdminCollection, b as AdminComponentRef, c as AdminElementProps, d as AdminField, e as AdminGlobal, f as AdminLayoutNode, g as AdminNavGroup, h as AdminNavItem, i as AdminNavNode, j as AdminPageRef, k as AdminPageRoute, l as AdminSchema, m as AdminWidgetRef, S as SetFieldDetail, w as warnDeprecated } from './plugin-
|
|
4
|
-
export { A as AdminBackup, a as AdminBackups, b as ApiHandlerOptions, B as BackupState, L as LoadConfigOptions, R as RestHandler, c as RestHandlerOptions, d as createApiHandler, e as createRestHandler, l as loadConfig, r as resolveConfig, s as sharedEasyCMS, f as slugify } from './handler-
|
|
1
|
+
import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-Bsp6rkuH.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 UnauthorizedError, cs as UncountedDocs, ct as UpdateInput, cu as UpdateOptions, cv as UploadConfig, cw as UploadField, cx as UploadFromURLConfig, cy as UserIdentity, cz as ValidationError, cA as Version, cB as VersionSummary, cC as VersionsConfig, cD as WEBHOOK_EVENTS, cE as WebhookConfig, cF as WebhookEvent, cG as Where, cH as WhereOperators, cI as anyone, cJ as consoleEmail, cK as consoleLogger, cL as createEasyCMS, cM as defineConfig, cN as defineFieldType, cO as definePlugin, cP as diskStorage, cQ as hasRows, cR as isAdmin, cS as isHasMany, cT as isSignedIn, cU as isStaff, cV as isSystemAdmin, cW as jsonLogger, cX as memorySearch, cY as mimeAllowedBy, cZ as rowFields, c_ as silentLogger, c$ as uniqueWithinOf } from './config-Bsp6rkuH.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-CUzEJN31.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-Br9Pu6z9.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
1
|
import { Config, Database, EasyCMS, NavGroup, CollectionConfig, ID, RawDocument, Field, ResolvedConfig, ConfigIssue } from './index.js';
|
|
2
|
-
export { d0 as API_KEYS, d1 as API_KEY_GLOBAL_OPERATIONS, d2 as API_KEY_OPERATIONS, d3 as DEFAULT_MAX_VERSIONS, d4 as DEFAULT_PASSWORD_EMAILS, d5 as FIELD_TYPE_BASES, d6 as FOLDER_LEVELS, d7 as MediaFolders, d8 as SSO_COOKIE, d9 as Secrets, cl as TRIGRAM_LIKE_MIN, da as codeOfStatus, cQ as hasRows, cS as isHasMany, db as isJsonLogger, dc as keyAllows, dd as logFormat, cY as mimeAllowedBy, cZ as rowFields, de as secretsOf, c$ as uniqueWithinOf } from './config-
|
|
3
|
-
export { C as CONFIG_FILE_NAMES, g as CSRF_COOKIE, h as CSRF_HEADER, D as DEFAULT_ADMIN_PATH, i as DEFAULT_API_PATH, j as DEFAULT_MAX_FILE_SIZE, k as DEFAULT_TOKEN_EXPIRATION, m as applyDefaults, n as applyPlugins, o as createRootEndpointHandler, p as decryptBackup, q as fillMissing, t as findConfigFile, u as forwardedClientIp, v as generateSlugs, w as importConfig, x as isEmail, y as mergeForUpdate, z as parseId, E as platformClientIp, F as readCookie, G as validateFields, H as writeBackupFile } from './handler-
|
|
2
|
+
export { d0 as API_KEYS, d1 as API_KEY_GLOBAL_OPERATIONS, d2 as API_KEY_OPERATIONS, d3 as DEFAULT_MAX_VERSIONS, d4 as DEFAULT_PASSWORD_EMAILS, d5 as FIELD_TYPE_BASES, d6 as FOLDER_LEVELS, d7 as MediaFolders, d8 as SSO_COOKIE, d9 as Secrets, cl as TRIGRAM_LIKE_MIN, da as codeOfStatus, cQ as hasRows, cS as isHasMany, db as isJsonLogger, dc as keyAllows, dd as logFormat, cY as mimeAllowedBy, cZ as rowFields, de as secretsOf, c$ as uniqueWithinOf } from './config-Bsp6rkuH.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-Br9Pu6z9.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 { 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-Bsp6rkuH.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, cr as UnauthorizedError, cz as ValidationError, cG as Where, cN as defineFieldType, cO as definePlugin } from './config-
|
|
2
|
-
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-
|
|
1
|
+
export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, 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, cr as UnauthorizedError, cz as ValidationError, cG as Where, cN as defineFieldType, cO as definePlugin } from './config-Bsp6rkuH.js';
|
|
2
|
+
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-CUzEJN31.js';
|
|
3
3
|
import './conditions.js';
|