mktcms 0.1.30 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +0 -6
- package/dist/runtime/server/api/admin/blob.js +2 -4
- package/dist/runtime/server/api/admin/csv.js +2 -4
- package/dist/runtime/server/api/admin/csv.post.js +2 -4
- package/dist/runtime/server/api/admin/delete.js +2 -4
- package/dist/runtime/server/api/admin/download.js +2 -4
- package/dist/runtime/server/api/admin/import.js +3 -8
- package/dist/runtime/server/api/admin/list.js +5 -7
- package/dist/runtime/server/api/admin/md.js +2 -4
- package/dist/runtime/server/api/admin/md.post.js +2 -4
- package/dist/runtime/server/api/admin/txt.js +2 -4
- package/dist/runtime/server/api/admin/txt.post.js +2 -4
- package/dist/runtime/server/api/admin/upload.js +2 -3
- package/dist/runtime/server/api/content/[path].js +30 -69
- package/dist/runtime/server/api/content/list.js +4 -5
- package/dist/runtime/server/plugins/storage.js +4 -16
- package/dist/runtime/server/utils/parsedFile.d.ts +1 -0
- package/dist/runtime/server/utils/parsedFile.js +47 -0
- package/package.json +1 -2
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -10,12 +10,6 @@ const module$1 = defineNuxtModule({
|
|
|
10
10
|
const resolver = createResolver(import.meta.url);
|
|
11
11
|
_nuxt.options.runtimeConfig.mktcms = defu((_nuxt.options.runtimeConfig.mktcms, {
|
|
12
12
|
adminAuthKey: "",
|
|
13
|
-
s3AccessKey: "",
|
|
14
|
-
s3SecretKey: "",
|
|
15
|
-
s3Endpoint: "",
|
|
16
|
-
s3Bucket: "",
|
|
17
|
-
s3Region: "",
|
|
18
|
-
s3Prefix: "",
|
|
19
13
|
smtpHost: "",
|
|
20
14
|
smtpPort: 465,
|
|
21
15
|
smtpSecure: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createError, defineEventHandler, getValidatedQuery, send } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
import { toNodeBuffer } from "../../utils/toNodeBuffer.js";
|
|
5
5
|
const querySchema = z.object({
|
|
6
6
|
path: z.string().min(1)
|
|
@@ -8,10 +8,8 @@ const querySchema = z.object({
|
|
|
8
8
|
export default defineEventHandler(async (event) => {
|
|
9
9
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
10
10
|
const decodedPath = decodeURIComponent(path);
|
|
11
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
12
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
13
11
|
const storage = useStorage("content");
|
|
14
|
-
const file = await storage.getItemRaw(
|
|
12
|
+
const file = await storage.getItemRaw(decodedPath);
|
|
15
13
|
if (!file) {
|
|
16
14
|
throw createError({
|
|
17
15
|
statusCode: 404,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createError, defineEventHandler, getValidatedQuery } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
import { parse } from "csv-parse/sync";
|
|
5
5
|
const querySchema = z.object({
|
|
6
6
|
path: z.string().min(1)
|
|
@@ -8,10 +8,8 @@ const querySchema = z.object({
|
|
|
8
8
|
export default defineEventHandler(async (event) => {
|
|
9
9
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
10
10
|
const decodedPath = decodeURIComponent(path);
|
|
11
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
12
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
13
11
|
const storage = useStorage("content");
|
|
14
|
-
const file = await storage.getItem(
|
|
12
|
+
const file = await storage.getItem(decodedPath);
|
|
15
13
|
if (!file) {
|
|
16
14
|
throw createError({
|
|
17
15
|
statusCode: 404,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineEventHandler, getValidatedQuery, readValidatedBody } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
import { stringify } from "csv-stringify/sync";
|
|
5
5
|
const querySchema = z.object({
|
|
6
6
|
path: z.string().min(1)
|
|
@@ -15,14 +15,12 @@ export default defineEventHandler(async (event) => {
|
|
|
15
15
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
16
16
|
const { table } = await readValidatedBody(event, (body) => bodySchema.parse(body));
|
|
17
17
|
const decodedPath = decodeURIComponent(path);
|
|
18
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
19
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
20
18
|
const content = stringify(table.rows, {
|
|
21
19
|
header: true,
|
|
22
20
|
columns: table.headers,
|
|
23
21
|
delimiter: ";"
|
|
24
22
|
});
|
|
25
23
|
const storage = useStorage("content");
|
|
26
|
-
await storage.setItem(
|
|
24
|
+
await storage.setItem(decodedPath, content);
|
|
27
25
|
return { success: true };
|
|
28
26
|
});
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineEventHandler, getValidatedQuery } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
const querySchema = z.object({
|
|
5
5
|
path: z.string().min(1)
|
|
6
6
|
});
|
|
7
7
|
export default defineEventHandler(async (event) => {
|
|
8
8
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
9
9
|
const decodedPath = decodeURIComponent(path);
|
|
10
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
11
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
12
10
|
const storage = useStorage("content");
|
|
13
|
-
await storage.removeItem(
|
|
11
|
+
await storage.removeItem(decodedPath);
|
|
14
12
|
return { success: true };
|
|
15
13
|
});
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineEventHandler, getValidatedQuery } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
const querySchema = z.object({
|
|
5
5
|
path: z.string().min(1)
|
|
6
6
|
});
|
|
7
7
|
export default defineEventHandler(async (event) => {
|
|
8
8
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
9
9
|
const decodedPath = decodeURIComponent(path);
|
|
10
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
11
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
12
10
|
const storage = useStorage("content");
|
|
13
|
-
const file = await storage.getItemRaw(
|
|
11
|
+
const file = await storage.getItemRaw(decodedPath);
|
|
14
12
|
const isImage = decodedPath.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i);
|
|
15
13
|
const isPdf = decodedPath.endsWith(".pdf");
|
|
16
14
|
const isJson = decodedPath.endsWith(".json");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createError, defineEventHandler, readMultipartFormData } from "h3";
|
|
2
|
-
import {
|
|
2
|
+
import { useStorage } from "nitropack/runtime";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import unzipper from "unzipper";
|
|
5
5
|
function sanitizePathSegment(segment) {
|
|
@@ -28,12 +28,8 @@ function zipPathToColonKey(entryPath) {
|
|
|
28
28
|
const sanitizedParts = parts.map(sanitizePathSegment);
|
|
29
29
|
return sanitizedParts.join(":");
|
|
30
30
|
}
|
|
31
|
-
function withPrefix(s3Prefix, colonKey) {
|
|
32
|
-
return [s3Prefix, colonKey].filter(Boolean).join(":");
|
|
33
|
-
}
|
|
34
31
|
export default defineEventHandler(async (event) => {
|
|
35
32
|
const form = await readMultipartFormData(event);
|
|
36
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
37
33
|
if (!form) {
|
|
38
34
|
throw createError({
|
|
39
35
|
statusCode: 400,
|
|
@@ -82,10 +78,9 @@ export default defineEventHandler(async (event) => {
|
|
|
82
78
|
statusMessage: `Invalid ZIP entry path: ${entry.path}`
|
|
83
79
|
});
|
|
84
80
|
}
|
|
85
|
-
const fullKey = withPrefix(s3Prefix, fileColonKey);
|
|
86
81
|
const data = await entry.buffer();
|
|
87
|
-
await storage.setItemRaw(
|
|
88
|
-
written.add(
|
|
82
|
+
await storage.setItemRaw(fileColonKey, data);
|
|
83
|
+
written.add(fileColonKey);
|
|
89
84
|
}
|
|
90
85
|
return { success: true, count: written.size };
|
|
91
86
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
|
-
import { useStorage
|
|
2
|
+
import { useStorage } from "nitropack/runtime";
|
|
3
3
|
import { defineEventHandler, getValidatedQuery } from "h3";
|
|
4
4
|
const querySchema = z.object({
|
|
5
5
|
path: z.string().optional(),
|
|
@@ -8,14 +8,12 @@ const querySchema = z.object({
|
|
|
8
8
|
export default defineEventHandler(async (event) => {
|
|
9
9
|
const { path, type } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
10
10
|
const decodedPath = path ? decodeURIComponent(path) : "";
|
|
11
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
12
|
-
const pathPrefix = s3Prefix + (decodedPath ? ":" + decodedPath : "");
|
|
13
11
|
const storage = useStorage("content");
|
|
14
|
-
const keys = await storage.getKeys(
|
|
15
|
-
const
|
|
16
|
-
const files =
|
|
12
|
+
const keys = await storage.getKeys(decodedPath);
|
|
13
|
+
const keysWithoutPath = decodedPath ? keys.map((key) => key.replace(decodedPath + ":", "")) : keys;
|
|
14
|
+
const files = keysWithoutPath.filter((key) => !key.includes(":"));
|
|
17
15
|
const filteredFiles = type === "image" ? files.filter((file) => file.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i)) : files;
|
|
18
|
-
const dirs =
|
|
16
|
+
const dirs = keysWithoutPath.filter((key) => key.includes(":")).map((key) => key.split(":")[0]);
|
|
19
17
|
const uniqueDirs = Array.from(new Set(dirs));
|
|
20
18
|
return {
|
|
21
19
|
files: filteredFiles,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createError, defineEventHandler, getValidatedQuery } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
import { parseFrontmatter } from "../../utils/parseFrontmatter.js";
|
|
5
5
|
const querySchema = z.object({
|
|
6
6
|
path: z.string().min(1)
|
|
@@ -8,10 +8,8 @@ const querySchema = z.object({
|
|
|
8
8
|
export default defineEventHandler(async (event) => {
|
|
9
9
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
10
10
|
const decodedPath = decodeURIComponent(path);
|
|
11
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
12
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
13
11
|
const storage = useStorage("content");
|
|
14
|
-
const file = await storage.getItem(
|
|
12
|
+
const file = await storage.getItem(decodedPath);
|
|
15
13
|
if (!file) {
|
|
16
14
|
throw createError({
|
|
17
15
|
statusCode: 404,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineEventHandler, getValidatedQuery, readValidatedBody } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
import { stringify } from "yaml";
|
|
5
5
|
const querySchema = z.object({
|
|
6
6
|
path: z.string().min(1)
|
|
@@ -23,9 +23,7 @@ export default defineEventHandler(async (event) => {
|
|
|
23
23
|
const { frontmatter, markdown } = await readValidatedBody(event, (body) => bodySchema.parse(body));
|
|
24
24
|
const decodedPath = decodeURIComponent(path);
|
|
25
25
|
const content = buildContent(frontmatter, markdown);
|
|
26
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
27
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
28
26
|
const storage = useStorage("content");
|
|
29
|
-
await storage.setItem(
|
|
27
|
+
await storage.setItem(decodedPath, content);
|
|
30
28
|
return { success: true };
|
|
31
29
|
});
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createError, defineEventHandler, getValidatedQuery } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
const querySchema = z.object({
|
|
5
5
|
path: z.string().min(1)
|
|
6
6
|
});
|
|
7
7
|
export default defineEventHandler(async (event) => {
|
|
8
8
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
9
9
|
const decodedPath = decodeURIComponent(path);
|
|
10
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
11
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
12
10
|
const storage = useStorage("content");
|
|
13
|
-
const file = await storage.getItem(
|
|
11
|
+
const file = await storage.getItem(decodedPath);
|
|
14
12
|
if (!file) {
|
|
15
13
|
throw createError({
|
|
16
14
|
statusCode: 404,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineEventHandler, getValidatedQuery, readValidatedBody } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
const querySchema = z.object({
|
|
5
5
|
path: z.string().min(1)
|
|
6
6
|
});
|
|
@@ -11,9 +11,7 @@ export default defineEventHandler(async (event) => {
|
|
|
11
11
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
12
12
|
const { text } = await readValidatedBody(event, (body) => bodySchema.parse(body));
|
|
13
13
|
const decodedPath = decodeURIComponent(path);
|
|
14
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
15
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
16
14
|
const storage = useStorage("content");
|
|
17
|
-
await storage.setItem(
|
|
15
|
+
await storage.setItem(decodedPath, text);
|
|
18
16
|
return { success: true };
|
|
19
17
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
2
|
import { createError, defineEventHandler, getValidatedQuery, readMultipartFormData } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
4
4
|
function sanitizeFilename(filename) {
|
|
5
5
|
return filename.replace(/[/:\\]/g, "_");
|
|
6
6
|
}
|
|
@@ -9,7 +9,6 @@ const querySchema = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
export default defineEventHandler(async (event) => {
|
|
11
11
|
const form = await readMultipartFormData(event);
|
|
12
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
13
12
|
const { path } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
14
13
|
const sanePath = path ? path.replace(/^\//, "").replace(/\/$/, "") : void 0;
|
|
15
14
|
if (!form) {
|
|
@@ -39,7 +38,7 @@ export default defineEventHandler(async (event) => {
|
|
|
39
38
|
statusMessage: "Invalid file type. Only PDF, JPG, JPEG, PNG, GIF, SVG, WEBP, MD, DOCX, TXT, CSV, and JSON files are allowed."
|
|
40
39
|
});
|
|
41
40
|
}
|
|
42
|
-
const filePath = [
|
|
41
|
+
const filePath = [sanePath, sanitizeFilename(file.filename)].filter(Boolean).join(":");
|
|
43
42
|
await useStorage("content").setItemRaw(filePath, Buffer.from(file.data));
|
|
44
43
|
return { success: true, path: filePath };
|
|
45
44
|
});
|
|
@@ -1,85 +1,46 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createError, defineEventHandler, getValidatedRouterParams, send } from "h3";
|
|
3
|
-
import {
|
|
4
|
-
import { parse } from "csv-parse/sync";
|
|
5
|
-
import { marked } from "marked";
|
|
6
|
-
import { parseFrontmatter } from "../../utils/parseFrontmatter.js";
|
|
3
|
+
import { useStorage } from "nitropack/runtime";
|
|
7
4
|
import { toNodeBuffer } from "../../utils/toNodeBuffer.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
if (fullPath.endsWith(".csv") && typeof file === "string") {
|
|
20
|
-
try {
|
|
21
|
-
const table = parse(file, {
|
|
22
|
-
skip_empty_lines: true,
|
|
23
|
-
delimiter: ";"
|
|
24
|
-
});
|
|
25
|
-
const headers = Array.isArray(table[0]) ? table[0].map((cell) => String(cell ?? "")) : [];
|
|
26
|
-
const rows = table.slice(1);
|
|
27
|
-
return { headers, rows };
|
|
28
|
-
} catch {
|
|
29
|
-
throw createError({
|
|
30
|
-
statusCode: 500,
|
|
31
|
-
statusMessage: "Invalid CSV file"
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
if (fullPath.endsWith(".md") && typeof file === "string") {
|
|
36
|
-
try {
|
|
37
|
-
const markdownItem = parseFrontmatter(file);
|
|
38
|
-
return {
|
|
39
|
-
...markdownItem,
|
|
40
|
-
html: marked.parse(markdownItem.markdown)
|
|
41
|
-
};
|
|
42
|
-
} catch {
|
|
43
|
-
throw createError({
|
|
44
|
-
statusCode: 500,
|
|
45
|
-
statusMessage: "Invalid Markdown file"
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return file;
|
|
5
|
+
import { parsedFile } from "../../utils/parsedFile.js";
|
|
6
|
+
function getFileType(path) {
|
|
7
|
+
const isImage = path.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i);
|
|
8
|
+
const isPdf = path.endsWith(".pdf");
|
|
9
|
+
const isJson = path.endsWith(".json");
|
|
10
|
+
const isCSV = path.endsWith(".csv");
|
|
11
|
+
const isMarkdown = path.endsWith(".md");
|
|
12
|
+
return { isImage, isPdf, isJson, isCSV, isMarkdown };
|
|
50
13
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
54
|
-
export default defineEventHandler(async (event) => {
|
|
55
|
-
const { path } = await getValidatedRouterParams(event, (params) => paramsSchema.parse(params));
|
|
56
|
-
const decodedPath = decodeURIComponent(path);
|
|
57
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
58
|
-
const fullPath = s3Prefix + ":" + decodedPath;
|
|
59
|
-
const isImage = decodedPath.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i);
|
|
60
|
-
const isPdf = decodedPath.endsWith(".pdf");
|
|
61
|
-
const isJson = decodedPath.endsWith(".json");
|
|
62
|
-
const isCSV = decodedPath.endsWith(".csv");
|
|
63
|
-
const isMarkdown = decodedPath.endsWith(".md");
|
|
14
|
+
function getContentType(path) {
|
|
15
|
+
const { isImage, isPdf, isJson, isCSV, isMarkdown } = getFileType(path);
|
|
64
16
|
if (isImage) {
|
|
65
|
-
const ext =
|
|
17
|
+
const ext = path.split(".").pop()?.toLowerCase();
|
|
66
18
|
if (ext === "svg") {
|
|
67
|
-
|
|
19
|
+
return "image/svg+xml";
|
|
68
20
|
} else if (ext === "jpg") {
|
|
69
|
-
|
|
21
|
+
return "image/jpeg";
|
|
70
22
|
} else {
|
|
71
|
-
|
|
23
|
+
return "image/" + ext;
|
|
72
24
|
}
|
|
73
25
|
} else if (isPdf) {
|
|
74
|
-
|
|
26
|
+
return "application/pdf";
|
|
75
27
|
} else if (isJson || isCSV || isMarkdown) {
|
|
76
|
-
|
|
28
|
+
return "application/json; charset=utf-8";
|
|
77
29
|
} else {
|
|
78
|
-
|
|
30
|
+
return "text/plain; charset=utf-8";
|
|
79
31
|
}
|
|
32
|
+
}
|
|
33
|
+
const paramsSchema = z.object({
|
|
34
|
+
path: z.string().min(1)
|
|
35
|
+
});
|
|
36
|
+
export default defineEventHandler(async (event) => {
|
|
37
|
+
const { path } = await getValidatedRouterParams(event, (params) => paramsSchema.parse(params));
|
|
38
|
+
const decodedPath = decodeURIComponent(path);
|
|
39
|
+
const { isImage, isPdf } = getFileType(decodedPath);
|
|
40
|
+
event.node.res.setHeader("Content-Type", getContentType(decodedPath));
|
|
80
41
|
const storage = useStorage("content");
|
|
81
42
|
if (isImage || isPdf) {
|
|
82
|
-
const raw = await storage.getItemRaw(
|
|
43
|
+
const raw = await storage.getItemRaw(decodedPath);
|
|
83
44
|
if (!raw) {
|
|
84
45
|
throw createError({
|
|
85
46
|
statusCode: 404,
|
|
@@ -90,12 +51,12 @@ export default defineEventHandler(async (event) => {
|
|
|
90
51
|
event.node.res.setHeader("Content-Length", String(body.byteLength));
|
|
91
52
|
return send(event, body);
|
|
92
53
|
}
|
|
93
|
-
const file = await storage.getItem(
|
|
54
|
+
const file = await storage.getItem(decodedPath);
|
|
94
55
|
if (!file) {
|
|
95
56
|
throw createError({
|
|
96
57
|
statusCode: 404,
|
|
97
58
|
statusMessage: "File not found"
|
|
98
59
|
});
|
|
99
60
|
}
|
|
100
|
-
return parsedFile(
|
|
61
|
+
return parsedFile(decodedPath, file);
|
|
101
62
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
|
-
import { useStorage
|
|
2
|
+
import { useStorage } from "nitropack/runtime";
|
|
3
3
|
import { defineEventHandler, getValidatedQuery } from "h3";
|
|
4
4
|
import { marked } from "marked";
|
|
5
5
|
import { parseFrontmatter } from "../../utils/parseFrontmatter.js";
|
|
@@ -10,9 +10,8 @@ const querySchema = z.object({
|
|
|
10
10
|
export default defineEventHandler(async (event) => {
|
|
11
11
|
const { path, type } = await getValidatedQuery(event, (query) => querySchema.parse(query));
|
|
12
12
|
const decodedPath = path ? decodeURIComponent(path) : void 0;
|
|
13
|
-
const { mktcms: { s3Prefix } } = useRuntimeConfig();
|
|
14
13
|
const storage = useStorage("content");
|
|
15
|
-
const keys = await storage.getKeys(
|
|
14
|
+
const keys = await storage.getKeys(decodedPath);
|
|
16
15
|
const filteredKeys = keys.filter((key) => {
|
|
17
16
|
if (type === "md") {
|
|
18
17
|
return key.endsWith(".md");
|
|
@@ -32,14 +31,14 @@ export default defineEventHandler(async (event) => {
|
|
|
32
31
|
return false;
|
|
33
32
|
});
|
|
34
33
|
if (type === "image") {
|
|
35
|
-
return filteredKeys
|
|
34
|
+
return filteredKeys;
|
|
36
35
|
}
|
|
37
36
|
const items = await storage.getItems(filteredKeys);
|
|
38
37
|
return items.map((item) => {
|
|
39
38
|
if (type === "md" && typeof item.value === "string") {
|
|
40
39
|
const markdownItem = parseFrontmatter(item.value);
|
|
41
40
|
return {
|
|
42
|
-
key: item.key
|
|
41
|
+
key: item.key,
|
|
43
42
|
value: {
|
|
44
43
|
...markdownItem,
|
|
45
44
|
html: marked.parse(markdownItem.markdown)
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
import createS3Driver from "unstorage/drivers/s3";
|
|
2
1
|
import createFsDriver from "unstorage/drivers/fs";
|
|
3
|
-
import { defineNitroPlugin, useStorage
|
|
2
|
+
import { defineNitroPlugin, useStorage } from "nitropack/runtime";
|
|
4
3
|
export default defineNitroPlugin(() => {
|
|
5
4
|
const storage = useStorage();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
accessKeyId: s3AccessKey,
|
|
10
|
-
secretAccessKey: s3SecretKey,
|
|
11
|
-
endpoint: s3Endpoint,
|
|
12
|
-
bucket: s3Bucket,
|
|
13
|
-
region: s3Region
|
|
14
|
-
}));
|
|
15
|
-
} else {
|
|
16
|
-
storage.mount("content", createFsDriver({
|
|
17
|
-
base: "./.storage"
|
|
18
|
-
}));
|
|
19
|
-
}
|
|
5
|
+
storage.mount("content", createFsDriver({
|
|
6
|
+
base: "./.storage"
|
|
7
|
+
}));
|
|
20
8
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parsedFile(fullPath: string, file: string | number | boolean | object): any;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createError } from "h3";
|
|
2
|
+
import { parse } from "csv-parse/sync";
|
|
3
|
+
import { marked } from "marked";
|
|
4
|
+
import { parseFrontmatter } from "./parseFrontmatter.js";
|
|
5
|
+
export function parsedFile(fullPath, file) {
|
|
6
|
+
if (fullPath.endsWith(".json") && typeof file === "string") {
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(file);
|
|
9
|
+
} catch {
|
|
10
|
+
throw createError({
|
|
11
|
+
statusCode: 500,
|
|
12
|
+
statusMessage: "Invalid JSON file"
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (fullPath.endsWith(".csv") && typeof file === "string") {
|
|
17
|
+
try {
|
|
18
|
+
const table = parse(file, {
|
|
19
|
+
skip_empty_lines: true,
|
|
20
|
+
delimiter: ";"
|
|
21
|
+
});
|
|
22
|
+
const headers = Array.isArray(table[0]) ? table[0].map((cell) => String(cell ?? "")) : [];
|
|
23
|
+
const rows = table.slice(1);
|
|
24
|
+
return { headers, rows };
|
|
25
|
+
} catch {
|
|
26
|
+
throw createError({
|
|
27
|
+
statusCode: 500,
|
|
28
|
+
statusMessage: "Invalid CSV file"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (fullPath.endsWith(".md") && typeof file === "string") {
|
|
33
|
+
try {
|
|
34
|
+
const markdownItem = parseFrontmatter(file);
|
|
35
|
+
return {
|
|
36
|
+
...markdownItem,
|
|
37
|
+
html: marked.parse(markdownItem.markdown)
|
|
38
|
+
};
|
|
39
|
+
} catch {
|
|
40
|
+
throw createError({
|
|
41
|
+
statusCode: 500,
|
|
42
|
+
statusMessage: "Invalid Markdown file"
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return file;
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mktcms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"description": "Simple CMS module for Nuxt",
|
|
5
5
|
"repository": "mktcode/mktcms",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@nuxt/kit": "^4.2.2",
|
|
41
41
|
"@vueuse/core": "^14.1.0",
|
|
42
|
-
"aws4fetch": "^1.0.20",
|
|
43
42
|
"csv-parse": "^6.1.0",
|
|
44
43
|
"csv-stringify": "^6.6.0",
|
|
45
44
|
"defu": "^6.1.4",
|