@dyrected/core 2.5.44 → 2.5.46
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/LICENSE.md +1 -1
- package/dist/index.cjs +95 -86
- package/dist/index.js +10 -16
- package/dist/server.cjs +339 -411
- package/dist/server.js +235 -312
- package/package.json +1 -1
package/LICENSE.md
CHANGED
|
@@ -4,7 +4,7 @@ Parameters
|
|
|
4
4
|
|
|
5
5
|
Licensor: Dyrected
|
|
6
6
|
Licensed Work: Dyrected
|
|
7
|
-
Additional Use Grant:
|
|
7
|
+
Additional Use Grant: Production use and commercial use of the Licensed Work are permitted for your own internal business operations, your own websites and applications, and client websites or applications that you build or deploy on behalf of a client, provided that you do not, without a separate commercial license from the Licensor, (a) provide the Licensed Work as a hosted or managed service to third parties, (b) embed, white-label, sublicense, or otherwise redistribute the Licensed Work as part of a multi-tenant or customer-facing SaaS, platform, or developer service, or (c) enable third parties to create, manage, or operate independent projects, sites, workspaces, or environments using the Licensed Work as a material part of the service you provide.
|
|
8
8
|
Change Date: 2030-05-18
|
|
9
9
|
Change License: Apache License 2.0
|
|
10
10
|
|
package/dist/index.cjs
CHANGED
|
@@ -51,7 +51,7 @@ __export(index_exports, {
|
|
|
51
51
|
});
|
|
52
52
|
module.exports = __toCommonJS(index_exports);
|
|
53
53
|
|
|
54
|
-
// src/types/workflows.
|
|
54
|
+
// src/types/workflows.ts
|
|
55
55
|
var LIFECYCLE_EVENT_NAMES = [
|
|
56
56
|
"revision.created",
|
|
57
57
|
"workflow.transitioned",
|
|
@@ -59,7 +59,7 @@ var LIFECYCLE_EVENT_NAMES = [
|
|
|
59
59
|
"entry.unpublished"
|
|
60
60
|
];
|
|
61
61
|
|
|
62
|
-
// src/workflows.
|
|
62
|
+
// src/workflows.ts
|
|
63
63
|
var WORKFLOW_HISTORY_COLLECTION = "__workflow_history";
|
|
64
64
|
var LIFECYCLE_EVENTS_COLLECTION = "__lifecycle_events";
|
|
65
65
|
function publishingWorkflow() {
|
|
@@ -92,18 +92,17 @@ function workflowCapabilities(workflow, user) {
|
|
|
92
92
|
const capabilities = new Set(Array.isArray(user?.capabilities) ? user.capabilities : []);
|
|
93
93
|
const roles = Array.isArray(user?.roles) ? user.roles : [];
|
|
94
94
|
for (const mapping of workflow.roles ?? []) {
|
|
95
|
-
if (roles.includes(mapping.role))
|
|
96
|
-
mapping.capabilities.forEach((capability) => capabilities.add(capability));
|
|
95
|
+
if (roles.includes(mapping.role)) mapping.capabilities.forEach((capability) => capabilities.add(capability));
|
|
97
96
|
}
|
|
98
97
|
return capabilities;
|
|
99
98
|
}
|
|
100
99
|
function canViewWorkflowDraft(workflow, user) {
|
|
101
|
-
if (!user)
|
|
102
|
-
return false;
|
|
100
|
+
if (!user) return false;
|
|
103
101
|
const capabilities = workflowCapabilities(workflow, user);
|
|
104
|
-
if (capabilities.has("entry.edit"))
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
if (capabilities.has("entry.edit")) return true;
|
|
103
|
+
return workflow.transitions.some(
|
|
104
|
+
(transition) => (transition.requiredCapabilities ?? []).some((capability) => capabilities.has(capability))
|
|
105
|
+
);
|
|
107
106
|
}
|
|
108
107
|
function availableWorkflowTransitions(workflow, state, user) {
|
|
109
108
|
const capabilities = workflowCapabilities(workflow, user);
|
|
@@ -120,12 +119,10 @@ function initializeWorkflowDocument(data, workflow) {
|
|
|
120
119
|
}
|
|
121
120
|
function materializeWorkflowDocument(doc, workflow, user) {
|
|
122
121
|
const meta = doc.__workflow;
|
|
123
|
-
if (!meta)
|
|
124
|
-
return doc;
|
|
122
|
+
if (!meta) return doc;
|
|
125
123
|
const { __published, __workflow, ...working } = doc;
|
|
126
124
|
if (!canViewWorkflowDraft(workflow, user)) {
|
|
127
|
-
if (!__published || typeof __published !== "object")
|
|
128
|
-
return null;
|
|
125
|
+
if (!__published || typeof __published !== "object") return null;
|
|
129
126
|
return { id: doc.id, ...__published, _workflow: publicMetadata(meta) };
|
|
130
127
|
}
|
|
131
128
|
return {
|
|
@@ -157,15 +154,13 @@ async function persistEvent(db, event) {
|
|
|
157
154
|
}
|
|
158
155
|
async function dispatchLifecycleEvent(config, event) {
|
|
159
156
|
const db = config.db;
|
|
160
|
-
if (!db || !config.events?.handlers.length)
|
|
161
|
-
return;
|
|
157
|
+
if (!db || !config.events?.handlers.length) return;
|
|
162
158
|
const maxAttempts = config.events.maxAttempts ?? 8;
|
|
163
159
|
const retryDelayMs = config.events.retryDelayMs ?? 1e3;
|
|
164
160
|
const attempts = event.attempts + 1;
|
|
165
161
|
try {
|
|
166
162
|
await db.update({ collection: LIFECYCLE_EVENTS_COLLECTION, id: event.id, data: { status: "processing", attempts } });
|
|
167
|
-
for (const handler of config.events.handlers)
|
|
168
|
-
await handler({ ...event, status: "processing", attempts });
|
|
163
|
+
for (const handler of config.events.handlers) await handler({ ...event, status: "processing", attempts });
|
|
169
164
|
await db.update({
|
|
170
165
|
collection: LIFECYCLE_EVENTS_COLLECTION,
|
|
171
166
|
id: event.id,
|
|
@@ -186,8 +181,7 @@ async function dispatchLifecycleEvent(config, event) {
|
|
|
186
181
|
}
|
|
187
182
|
}
|
|
188
183
|
async function dispatchPendingLifecycleEvents(config, limit = 50) {
|
|
189
|
-
if (!config.db || !config.events?.handlers.length)
|
|
190
|
-
return 0;
|
|
184
|
+
if (!config.db || !config.events?.handlers.length) return 0;
|
|
191
185
|
const maxAttempts = config.events.maxAttempts ?? 8;
|
|
192
186
|
const result = await config.db.find({
|
|
193
187
|
collection: LIFECYCLE_EVENTS_COLLECTION,
|
|
@@ -196,17 +190,17 @@ async function dispatchPendingLifecycleEvents(config, limit = 50) {
|
|
|
196
190
|
limit
|
|
197
191
|
});
|
|
198
192
|
const now = Date.now();
|
|
199
|
-
const due = result.docs.filter(
|
|
200
|
-
|
|
201
|
-
|
|
193
|
+
const due = result.docs.filter(
|
|
194
|
+
(doc) => Number(doc.attempts ?? 0) < maxAttempts && (!doc.nextAttemptAt || new Date(doc.nextAttemptAt).getTime() <= now)
|
|
195
|
+
);
|
|
196
|
+
for (const event of due) await dispatchLifecycleEvent(config, event);
|
|
202
197
|
return due.length;
|
|
203
198
|
}
|
|
204
199
|
async function saveWorkflowDraft(args) {
|
|
205
200
|
const { config, collection, id, originalDoc, data, user } = args;
|
|
206
201
|
const db = config.db;
|
|
207
202
|
const workflow = collection.workflow;
|
|
208
|
-
if (!db.transaction)
|
|
209
|
-
throw new Error(`The configured database adapter does not support workflow transactions.`);
|
|
203
|
+
if (!db.transaction) throw new Error(`The configured database adapter does not support workflow transactions.`);
|
|
210
204
|
const previous = originalDoc.__workflow;
|
|
211
205
|
const event = createLifecycleEvent({
|
|
212
206
|
name: "revision.created",
|
|
@@ -231,8 +225,7 @@ async function saveWorkflowDraft(args) {
|
|
|
231
225
|
async function createWorkflowDocument(args) {
|
|
232
226
|
const { config, collection, data, user } = args;
|
|
233
227
|
const db = config.db;
|
|
234
|
-
if (!db.transaction)
|
|
235
|
-
throw new Error(`The configured database adapter does not support workflow transactions.`);
|
|
228
|
+
if (!db.transaction) throw new Error(`The configured database adapter does not support workflow transactions.`);
|
|
236
229
|
let event;
|
|
237
230
|
const doc = await db.transaction(async (tx) => {
|
|
238
231
|
const created = await tx.create({ collection: collection.slug, data });
|
|
@@ -253,14 +246,11 @@ async function transitionWorkflow(args) {
|
|
|
253
246
|
const { config, collection, id, transitionName, expectedRevision, comment, user, req } = args;
|
|
254
247
|
const db = config.db;
|
|
255
248
|
const workflow = collection.workflow;
|
|
256
|
-
if (!db.transaction)
|
|
257
|
-
throw new Error(`The configured database adapter does not support workflow transactions.`);
|
|
249
|
+
if (!db.transaction) throw new Error(`The configured database adapter does not support workflow transactions.`);
|
|
258
250
|
const original = await db.findOne({ collection: collection.slug, id });
|
|
259
|
-
if (!original)
|
|
260
|
-
throw Object.assign(new Error("Not Found"), { statusCode: 404 });
|
|
251
|
+
if (!original) throw Object.assign(new Error("Not Found"), { statusCode: 404 });
|
|
261
252
|
const meta = original.__workflow;
|
|
262
|
-
if (!meta)
|
|
263
|
-
throw Object.assign(new Error("Entry has no workflow metadata"), { statusCode: 409 });
|
|
253
|
+
if (!meta) throw Object.assign(new Error("Entry has no workflow metadata"), { statusCode: 409 });
|
|
264
254
|
if (expectedRevision !== void 0 && expectedRevision !== meta.revision) {
|
|
265
255
|
throw Object.assign(new Error("This entry changed since it was loaded. Refresh before transitioning it."), { statusCode: 409 });
|
|
266
256
|
}
|
|
@@ -276,8 +266,7 @@ async function transitionWorkflow(args) {
|
|
|
276
266
|
throw Object.assign(new Error(`A comment is required for "${transition.label}".`), { statusCode: 400 });
|
|
277
267
|
}
|
|
278
268
|
const hookContext = { transition, from: meta.state, to: transition.to, doc: original, user, comment, req, db };
|
|
279
|
-
for (const hook of workflow.hooks?.beforeTransition ?? [])
|
|
280
|
-
await hook(hookContext);
|
|
269
|
+
for (const hook of workflow.hooks?.beforeTransition ?? []) await hook(hookContext);
|
|
281
270
|
const events = [createLifecycleEvent({
|
|
282
271
|
name: "workflow.transitioned",
|
|
283
272
|
collection: collection.slug,
|
|
@@ -293,8 +282,7 @@ async function transitionWorkflow(args) {
|
|
|
293
282
|
}
|
|
294
283
|
const updated = await db.transaction(async (tx) => {
|
|
295
284
|
const locked = await tx.findOne({ collection: collection.slug, id });
|
|
296
|
-
if (!locked)
|
|
297
|
-
throw Object.assign(new Error("Not Found"), { statusCode: 404 });
|
|
285
|
+
if (!locked) throw Object.assign(new Error("Not Found"), { statusCode: 404 });
|
|
298
286
|
const lockedMeta = locked.__workflow;
|
|
299
287
|
if (lockedMeta.revision !== meta.revision || lockedMeta.state !== meta.state || expectedRevision !== void 0 && lockedMeta.revision !== expectedRevision) {
|
|
300
288
|
throw Object.assign(new Error("This entry changed since it was loaded. Refresh before transitioning it."), { statusCode: 409 });
|
|
@@ -308,24 +296,20 @@ async function transitionWorkflow(args) {
|
|
|
308
296
|
...transition.unpublish ? { publishedRevision: void 0, publishedAt: void 0, publishedBy: void 0 } : {}
|
|
309
297
|
};
|
|
310
298
|
const data = { __workflow: nextMeta };
|
|
311
|
-
if (targetState.published)
|
|
312
|
-
|
|
313
|
-
if (transition.unpublish)
|
|
314
|
-
data.__published = null;
|
|
299
|
+
if (targetState.published) data.__published = working;
|
|
300
|
+
if (transition.unpublish) data.__published = null;
|
|
315
301
|
const next = await tx.update({ collection: collection.slug, id, data });
|
|
316
302
|
await tx.create({
|
|
317
303
|
collection: WORKFLOW_HISTORY_COLLECTION,
|
|
318
304
|
data: { collection: collection.slug, documentId: id, transition: transition.name, from: lockedMeta.state, to: transition.to, revision: lockedMeta.revision, comment: comment ?? null, actorId: user?.sub ?? null, createdAt: now }
|
|
319
305
|
});
|
|
320
|
-
for (const event of events)
|
|
321
|
-
await persistEvent(tx, event);
|
|
306
|
+
for (const event of events) await persistEvent(tx, event);
|
|
322
307
|
if (collection.audit) {
|
|
323
308
|
await tx.create({ collection: "__audit", data: { collection: collection.slug, documentId: id, operation: "workflow.transition", user: user?.sub ?? null, timestamp: now, changes: JSON.stringify({ transition: transition.name, from: lockedMeta.state, to: transition.to, revision: lockedMeta.revision }) } });
|
|
324
309
|
}
|
|
325
310
|
return next;
|
|
326
311
|
});
|
|
327
|
-
for (const event of events)
|
|
328
|
-
void dispatchLifecycleEvent(config, event);
|
|
312
|
+
for (const event of events) void dispatchLifecycleEvent(config, event);
|
|
329
313
|
for (const hook of workflow.hooks?.afterTransition ?? []) {
|
|
330
314
|
try {
|
|
331
315
|
await hook({ ...hookContext, doc: updated, event: events[0] });
|
|
@@ -336,7 +320,7 @@ async function transitionWorkflow(args) {
|
|
|
336
320
|
return updated;
|
|
337
321
|
}
|
|
338
322
|
|
|
339
|
-
// src/utils/admin-auth.
|
|
323
|
+
// src/utils/admin-auth.ts
|
|
340
324
|
function getAdminAuthCollection(config) {
|
|
341
325
|
const requestedSlug = config.adminAuth?.collectionSlug;
|
|
342
326
|
if (requestedSlug) {
|
|
@@ -360,12 +344,11 @@ function getPublicAdminAuthConfig(adminAuth) {
|
|
|
360
344
|
}
|
|
361
345
|
function humanizeProviderName(id, type) {
|
|
362
346
|
const cleaned = id.replace(/[-_]+/g, " ").trim();
|
|
363
|
-
if (!cleaned)
|
|
364
|
-
return type.toUpperCase();
|
|
347
|
+
if (!cleaned) return type.toUpperCase();
|
|
365
348
|
return cleaned.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
366
349
|
}
|
|
367
350
|
|
|
368
|
-
// src/utils/config.
|
|
351
|
+
// src/utils/config.ts
|
|
369
352
|
var AUDIT_COLLECTION_SLUG = "__audit";
|
|
370
353
|
var SYSTEM_FIELDS = [
|
|
371
354
|
{
|
|
@@ -579,8 +562,7 @@ function normalizeConfig(config) {
|
|
|
579
562
|
});
|
|
580
563
|
const hasAuditCollection = normalizedCollections.some((col) => col.slug === AUDIT_COLLECTION_SLUG);
|
|
581
564
|
const systemCollections = [];
|
|
582
|
-
if (needsAudit && !hasAuditCollection)
|
|
583
|
-
systemCollections.push(AUDIT_COLLECTION);
|
|
565
|
+
if (needsAudit && !hasAuditCollection) systemCollections.push(AUDIT_COLLECTION);
|
|
584
566
|
if (needsWorkflow && !normalizedCollections.some((col) => col.slug === WORKFLOW_HISTORY_COLLECTION)) {
|
|
585
567
|
systemCollections.push(WORKFLOW_HISTORY_COLLECTION_CONFIG);
|
|
586
568
|
}
|
|
@@ -594,7 +576,7 @@ function normalizeConfig(config) {
|
|
|
594
576
|
};
|
|
595
577
|
}
|
|
596
578
|
|
|
597
|
-
// src/utils/parse-where.
|
|
579
|
+
// src/utils/parse-where.ts
|
|
598
580
|
function assertNever(op, context) {
|
|
599
581
|
throw new Error(`[dyrected/core] Unhandled where operator "${op}" in ${context}`);
|
|
600
582
|
}
|
|
@@ -630,8 +612,7 @@ function parseSqlWhere(where, getJsonField, placeholder = "?") {
|
|
|
630
612
|
return `${c} != ${next()}`;
|
|
631
613
|
case "in": {
|
|
632
614
|
const vals = Array.isArray(operand) ? operand : [operand];
|
|
633
|
-
if (vals.length === 0)
|
|
634
|
-
return "1=0";
|
|
615
|
+
if (vals.length === 0) return "1=0";
|
|
635
616
|
const placeholders = vals.map((v) => {
|
|
636
617
|
params.push(v);
|
|
637
618
|
return next();
|
|
@@ -640,8 +621,7 @@ function parseSqlWhere(where, getJsonField, placeholder = "?") {
|
|
|
640
621
|
}
|
|
641
622
|
case "not_in": {
|
|
642
623
|
const vals = Array.isArray(operand) ? operand : [operand];
|
|
643
|
-
if (vals.length === 0)
|
|
644
|
-
return "1=1";
|
|
624
|
+
if (vals.length === 0) return "1=1";
|
|
645
625
|
const placeholders = vals.map((v) => {
|
|
646
626
|
params.push(v);
|
|
647
627
|
return next();
|
|
@@ -747,26 +727,22 @@ function parseMongoWhere(where) {
|
|
|
747
727
|
conditions.push(buildOperator(field, value));
|
|
748
728
|
}
|
|
749
729
|
}
|
|
750
|
-
if (conditions.length === 0)
|
|
751
|
-
|
|
752
|
-
if (conditions.length === 1)
|
|
753
|
-
return conditions[0];
|
|
730
|
+
if (conditions.length === 0) return {};
|
|
731
|
+
if (conditions.length === 1) return conditions[0];
|
|
754
732
|
return { $and: conditions };
|
|
755
733
|
}
|
|
756
734
|
return buildClause(where);
|
|
757
735
|
}
|
|
758
736
|
|
|
759
|
-
// src/utils/parse-sort.
|
|
737
|
+
// src/utils/parse-sort.ts
|
|
760
738
|
var SORT_FIELD_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)(?:\s+(ASC|DESC))?$/i;
|
|
761
739
|
function parseSort(sort, fallback = { field: "createdAt", direction: "DESC" }) {
|
|
762
|
-
if (!sort)
|
|
763
|
-
return [fallback];
|
|
740
|
+
if (!sort) return [fallback];
|
|
764
741
|
const clauses = sort.split(",").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
765
742
|
const descByPrefix = part.startsWith("-");
|
|
766
743
|
const withoutPrefix = descByPrefix ? part.slice(1).trim() : part;
|
|
767
744
|
const match = withoutPrefix.match(SORT_FIELD_PATTERN);
|
|
768
|
-
if (!match)
|
|
769
|
-
return null;
|
|
745
|
+
if (!match) return null;
|
|
770
746
|
return {
|
|
771
747
|
field: match[1],
|
|
772
748
|
direction: descByPrefix || match[2]?.toUpperCase() === "DESC" ? "DESC" : "ASC"
|
|
@@ -775,7 +751,7 @@ function parseSort(sort, fallback = { field: "createdAt", direction: "DESC" }) {
|
|
|
775
751
|
return clauses.length > 0 ? clauses : [fallback];
|
|
776
752
|
}
|
|
777
753
|
|
|
778
|
-
// src/utils/hooks.
|
|
754
|
+
// src/utils/hooks.ts
|
|
779
755
|
async function runCollectionHooks(hooks, args, options = {}) {
|
|
780
756
|
if (!hooks || hooks.length === 0) {
|
|
781
757
|
return args.data ?? args.doc ?? void 0;
|
|
@@ -802,12 +778,10 @@ async function runCollectionHooks(hooks, args, options = {}) {
|
|
|
802
778
|
return currentPayload;
|
|
803
779
|
}
|
|
804
780
|
async function executeFieldBeforeChange(fields, data, originalDoc, user, db) {
|
|
805
|
-
if (!data || typeof data !== "object")
|
|
806
|
-
return data;
|
|
781
|
+
if (!data || typeof data !== "object") return data;
|
|
807
782
|
const result = { ...data };
|
|
808
783
|
for (const field of fields) {
|
|
809
|
-
if (!field.name)
|
|
810
|
-
continue;
|
|
784
|
+
if (!field.name) continue;
|
|
811
785
|
const value = result[field.name];
|
|
812
786
|
const origValue = originalDoc?.[field.name];
|
|
813
787
|
let updatedValue = value;
|
|
@@ -827,13 +801,21 @@ async function executeFieldBeforeChange(fields, data, originalDoc, user, db) {
|
|
|
827
801
|
}
|
|
828
802
|
if (updatedValue !== void 0 && updatedValue !== null) {
|
|
829
803
|
if (field.type === "object" && field.fields) {
|
|
830
|
-
result[field.name] = await executeFieldBeforeChange(
|
|
804
|
+
result[field.name] = await executeFieldBeforeChange(
|
|
805
|
+
field.fields,
|
|
806
|
+
updatedValue,
|
|
807
|
+
origValue,
|
|
808
|
+
user,
|
|
809
|
+
db
|
|
810
|
+
);
|
|
831
811
|
} else if (field.type === "array" && field.fields && Array.isArray(updatedValue)) {
|
|
832
812
|
const arrayResult = [];
|
|
833
813
|
for (let i = 0; i < updatedValue.length; i++) {
|
|
834
814
|
const item = updatedValue[i];
|
|
835
815
|
const origItem = Array.isArray(origValue) ? origValue[i] : null;
|
|
836
|
-
arrayResult.push(
|
|
816
|
+
arrayResult.push(
|
|
817
|
+
await executeFieldBeforeChange(field.fields, item, origItem, user, db)
|
|
818
|
+
);
|
|
837
819
|
}
|
|
838
820
|
result[field.name] = arrayResult;
|
|
839
821
|
} else if (field.type === "blocks" && field.blocks && Array.isArray(updatedValue)) {
|
|
@@ -841,9 +823,19 @@ async function executeFieldBeforeChange(fields, data, originalDoc, user, db) {
|
|
|
841
823
|
for (let i = 0; i < updatedValue.length; i++) {
|
|
842
824
|
const blockData = updatedValue[i];
|
|
843
825
|
const origBlock = Array.isArray(origValue) ? origValue[i] : null;
|
|
844
|
-
const blockConfig = field.blocks.find(
|
|
826
|
+
const blockConfig = field.blocks.find(
|
|
827
|
+
(b) => b.slug === blockData.blockType
|
|
828
|
+
);
|
|
845
829
|
if (blockConfig) {
|
|
846
|
-
blocksResult.push(
|
|
830
|
+
blocksResult.push(
|
|
831
|
+
await executeFieldBeforeChange(
|
|
832
|
+
blockConfig.fields,
|
|
833
|
+
blockData,
|
|
834
|
+
origBlock,
|
|
835
|
+
user,
|
|
836
|
+
db
|
|
837
|
+
)
|
|
838
|
+
);
|
|
847
839
|
} else {
|
|
848
840
|
blocksResult.push(blockData);
|
|
849
841
|
}
|
|
@@ -855,12 +847,10 @@ async function executeFieldBeforeChange(fields, data, originalDoc, user, db) {
|
|
|
855
847
|
return result;
|
|
856
848
|
}
|
|
857
849
|
async function executeFieldAfterRead(fields, doc, user, db) {
|
|
858
|
-
if (!doc || typeof doc !== "object")
|
|
859
|
-
return doc;
|
|
850
|
+
if (!doc || typeof doc !== "object") return doc;
|
|
860
851
|
const result = { ...doc };
|
|
861
852
|
for (const field of fields) {
|
|
862
|
-
if (!field.name)
|
|
863
|
-
continue;
|
|
853
|
+
if (!field.name) continue;
|
|
864
854
|
const value = result[field.name];
|
|
865
855
|
let updatedValue = value;
|
|
866
856
|
if (field.hooks?.afterRead) {
|
|
@@ -878,20 +868,41 @@ async function executeFieldAfterRead(fields, doc, user, db) {
|
|
|
878
868
|
}
|
|
879
869
|
if (updatedValue !== void 0 && updatedValue !== null) {
|
|
880
870
|
if (field.type === "object" && field.fields) {
|
|
881
|
-
result[field.name] = await executeFieldAfterRead(
|
|
871
|
+
result[field.name] = await executeFieldAfterRead(
|
|
872
|
+
field.fields,
|
|
873
|
+
updatedValue,
|
|
874
|
+
user,
|
|
875
|
+
db
|
|
876
|
+
);
|
|
882
877
|
} else if (field.type === "array" && field.fields && Array.isArray(updatedValue)) {
|
|
883
878
|
const arrayResult = [];
|
|
884
879
|
for (const item of updatedValue) {
|
|
885
|
-
arrayResult.push(
|
|
880
|
+
arrayResult.push(
|
|
881
|
+
await executeFieldAfterRead(
|
|
882
|
+
field.fields,
|
|
883
|
+
item,
|
|
884
|
+
user,
|
|
885
|
+
db
|
|
886
|
+
)
|
|
887
|
+
);
|
|
886
888
|
}
|
|
887
889
|
result[field.name] = arrayResult;
|
|
888
890
|
} else if (field.type === "blocks" && field.blocks && Array.isArray(updatedValue)) {
|
|
889
891
|
const blocksResult = [];
|
|
890
892
|
for (const blockData of updatedValue) {
|
|
891
893
|
const typedBlock = blockData;
|
|
892
|
-
const blockConfig = field.blocks.find(
|
|
894
|
+
const blockConfig = field.blocks.find(
|
|
895
|
+
(b) => b.slug === typedBlock.blockType
|
|
896
|
+
);
|
|
893
897
|
if (blockConfig) {
|
|
894
|
-
blocksResult.push(
|
|
898
|
+
blocksResult.push(
|
|
899
|
+
await executeFieldAfterRead(
|
|
900
|
+
blockConfig.fields,
|
|
901
|
+
typedBlock,
|
|
902
|
+
user,
|
|
903
|
+
db
|
|
904
|
+
)
|
|
905
|
+
);
|
|
895
906
|
} else {
|
|
896
907
|
blocksResult.push(blockData);
|
|
897
908
|
}
|
|
@@ -903,7 +914,7 @@ async function executeFieldAfterRead(fields, doc, user, db) {
|
|
|
903
914
|
return result;
|
|
904
915
|
}
|
|
905
916
|
|
|
906
|
-
// src/utils/openapi.
|
|
917
|
+
// src/utils/openapi.ts
|
|
907
918
|
function generateOpenApi(config) {
|
|
908
919
|
const spec = {
|
|
909
920
|
openapi: "3.0.0",
|
|
@@ -1612,8 +1623,7 @@ function fieldsToProperties(fields) {
|
|
|
1612
1623
|
required.push(...nested.required);
|
|
1613
1624
|
continue;
|
|
1614
1625
|
}
|
|
1615
|
-
if (!field.name)
|
|
1616
|
-
continue;
|
|
1626
|
+
if (!field.name) continue;
|
|
1617
1627
|
props[field.name] = fieldToSchema(field);
|
|
1618
1628
|
if (field.required) {
|
|
1619
1629
|
required.push(field.name);
|
|
@@ -1725,8 +1735,7 @@ function fieldToSchema(field) {
|
|
|
1725
1735
|
default:
|
|
1726
1736
|
schema = { type: "string" };
|
|
1727
1737
|
}
|
|
1728
|
-
if (field.label)
|
|
1729
|
-
schema.description = field.label;
|
|
1738
|
+
if (field.label) schema.description = field.label;
|
|
1730
1739
|
return schema;
|
|
1731
1740
|
}
|
|
1732
1741
|
|
package/dist/index.js
CHANGED
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
saveWorkflowDraft,
|
|
21
21
|
transitionWorkflow,
|
|
22
22
|
workflowCapabilities
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-FCXE5CVC.js";
|
|
24
24
|
|
|
25
|
-
// src/types/workflows.
|
|
25
|
+
// src/types/workflows.ts
|
|
26
26
|
var LIFECYCLE_EVENT_NAMES = [
|
|
27
27
|
"revision.created",
|
|
28
28
|
"workflow.transitioned",
|
|
@@ -30,7 +30,7 @@ var LIFECYCLE_EVENT_NAMES = [
|
|
|
30
30
|
"entry.unpublished"
|
|
31
31
|
];
|
|
32
32
|
|
|
33
|
-
// src/utils/parse-where.
|
|
33
|
+
// src/utils/parse-where.ts
|
|
34
34
|
function assertNever(op, context) {
|
|
35
35
|
throw new Error(`[dyrected/core] Unhandled where operator "${op}" in ${context}`);
|
|
36
36
|
}
|
|
@@ -66,8 +66,7 @@ function parseSqlWhere(where, getJsonField, placeholder = "?") {
|
|
|
66
66
|
return `${c} != ${next()}`;
|
|
67
67
|
case "in": {
|
|
68
68
|
const vals = Array.isArray(operand) ? operand : [operand];
|
|
69
|
-
if (vals.length === 0)
|
|
70
|
-
return "1=0";
|
|
69
|
+
if (vals.length === 0) return "1=0";
|
|
71
70
|
const placeholders = vals.map((v) => {
|
|
72
71
|
params.push(v);
|
|
73
72
|
return next();
|
|
@@ -76,8 +75,7 @@ function parseSqlWhere(where, getJsonField, placeholder = "?") {
|
|
|
76
75
|
}
|
|
77
76
|
case "not_in": {
|
|
78
77
|
const vals = Array.isArray(operand) ? operand : [operand];
|
|
79
|
-
if (vals.length === 0)
|
|
80
|
-
return "1=1";
|
|
78
|
+
if (vals.length === 0) return "1=1";
|
|
81
79
|
const placeholders = vals.map((v) => {
|
|
82
80
|
params.push(v);
|
|
83
81
|
return next();
|
|
@@ -183,26 +181,22 @@ function parseMongoWhere(where) {
|
|
|
183
181
|
conditions.push(buildOperator(field, value));
|
|
184
182
|
}
|
|
185
183
|
}
|
|
186
|
-
if (conditions.length === 0)
|
|
187
|
-
|
|
188
|
-
if (conditions.length === 1)
|
|
189
|
-
return conditions[0];
|
|
184
|
+
if (conditions.length === 0) return {};
|
|
185
|
+
if (conditions.length === 1) return conditions[0];
|
|
190
186
|
return { $and: conditions };
|
|
191
187
|
}
|
|
192
188
|
return buildClause(where);
|
|
193
189
|
}
|
|
194
190
|
|
|
195
|
-
// src/utils/parse-sort.
|
|
191
|
+
// src/utils/parse-sort.ts
|
|
196
192
|
var SORT_FIELD_PATTERN = /^([A-Za-z_][A-Za-z0-9_]*)(?:\s+(ASC|DESC))?$/i;
|
|
197
193
|
function parseSort(sort, fallback = { field: "createdAt", direction: "DESC" }) {
|
|
198
|
-
if (!sort)
|
|
199
|
-
return [fallback];
|
|
194
|
+
if (!sort) return [fallback];
|
|
200
195
|
const clauses = sort.split(",").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
201
196
|
const descByPrefix = part.startsWith("-");
|
|
202
197
|
const withoutPrefix = descByPrefix ? part.slice(1).trim() : part;
|
|
203
198
|
const match = withoutPrefix.match(SORT_FIELD_PATTERN);
|
|
204
|
-
if (!match)
|
|
205
|
-
return null;
|
|
199
|
+
if (!match) return null;
|
|
206
200
|
return {
|
|
207
201
|
field: match[1],
|
|
208
202
|
direction: descByPrefix || match[2]?.toUpperCase() === "DESC" ? "DESC" : "ASC"
|