@structcms/api 0.1.0 → 0.1.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/README.md +2 -2
- package/dist/index.cjs +266 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +241 -12
- package/dist/index.d.ts +241 -12
- package/dist/index.js +250 -20
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +147 -33
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +3 -2
- package/dist/next/index.d.ts +3 -2
- package/dist/next/index.js +147 -33
- package/dist/next/index.js.map +1 -1
- package/dist/supabase/index.cjs +37 -1
- package/dist/supabase/index.cjs.map +1 -1
- package/dist/supabase/index.d.cts +1 -1
- package/dist/supabase/index.d.ts +1 -1
- package/dist/supabase/index.js +37 -1
- package/dist/supabase/index.js.map +1 -1
- package/dist/{types-Zi0Iyow1.d.cts → types-Cdui_Ets.d.cts} +21 -2
- package/dist/{types-Zi0Iyow1.d.ts → types-Cdui_Ets.d.ts} +21 -2
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -215,6 +215,12 @@ var SANITIZE_OPTIONS = {
|
|
|
215
215
|
function sanitizeString(value) {
|
|
216
216
|
return sanitizeHtml(value, SANITIZE_OPTIONS);
|
|
217
217
|
}
|
|
218
|
+
function stripTags(value) {
|
|
219
|
+
return sanitizeHtml(value, {
|
|
220
|
+
allowedTags: [],
|
|
221
|
+
allowedAttributes: {}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
218
224
|
function sanitizeValue(value) {
|
|
219
225
|
if (typeof value === "string") {
|
|
220
226
|
return sanitizeString(value);
|
|
@@ -281,10 +287,11 @@ var StorageValidationError = class extends Error {
|
|
|
281
287
|
}
|
|
282
288
|
};
|
|
283
289
|
async function handleCreatePage(adapter, input) {
|
|
284
|
-
|
|
290
|
+
const sanitizedTitle = stripTags(input.title).trim();
|
|
291
|
+
if (!sanitizedTitle) {
|
|
285
292
|
throw new StorageValidationError("Page title must not be empty", "EMPTY_TITLE");
|
|
286
293
|
}
|
|
287
|
-
const slug = input.slug?.trim() || generateSlug(
|
|
294
|
+
const slug = input.slug?.trim() || generateSlug(sanitizedTitle);
|
|
288
295
|
if (!slug) {
|
|
289
296
|
throw new StorageValidationError(
|
|
290
297
|
"Could not generate a valid slug from the provided title",
|
|
@@ -297,6 +304,7 @@ async function handleCreatePage(adapter, input) {
|
|
|
297
304
|
const sanitizedSections = input.sections ? sanitizeSectionData(input.sections) : void 0;
|
|
298
305
|
return adapter.createPage({
|
|
299
306
|
...input,
|
|
307
|
+
title: sanitizedTitle,
|
|
300
308
|
slug: uniqueSlug,
|
|
301
309
|
sections: sanitizedSections
|
|
302
310
|
});
|
|
@@ -305,8 +313,12 @@ async function handleUpdatePage(adapter, input) {
|
|
|
305
313
|
if (!input.id.trim()) {
|
|
306
314
|
throw new StorageValidationError("Page ID must not be empty", "EMPTY_ID");
|
|
307
315
|
}
|
|
308
|
-
|
|
309
|
-
|
|
316
|
+
let sanitizedTitle;
|
|
317
|
+
if (input.title !== void 0) {
|
|
318
|
+
sanitizedTitle = stripTags(input.title).trim();
|
|
319
|
+
if (!sanitizedTitle) {
|
|
320
|
+
throw new StorageValidationError("Page title must not be empty", "EMPTY_TITLE");
|
|
321
|
+
}
|
|
310
322
|
}
|
|
311
323
|
if (input.slug !== void 0) {
|
|
312
324
|
const slug = input.slug.trim();
|
|
@@ -319,7 +331,11 @@ async function handleUpdatePage(adapter, input) {
|
|
|
319
331
|
throw new StorageValidationError(`Slug "${slug}" is already in use`, "DUPLICATE_SLUG");
|
|
320
332
|
}
|
|
321
333
|
}
|
|
322
|
-
const sanitizedInput =
|
|
334
|
+
const sanitizedInput = {
|
|
335
|
+
...input,
|
|
336
|
+
...sanitizedTitle !== void 0 && { title: sanitizedTitle },
|
|
337
|
+
...input.sections && { sections: sanitizeSectionData(input.sections) }
|
|
338
|
+
};
|
|
323
339
|
return adapter.updatePage(sanitizedInput);
|
|
324
340
|
}
|
|
325
341
|
async function handleDeletePage(adapter, id) {
|
|
@@ -329,38 +345,46 @@ async function handleDeletePage(adapter, id) {
|
|
|
329
345
|
return adapter.deletePage(id);
|
|
330
346
|
}
|
|
331
347
|
async function handleCreateNavigation(adapter, input) {
|
|
332
|
-
|
|
348
|
+
const sanitizedName = stripTags(input.name).trim();
|
|
349
|
+
if (!sanitizedName) {
|
|
333
350
|
throw new StorageValidationError("Navigation name must not be empty", "EMPTY_NAME");
|
|
334
351
|
}
|
|
335
352
|
const existingNavigations = await adapter.listNavigations();
|
|
336
353
|
const existingNames = existingNavigations.map((n) => n.name);
|
|
337
|
-
if (existingNames.includes(
|
|
354
|
+
if (existingNames.includes(sanitizedName)) {
|
|
338
355
|
throw new StorageValidationError(
|
|
339
|
-
`Navigation name "${
|
|
356
|
+
`Navigation name "${sanitizedName}" is already in use`,
|
|
340
357
|
"DUPLICATE_NAME"
|
|
341
358
|
);
|
|
342
359
|
}
|
|
343
|
-
return adapter.createNavigation(
|
|
360
|
+
return adapter.createNavigation({
|
|
361
|
+
...input,
|
|
362
|
+
name: sanitizedName
|
|
363
|
+
});
|
|
344
364
|
}
|
|
345
365
|
async function handleUpdateNavigation(adapter, input) {
|
|
346
366
|
if (!input.id.trim()) {
|
|
347
367
|
throw new StorageValidationError("Navigation ID must not be empty", "EMPTY_ID");
|
|
348
368
|
}
|
|
369
|
+
let sanitizedName;
|
|
349
370
|
if (input.name !== void 0) {
|
|
350
|
-
|
|
351
|
-
if (!
|
|
371
|
+
sanitizedName = stripTags(input.name).trim();
|
|
372
|
+
if (!sanitizedName) {
|
|
352
373
|
throw new StorageValidationError("Navigation name must not be empty", "EMPTY_NAME");
|
|
353
374
|
}
|
|
354
375
|
const existingNavigations = await adapter.listNavigations();
|
|
355
376
|
const existingNames = existingNavigations.filter((n) => n.id !== input.id).map((n) => n.name);
|
|
356
|
-
if (existingNames.includes(
|
|
377
|
+
if (existingNames.includes(sanitizedName)) {
|
|
357
378
|
throw new StorageValidationError(
|
|
358
|
-
`Navigation name "${
|
|
379
|
+
`Navigation name "${sanitizedName}" is already in use`,
|
|
359
380
|
"DUPLICATE_NAME"
|
|
360
381
|
);
|
|
361
382
|
}
|
|
362
383
|
}
|
|
363
|
-
return adapter.updateNavigation(
|
|
384
|
+
return adapter.updateNavigation({
|
|
385
|
+
...input,
|
|
386
|
+
...sanitizedName !== void 0 && { name: sanitizedName }
|
|
387
|
+
});
|
|
364
388
|
}
|
|
365
389
|
async function handleDeleteNavigation(adapter, id) {
|
|
366
390
|
if (!id.trim()) {
|
|
@@ -369,12 +393,61 @@ async function handleDeleteNavigation(adapter, id) {
|
|
|
369
393
|
return adapter.deleteNavigation(id);
|
|
370
394
|
}
|
|
371
395
|
|
|
396
|
+
// src/validation/schemas.ts
|
|
397
|
+
import { z } from "zod";
|
|
398
|
+
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
399
|
+
var PageSectionSchema = z.object({
|
|
400
|
+
id: z.string().optional(),
|
|
401
|
+
type: z.string(),
|
|
402
|
+
data: z.record(z.unknown())
|
|
403
|
+
});
|
|
404
|
+
var CreatePageSchema = z.object({
|
|
405
|
+
title: z.string().max(200, "Title must not exceed 200 characters"),
|
|
406
|
+
pageType: z.string(),
|
|
407
|
+
slug: z.string().max(200, "Slug must not exceed 200 characters").optional(),
|
|
408
|
+
sections: z.array(PageSectionSchema).optional()
|
|
409
|
+
});
|
|
410
|
+
var UpdatePageSchema = CreatePageSchema.partial();
|
|
411
|
+
var NavigationItemSchema = z.lazy(
|
|
412
|
+
() => z.object({
|
|
413
|
+
label: z.string(),
|
|
414
|
+
href: z.string(),
|
|
415
|
+
children: z.array(NavigationItemSchema).optional()
|
|
416
|
+
})
|
|
417
|
+
);
|
|
418
|
+
var CreateNavigationSchema = z.object({
|
|
419
|
+
name: z.string().max(100, "Name must not exceed 100 characters"),
|
|
420
|
+
items: z.array(NavigationItemSchema)
|
|
421
|
+
});
|
|
422
|
+
var UpdateNavigationSchema = CreateNavigationSchema.partial();
|
|
423
|
+
var SignInSchema = z.object({
|
|
424
|
+
email: z.string().email("Invalid email address"),
|
|
425
|
+
password: z.string().min(1, "Password is required")
|
|
426
|
+
});
|
|
427
|
+
var MediaUploadSchema = z.object({
|
|
428
|
+
filename: z.string().max(255, "Filename must not exceed 255 characters"),
|
|
429
|
+
mimeType: z.string(),
|
|
430
|
+
size: z.number().max(MAX_FILE_SIZE, `File size must not exceed ${MAX_FILE_SIZE / 1024 / 1024}MB`),
|
|
431
|
+
data: z.instanceof(ArrayBuffer)
|
|
432
|
+
});
|
|
433
|
+
|
|
372
434
|
// src/media/resolve.ts
|
|
373
435
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
374
|
-
var MEDIA_FIELD_SUFFIXES = [
|
|
436
|
+
var MEDIA_FIELD_SUFFIXES = [
|
|
437
|
+
"_image",
|
|
438
|
+
"_media",
|
|
439
|
+
"_photo",
|
|
440
|
+
"_thumbnail",
|
|
441
|
+
"_avatar",
|
|
442
|
+
"_icon",
|
|
443
|
+
"_file",
|
|
444
|
+
"_document",
|
|
445
|
+
"_attachment",
|
|
446
|
+
"_download"
|
|
447
|
+
];
|
|
375
448
|
function isMediaField(fieldName) {
|
|
376
449
|
const lower = fieldName.toLowerCase();
|
|
377
|
-
if (lower === "image" || lower === "media" || lower === "photo" || lower === "thumbnail" || lower === "avatar" || lower === "icon") {
|
|
450
|
+
if (lower === "image" || lower === "media" || lower === "photo" || lower === "thumbnail" || lower === "avatar" || lower === "icon" || lower === "file" || lower === "document" || lower === "attachment" || lower === "download") {
|
|
378
451
|
return true;
|
|
379
452
|
}
|
|
380
453
|
return MEDIA_FIELD_SUFFIXES.some((suffix) => lower.endsWith(suffix));
|
|
@@ -462,6 +535,7 @@ async function handleGetNavigation(adapter, name) {
|
|
|
462
535
|
}
|
|
463
536
|
|
|
464
537
|
// src/media/types.ts
|
|
538
|
+
var MAX_FILE_SIZE2 = 50 * 1024 * 1024;
|
|
465
539
|
var ALLOWED_MIME_TYPES = [
|
|
466
540
|
"image/jpeg",
|
|
467
541
|
"image/png",
|
|
@@ -469,8 +543,29 @@ var ALLOWED_MIME_TYPES = [
|
|
|
469
543
|
"image/webp",
|
|
470
544
|
"image/svg+xml"
|
|
471
545
|
];
|
|
546
|
+
var ALLOWED_DOCUMENT_MIME_TYPES = [
|
|
547
|
+
"application/pdf",
|
|
548
|
+
"application/msword",
|
|
549
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
550
|
+
"application/vnd.ms-excel",
|
|
551
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
552
|
+
"application/vnd.ms-powerpoint",
|
|
553
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
554
|
+
"text/plain",
|
|
555
|
+
"text/csv",
|
|
556
|
+
"application/zip",
|
|
557
|
+
"application/gzip"
|
|
558
|
+
];
|
|
559
|
+
var ALL_ALLOWED_MIME_TYPES = [
|
|
560
|
+
...ALLOWED_MIME_TYPES,
|
|
561
|
+
...ALLOWED_DOCUMENT_MIME_TYPES
|
|
562
|
+
];
|
|
472
563
|
|
|
473
564
|
// src/media/supabase-adapter.ts
|
|
565
|
+
function deriveCategory(mimeType) {
|
|
566
|
+
const imageMimes = ALLOWED_MIME_TYPES;
|
|
567
|
+
return imageMimes.includes(mimeType) ? "image" : "document";
|
|
568
|
+
}
|
|
474
569
|
var MediaError = class extends Error {
|
|
475
570
|
constructor(message, code, details) {
|
|
476
571
|
super(message);
|
|
@@ -512,6 +607,7 @@ var SupabaseMediaAdapter = class {
|
|
|
512
607
|
url: this.getPublicUrl(row.storage_path),
|
|
513
608
|
mimeType: row.mime_type,
|
|
514
609
|
size: row.size,
|
|
610
|
+
category: row.category,
|
|
515
611
|
createdAt: new Date(row.created_at)
|
|
516
612
|
};
|
|
517
613
|
}
|
|
@@ -532,7 +628,8 @@ var SupabaseMediaAdapter = class {
|
|
|
532
628
|
filename: input.filename,
|
|
533
629
|
storage_path: storagePath,
|
|
534
630
|
mime_type: input.mimeType,
|
|
535
|
-
size: input.size
|
|
631
|
+
size: input.size,
|
|
632
|
+
category: deriveCategory(input.mimeType)
|
|
536
633
|
}).select().single();
|
|
537
634
|
if (dbError) {
|
|
538
635
|
await this.client.storage.from(this.bucketName).remove([storagePath]);
|
|
@@ -559,6 +656,9 @@ var SupabaseMediaAdapter = class {
|
|
|
559
656
|
if (filter?.mimeType) {
|
|
560
657
|
query = query.eq("mime_type", filter.mimeType);
|
|
561
658
|
}
|
|
659
|
+
if (filter?.category) {
|
|
660
|
+
query = query.eq("category", filter.category);
|
|
661
|
+
}
|
|
562
662
|
query = query.order("created_at", { ascending: false });
|
|
563
663
|
if (filter?.limit) {
|
|
564
664
|
query = query.limit(filter.limit);
|
|
@@ -608,16 +708,25 @@ var MediaValidationError = class extends Error {
|
|
|
608
708
|
}
|
|
609
709
|
};
|
|
610
710
|
function validateMimeType(mimeType) {
|
|
611
|
-
const allowed =
|
|
711
|
+
const allowed = ALL_ALLOWED_MIME_TYPES;
|
|
612
712
|
if (!allowed.includes(mimeType)) {
|
|
613
713
|
throw new MediaValidationError(
|
|
614
|
-
`Invalid file type: ${mimeType}. Allowed types: ${
|
|
714
|
+
`Invalid file type: ${mimeType}. Allowed types: ${ALL_ALLOWED_MIME_TYPES.join(", ")}`,
|
|
615
715
|
"INVALID_MIME_TYPE"
|
|
616
716
|
);
|
|
617
717
|
}
|
|
618
718
|
}
|
|
719
|
+
function validateFileSize(size) {
|
|
720
|
+
if (size > MAX_FILE_SIZE2) {
|
|
721
|
+
throw new MediaValidationError(
|
|
722
|
+
`File size exceeds maximum allowed size of ${MAX_FILE_SIZE2 / 1024 / 1024}MB`,
|
|
723
|
+
"FILE_TOO_LARGE"
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
619
727
|
async function handleUploadMedia(adapter, input) {
|
|
620
728
|
validateMimeType(input.mimeType);
|
|
729
|
+
validateFileSize(input.size);
|
|
621
730
|
return adapter.upload(input);
|
|
622
731
|
}
|
|
623
732
|
async function handleGetMedia(adapter, id) {
|
|
@@ -871,6 +980,82 @@ function createAuthMiddleware(config) {
|
|
|
871
980
|
};
|
|
872
981
|
}
|
|
873
982
|
|
|
983
|
+
// src/auth/csrf.ts
|
|
984
|
+
function generateCsrfToken() {
|
|
985
|
+
const bytes = new Uint8Array(32);
|
|
986
|
+
crypto.getRandomValues(bytes);
|
|
987
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
988
|
+
}
|
|
989
|
+
function validateCsrfToken(cookieToken, headerToken) {
|
|
990
|
+
if (!cookieToken || !headerToken) {
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
if (cookieToken.trim() === "" || headerToken.trim() === "") {
|
|
994
|
+
return false;
|
|
995
|
+
}
|
|
996
|
+
return cookieToken === headerToken;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// src/auth/rate-limiter.ts
|
|
1000
|
+
function createRateLimiter(config) {
|
|
1001
|
+
const { windowMs, maxRequests } = config;
|
|
1002
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1003
|
+
function cleanupEntry(entry, now) {
|
|
1004
|
+
const windowStart = now - windowMs;
|
|
1005
|
+
entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);
|
|
1006
|
+
}
|
|
1007
|
+
function scheduleCleanup(key) {
|
|
1008
|
+
const entry = entries.get(key);
|
|
1009
|
+
if (!entry) return;
|
|
1010
|
+
if (entry.timeoutId) {
|
|
1011
|
+
clearTimeout(entry.timeoutId);
|
|
1012
|
+
}
|
|
1013
|
+
entry.timeoutId = setTimeout(() => {
|
|
1014
|
+
const currentEntry = entries.get(key);
|
|
1015
|
+
if (currentEntry) {
|
|
1016
|
+
cleanupEntry(currentEntry, Date.now());
|
|
1017
|
+
if (currentEntry.timestamps.length === 0) {
|
|
1018
|
+
entries.delete(key);
|
|
1019
|
+
} else {
|
|
1020
|
+
scheduleCleanup(key);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}, windowMs);
|
|
1024
|
+
}
|
|
1025
|
+
return {
|
|
1026
|
+
check(key) {
|
|
1027
|
+
const now = Date.now();
|
|
1028
|
+
let entry = entries.get(key);
|
|
1029
|
+
if (!entry) {
|
|
1030
|
+
entry = { timestamps: [] };
|
|
1031
|
+
entries.set(key, entry);
|
|
1032
|
+
}
|
|
1033
|
+
cleanupEntry(entry, now);
|
|
1034
|
+
if (entry.timestamps.length >= maxRequests) {
|
|
1035
|
+
const oldestTimestamp = entry.timestamps[0] ?? now;
|
|
1036
|
+
const retryAfterMs = oldestTimestamp + windowMs - now;
|
|
1037
|
+
const retryAfterSeconds = Math.ceil(retryAfterMs / 1e3);
|
|
1038
|
+
return {
|
|
1039
|
+
allowed: false,
|
|
1040
|
+
retryAfter: retryAfterSeconds
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
entry.timestamps.push(now);
|
|
1044
|
+
scheduleCleanup(key);
|
|
1045
|
+
return {
|
|
1046
|
+
allowed: true
|
|
1047
|
+
};
|
|
1048
|
+
},
|
|
1049
|
+
reset(key) {
|
|
1050
|
+
const entry = entries.get(key);
|
|
1051
|
+
if (entry?.timeoutId) {
|
|
1052
|
+
clearTimeout(entry.timeoutId);
|
|
1053
|
+
}
|
|
1054
|
+
entries.delete(key);
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
|
|
874
1059
|
// src/supabase/factory.ts
|
|
875
1060
|
function readEnv(name) {
|
|
876
1061
|
const processLike = globalThis.process;
|
|
@@ -1001,23 +1186,65 @@ async function handleExportSite(storageAdapter, mediaAdapter) {
|
|
|
1001
1186
|
contentDisposition: contentDisposition("site-export.json")
|
|
1002
1187
|
};
|
|
1003
1188
|
}
|
|
1189
|
+
|
|
1190
|
+
// src/audit/logger.ts
|
|
1191
|
+
var defaultSink = (entry) => {
|
|
1192
|
+
const output = JSON.stringify(entry, null, 2);
|
|
1193
|
+
globalThis.console?.log?.(output);
|
|
1194
|
+
};
|
|
1195
|
+
function createAuditLogger(sink = defaultSink) {
|
|
1196
|
+
return {
|
|
1197
|
+
log: async (entry) => {
|
|
1198
|
+
await sink({
|
|
1199
|
+
...entry,
|
|
1200
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
function withAuditLog(handler, options, sink) {
|
|
1206
|
+
const logger = createAuditLogger(sink);
|
|
1207
|
+
return (async (...args) => {
|
|
1208
|
+
const result = await handler(...args);
|
|
1209
|
+
await logger.log({
|
|
1210
|
+
action: options.action,
|
|
1211
|
+
entity: options.entity,
|
|
1212
|
+
entityId: options.extractEntityId(args),
|
|
1213
|
+
userId: options.extractUserId?.(args),
|
|
1214
|
+
metadata: options.metadata?.(args)
|
|
1215
|
+
});
|
|
1216
|
+
return result;
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1004
1219
|
export {
|
|
1220
|
+
ALLOWED_DOCUMENT_MIME_TYPES,
|
|
1005
1221
|
ALLOWED_MIME_TYPES,
|
|
1222
|
+
ALL_ALLOWED_MIME_TYPES,
|
|
1006
1223
|
AuthError,
|
|
1007
1224
|
AuthValidationError,
|
|
1225
|
+
CreateNavigationSchema,
|
|
1226
|
+
CreatePageSchema,
|
|
1227
|
+
MAX_FILE_SIZE2 as MAX_FILE_SIZE,
|
|
1008
1228
|
MediaError,
|
|
1229
|
+
MediaUploadSchema,
|
|
1009
1230
|
MediaValidationError,
|
|
1231
|
+
SignInSchema,
|
|
1010
1232
|
StorageError,
|
|
1011
1233
|
StorageValidationError,
|
|
1012
1234
|
SupabaseAuthAdapter,
|
|
1013
1235
|
SupabaseMediaAdapter,
|
|
1014
1236
|
SupabaseStorageAdapter,
|
|
1237
|
+
UpdateNavigationSchema,
|
|
1238
|
+
UpdatePageSchema,
|
|
1239
|
+
createAuditLogger,
|
|
1015
1240
|
createAuthAdapter,
|
|
1016
1241
|
createAuthMiddleware,
|
|
1017
1242
|
createMediaAdapter,
|
|
1243
|
+
createRateLimiter,
|
|
1018
1244
|
createStorageAdapter,
|
|
1019
1245
|
createSupabaseAdapters,
|
|
1020
1246
|
ensureUniqueSlug,
|
|
1247
|
+
generateCsrfToken,
|
|
1021
1248
|
generateSlug,
|
|
1022
1249
|
handleCreateNavigation,
|
|
1023
1250
|
handleCreatePage,
|
|
@@ -1042,6 +1269,9 @@ export {
|
|
|
1042
1269
|
handleUpdatePage,
|
|
1043
1270
|
handleUploadMedia,
|
|
1044
1271
|
handleVerifySession,
|
|
1045
|
-
resolveMediaReferences
|
|
1272
|
+
resolveMediaReferences,
|
|
1273
|
+
stripTags,
|
|
1274
|
+
validateCsrfToken,
|
|
1275
|
+
withAuditLog
|
|
1046
1276
|
};
|
|
1047
1277
|
//# sourceMappingURL=index.js.map
|