@dyrected/core 2.5.44 → 2.5.45
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/dist/server.js
CHANGED
|
@@ -13,14 +13,14 @@ import {
|
|
|
13
13
|
runCollectionHooks,
|
|
14
14
|
saveWorkflowDraft,
|
|
15
15
|
transitionWorkflow
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-FCXE5CVC.js";
|
|
17
17
|
|
|
18
|
-
// src/app.
|
|
18
|
+
// src/app.ts
|
|
19
19
|
import { Hono } from "hono";
|
|
20
20
|
import { cors } from "hono/cors";
|
|
21
21
|
import { requestId } from "hono/request-id";
|
|
22
22
|
|
|
23
|
-
// src/services/defaults.service.
|
|
23
|
+
// src/services/defaults.service.ts
|
|
24
24
|
var DefaultsService = class {
|
|
25
25
|
/**
|
|
26
26
|
* Recursively apply default values to a data object based on field definitions.
|
|
@@ -28,14 +28,12 @@ var DefaultsService = class {
|
|
|
28
28
|
static apply(fields, data = {}) {
|
|
29
29
|
const result = { ...data || {} };
|
|
30
30
|
fields.forEach((field) => {
|
|
31
|
-
if (field.type === "join")
|
|
32
|
-
return;
|
|
31
|
+
if (field.type === "join") return;
|
|
33
32
|
if (field.type === "row" && field.fields) {
|
|
34
33
|
Object.assign(result, this.apply(field.fields, data));
|
|
35
34
|
return;
|
|
36
35
|
}
|
|
37
|
-
if (!field.name)
|
|
38
|
-
return;
|
|
36
|
+
if (!field.name) return;
|
|
39
37
|
let value = result[field.name];
|
|
40
38
|
if ((value === void 0 || value === null) && field.renameTo) {
|
|
41
39
|
const legacyValue = result[field.renameTo];
|
|
@@ -48,12 +46,9 @@ var DefaultsService = class {
|
|
|
48
46
|
if (field.defaultValue !== void 0) {
|
|
49
47
|
result[field.name] = field.defaultValue;
|
|
50
48
|
} else {
|
|
51
|
-
if (field.type === "boolean")
|
|
52
|
-
|
|
53
|
-
else if (field.type === "
|
|
54
|
-
result[field.name] = [];
|
|
55
|
-
else if (field.type === "multiSelect")
|
|
56
|
-
result[field.name] = [];
|
|
49
|
+
if (field.type === "boolean") result[field.name] = false;
|
|
50
|
+
else if (field.type === "array") result[field.name] = [];
|
|
51
|
+
else if (field.type === "multiSelect") result[field.name] = [];
|
|
57
52
|
else if (field.type === "object") {
|
|
58
53
|
result[field.name] = this.apply(field.fields || [], {});
|
|
59
54
|
}
|
|
@@ -68,7 +63,7 @@ var DefaultsService = class {
|
|
|
68
63
|
}
|
|
69
64
|
};
|
|
70
65
|
|
|
71
|
-
// src/services/population.service.
|
|
66
|
+
// src/services/population.service.ts
|
|
72
67
|
var PopulationService = class {
|
|
73
68
|
db;
|
|
74
69
|
collections;
|
|
@@ -121,31 +116,29 @@ var PopulationService = class {
|
|
|
121
116
|
Object.assign(populatedDoc, rowPopulated);
|
|
122
117
|
continue;
|
|
123
118
|
}
|
|
124
|
-
if (!field.name)
|
|
125
|
-
continue;
|
|
119
|
+
if (!field.name) continue;
|
|
126
120
|
const value = populatedDoc[field.name];
|
|
127
121
|
if (field.type === "relationship" && field.relationTo && value) {
|
|
128
122
|
const relatedCollection = this.collections.find((c) => c.slug === field.relationTo);
|
|
129
|
-
if (!relatedCollection)
|
|
130
|
-
continue;
|
|
123
|
+
if (!relatedCollection) continue;
|
|
131
124
|
if (Array.isArray(value)) {
|
|
132
|
-
populatedDoc[field.name] = await Promise.all(
|
|
133
|
-
|
|
134
|
-
return id;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
})
|
|
148
|
-
|
|
125
|
+
populatedDoc[field.name] = await Promise.all(
|
|
126
|
+
value.map(async (id) => {
|
|
127
|
+
if (!id) return id;
|
|
128
|
+
let doc = id;
|
|
129
|
+
if (typeof id === "string") {
|
|
130
|
+
doc = await this.db.findOne({ collection: field.relationTo, id });
|
|
131
|
+
}
|
|
132
|
+
if (!doc || typeof doc !== "object") return id;
|
|
133
|
+
const docWithDefaults = DefaultsService.apply(relatedCollection.fields, doc);
|
|
134
|
+
return this.populate({
|
|
135
|
+
data: docWithDefaults,
|
|
136
|
+
fields: relatedCollection.fields,
|
|
137
|
+
currentDepth: currentDepth + 1,
|
|
138
|
+
maxDepth
|
|
139
|
+
});
|
|
140
|
+
})
|
|
141
|
+
);
|
|
149
142
|
} else if (value) {
|
|
150
143
|
let doc = value;
|
|
151
144
|
if (typeof value === "string") {
|
|
@@ -194,17 +187,18 @@ var PopulationService = class {
|
|
|
194
187
|
});
|
|
195
188
|
}
|
|
196
189
|
if (field.type === "blocks" && field.blocks && Array.isArray(value)) {
|
|
197
|
-
populatedDoc[field.name] = await Promise.all(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return blockData;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
190
|
+
populatedDoc[field.name] = await Promise.all(
|
|
191
|
+
value.map(async (blockData) => {
|
|
192
|
+
const blockConfig = field.blocks.find((b) => b.slug === blockData.blockType);
|
|
193
|
+
if (!blockConfig) return blockData;
|
|
194
|
+
return this.populate({
|
|
195
|
+
data: blockData,
|
|
196
|
+
fields: blockConfig.fields,
|
|
197
|
+
currentDepth,
|
|
198
|
+
maxDepth
|
|
199
|
+
});
|
|
200
|
+
})
|
|
201
|
+
);
|
|
208
202
|
}
|
|
209
203
|
}
|
|
210
204
|
return populatedDoc;
|
|
@@ -213,8 +207,7 @@ var PopulationService = class {
|
|
|
213
207
|
* Helper to populate a PaginatedResult
|
|
214
208
|
*/
|
|
215
209
|
async populateResult(result, fields, maxDepth) {
|
|
216
|
-
if (maxDepth <= 0)
|
|
217
|
-
return result;
|
|
210
|
+
if (maxDepth <= 0) return result;
|
|
218
211
|
const populatedDocs = await this.populate({
|
|
219
212
|
data: result.docs,
|
|
220
213
|
fields,
|
|
@@ -228,7 +221,7 @@ var PopulationService = class {
|
|
|
228
221
|
}
|
|
229
222
|
};
|
|
230
223
|
|
|
231
|
-
// src/services/audit.service.
|
|
224
|
+
// src/services/audit.service.ts
|
|
232
225
|
var AuditService = class {
|
|
233
226
|
/**
|
|
234
227
|
* Writes a single entry to the __audit collection.
|
|
@@ -256,7 +249,7 @@ var AuditService = class {
|
|
|
256
249
|
}
|
|
257
250
|
};
|
|
258
251
|
|
|
259
|
-
// src/auth/password.
|
|
252
|
+
// src/auth/password.ts
|
|
260
253
|
import { promisify } from "util";
|
|
261
254
|
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
|
|
262
255
|
var scryptAsync = promisify(scrypt);
|
|
@@ -269,23 +262,23 @@ async function hashPassword(plain) {
|
|
|
269
262
|
}
|
|
270
263
|
async function verifyPassword(plain, stored) {
|
|
271
264
|
const [salt, storedHash] = stored.split(":");
|
|
272
|
-
if (!salt || !storedHash)
|
|
273
|
-
return false;
|
|
265
|
+
if (!salt || !storedHash) return false;
|
|
274
266
|
const derivedKey = await scryptAsync(plain, salt, KEY_LEN);
|
|
275
267
|
const storedBuffer = Buffer.from(storedHash, "hex");
|
|
276
|
-
if (derivedKey.length !== storedBuffer.length)
|
|
277
|
-
return false;
|
|
268
|
+
if (derivedKey.length !== storedBuffer.length) return false;
|
|
278
269
|
return timingSafeEqual(derivedKey, storedBuffer);
|
|
279
270
|
}
|
|
280
271
|
|
|
281
|
-
// src/utils/readonly-db.
|
|
272
|
+
// src/utils/readonly-db.ts
|
|
282
273
|
var WRITE_METHODS = ["create", "update", "delete", "updateGlobal", "execute"];
|
|
283
274
|
function createReadonlyDb(db) {
|
|
284
275
|
return new Proxy(db, {
|
|
285
276
|
get(target, prop) {
|
|
286
277
|
if (WRITE_METHODS.includes(prop)) {
|
|
287
278
|
return () => {
|
|
288
|
-
throw new Error(
|
|
279
|
+
throw new Error(
|
|
280
|
+
`[dyrected] Write operation "${String(prop)}" is not allowed in this hook phase. Use afterChange/afterDelete hooks for write operations.`
|
|
281
|
+
);
|
|
289
282
|
};
|
|
290
283
|
}
|
|
291
284
|
return Reflect.get(target, prop);
|
|
@@ -293,13 +286,11 @@ function createReadonlyDb(db) {
|
|
|
293
286
|
});
|
|
294
287
|
}
|
|
295
288
|
|
|
296
|
-
// src/auth/jexl.
|
|
289
|
+
// src/auth/jexl.ts
|
|
297
290
|
import jexl from "jexl";
|
|
298
291
|
async function evaluateAccess(expression, context) {
|
|
299
|
-
if (expression === void 0 || expression === null)
|
|
300
|
-
|
|
301
|
-
if (typeof expression === "boolean")
|
|
302
|
-
return expression;
|
|
292
|
+
if (expression === void 0 || expression === null) return false;
|
|
293
|
+
if (typeof expression === "boolean") return expression;
|
|
303
294
|
try {
|
|
304
295
|
const result = await jexl.eval(expression, context);
|
|
305
296
|
return !!result;
|
|
@@ -309,7 +300,7 @@ async function evaluateAccess(expression, context) {
|
|
|
309
300
|
}
|
|
310
301
|
}
|
|
311
302
|
|
|
312
|
-
// src/controllers/collection.controller.
|
|
303
|
+
// src/controllers/collection.controller.ts
|
|
313
304
|
var CollectionController = class {
|
|
314
305
|
collection;
|
|
315
306
|
constructor(collection) {
|
|
@@ -317,8 +308,8 @@ var CollectionController = class {
|
|
|
317
308
|
}
|
|
318
309
|
getDelegatedProvider(c) {
|
|
319
310
|
const config = c.get("config");
|
|
320
|
-
const
|
|
321
|
-
if (this.collection.slug !==
|
|
311
|
+
const authCollection = getAdminAuthCollection(config);
|
|
312
|
+
if (!authCollection || this.collection.slug !== authCollection.slug) {
|
|
322
313
|
return null;
|
|
323
314
|
}
|
|
324
315
|
return config.adminAuth?.providers?.find((p) => p.members) || null;
|
|
@@ -326,8 +317,7 @@ var CollectionController = class {
|
|
|
326
317
|
async find(c) {
|
|
327
318
|
const config = c.get("config");
|
|
328
319
|
const db = config.db;
|
|
329
|
-
if (!db)
|
|
330
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
320
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
331
321
|
const provider = this.getDelegatedProvider(c);
|
|
332
322
|
if (provider && provider.members?.list) {
|
|
333
323
|
const limit2 = Number(c.req.query("limit")) || 10;
|
|
@@ -382,7 +372,7 @@ var CollectionController = class {
|
|
|
382
372
|
if (this.collection.admin?.filterable === false) {
|
|
383
373
|
where = void 0;
|
|
384
374
|
} else {
|
|
385
|
-
const { sanitizeWhereClause } = await import("./where-sanitizer-
|
|
375
|
+
const { sanitizeWhereClause } = await import("./where-sanitizer-WJ2W2QCE.js");
|
|
386
376
|
where = sanitizeWhereClause(where, this.collection.fields);
|
|
387
377
|
if (Object.keys(where).length === 0) {
|
|
388
378
|
where = void 0;
|
|
@@ -445,13 +435,11 @@ var CollectionController = class {
|
|
|
445
435
|
async findOne(c) {
|
|
446
436
|
const config = c.get("config");
|
|
447
437
|
const db = config.db;
|
|
448
|
-
if (!db)
|
|
449
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
438
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
450
439
|
const provider = this.getDelegatedProvider(c);
|
|
451
440
|
if (provider && (provider.members?.get || provider.members?.list)) {
|
|
452
441
|
const id2 = c.req.param("id");
|
|
453
|
-
if (!id2)
|
|
454
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
442
|
+
if (!id2) return c.json({ message: "Missing ID" }, 400);
|
|
455
443
|
const localDoc = await db.findOne({ collection: this.collection.slug, id: id2 });
|
|
456
444
|
const externalSubject = localDoc?.externalSubject || id2;
|
|
457
445
|
let member = null;
|
|
@@ -461,8 +449,7 @@ var CollectionController = class {
|
|
|
461
449
|
const listResult = await provider.members.list({ req: c.req });
|
|
462
450
|
member = listResult.docs.find((m) => m.id === externalSubject) || null;
|
|
463
451
|
}
|
|
464
|
-
if (!member)
|
|
465
|
-
return c.json({ message: "Not Found" }, 404);
|
|
452
|
+
if (!member) return c.json({ message: "Not Found" }, 404);
|
|
466
453
|
return c.json({
|
|
467
454
|
...member,
|
|
468
455
|
id: localDoc ? localDoc.id : member.id,
|
|
@@ -473,15 +460,12 @@ var CollectionController = class {
|
|
|
473
460
|
const id = c.req.param("id");
|
|
474
461
|
const depth = c.req.query("depth") !== void 0 ? Number(c.req.query("depth")) : 10;
|
|
475
462
|
const user = c.get("user");
|
|
476
|
-
if (!id)
|
|
477
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
463
|
+
if (!id) return c.json({ message: "Missing ID" }, 400);
|
|
478
464
|
let doc = await db.findOne({ collection: this.collection.slug, id });
|
|
479
|
-
if (!doc)
|
|
480
|
-
return c.json({ message: "Not Found" }, 404);
|
|
465
|
+
if (!doc) return c.json({ message: "Not Found" }, 404);
|
|
481
466
|
if (this.collection.workflow) {
|
|
482
467
|
doc = materializeWorkflowDocument(doc, this.collection.workflow, user);
|
|
483
|
-
if (!doc)
|
|
484
|
-
return c.json({ message: "Not Found" }, 404);
|
|
468
|
+
if (!doc) return c.json({ message: "Not Found" }, 404);
|
|
485
469
|
}
|
|
486
470
|
const docWithDefaults = DefaultsService.apply(this.collection.fields, doc);
|
|
487
471
|
const docWithCollectionHooks = await runCollectionHooks(this.collection.hooks?.afterRead, {
|
|
@@ -506,8 +490,7 @@ var CollectionController = class {
|
|
|
506
490
|
async create(c) {
|
|
507
491
|
const config = c.get("config");
|
|
508
492
|
const db = config.db;
|
|
509
|
-
if (!db)
|
|
510
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
493
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
511
494
|
const provider = this.getDelegatedProvider(c);
|
|
512
495
|
if (provider && provider.members?.create) {
|
|
513
496
|
const contentType2 = c.req.header("Content-Type") || "";
|
|
@@ -582,16 +565,13 @@ var CollectionController = class {
|
|
|
582
565
|
async upload(c) {
|
|
583
566
|
const config = c.get("config");
|
|
584
567
|
const storage = config.storage;
|
|
585
|
-
if (!storage)
|
|
586
|
-
return c.json({ message: "Storage not configured" }, 500);
|
|
568
|
+
if (!storage) return c.json({ message: "Storage not configured" }, 500);
|
|
587
569
|
const db = config.db;
|
|
588
|
-
if (!db)
|
|
589
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
570
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
590
571
|
const readonlyDb = createReadonlyDb(db);
|
|
591
572
|
const formData = await c.req.formData();
|
|
592
573
|
const file = formData.get("file");
|
|
593
|
-
if (!file)
|
|
594
|
-
return c.json({ message: "No file uploaded" }, 400);
|
|
574
|
+
if (!file) return c.json({ message: "No file uploaded" }, 400);
|
|
595
575
|
const buffer = new Uint8Array(await file.arrayBuffer());
|
|
596
576
|
const siteId = c.get("siteId");
|
|
597
577
|
const workspaceId = c.get("workspaceId");
|
|
@@ -650,13 +630,11 @@ var CollectionController = class {
|
|
|
650
630
|
async update(c) {
|
|
651
631
|
const config = c.get("config");
|
|
652
632
|
const db = config.db;
|
|
653
|
-
if (!db)
|
|
654
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
633
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
655
634
|
const provider = this.getDelegatedProvider(c);
|
|
656
635
|
if (provider && provider.members?.update) {
|
|
657
636
|
const id2 = c.req.param("id");
|
|
658
|
-
if (!id2)
|
|
659
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
637
|
+
if (!id2) return c.json({ message: "Missing ID" }, 400);
|
|
660
638
|
const body2 = await c.req.json();
|
|
661
639
|
const localDoc = await db.findOne({ collection: this.collection.slug, id: id2 });
|
|
662
640
|
const externalSubject = localDoc?.externalSubject || id2;
|
|
@@ -669,8 +647,7 @@ var CollectionController = class {
|
|
|
669
647
|
}
|
|
670
648
|
const readonlyDb = createReadonlyDb(db);
|
|
671
649
|
const id = c.req.param("id");
|
|
672
|
-
if (!id)
|
|
673
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
650
|
+
if (!id) return c.json({ message: "Missing ID" }, 400);
|
|
674
651
|
const body = await c.req.json();
|
|
675
652
|
const user = c.get("user");
|
|
676
653
|
let data = { ...body };
|
|
@@ -684,8 +661,7 @@ var CollectionController = class {
|
|
|
684
661
|
updatedBy: user?.sub ?? null
|
|
685
662
|
});
|
|
686
663
|
const originalDoc = await db.findOne({ collection: this.collection.slug, id });
|
|
687
|
-
if (!originalDoc)
|
|
688
|
-
return c.json({ message: "Not Found" }, 404);
|
|
664
|
+
if (!originalDoc) return c.json({ message: "Not Found" }, 404);
|
|
689
665
|
let before = null;
|
|
690
666
|
if (this.collection.audit) {
|
|
691
667
|
before = originalDoc;
|
|
@@ -729,10 +705,8 @@ var CollectionController = class {
|
|
|
729
705
|
}
|
|
730
706
|
async transition(c) {
|
|
731
707
|
const config = c.get("config");
|
|
732
|
-
if (!config.db)
|
|
733
|
-
|
|
734
|
-
if (!this.collection.workflow)
|
|
735
|
-
return c.json({ message: "Workflows are not enabled for this collection" }, 404);
|
|
708
|
+
if (!config.db) return c.json({ message: "Database not configured" }, 500);
|
|
709
|
+
if (!this.collection.workflow) return c.json({ message: "Workflows are not enabled for this collection" }, 404);
|
|
736
710
|
const id = c.req.param("id");
|
|
737
711
|
const transitionName = c.req.param("transition");
|
|
738
712
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -755,16 +729,12 @@ var CollectionController = class {
|
|
|
755
729
|
}
|
|
756
730
|
async workflowHistory(c) {
|
|
757
731
|
const config = c.get("config");
|
|
758
|
-
if (!config.db)
|
|
759
|
-
|
|
760
|
-
if (!this.collection.workflow)
|
|
761
|
-
return c.json({ message: "Workflows are not enabled for this collection" }, 404);
|
|
732
|
+
if (!config.db) return c.json({ message: "Database not configured" }, 500);
|
|
733
|
+
if (!this.collection.workflow) return c.json({ message: "Workflows are not enabled for this collection" }, 404);
|
|
762
734
|
const documentId = c.req.param("id");
|
|
763
|
-
if (!documentId)
|
|
764
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
735
|
+
if (!documentId) return c.json({ message: "Missing ID" }, 400);
|
|
765
736
|
const document = await config.db.findOne({ collection: this.collection.slug, id: documentId });
|
|
766
|
-
if (!document)
|
|
767
|
-
return c.json({ message: "Not Found" }, 404);
|
|
737
|
+
if (!document) return c.json({ message: "Not Found" }, 404);
|
|
768
738
|
const readAccess = this.collection.access?.read;
|
|
769
739
|
if (readAccess !== void 0 && readAccess !== null) {
|
|
770
740
|
const args = { user: c.get("user"), req: c.req, doc: document };
|
|
@@ -778,8 +748,7 @@ var CollectionController = class {
|
|
|
778
748
|
});
|
|
779
749
|
allowed = match.total > 0;
|
|
780
750
|
}
|
|
781
|
-
if (!allowed)
|
|
782
|
-
return c.json({ error: true, message: `Access denied: read on ${this.collection.slug}` }, 403);
|
|
751
|
+
if (!allowed) return c.json({ error: true, message: `Access denied: read on ${this.collection.slug}` }, 403);
|
|
783
752
|
}
|
|
784
753
|
const result = await config.db.find({
|
|
785
754
|
collection: WORKFLOW_HISTORY_COLLECTION,
|
|
@@ -803,17 +772,14 @@ var CollectionController = class {
|
|
|
803
772
|
async changePassword(c) {
|
|
804
773
|
const config = c.get("config");
|
|
805
774
|
const db = config.db;
|
|
806
|
-
if (!db)
|
|
807
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
775
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
808
776
|
if (!this.collection.auth) {
|
|
809
777
|
return c.json({ message: "This collection does not support authentication" }, 400);
|
|
810
778
|
}
|
|
811
779
|
const id = c.req.param("id");
|
|
812
|
-
if (!id)
|
|
813
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
780
|
+
if (!id) return c.json({ message: "Missing ID" }, 400);
|
|
814
781
|
const user = c.get("user");
|
|
815
|
-
if (!user)
|
|
816
|
-
return c.json({ message: "Authentication required" }, 401);
|
|
782
|
+
if (!user) return c.json({ message: "Authentication required" }, 401);
|
|
817
783
|
const body = await c.req.json().catch(() => null);
|
|
818
784
|
const { oldPassword, newPassword, confirmPassword } = body ?? {};
|
|
819
785
|
if (!newPassword) {
|
|
@@ -835,8 +801,7 @@ var CollectionController = class {
|
|
|
835
801
|
return c.json({ message: "Current password is required" }, 400);
|
|
836
802
|
}
|
|
837
803
|
const existing = await db.findOne({ collection: this.collection.slug, id });
|
|
838
|
-
if (!existing)
|
|
839
|
-
return c.json({ message: "User not found" }, 404);
|
|
804
|
+
if (!existing) return c.json({ message: "User not found" }, 404);
|
|
840
805
|
const valid = await verifyPassword(oldPassword, existing.password);
|
|
841
806
|
if (!valid) {
|
|
842
807
|
return c.json({ message: "Invalid current password" }, 400);
|
|
@@ -867,13 +832,11 @@ var CollectionController = class {
|
|
|
867
832
|
async delete(c) {
|
|
868
833
|
const config = c.get("config");
|
|
869
834
|
const db = config.db;
|
|
870
|
-
if (!db)
|
|
871
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
835
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
872
836
|
const provider = this.getDelegatedProvider(c);
|
|
873
837
|
if (provider && provider.members?.delete) {
|
|
874
838
|
const id2 = c.req.param("id");
|
|
875
|
-
if (!id2)
|
|
876
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
839
|
+
if (!id2) return c.json({ message: "Missing ID" }, 400);
|
|
877
840
|
const localDoc = await db.findOne({ collection: this.collection.slug, id: id2 });
|
|
878
841
|
const externalSubject = localDoc?.externalSubject || id2;
|
|
879
842
|
await provider.members.delete({ externalSubject, req: c.req });
|
|
@@ -881,12 +844,10 @@ var CollectionController = class {
|
|
|
881
844
|
}
|
|
882
845
|
const readonlyDb = createReadonlyDb(db);
|
|
883
846
|
const id = c.req.param("id");
|
|
884
|
-
if (!id)
|
|
885
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
847
|
+
if (!id) return c.json({ message: "Missing ID" }, 400);
|
|
886
848
|
const user = c.get("user");
|
|
887
849
|
const doc = await db.findOne({ collection: this.collection.slug, id });
|
|
888
|
-
if (!doc)
|
|
889
|
-
return c.json({ message: "Not Found" }, 404);
|
|
850
|
+
if (!doc) return c.json({ message: "Not Found" }, 404);
|
|
890
851
|
let before = null;
|
|
891
852
|
if (this.collection.audit) {
|
|
892
853
|
before = doc;
|
|
@@ -921,8 +882,7 @@ var CollectionController = class {
|
|
|
921
882
|
async deleteMany(c) {
|
|
922
883
|
const config = c.get("config");
|
|
923
884
|
const db = config.db;
|
|
924
|
-
if (!db)
|
|
925
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
885
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
926
886
|
const readonlyDb = createReadonlyDb(db);
|
|
927
887
|
const user = c.get("user");
|
|
928
888
|
let ids = [];
|
|
@@ -937,8 +897,7 @@ var CollectionController = class {
|
|
|
937
897
|
const raw = c.req.queries("ids") ?? c.req.queries("ids[]") ?? [];
|
|
938
898
|
ids = raw.filter(Boolean);
|
|
939
899
|
}
|
|
940
|
-
if (!ids.length)
|
|
941
|
-
return c.json({ message: "No IDs provided" }, 400);
|
|
900
|
+
if (!ids.length) return c.json({ message: "No IDs provided" }, 400);
|
|
942
901
|
const deleted = [];
|
|
943
902
|
const failed = [];
|
|
944
903
|
for (const id of ids) {
|
|
@@ -991,8 +950,7 @@ var CollectionController = class {
|
|
|
991
950
|
async seed(c) {
|
|
992
951
|
const config = c.get("config");
|
|
993
952
|
const db = config.db;
|
|
994
|
-
if (!db)
|
|
995
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
953
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
996
954
|
const body = await c.req.json();
|
|
997
955
|
const initialData = body.data;
|
|
998
956
|
if (!initialData || !Array.isArray(initialData)) {
|
|
@@ -1012,7 +970,7 @@ var CollectionController = class {
|
|
|
1012
970
|
}
|
|
1013
971
|
};
|
|
1014
972
|
|
|
1015
|
-
// src/controllers/global.controller.
|
|
973
|
+
// src/controllers/global.controller.ts
|
|
1016
974
|
var GlobalController = class {
|
|
1017
975
|
global;
|
|
1018
976
|
constructor(global) {
|
|
@@ -1021,8 +979,7 @@ var GlobalController = class {
|
|
|
1021
979
|
async get(c) {
|
|
1022
980
|
const config = c.get("config");
|
|
1023
981
|
const db = config.db;
|
|
1024
|
-
if (!db)
|
|
1025
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
982
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1026
983
|
const readonlyDb = createReadonlyDb(db);
|
|
1027
984
|
const depth = c.req.query("depth") !== void 0 ? Number(c.req.query("depth")) : 10;
|
|
1028
985
|
const user = c.get("user");
|
|
@@ -1066,8 +1023,7 @@ var GlobalController = class {
|
|
|
1066
1023
|
async update(c) {
|
|
1067
1024
|
const config = c.get("config");
|
|
1068
1025
|
const db = config.db;
|
|
1069
|
-
if (!db)
|
|
1070
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1026
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1071
1027
|
const readonlyDb = createReadonlyDb(db);
|
|
1072
1028
|
const body = await c.req.json();
|
|
1073
1029
|
const user = c.get("user");
|
|
@@ -1102,8 +1058,7 @@ var GlobalController = class {
|
|
|
1102
1058
|
async seed(c) {
|
|
1103
1059
|
const config = c.get("config");
|
|
1104
1060
|
const db = config.db;
|
|
1105
|
-
if (!db)
|
|
1106
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1061
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1107
1062
|
const body = await c.req.json();
|
|
1108
1063
|
const initialData = body.data;
|
|
1109
1064
|
if (!initialData) {
|
|
@@ -1119,23 +1074,20 @@ var GlobalController = class {
|
|
|
1119
1074
|
}
|
|
1120
1075
|
};
|
|
1121
1076
|
function isFunctionallyEmpty(obj) {
|
|
1122
|
-
if (obj === null || obj === void 0 || obj === "")
|
|
1123
|
-
return true;
|
|
1077
|
+
if (obj === null || obj === void 0 || obj === "") return true;
|
|
1124
1078
|
if (Array.isArray(obj)) {
|
|
1125
|
-
if (obj.length === 0)
|
|
1126
|
-
return true;
|
|
1079
|
+
if (obj.length === 0) return true;
|
|
1127
1080
|
return obj.every(isFunctionallyEmpty);
|
|
1128
1081
|
}
|
|
1129
1082
|
if (typeof obj === "object") {
|
|
1130
1083
|
const keys = Object.keys(obj);
|
|
1131
|
-
if (keys.length === 0)
|
|
1132
|
-
return true;
|
|
1084
|
+
if (keys.length === 0) return true;
|
|
1133
1085
|
return keys.every((key) => isFunctionallyEmpty(obj[key]));
|
|
1134
1086
|
}
|
|
1135
1087
|
return false;
|
|
1136
1088
|
}
|
|
1137
1089
|
|
|
1138
|
-
// src/controllers/media.controller.
|
|
1090
|
+
// src/controllers/media.controller.ts
|
|
1139
1091
|
var MediaController = class {
|
|
1140
1092
|
collection;
|
|
1141
1093
|
constructor(collection = "media") {
|
|
@@ -1215,8 +1167,7 @@ var MediaController = class {
|
|
|
1215
1167
|
}
|
|
1216
1168
|
}
|
|
1217
1169
|
const db = config.db;
|
|
1218
|
-
if (!db)
|
|
1219
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1170
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1220
1171
|
const doc = await db.create({
|
|
1221
1172
|
collection: this.collection,
|
|
1222
1173
|
data: finalFileData
|
|
@@ -1225,8 +1176,7 @@ var MediaController = class {
|
|
|
1225
1176
|
}
|
|
1226
1177
|
async find(c) {
|
|
1227
1178
|
const db = c.get("config").db;
|
|
1228
|
-
if (!db)
|
|
1229
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1179
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1230
1180
|
const limit = Number(c.req.query("limit")) || 10;
|
|
1231
1181
|
const page = Number(c.req.query("page")) || 1;
|
|
1232
1182
|
const result = await db.find({
|
|
@@ -1240,14 +1190,11 @@ var MediaController = class {
|
|
|
1240
1190
|
const config = c.get("config");
|
|
1241
1191
|
const storage = config.storage;
|
|
1242
1192
|
const db = config.db;
|
|
1243
|
-
if (!db)
|
|
1244
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1193
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1245
1194
|
const id = c.req.param("id");
|
|
1246
|
-
if (!id)
|
|
1247
|
-
return c.json({ message: "Missing ID" }, 400);
|
|
1195
|
+
if (!id) return c.json({ message: "Missing ID" }, 400);
|
|
1248
1196
|
const doc = await db.findOne({ collection: this.collection, id });
|
|
1249
|
-
if (!doc)
|
|
1250
|
-
return c.json({ message: "Not Found" }, 404);
|
|
1197
|
+
if (!doc) return c.json({ message: "Not Found" }, 404);
|
|
1251
1198
|
if (storage) {
|
|
1252
1199
|
await storage.delete({ filename: doc.filename });
|
|
1253
1200
|
if (doc.sizes) {
|
|
@@ -1268,26 +1215,26 @@ var MediaController = class {
|
|
|
1268
1215
|
return c.json({ message: "Storage not configured for serving" }, 404);
|
|
1269
1216
|
}
|
|
1270
1217
|
const filename = c.req.param("filename");
|
|
1271
|
-
if (!filename)
|
|
1272
|
-
return c.json({ message: "Missing filename" }, 400);
|
|
1218
|
+
if (!filename) return c.json({ message: "Missing filename" }, 400);
|
|
1273
1219
|
let res = await storage.resolve({ filename });
|
|
1274
1220
|
if (!res && !filename.includes("/")) {
|
|
1275
1221
|
res = await storage.resolve({ filename: `default/${filename}` });
|
|
1276
1222
|
}
|
|
1277
|
-
if (!res)
|
|
1278
|
-
return c.json({ message: "Not Found" }, 404);
|
|
1223
|
+
if (!res) return c.json({ message: "Not Found" }, 404);
|
|
1279
1224
|
c.header("Content-Type", res.mimeType);
|
|
1280
1225
|
return c.body(res.buffer);
|
|
1281
1226
|
}
|
|
1282
1227
|
};
|
|
1283
1228
|
|
|
1284
|
-
// src/auth/token.
|
|
1229
|
+
// src/auth/token.ts
|
|
1285
1230
|
import { SignJWT, jwtVerify, decodeJwt } from "jose";
|
|
1286
1231
|
import { TextEncoder } from "util";
|
|
1287
1232
|
function getSecret() {
|
|
1288
1233
|
const secret = process.env.DYRECTED_JWT_SECRET || process.env.JWT_SECRET;
|
|
1289
1234
|
if (!secret) {
|
|
1290
|
-
throw new Error(
|
|
1235
|
+
throw new Error(
|
|
1236
|
+
"[dyrected/core] DYRECTED_JWT_SECRET is not set. Add it to your environment variables to enable auth collections."
|
|
1237
|
+
);
|
|
1291
1238
|
}
|
|
1292
1239
|
return new TextEncoder().encode(secret);
|
|
1293
1240
|
}
|
|
@@ -1300,7 +1247,7 @@ async function verifyCollectionToken(token) {
|
|
|
1300
1247
|
return payload;
|
|
1301
1248
|
}
|
|
1302
1249
|
|
|
1303
|
-
// src/services/email-template.
|
|
1250
|
+
// src/services/email-template.ts
|
|
1304
1251
|
var emailTokens = {
|
|
1305
1252
|
colors: {
|
|
1306
1253
|
canvas: "#f6f7f2",
|
|
@@ -1364,9 +1311,11 @@ function detailBox(content, monospace = false) {
|
|
|
1364
1311
|
}
|
|
1365
1312
|
function ctaButton(label, href) {
|
|
1366
1313
|
const safeHref = safeHttpUrl(href);
|
|
1367
|
-
if (!safeHref)
|
|
1368
|
-
|
|
1369
|
-
|
|
1314
|
+
if (!safeHref) return "";
|
|
1315
|
+
return table(row(
|
|
1316
|
+
`<a href="${safeHref}" style="display:inline-block;padding:13px 22px;border-radius:${emailTokens.radius.control};background:${emailTokens.colors.accent};font-family:${emailTokens.font};font-size:14px;line-height:1.2;font-weight:700;color:${emailTokens.colors.text};text-decoration:none">${escapeHtml(label)}</a>`,
|
|
1317
|
+
"padding:8px 0 24px"
|
|
1318
|
+
), "width:auto");
|
|
1370
1319
|
}
|
|
1371
1320
|
function alertBox(content) {
|
|
1372
1321
|
return table(row(escapeHtml(content), `padding:13px 16px;font-family:${emailTokens.font};font-size:13px;line-height:1.5;color:${emailTokens.colors.dangerText}`), `width:100%;background:${emailTokens.colors.dangerSurface};border:1px solid ${emailTokens.colors.dangerBorder};border-radius:${emailTokens.radius.control}`);
|
|
@@ -1377,19 +1326,23 @@ function layout({ preheader, title, content, footer }) {
|
|
|
1377
1326
|
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head>
|
|
1378
1327
|
<body style="margin:0;padding:0;background:${emailTokens.colors.canvas}">
|
|
1379
1328
|
<div style="display:none;max-height:0;overflow:hidden;opacity:0;color:transparent">${escapeHtml(preheader)}</div>
|
|
1380
|
-
${table(row(
|
|
1329
|
+
${table(row(
|
|
1330
|
+
table(
|
|
1331
|
+
row(" ", `height:5px;background:${emailTokens.colors.accent};font-size:0;line-height:0`) + row(`${sectionLabel("Dyrected")}${heading(title)}`, "padding:30px 32px 24px") + row(content, "padding:0 32px 32px") + row(`${divider()}${paragraph(footer, "20px 0 6px")}${paragraph("Privacy: this message contains account-related information; please avoid forwarding it.", "0")}`, "padding:0 32px 28px"),
|
|
1332
|
+
`width:100%;max-width:${emailTokens.width};background:${emailTokens.colors.surface};border:1px solid ${emailTokens.colors.border};border-radius:${emailTokens.radius.card};overflow:hidden`
|
|
1333
|
+
),
|
|
1334
|
+
"padding:32px 12px"
|
|
1335
|
+
), `width:100%;background:${emailTokens.colors.canvas}`)}
|
|
1381
1336
|
</body>
|
|
1382
1337
|
</html>`;
|
|
1383
1338
|
}
|
|
1384
1339
|
|
|
1385
|
-
// src/services/email.service.
|
|
1340
|
+
// src/services/email.service.ts
|
|
1386
1341
|
var _devSend = null;
|
|
1387
1342
|
var _devSendPromise = null;
|
|
1388
1343
|
async function getDevSend() {
|
|
1389
|
-
if (_devSend)
|
|
1390
|
-
|
|
1391
|
-
if (_devSendPromise)
|
|
1392
|
-
return _devSendPromise;
|
|
1344
|
+
if (_devSend) return _devSend;
|
|
1345
|
+
if (_devSendPromise) return _devSendPromise;
|
|
1393
1346
|
_devSendPromise = (async () => {
|
|
1394
1347
|
try {
|
|
1395
1348
|
const nodemailer = await import("nodemailer");
|
|
@@ -1473,7 +1426,7 @@ function buildPasswordChangedEmail(config, args) {
|
|
|
1473
1426
|
};
|
|
1474
1427
|
}
|
|
1475
1428
|
|
|
1476
|
-
// src/controllers/auth.controller.
|
|
1429
|
+
// src/controllers/auth.controller.ts
|
|
1477
1430
|
var AuthController = class {
|
|
1478
1431
|
collection;
|
|
1479
1432
|
constructor(collection) {
|
|
@@ -1485,8 +1438,7 @@ var AuthController = class {
|
|
|
1485
1438
|
// ---------------------------------------------------------------------------
|
|
1486
1439
|
async init(c) {
|
|
1487
1440
|
const db = c.get("config").db;
|
|
1488
|
-
if (!db)
|
|
1489
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1441
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1490
1442
|
const result = await db.find({
|
|
1491
1443
|
collection: this.collection.slug,
|
|
1492
1444
|
limit: 1
|
|
@@ -1502,8 +1454,7 @@ var AuthController = class {
|
|
|
1502
1454
|
async registerFirstUser(c) {
|
|
1503
1455
|
const config = c.get("config");
|
|
1504
1456
|
const db = config.db;
|
|
1505
|
-
if (!db)
|
|
1506
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1457
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1507
1458
|
const check = await db.find({
|
|
1508
1459
|
collection: this.collection.slug,
|
|
1509
1460
|
limit: 1
|
|
@@ -1531,7 +1482,9 @@ var AuthController = class {
|
|
|
1531
1482
|
collection: this.collection.slug
|
|
1532
1483
|
});
|
|
1533
1484
|
const { subject, html } = buildWelcomeEmail(config, { email: body.email });
|
|
1534
|
-
sendEmail(config, { to: body.email, subject, html }).catch(
|
|
1485
|
+
sendEmail(config, { to: body.email, subject, html }).catch(
|
|
1486
|
+
(err) => console.error("[dyrected/core] Failed to send welcome email:", err)
|
|
1487
|
+
);
|
|
1535
1488
|
const { password: _, ...safeUser } = user;
|
|
1536
1489
|
return c.json({ token, user: safeUser });
|
|
1537
1490
|
}
|
|
@@ -1540,8 +1493,7 @@ var AuthController = class {
|
|
|
1540
1493
|
// ---------------------------------------------------------------------------
|
|
1541
1494
|
async login(c) {
|
|
1542
1495
|
const db = c.get("config").db;
|
|
1543
|
-
if (!db)
|
|
1544
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1496
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1545
1497
|
const body = await c.req.json().catch(() => null);
|
|
1546
1498
|
if (!body?.email || !body?.password) {
|
|
1547
1499
|
return c.json({ error: true, message: "email and password are required." }, 400);
|
|
@@ -1580,8 +1532,7 @@ var AuthController = class {
|
|
|
1580
1532
|
// ---------------------------------------------------------------------------
|
|
1581
1533
|
async me(c) {
|
|
1582
1534
|
const db = c.get("config").db;
|
|
1583
|
-
if (!db)
|
|
1584
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1535
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1585
1536
|
const requestUser = c.get("user");
|
|
1586
1537
|
if (!requestUser) {
|
|
1587
1538
|
return c.json({ error: true, message: "Authentication required." }, 401);
|
|
@@ -1616,8 +1567,7 @@ var AuthController = class {
|
|
|
1616
1567
|
async forgotPassword(c) {
|
|
1617
1568
|
const config = c.get("config");
|
|
1618
1569
|
const db = config.db;
|
|
1619
|
-
if (!db)
|
|
1620
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1570
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1621
1571
|
const body = await c.req.json().catch(() => null);
|
|
1622
1572
|
if (!body?.email) {
|
|
1623
1573
|
return c.json({ error: true, message: "email is required." }, 400);
|
|
@@ -1629,7 +1579,10 @@ var AuthController = class {
|
|
|
1629
1579
|
});
|
|
1630
1580
|
const user = result.docs[0];
|
|
1631
1581
|
if (user) {
|
|
1632
|
-
const resetToken = await signCollectionToken(
|
|
1582
|
+
const resetToken = await signCollectionToken(
|
|
1583
|
+
{ sub: user.id, email: user.email, collection: this.collection.slug, purpose: "reset" },
|
|
1584
|
+
"1h"
|
|
1585
|
+
);
|
|
1633
1586
|
const resetUrl = body?.resetUrl;
|
|
1634
1587
|
const url = resetUrl ? `${resetUrl}${resetUrl.includes("?") ? "&" : "?"}token=${encodeURIComponent(resetToken)}` : void 0;
|
|
1635
1588
|
try {
|
|
@@ -1652,8 +1605,7 @@ var AuthController = class {
|
|
|
1652
1605
|
async resetPassword(c) {
|
|
1653
1606
|
const config = c.get("config");
|
|
1654
1607
|
const db = config.db;
|
|
1655
|
-
if (!db)
|
|
1656
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1608
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1657
1609
|
const body = await c.req.json().catch(() => null);
|
|
1658
1610
|
if (!body?.token || !body?.password) {
|
|
1659
1611
|
return c.json({ error: true, message: "token and password are required." }, 400);
|
|
@@ -1674,7 +1626,9 @@ var AuthController = class {
|
|
|
1674
1626
|
data: { password: hashedPassword }
|
|
1675
1627
|
});
|
|
1676
1628
|
const { subject, html } = buildPasswordChangedEmail(config, { email: payload.email });
|
|
1677
|
-
sendEmail(config, { to: payload.email, subject, html }).catch(
|
|
1629
|
+
sendEmail(config, { to: payload.email, subject, html }).catch(
|
|
1630
|
+
(err) => console.error("[dyrected/core] Failed to send password-changed email:", err)
|
|
1631
|
+
);
|
|
1678
1632
|
return c.json({ success: true, message: "Password has been reset. You can now log in." });
|
|
1679
1633
|
}
|
|
1680
1634
|
// ---------------------------------------------------------------------------
|
|
@@ -1684,8 +1638,7 @@ var AuthController = class {
|
|
|
1684
1638
|
async invite(c) {
|
|
1685
1639
|
const config = c.get("config");
|
|
1686
1640
|
const db = config.db;
|
|
1687
|
-
if (!db)
|
|
1688
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1641
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1689
1642
|
const requestUser = c.get("user");
|
|
1690
1643
|
if (!requestUser) {
|
|
1691
1644
|
return c.json({ error: true, message: "Authentication required." }, 401);
|
|
@@ -1702,7 +1655,10 @@ var AuthController = class {
|
|
|
1702
1655
|
if (existing.total > 0) {
|
|
1703
1656
|
return c.json({ error: true, message: "An account with that email already exists." }, 409);
|
|
1704
1657
|
}
|
|
1705
|
-
const inviteToken = await signCollectionToken(
|
|
1658
|
+
const inviteToken = await signCollectionToken(
|
|
1659
|
+
{ sub: body.email, email: body.email, collection: this.collection.slug, purpose: "invite" },
|
|
1660
|
+
"7d"
|
|
1661
|
+
);
|
|
1706
1662
|
try {
|
|
1707
1663
|
const { subject, html } = buildInviteEmail(config, {
|
|
1708
1664
|
token: inviteToken,
|
|
@@ -1722,8 +1678,7 @@ var AuthController = class {
|
|
|
1722
1678
|
async acceptInvite(c) {
|
|
1723
1679
|
const config = c.get("config");
|
|
1724
1680
|
const db = config.db;
|
|
1725
|
-
if (!db)
|
|
1726
|
-
return c.json({ message: "Database not configured" }, 500);
|
|
1681
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
1727
1682
|
const body = await c.req.json().catch(() => null);
|
|
1728
1683
|
if (!body?.token || !body?.password) {
|
|
1729
1684
|
return c.json({ error: true, message: "token and password are required." }, 400);
|
|
@@ -1758,21 +1713,28 @@ var AuthController = class {
|
|
|
1758
1713
|
collection: this.collection.slug
|
|
1759
1714
|
});
|
|
1760
1715
|
const { subject, html } = buildWelcomeEmail(config, { email: inviteeEmail });
|
|
1761
|
-
sendEmail(config, { to: inviteeEmail, subject, html }).catch(
|
|
1716
|
+
sendEmail(config, { to: inviteeEmail, subject, html }).catch(
|
|
1717
|
+
(err) => console.error("[dyrected/core] Failed to send welcome email:", err)
|
|
1718
|
+
);
|
|
1762
1719
|
const { password: _, ...safeUser } = user;
|
|
1763
1720
|
return c.json({ token: sessionToken, user: safeUser }, 201);
|
|
1764
1721
|
}
|
|
1765
1722
|
};
|
|
1766
1723
|
|
|
1767
|
-
// src/controllers/admin-auth.controller.
|
|
1724
|
+
// src/controllers/admin-auth.controller.ts
|
|
1768
1725
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
1769
1726
|
import { TextEncoder as TextEncoder2 } from "util";
|
|
1770
|
-
import {
|
|
1727
|
+
import {
|
|
1728
|
+
SignJWT as SignJWT2,
|
|
1729
|
+
createRemoteJWKSet,
|
|
1730
|
+
jwtVerify as jwtVerify2,
|
|
1731
|
+
decodeJwt as decodeJwt2
|
|
1732
|
+
} from "jose";
|
|
1771
1733
|
var AdminAuthController = class {
|
|
1772
|
-
config;
|
|
1773
1734
|
constructor(config) {
|
|
1774
1735
|
this.config = config;
|
|
1775
1736
|
}
|
|
1737
|
+
config;
|
|
1776
1738
|
providers(c) {
|
|
1777
1739
|
return c.json(getPublicAdminAuthConfig(this.config.adminAuth));
|
|
1778
1740
|
}
|
|
@@ -1785,7 +1747,12 @@ var AdminAuthController = class {
|
|
|
1785
1747
|
const siteId = this.getSiteId(c);
|
|
1786
1748
|
const returnTo = this.normalizeReturnTo(c.req.query("returnTo"), c);
|
|
1787
1749
|
if (provider.type === "oidc") {
|
|
1788
|
-
const redirectUrl = await this.buildOidcStartUrl(
|
|
1750
|
+
const redirectUrl = await this.buildOidcStartUrl(
|
|
1751
|
+
provider,
|
|
1752
|
+
returnTo,
|
|
1753
|
+
siteId,
|
|
1754
|
+
new URL(c.req.url).origin
|
|
1755
|
+
);
|
|
1789
1756
|
return c.redirect(redirectUrl, 302);
|
|
1790
1757
|
}
|
|
1791
1758
|
if (!provider.startUrl) {
|
|
@@ -1793,14 +1760,16 @@ var AdminAuthController = class {
|
|
|
1793
1760
|
}
|
|
1794
1761
|
const url = this.buildCustomProviderStartUrl(provider.startUrl, new URL(c.req.url).origin);
|
|
1795
1762
|
if (!url) {
|
|
1796
|
-
return c.json(
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1763
|
+
return c.json(
|
|
1764
|
+
{
|
|
1765
|
+
error: true,
|
|
1766
|
+
message: `Admin auth provider "${provider.id}" has an invalid start URL.`
|
|
1767
|
+
},
|
|
1768
|
+
500
|
|
1769
|
+
);
|
|
1800
1770
|
}
|
|
1801
1771
|
url.searchParams.set("returnTo", returnTo);
|
|
1802
|
-
if (siteId)
|
|
1803
|
-
url.searchParams.set("siteId", siteId);
|
|
1772
|
+
if (siteId) url.searchParams.set("siteId", siteId);
|
|
1804
1773
|
url.searchParams.set("provider", provider.id);
|
|
1805
1774
|
return c.redirect(url.toString(), 302);
|
|
1806
1775
|
}
|
|
@@ -1847,8 +1816,7 @@ var AdminAuthController = class {
|
|
|
1847
1816
|
return c.json({ success: true, message: "Logged out. Discard your token." });
|
|
1848
1817
|
}
|
|
1849
1818
|
getProvider(config, id) {
|
|
1850
|
-
if (config.adminAuth?.mode !== "external")
|
|
1851
|
-
return void 0;
|
|
1819
|
+
if (config.adminAuth?.mode !== "external") return void 0;
|
|
1852
1820
|
return config.adminAuth.providers.find((provider) => provider.id === id);
|
|
1853
1821
|
}
|
|
1854
1822
|
async completeProviderAuth(requestConfig, provider, c) {
|
|
@@ -1860,8 +1828,7 @@ var AdminAuthController = class {
|
|
|
1860
1828
|
throw new Error("Admin auth collection is not configured.");
|
|
1861
1829
|
}
|
|
1862
1830
|
const db = c.get("config").db;
|
|
1863
|
-
if (!db)
|
|
1864
|
-
throw new Error("Database not configured.");
|
|
1831
|
+
if (!db) throw new Error("Database not configured.");
|
|
1865
1832
|
let user = await this.findUserByExternalIdentity(db, adminCollection.slug, provider.id, identity.sub) ?? (identity.email ? (await db.find({
|
|
1866
1833
|
collection: adminCollection.slug,
|
|
1867
1834
|
where: { email: identity.email },
|
|
@@ -1921,8 +1888,7 @@ var AdminAuthController = class {
|
|
|
1921
1888
|
},
|
|
1922
1889
|
user
|
|
1923
1890
|
});
|
|
1924
|
-
if (resolved)
|
|
1925
|
-
return resolved;
|
|
1891
|
+
if (resolved) return resolved;
|
|
1926
1892
|
return { allowed: true, roles: identity.roles, data: {} };
|
|
1927
1893
|
}
|
|
1928
1894
|
async buildUserData(identity, providerId, roles, extraData) {
|
|
@@ -1953,8 +1919,7 @@ var AdminAuthController = class {
|
|
|
1953
1919
|
}
|
|
1954
1920
|
async getRequestConfig(c) {
|
|
1955
1921
|
const siteId = this.getSiteId(c);
|
|
1956
|
-
if (!siteId || !this.config.onSchemaFetch)
|
|
1957
|
-
return this.config;
|
|
1922
|
+
if (!siteId || !this.config.onSchemaFetch) return this.config;
|
|
1958
1923
|
const dynamic = await this.config.onSchemaFetch(siteId);
|
|
1959
1924
|
return {
|
|
1960
1925
|
...this.config,
|
|
@@ -1985,8 +1950,7 @@ var AdminAuthController = class {
|
|
|
1985
1950
|
async resolveOidcIdentity(provider, c) {
|
|
1986
1951
|
const code = c.req.query("code");
|
|
1987
1952
|
const state = c.req.query("state");
|
|
1988
|
-
if (!code || !state)
|
|
1989
|
-
throw new Error("Missing OIDC callback parameters.");
|
|
1953
|
+
if (!code || !state) throw new Error("Missing OIDC callback parameters.");
|
|
1990
1954
|
const parsedState = await this.verifyState(state, provider.id);
|
|
1991
1955
|
const discovery = await this.getOidcDiscovery(provider);
|
|
1992
1956
|
const redirectUri = provider.redirectUri || this.defaultCallbackPath(provider.id, new URL(c.req.url).origin);
|
|
@@ -2021,8 +1985,7 @@ var AdminAuthController = class {
|
|
|
2021
1985
|
const userInfo = await fetch(provider.userInfoEndpoint || discovery.userinfo_endpoint, {
|
|
2022
1986
|
headers: { Authorization: `Bearer ${tokenBody.access_token}` }
|
|
2023
1987
|
});
|
|
2024
|
-
if (!userInfo.ok)
|
|
2025
|
-
throw new Error("OIDC userinfo request failed.");
|
|
1988
|
+
if (!userInfo.ok) throw new Error("OIDC userinfo request failed.");
|
|
2026
1989
|
claims = await userInfo.json();
|
|
2027
1990
|
} else {
|
|
2028
1991
|
throw new Error("OIDC provider did not return usable identity claims.");
|
|
@@ -2062,13 +2025,15 @@ var AdminAuthController = class {
|
|
|
2062
2025
|
if (provider.audience) {
|
|
2063
2026
|
const aud = claims.aud;
|
|
2064
2027
|
const matches = Array.isArray(aud) ? aud.includes(provider.audience) : aud === provider.audience;
|
|
2065
|
-
if (!matches)
|
|
2066
|
-
throw new Error("External auth audience mismatch.");
|
|
2028
|
+
if (!matches) throw new Error("External auth audience mismatch.");
|
|
2067
2029
|
}
|
|
2068
2030
|
}
|
|
2069
2031
|
return {
|
|
2070
2032
|
identity: this.mapClaims(claims, provider.claimMapping),
|
|
2071
|
-
returnTo: this.normalizeReturnTo(
|
|
2033
|
+
returnTo: this.normalizeReturnTo(
|
|
2034
|
+
body?.returnTo || c.req.query("returnTo"),
|
|
2035
|
+
c
|
|
2036
|
+
)
|
|
2072
2037
|
};
|
|
2073
2038
|
}
|
|
2074
2039
|
mapClaims(claims, mapping) {
|
|
@@ -2098,20 +2063,19 @@ var AdminAuthController = class {
|
|
|
2098
2063
|
return typeof value === "string" ? value : void 0;
|
|
2099
2064
|
}
|
|
2100
2065
|
readStringArrayClaim(value) {
|
|
2101
|
-
if (!value)
|
|
2102
|
-
return void 0;
|
|
2066
|
+
if (!value) return void 0;
|
|
2103
2067
|
if (Array.isArray(value)) {
|
|
2104
2068
|
return value.filter((entry) => typeof entry === "string");
|
|
2105
2069
|
}
|
|
2106
|
-
if (typeof value === "string")
|
|
2107
|
-
return [value];
|
|
2070
|
+
if (typeof value === "string") return [value];
|
|
2108
2071
|
return void 0;
|
|
2109
2072
|
}
|
|
2110
2073
|
async getOidcDiscovery(provider) {
|
|
2111
|
-
const discoveryUrl = new URL(
|
|
2074
|
+
const discoveryUrl = new URL(
|
|
2075
|
+
provider.issuer.replace(/\/$/, "") + "/.well-known/openid-configuration"
|
|
2076
|
+
);
|
|
2112
2077
|
const response = await fetch(discoveryUrl.toString());
|
|
2113
|
-
if (!response.ok)
|
|
2114
|
-
throw new Error("Failed to load OIDC discovery document.");
|
|
2078
|
+
if (!response.ok) throw new Error("Failed to load OIDC discovery document.");
|
|
2115
2079
|
return response.json();
|
|
2116
2080
|
}
|
|
2117
2081
|
defaultCallbackPath(providerId, origin = "") {
|
|
@@ -2119,12 +2083,10 @@ var AdminAuthController = class {
|
|
|
2119
2083
|
}
|
|
2120
2084
|
buildCustomProviderStartUrl(startUrl, origin) {
|
|
2121
2085
|
const value = startUrl.trim();
|
|
2122
|
-
if (!value || /^(undefined|null)(\/|$)/i.test(value))
|
|
2123
|
-
return null;
|
|
2086
|
+
if (!value || /^(undefined|null)(\/|$)/i.test(value)) return null;
|
|
2124
2087
|
try {
|
|
2125
2088
|
const url = new URL(value, origin);
|
|
2126
|
-
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
2127
|
-
return null;
|
|
2089
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
2128
2090
|
return url;
|
|
2129
2091
|
} catch {
|
|
2130
2092
|
return null;
|
|
@@ -2149,14 +2111,13 @@ var AdminAuthController = class {
|
|
|
2149
2111
|
return new TextEncoder2().encode(secret);
|
|
2150
2112
|
}
|
|
2151
2113
|
normalizeReturnTo(returnTo, c) {
|
|
2152
|
-
if (returnTo)
|
|
2153
|
-
return returnTo;
|
|
2114
|
+
if (returnTo) return returnTo;
|
|
2154
2115
|
const url = new URL(c.req.url);
|
|
2155
2116
|
return `${url.origin}/admin`;
|
|
2156
2117
|
}
|
|
2157
2118
|
};
|
|
2158
2119
|
|
|
2159
|
-
// src/controllers/preview.controller.
|
|
2120
|
+
// src/controllers/preview.controller.ts
|
|
2160
2121
|
import { SignJWT as SignJWT3, jwtVerify as jwtVerify3 } from "jose";
|
|
2161
2122
|
import { TextEncoder as TextEncoder3 } from "util";
|
|
2162
2123
|
var PreviewController = class {
|
|
@@ -2199,7 +2160,7 @@ var PreviewController = class {
|
|
|
2199
2160
|
}
|
|
2200
2161
|
};
|
|
2201
2162
|
|
|
2202
|
-
// src/middleware/auth.
|
|
2163
|
+
// src/middleware/auth.ts
|
|
2203
2164
|
function requireAuth() {
|
|
2204
2165
|
return async (c, next) => {
|
|
2205
2166
|
const authHeader = c.req.header("Authorization");
|
|
@@ -2231,7 +2192,7 @@ function optionalAuth() {
|
|
|
2231
2192
|
};
|
|
2232
2193
|
}
|
|
2233
2194
|
|
|
2234
|
-
// src/utils/swagger.
|
|
2195
|
+
// src/utils/swagger.ts
|
|
2235
2196
|
function getSwaggerHtml(specUrl = "/api/openapi.json") {
|
|
2236
2197
|
return `
|
|
2237
2198
|
<!DOCTYPE html>
|
|
@@ -2280,7 +2241,7 @@ function getSwaggerHtml(specUrl = "/api/openapi.json") {
|
|
|
2280
2241
|
`;
|
|
2281
2242
|
}
|
|
2282
2243
|
|
|
2283
|
-
// src/router.
|
|
2244
|
+
// src/router.ts
|
|
2284
2245
|
function accessGate(target, action) {
|
|
2285
2246
|
return async (c, next) => {
|
|
2286
2247
|
const user = c.get("user");
|
|
@@ -2297,8 +2258,7 @@ function accessGate(target, action) {
|
|
|
2297
2258
|
};
|
|
2298
2259
|
}
|
|
2299
2260
|
async function checkAccess(access, accessArgs) {
|
|
2300
|
-
if (access === void 0 || access === null)
|
|
2301
|
-
return true;
|
|
2261
|
+
if (access === void 0 || access === null) return true;
|
|
2302
2262
|
if (typeof access === "function") {
|
|
2303
2263
|
try {
|
|
2304
2264
|
const result = await access(accessArgs);
|
|
@@ -2314,8 +2274,7 @@ async function checkAccess(access, accessArgs) {
|
|
|
2314
2274
|
return true;
|
|
2315
2275
|
}
|
|
2316
2276
|
function serializeFieldForApi(f) {
|
|
2317
|
-
if (!f)
|
|
2318
|
-
return f;
|
|
2277
|
+
if (!f) return f;
|
|
2319
2278
|
const serialized = { ...f };
|
|
2320
2279
|
if (serialized.admin?.hooks) {
|
|
2321
2280
|
const hooks = { ...serialized.admin.hooks };
|
|
@@ -2348,10 +2307,8 @@ function registerRoutes(app, config) {
|
|
|
2348
2307
|
let globals = [...config.globals];
|
|
2349
2308
|
if (siteId && config.onSchemaFetch) {
|
|
2350
2309
|
const dynamic = await config.onSchemaFetch(siteId);
|
|
2351
|
-
if (dynamic.collections)
|
|
2352
|
-
|
|
2353
|
-
if (dynamic.globals)
|
|
2354
|
-
globals = [...globals, ...dynamic.globals];
|
|
2310
|
+
if (dynamic.collections) collections = [...collections, ...dynamic.collections];
|
|
2311
|
+
if (dynamic.globals) globals = [...globals, ...dynamic.globals];
|
|
2355
2312
|
if (dynamic.admin) {
|
|
2356
2313
|
config.admin = { ...config.admin, ...dynamic.admin };
|
|
2357
2314
|
}
|
|
@@ -2362,10 +2319,8 @@ function registerRoutes(app, config) {
|
|
|
2362
2319
|
const user = c.get("user");
|
|
2363
2320
|
const accessArgs = { user, req: c.req, doc: null };
|
|
2364
2321
|
const serializeAccess = async (access) => {
|
|
2365
|
-
if (typeof access === "string")
|
|
2366
|
-
|
|
2367
|
-
if (typeof access === "boolean")
|
|
2368
|
-
return access;
|
|
2322
|
+
if (typeof access === "string") return access;
|
|
2323
|
+
if (typeof access === "boolean") return access;
|
|
2369
2324
|
return checkAccess(access, accessArgs);
|
|
2370
2325
|
};
|
|
2371
2326
|
const filteredCollections = await Promise.all(collections.filter((col) => !siteId || col.shared || !col.siteId || col.siteId === siteId).map(async (col) => ({
|
|
@@ -2458,8 +2413,7 @@ function registerRoutes(app, config) {
|
|
|
2458
2413
|
let collections = [...config.collections];
|
|
2459
2414
|
if (siteId && config.onSchemaFetch) {
|
|
2460
2415
|
const dynamic = await config.onSchemaFetch(siteId);
|
|
2461
|
-
if (dynamic.collections)
|
|
2462
|
-
collections = [...collections, ...dynamic.collections];
|
|
2416
|
+
if (dynamic.collections) collections = [...collections, ...dynamic.collections];
|
|
2463
2417
|
}
|
|
2464
2418
|
const user = c.get("user");
|
|
2465
2419
|
let collection = collections.find((col) => col.slug === colSlug);
|
|
@@ -2478,8 +2432,7 @@ function registerRoutes(app, config) {
|
|
|
2478
2432
|
let globals = [...config.globals];
|
|
2479
2433
|
if (siteId && config.onSchemaFetch) {
|
|
2480
2434
|
const dynamic = await config.onSchemaFetch(siteId);
|
|
2481
|
-
if (dynamic.globals)
|
|
2482
|
-
globals = [...globals, ...dynamic.globals];
|
|
2435
|
+
if (dynamic.globals) globals = [...globals, ...dynamic.globals];
|
|
2483
2436
|
}
|
|
2484
2437
|
const glb = globals.find((g) => g.slug === colSlug);
|
|
2485
2438
|
if (!glb) {
|
|
@@ -2537,12 +2490,9 @@ function registerRoutes(app, config) {
|
|
|
2537
2490
|
const user = c.get("user");
|
|
2538
2491
|
const key = c.req.param("key");
|
|
2539
2492
|
const scope = c.req.query("scope");
|
|
2540
|
-
if (!db)
|
|
2541
|
-
|
|
2542
|
-
if (!
|
|
2543
|
-
return c.json({ error: true, message: "Authentication required." }, 401);
|
|
2544
|
-
if (!key)
|
|
2545
|
-
return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
2493
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
2494
|
+
if (!user?.collection || !user.sub) return c.json({ error: true, message: "Authentication required." }, 401);
|
|
2495
|
+
if (!key) return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
2546
2496
|
const getGlobalPreference = async () => {
|
|
2547
2497
|
const globalDoc = await db.findOne({ collection: "__global_preferences", id: key });
|
|
2548
2498
|
return globalDoc ? globalDoc.value : null;
|
|
@@ -2552,8 +2502,7 @@ function registerRoutes(app, config) {
|
|
|
2552
2502
|
return c.json({ key, value: globalValue2 });
|
|
2553
2503
|
}
|
|
2554
2504
|
const doc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
2555
|
-
if (!doc)
|
|
2556
|
-
return c.json({ error: true, message: "User not found." }, 404);
|
|
2505
|
+
if (!doc) return c.json({ error: true, message: "User not found." }, 404);
|
|
2557
2506
|
const preferences = typeof doc.__preferences === "object" && doc.__preferences !== null ? doc.__preferences : {};
|
|
2558
2507
|
if (key in preferences) {
|
|
2559
2508
|
return c.json({ key, value: preferences[key] ?? null });
|
|
@@ -2566,12 +2515,9 @@ function registerRoutes(app, config) {
|
|
|
2566
2515
|
const user = c.get("user");
|
|
2567
2516
|
const key = c.req.param("key");
|
|
2568
2517
|
const scope = c.req.query("scope");
|
|
2569
|
-
if (!db)
|
|
2570
|
-
|
|
2571
|
-
if (!
|
|
2572
|
-
return c.json({ error: true, message: "Authentication required." }, 401);
|
|
2573
|
-
if (!key)
|
|
2574
|
-
return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
2518
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
2519
|
+
if (!user?.collection || !user.sub) return c.json({ error: true, message: "Authentication required." }, 401);
|
|
2520
|
+
if (!key) return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
2575
2521
|
const body = await c.req.json().catch(() => ({}));
|
|
2576
2522
|
if (scope === "global") {
|
|
2577
2523
|
const isAdminUser = Array.isArray(user?.roles) && user.roles.includes("admin");
|
|
@@ -2594,8 +2540,7 @@ function registerRoutes(app, config) {
|
|
|
2594
2540
|
return c.json({ key, value: body.value });
|
|
2595
2541
|
}
|
|
2596
2542
|
const doc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
2597
|
-
if (!doc)
|
|
2598
|
-
return c.json({ error: true, message: "User not found." }, 404);
|
|
2543
|
+
if (!doc) return c.json({ error: true, message: "User not found." }, 404);
|
|
2599
2544
|
const preferences = typeof doc.__preferences === "object" && doc.__preferences !== null ? doc.__preferences : {};
|
|
2600
2545
|
const nextPreferences = { ...preferences, [key]: body.value };
|
|
2601
2546
|
await db.update({
|
|
@@ -2610,12 +2555,9 @@ function registerRoutes(app, config) {
|
|
|
2610
2555
|
const user = c.get("user");
|
|
2611
2556
|
const key = c.req.param("key");
|
|
2612
2557
|
const scope = c.req.query("scope");
|
|
2613
|
-
if (!db)
|
|
2614
|
-
|
|
2615
|
-
if (!
|
|
2616
|
-
return c.json({ error: true, message: "Authentication required." }, 401);
|
|
2617
|
-
if (!key)
|
|
2618
|
-
return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
2558
|
+
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
2559
|
+
if (!user?.collection || !user.sub) return c.json({ error: true, message: "Authentication required." }, 401);
|
|
2560
|
+
if (!key) return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
2619
2561
|
if (scope === "global") {
|
|
2620
2562
|
const isAdminUser = Array.isArray(user?.roles) && user.roles.includes("admin");
|
|
2621
2563
|
if (!isAdminUser) {
|
|
@@ -2625,8 +2567,7 @@ function registerRoutes(app, config) {
|
|
|
2625
2567
|
return c.json({ success: true });
|
|
2626
2568
|
}
|
|
2627
2569
|
const doc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
2628
|
-
if (!doc)
|
|
2629
|
-
return c.json({ error: true, message: "User not found." }, 404);
|
|
2570
|
+
if (!doc) return c.json({ error: true, message: "User not found." }, 404);
|
|
2630
2571
|
const preferences = typeof doc.__preferences === "object" && doc.__preferences !== null ? { ...doc.__preferences } : {};
|
|
2631
2572
|
delete preferences[key];
|
|
2632
2573
|
await db.update({
|
|
@@ -2662,8 +2603,7 @@ function registerRoutes(app, config) {
|
|
|
2662
2603
|
app.post("/api/admin/auth/:provider/exchange", (c) => adminAuthController.exchange(c));
|
|
2663
2604
|
app.post("/api/admin/logout", (c) => adminAuthController.logout(c));
|
|
2664
2605
|
for (const collection of config.collections) {
|
|
2665
|
-
if (!collection.auth)
|
|
2666
|
-
continue;
|
|
2606
|
+
if (!collection.auth) continue;
|
|
2667
2607
|
const path = `/api/collections/${collection.slug}`;
|
|
2668
2608
|
const authController = new AuthController(collection);
|
|
2669
2609
|
app.post(`${path}/login`, (c) => authController.login(c));
|
|
@@ -2765,39 +2705,25 @@ function registerRoutes(app, config) {
|
|
|
2765
2705
|
if (collection.auth && id) {
|
|
2766
2706
|
const authController = new AuthController(collection);
|
|
2767
2707
|
const method2 = c.req.method;
|
|
2768
|
-
if (method2 === "POST" && id === "login")
|
|
2769
|
-
|
|
2770
|
-
if (method2 === "
|
|
2771
|
-
|
|
2772
|
-
if (method2 === "
|
|
2773
|
-
|
|
2774
|
-
if (method2 === "POST" && id === "refresh-token")
|
|
2775
|
-
return authController.refreshToken(c);
|
|
2776
|
-
if (method2 === "POST" && id === "forgot-password")
|
|
2777
|
-
return authController.forgotPassword(c);
|
|
2778
|
-
if (method2 === "POST" && id === "reset-password")
|
|
2779
|
-
return authController.resetPassword(c);
|
|
2708
|
+
if (method2 === "POST" && id === "login") return authController.login(c);
|
|
2709
|
+
if (method2 === "POST" && id === "logout") return authController.logout(c);
|
|
2710
|
+
if (method2 === "GET" && id === "me") return authController.me(c);
|
|
2711
|
+
if (method2 === "POST" && id === "refresh-token") return authController.refreshToken(c);
|
|
2712
|
+
if (method2 === "POST" && id === "forgot-password") return authController.forgotPassword(c);
|
|
2713
|
+
if (method2 === "POST" && id === "reset-password") return authController.resetPassword(c);
|
|
2780
2714
|
}
|
|
2781
2715
|
const controller = new CollectionController(collection);
|
|
2782
2716
|
const method = c.req.method;
|
|
2783
2717
|
if (id) {
|
|
2784
|
-
if (method === "GET")
|
|
2785
|
-
|
|
2786
|
-
if (method === "
|
|
2787
|
-
|
|
2788
|
-
if (method === "
|
|
2789
|
-
|
|
2790
|
-
if (method === "DELETE")
|
|
2791
|
-
return controller.delete(c);
|
|
2792
|
-
if (method === "POST" && id === "media")
|
|
2793
|
-
return controller.create(c);
|
|
2794
|
-
if (method === "POST" && id === "seed")
|
|
2795
|
-
return controller.seed(c);
|
|
2718
|
+
if (method === "GET") return controller.findOne(c);
|
|
2719
|
+
if (method === "PATCH") return controller.update(c);
|
|
2720
|
+
if (method === "DELETE" && id === "delete-many") return controller.deleteMany(c);
|
|
2721
|
+
if (method === "DELETE") return controller.delete(c);
|
|
2722
|
+
if (method === "POST" && id === "media") return controller.create(c);
|
|
2723
|
+
if (method === "POST" && id === "seed") return controller.seed(c);
|
|
2796
2724
|
} else {
|
|
2797
|
-
if (method === "GET")
|
|
2798
|
-
|
|
2799
|
-
if (method === "POST")
|
|
2800
|
-
return controller.create(c);
|
|
2725
|
+
if (method === "GET") return controller.find(c);
|
|
2726
|
+
if (method === "POST") return controller.create(c);
|
|
2801
2727
|
}
|
|
2802
2728
|
}
|
|
2803
2729
|
}
|
|
@@ -2818,13 +2744,10 @@ function registerRoutes(app, config) {
|
|
|
2818
2744
|
const controller = new GlobalController(global);
|
|
2819
2745
|
const method = c.req.method;
|
|
2820
2746
|
if (id) {
|
|
2821
|
-
if (method === "POST" && id === "seed")
|
|
2822
|
-
return controller.seed(c);
|
|
2747
|
+
if (method === "POST" && id === "seed") return controller.seed(c);
|
|
2823
2748
|
} else {
|
|
2824
|
-
if (method === "GET")
|
|
2825
|
-
|
|
2826
|
-
if (method === "PATCH")
|
|
2827
|
-
return controller.update(c);
|
|
2749
|
+
if (method === "GET") return controller.get(c);
|
|
2750
|
+
if (method === "PATCH") return controller.update(c);
|
|
2828
2751
|
}
|
|
2829
2752
|
}
|
|
2830
2753
|
}
|
|
@@ -2832,7 +2755,7 @@ function registerRoutes(app, config) {
|
|
|
2832
2755
|
});
|
|
2833
2756
|
}
|
|
2834
2757
|
|
|
2835
|
-
// src/app.
|
|
2758
|
+
// src/app.ts
|
|
2836
2759
|
async function createDyrectedApp(rawConfig) {
|
|
2837
2760
|
const config = normalizeConfig(rawConfig);
|
|
2838
2761
|
const app = new Hono();
|