@isardsat/editorial-server 6.0.2 → 6.0.4
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/app.js +2 -0
- package/dist/lib/hooks.d.ts +2 -2
- package/dist/lib/hooks.js +18 -10
- package/dist/lib/i18n.d.ts +35 -0
- package/dist/lib/i18n.js +67 -0
- package/dist/lib/lang.d.ts +35 -0
- package/dist/lib/lang.js +67 -0
- package/dist/lib/storage copy.d.ts +35 -0
- package/dist/lib/storage copy.js +67 -0
- package/dist/lib/storage.d.ts +6 -3
- package/dist/lib/storage.js +18 -14
- package/dist/routes/actions.d.ts +3 -3
- package/dist/routes/actions.js +47 -15
- package/dist/routes/config.d.ts +3 -0
- package/dist/routes/config.js +23 -0
- package/dist/routes/data.js +36 -8
- package/dist/routes/files.d.ts +1 -1
- package/dist/routes/files.js +44 -32
- package/package.json +3 -3
package/dist/app.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createHooks } from "./lib/hooks.js";
|
|
|
7
7
|
import { createStorage } from "./lib/storage.js";
|
|
8
8
|
import { createActionRoutes } from "./routes/actions.js";
|
|
9
9
|
import { createAdminRoutes } from "./routes/admin.js";
|
|
10
|
+
import { createConfigRoutes } from "./routes/config.js";
|
|
10
11
|
import { createDataRoutes } from "./routes/data.js";
|
|
11
12
|
import { createFilesRoutes } from "./routes/files.js";
|
|
12
13
|
export const BASE_EDITORIAL_PATH = "./editorial";
|
|
@@ -16,6 +17,7 @@ export async function createEditorialServer({ configDirectory = BASE_EDITORIAL_P
|
|
|
16
17
|
const storage = createStorage(editorialDirectory);
|
|
17
18
|
const hooks = await createHooks(configDirectory);
|
|
18
19
|
app.use(logger());
|
|
20
|
+
app.route("/api/v1", createConfigRoutes(config));
|
|
19
21
|
app.route("/api/v1", createDataRoutes(storage));
|
|
20
22
|
app.route("/api/v1", createFilesRoutes());
|
|
21
23
|
app.route("/api/v1", createActionRoutes(storage, hooks));
|
package/dist/lib/hooks.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export declare function createHooks(configDirectory: string): Promise<{
|
|
|
2
2
|
onPublish: (content: any, schema: any) => Promise<any>;
|
|
3
3
|
onLocalize: (content: any, schema: any) => Promise<any>;
|
|
4
4
|
onLocalizeEnd: (content: any, schema: any) => Promise<any>;
|
|
5
|
-
onPull: () => Promise<any>;
|
|
6
|
-
onPush: () => Promise<any>;
|
|
5
|
+
onPull: (author: string) => Promise<any>;
|
|
6
|
+
onPush: (author: string) => Promise<any>;
|
|
7
7
|
}>;
|
|
8
8
|
export type Hooks = Awaited<ReturnType<typeof createHooks>>;
|
package/dist/lib/hooks.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { join } from
|
|
1
|
+
import { join } from "node:path";
|
|
2
2
|
export async function createHooks(configDirectory) {
|
|
3
|
-
const hooksDirPath = join(configDirectory,
|
|
3
|
+
const hooksDirPath = join(configDirectory, "hooks");
|
|
4
4
|
async function loadHook(name) {
|
|
5
5
|
const hookScript = join(process.cwd(), hooksDirPath, name);
|
|
6
6
|
const module = await import(`${hookScript}.mjs`);
|
|
7
|
-
const hookFunction = typeof module.default ===
|
|
7
|
+
const hookFunction = typeof module.default === "function" ? module.default : null;
|
|
8
8
|
return hookFunction;
|
|
9
9
|
}
|
|
10
10
|
async function executeHook(hookName, ...args) {
|
|
@@ -14,19 +14,27 @@ export async function createHooks(configDirectory) {
|
|
|
14
14
|
return hook(...args);
|
|
15
15
|
}
|
|
16
16
|
async function onPublish(content, schema) {
|
|
17
|
-
return executeHook(
|
|
17
|
+
return executeHook("onPublish", content, schema);
|
|
18
18
|
}
|
|
19
19
|
async function onLocalize(content, schema) {
|
|
20
|
-
return executeHook(
|
|
20
|
+
return executeHook("onLocalize", content, schema);
|
|
21
21
|
}
|
|
22
22
|
async function onLocalizeEnd(content, schema) {
|
|
23
|
-
return executeHook(
|
|
23
|
+
return executeHook("onLocalizeEnd", content, schema);
|
|
24
24
|
}
|
|
25
|
-
async function onPull() {
|
|
26
|
-
|
|
25
|
+
async function onPull(author) {
|
|
26
|
+
if (process.env.NODE_ENV !== "production") {
|
|
27
|
+
console.info("Dropping onPull hook event in development environment");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
return executeHook("onPull", author);
|
|
27
31
|
}
|
|
28
|
-
async function onPush() {
|
|
29
|
-
|
|
32
|
+
async function onPush(author) {
|
|
33
|
+
if (process.env.NODE_ENV !== "production") {
|
|
34
|
+
console.info("Dropping onPush hook event in development environment");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
return executeHook("onPush", author);
|
|
30
38
|
}
|
|
31
39
|
return { onPublish, onLocalize, onLocalizeEnd, onPull, onPush };
|
|
32
40
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EditorialData, EditorialDataObjectWithType } from "@isardsat/editorial-common";
|
|
2
|
+
export declare function createI18n(dataDirectory: string): {
|
|
3
|
+
getSchema: () => Promise<Record<string, {
|
|
4
|
+
displayName: string;
|
|
5
|
+
fields: Record<string, import("zod").objectOutputType<{
|
|
6
|
+
type: import("zod").ZodEnum<["string", "url", "boolean", "date", "datetime", "markdown", "number", "color", "select", "color"]>;
|
|
7
|
+
displayName: import("zod").ZodString;
|
|
8
|
+
displayExtra: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
|
+
placeholder: import("zod").ZodOptional<import("zod").ZodString>;
|
|
10
|
+
isRequired: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
11
|
+
showInSummary: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
12
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
13
|
+
singleton?: boolean | undefined;
|
|
14
|
+
}>>;
|
|
15
|
+
getContent: () => Promise<EditorialData>;
|
|
16
|
+
saveLocalisationMessages: (messages: any) => Promise<boolean>;
|
|
17
|
+
createItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
18
|
+
id: import("zod").ZodString;
|
|
19
|
+
type: import("zod").ZodString;
|
|
20
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
21
|
+
updateItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
22
|
+
id: import("zod").ZodString;
|
|
23
|
+
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
24
|
+
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
25
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
26
|
+
deleteItem: (item: EditorialDataObjectWithType) => Promise<Record<string, Record<string, import("zod").objectOutputType<{
|
|
27
|
+
id: import("zod").ZodString;
|
|
28
|
+
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
29
|
+
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
30
|
+
}, import("zod").ZodTypeAny, "passthrough">>>>;
|
|
31
|
+
saveContent: ({ production }: {
|
|
32
|
+
production?: boolean;
|
|
33
|
+
}) => Promise<boolean>;
|
|
34
|
+
};
|
|
35
|
+
export type Storage = ReturnType<typeof createStorage>;
|
package/dist/lib/i18n.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { EditorialDataItemSchema, EditorialDataSchema, EditorialSchemaSchema, } from "@isardsat/editorial-common";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { writeFileSafe } from "./utils/fs.js";
|
|
6
|
+
export function createI18n(dataDirectory) {
|
|
7
|
+
const schemaPath = join(dataDirectory, "schema.yaml");
|
|
8
|
+
const dataPath = join(dataDirectory, "data.json");
|
|
9
|
+
const dataProdPath = join(dataDirectory, "data.prod.json");
|
|
10
|
+
const dataExtractedPath = join(dataDirectory, "data.messages.json");
|
|
11
|
+
async function getSchema() {
|
|
12
|
+
const schemaFile = await readFile(schemaPath, "utf-8").then((value) => parse(value));
|
|
13
|
+
const schema = EditorialSchemaSchema.parse(schemaFile);
|
|
14
|
+
return schema;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* TODO: This should ideally cache the result of reading the file until an update occurs.
|
|
18
|
+
*/
|
|
19
|
+
async function getContent() {
|
|
20
|
+
return await readFile(dataPath, "utf-8").then((value) => JSON.parse(value));
|
|
21
|
+
}
|
|
22
|
+
async function saveContent({ production }) {
|
|
23
|
+
const content = await getContent();
|
|
24
|
+
await writeFileSafe(production ? dataProdPath : dataPath, JSON.stringify(EditorialDataSchema.parse(content), null, 2));
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
async function saveLocalisationMessages(messages) {
|
|
28
|
+
await writeFileSafe(dataExtractedPath, JSON.stringify(messages, null, 2));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
async function createItem(item) {
|
|
32
|
+
const content = await getContent();
|
|
33
|
+
content[item.type][item.id] = EditorialDataItemSchema.parse(item);
|
|
34
|
+
// TODO: Use superjson to safely encode different types.
|
|
35
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
36
|
+
return item;
|
|
37
|
+
}
|
|
38
|
+
async function updateItem(item) {
|
|
39
|
+
const content = await getContent();
|
|
40
|
+
const oldItem = content[item.type][item.id];
|
|
41
|
+
const newItem = EditorialDataItemSchema.parse({
|
|
42
|
+
...oldItem,
|
|
43
|
+
...item,
|
|
44
|
+
updatedAt: new Date().toISOString(),
|
|
45
|
+
});
|
|
46
|
+
content[item.type][item.id] = newItem;
|
|
47
|
+
// TODO: Use superjson to safely encode different types.
|
|
48
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
49
|
+
return newItem;
|
|
50
|
+
}
|
|
51
|
+
async function deleteItem(item) {
|
|
52
|
+
const content = await getContent();
|
|
53
|
+
delete content[item.type][item.id];
|
|
54
|
+
// TODO: Use superjson to safely encode different types.
|
|
55
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
56
|
+
return content;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
getSchema,
|
|
60
|
+
getContent,
|
|
61
|
+
saveLocalisationMessages,
|
|
62
|
+
createItem,
|
|
63
|
+
updateItem,
|
|
64
|
+
deleteItem,
|
|
65
|
+
saveContent,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EditorialData, EditorialDataObjectWithType } from "@isardsat/editorial-common";
|
|
2
|
+
export declare function createStorage(dataDirectory: string): {
|
|
3
|
+
getSchema: () => Promise<Record<string, {
|
|
4
|
+
displayName: string;
|
|
5
|
+
fields: Record<string, import("zod").objectOutputType<{
|
|
6
|
+
type: import("zod").ZodEnum<["string", "url", "boolean", "date", "datetime", "markdown", "number", "color", "select", "color"]>;
|
|
7
|
+
displayName: import("zod").ZodString;
|
|
8
|
+
displayExtra: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
|
+
placeholder: import("zod").ZodOptional<import("zod").ZodString>;
|
|
10
|
+
isRequired: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
11
|
+
showInSummary: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
12
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
13
|
+
singleton?: boolean | undefined;
|
|
14
|
+
}>>;
|
|
15
|
+
getContent: () => Promise<EditorialData>;
|
|
16
|
+
saveLocalisationMessages: (messages: any) => Promise<boolean>;
|
|
17
|
+
createItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
18
|
+
id: import("zod").ZodString;
|
|
19
|
+
type: import("zod").ZodString;
|
|
20
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
21
|
+
updateItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
22
|
+
id: import("zod").ZodString;
|
|
23
|
+
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
24
|
+
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
25
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
26
|
+
deleteItem: (item: EditorialDataObjectWithType) => Promise<Record<string, Record<string, import("zod").objectOutputType<{
|
|
27
|
+
id: import("zod").ZodString;
|
|
28
|
+
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
29
|
+
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
30
|
+
}, import("zod").ZodTypeAny, "passthrough">>>>;
|
|
31
|
+
saveContent: ({ production }: {
|
|
32
|
+
production?: boolean;
|
|
33
|
+
}) => Promise<boolean>;
|
|
34
|
+
};
|
|
35
|
+
export type Storage = ReturnType<typeof createStorage>;
|
package/dist/lib/lang.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { EditorialDataItemSchema, EditorialDataSchema, EditorialSchemaSchema, } from "@isardsat/editorial-common";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { writeFileSafe } from "./utils/fs.js";
|
|
6
|
+
export function createStorage(dataDirectory) {
|
|
7
|
+
const schemaPath = join(dataDirectory, "schema.yaml");
|
|
8
|
+
const dataPath = join(dataDirectory, "data.json");
|
|
9
|
+
const dataProdPath = join(dataDirectory, "data.prod.json");
|
|
10
|
+
const dataExtractedPath = join(dataDirectory, "data.messages.json");
|
|
11
|
+
async function getSchema() {
|
|
12
|
+
const schemaFile = await readFile(schemaPath, "utf-8").then((value) => parse(value));
|
|
13
|
+
const schema = EditorialSchemaSchema.parse(schemaFile);
|
|
14
|
+
return schema;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* TODO: This should ideally cache the result of reading the file until an update occurs.
|
|
18
|
+
*/
|
|
19
|
+
async function getContent() {
|
|
20
|
+
return await readFile(dataPath, "utf-8").then((value) => JSON.parse(value));
|
|
21
|
+
}
|
|
22
|
+
async function saveContent({ production }) {
|
|
23
|
+
const content = await getContent();
|
|
24
|
+
await writeFileSafe(production ? dataProdPath : dataPath, JSON.stringify(EditorialDataSchema.parse(content), null, 2));
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
async function saveLocalisationMessages(messages) {
|
|
28
|
+
await writeFileSafe(dataExtractedPath, JSON.stringify(messages, null, 2));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
async function createItem(item) {
|
|
32
|
+
const content = await getContent();
|
|
33
|
+
content[item.type][item.id] = EditorialDataItemSchema.parse(item);
|
|
34
|
+
// TODO: Use superjson to safely encode different types.
|
|
35
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
36
|
+
return item;
|
|
37
|
+
}
|
|
38
|
+
async function updateItem(item) {
|
|
39
|
+
const content = await getContent();
|
|
40
|
+
const oldItem = content[item.type][item.id];
|
|
41
|
+
const newItem = EditorialDataItemSchema.parse({
|
|
42
|
+
...oldItem,
|
|
43
|
+
...item,
|
|
44
|
+
updatedAt: new Date().toISOString(),
|
|
45
|
+
});
|
|
46
|
+
content[item.type][item.id] = newItem;
|
|
47
|
+
// TODO: Use superjson to safely encode different types.
|
|
48
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
49
|
+
return newItem;
|
|
50
|
+
}
|
|
51
|
+
async function deleteItem(item) {
|
|
52
|
+
const content = await getContent();
|
|
53
|
+
delete content[item.type][item.id];
|
|
54
|
+
// TODO: Use superjson to safely encode different types.
|
|
55
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
56
|
+
return content;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
getSchema,
|
|
60
|
+
getContent,
|
|
61
|
+
saveLocalisationMessages,
|
|
62
|
+
createItem,
|
|
63
|
+
updateItem,
|
|
64
|
+
deleteItem,
|
|
65
|
+
saveContent,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EditorialData, EditorialDataObjectWithType } from "@isardsat/editorial-common";
|
|
2
|
+
export declare function createStorage(dataDirectory: string): {
|
|
3
|
+
getSchema: () => Promise<Record<string, {
|
|
4
|
+
displayName: string;
|
|
5
|
+
fields: Record<string, import("zod").objectOutputType<{
|
|
6
|
+
type: import("zod").ZodEnum<["string", "url", "boolean", "date", "datetime", "markdown", "number", "color", "select", "color"]>;
|
|
7
|
+
displayName: import("zod").ZodString;
|
|
8
|
+
displayExtra: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
|
+
placeholder: import("zod").ZodOptional<import("zod").ZodString>;
|
|
10
|
+
isRequired: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
11
|
+
showInSummary: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
12
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
13
|
+
singleton?: boolean | undefined;
|
|
14
|
+
}>>;
|
|
15
|
+
getContent: () => Promise<EditorialData>;
|
|
16
|
+
saveLocalisationMessages: (messages: any) => Promise<boolean>;
|
|
17
|
+
createItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
18
|
+
id: import("zod").ZodString;
|
|
19
|
+
type: import("zod").ZodString;
|
|
20
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
21
|
+
updateItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
22
|
+
id: import("zod").ZodString;
|
|
23
|
+
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
24
|
+
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
25
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
26
|
+
deleteItem: (item: EditorialDataObjectWithType) => Promise<Record<string, Record<string, import("zod").objectOutputType<{
|
|
27
|
+
id: import("zod").ZodString;
|
|
28
|
+
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
29
|
+
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
30
|
+
}, import("zod").ZodTypeAny, "passthrough">>>>;
|
|
31
|
+
saveContent: ({ production }: {
|
|
32
|
+
production?: boolean;
|
|
33
|
+
}) => Promise<boolean>;
|
|
34
|
+
};
|
|
35
|
+
export type Storage = ReturnType<typeof createStorage>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { EditorialDataItemSchema, EditorialDataSchema, EditorialSchemaSchema, } from "@isardsat/editorial-common";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { writeFileSafe } from "./utils/fs.js";
|
|
6
|
+
export function createStorage(dataDirectory) {
|
|
7
|
+
const schemaPath = join(dataDirectory, "schema.yaml");
|
|
8
|
+
const dataPath = join(dataDirectory, "data.json");
|
|
9
|
+
const dataProdPath = join(dataDirectory, "data.prod.json");
|
|
10
|
+
const dataExtractedPath = join(dataDirectory, "data.messages.json");
|
|
11
|
+
async function getSchema() {
|
|
12
|
+
const schemaFile = await readFile(schemaPath, "utf-8").then((value) => parse(value));
|
|
13
|
+
const schema = EditorialSchemaSchema.parse(schemaFile);
|
|
14
|
+
return schema;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* TODO: This should ideally cache the result of reading the file until an update occurs.
|
|
18
|
+
*/
|
|
19
|
+
async function getContent() {
|
|
20
|
+
return await readFile(dataPath, "utf-8").then((value) => JSON.parse(value));
|
|
21
|
+
}
|
|
22
|
+
async function saveContent({ production }) {
|
|
23
|
+
const content = await getContent();
|
|
24
|
+
await writeFileSafe(production ? dataProdPath : dataPath, JSON.stringify(EditorialDataSchema.parse(content), null, 2));
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
async function saveLocalisationMessages(messages) {
|
|
28
|
+
await writeFileSafe(dataExtractedPath, JSON.stringify(messages, null, 2));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
async function createItem(item) {
|
|
32
|
+
const content = await getContent();
|
|
33
|
+
content[item.type][item.id] = EditorialDataItemSchema.parse(item);
|
|
34
|
+
// TODO: Use superjson to safely encode different types.
|
|
35
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
36
|
+
return item;
|
|
37
|
+
}
|
|
38
|
+
async function updateItem(item) {
|
|
39
|
+
const content = await getContent();
|
|
40
|
+
const oldItem = content[item.type][item.id];
|
|
41
|
+
const newItem = EditorialDataItemSchema.parse({
|
|
42
|
+
...oldItem,
|
|
43
|
+
...item,
|
|
44
|
+
updatedAt: new Date().toISOString(),
|
|
45
|
+
});
|
|
46
|
+
content[item.type][item.id] = newItem;
|
|
47
|
+
// TODO: Use superjson to safely encode different types.
|
|
48
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
49
|
+
return newItem;
|
|
50
|
+
}
|
|
51
|
+
async function deleteItem(item) {
|
|
52
|
+
const content = await getContent();
|
|
53
|
+
delete content[item.type][item.id];
|
|
54
|
+
// TODO: Use superjson to safely encode different types.
|
|
55
|
+
await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
|
|
56
|
+
return content;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
getSchema,
|
|
60
|
+
getContent,
|
|
61
|
+
saveLocalisationMessages,
|
|
62
|
+
createItem,
|
|
63
|
+
updateItem,
|
|
64
|
+
deleteItem,
|
|
65
|
+
saveContent,
|
|
66
|
+
};
|
|
67
|
+
}
|
package/dist/lib/storage.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { EditorialData, EditorialDataObjectWithType } from
|
|
1
|
+
import type { EditorialData, EditorialDataObjectWithType } from "@isardsat/editorial-common";
|
|
2
2
|
export declare function createStorage(dataDirectory: string): {
|
|
3
3
|
getSchema: () => Promise<Record<string, {
|
|
4
4
|
displayName: string;
|
|
5
5
|
fields: Record<string, import("zod").objectOutputType<{
|
|
6
|
-
type: import("zod").ZodEnum<["string", "boolean", "date", "datetime", "markdown", "number", "color", "select", "color"]>;
|
|
6
|
+
type: import("zod").ZodEnum<["string", "url", "boolean", "date", "datetime", "markdown", "number", "color", "select", "color"]>;
|
|
7
7
|
displayName: import("zod").ZodString;
|
|
8
8
|
displayExtra: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
9
|
placeholder: import("zod").ZodOptional<import("zod").ZodString>;
|
|
@@ -13,6 +13,7 @@ export declare function createStorage(dataDirectory: string): {
|
|
|
13
13
|
singleton?: boolean | undefined;
|
|
14
14
|
}>>;
|
|
15
15
|
getContent: () => Promise<EditorialData>;
|
|
16
|
+
getLocalisationMessages: (langCode: string) => Promise<any>;
|
|
16
17
|
saveLocalisationMessages: (messages: any) => Promise<boolean>;
|
|
17
18
|
createItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
|
|
18
19
|
id: import("zod").ZodString;
|
|
@@ -28,6 +29,8 @@ export declare function createStorage(dataDirectory: string): {
|
|
|
28
29
|
createdAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
29
30
|
updatedAt: import("zod").ZodDefault<import("zod").ZodString>;
|
|
30
31
|
}, import("zod").ZodTypeAny, "passthrough">>>>;
|
|
31
|
-
|
|
32
|
+
saveContent: ({ production }: {
|
|
33
|
+
production?: boolean;
|
|
34
|
+
}) => Promise<boolean>;
|
|
32
35
|
};
|
|
33
36
|
export type Storage = ReturnType<typeof createStorage>;
|
package/dist/lib/storage.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { EditorialDataItemSchema, EditorialDataSchema, EditorialSchemaSchema, } from
|
|
2
|
-
import { readFile } from
|
|
3
|
-
import { join } from
|
|
4
|
-
import { parse } from
|
|
5
|
-
import { writeFileSafe } from
|
|
1
|
+
import { EditorialDataItemSchema, EditorialDataSchema, EditorialSchemaSchema, } from "@isardsat/editorial-common";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { writeFileSafe } from "./utils/fs.js";
|
|
6
6
|
export function createStorage(dataDirectory) {
|
|
7
|
-
const schemaPath = join(dataDirectory,
|
|
8
|
-
const dataPath = join(dataDirectory,
|
|
9
|
-
const dataProdPath = join(dataDirectory,
|
|
10
|
-
const dataExtractedPath = join(dataDirectory,
|
|
7
|
+
const schemaPath = join(dataDirectory, "schema.yaml");
|
|
8
|
+
const dataPath = join(dataDirectory, "data.json");
|
|
9
|
+
const dataProdPath = join(dataDirectory, "data.prod.json");
|
|
10
|
+
const dataExtractedPath = join(dataDirectory, "data.messages.json");
|
|
11
11
|
async function getSchema() {
|
|
12
|
-
const schemaFile = await readFile(schemaPath,
|
|
12
|
+
const schemaFile = await readFile(schemaPath, "utf-8").then((value) => parse(value));
|
|
13
13
|
const schema = EditorialSchemaSchema.parse(schemaFile);
|
|
14
14
|
return schema;
|
|
15
15
|
}
|
|
@@ -17,11 +17,14 @@ export function createStorage(dataDirectory) {
|
|
|
17
17
|
* TODO: This should ideally cache the result of reading the file until an update occurs.
|
|
18
18
|
*/
|
|
19
19
|
async function getContent() {
|
|
20
|
-
return await readFile(dataPath,
|
|
20
|
+
return await readFile(dataPath, "utf-8").then((value) => JSON.parse(value));
|
|
21
21
|
}
|
|
22
|
-
async function
|
|
22
|
+
async function getLocalisationMessages(langCode) {
|
|
23
|
+
return await readFile(join(dataDirectory, "locales", "messages", `${langCode}.json`), "utf-8").then((value) => JSON.parse(value));
|
|
24
|
+
}
|
|
25
|
+
async function saveContent({ production }) {
|
|
23
26
|
const content = await getContent();
|
|
24
|
-
await writeFileSafe(dataProdPath, JSON.stringify(EditorialDataSchema.parse(content), null, 2));
|
|
27
|
+
await writeFileSafe(production ? dataProdPath : dataPath, JSON.stringify(EditorialDataSchema.parse(content), null, 2));
|
|
25
28
|
return true;
|
|
26
29
|
}
|
|
27
30
|
async function saveLocalisationMessages(messages) {
|
|
@@ -58,10 +61,11 @@ export function createStorage(dataDirectory) {
|
|
|
58
61
|
return {
|
|
59
62
|
getSchema,
|
|
60
63
|
getContent,
|
|
64
|
+
getLocalisationMessages,
|
|
61
65
|
saveLocalisationMessages,
|
|
62
66
|
createItem,
|
|
63
67
|
updateItem,
|
|
64
68
|
deleteItem,
|
|
65
|
-
|
|
69
|
+
saveContent,
|
|
66
70
|
};
|
|
67
71
|
}
|
package/dist/routes/actions.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OpenAPIHono } from
|
|
2
|
-
import type { Hooks } from
|
|
3
|
-
import type { Storage } from
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Hooks } from "../lib/hooks.js";
|
|
3
|
+
import type { Storage } from "../lib/storage.js";
|
|
4
4
|
export declare function createActionRoutes(storage: Storage, hooks: Hooks): OpenAPIHono<import("hono").Env, {}, "/">;
|
package/dist/routes/actions.js
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
|
-
import { createRoute, OpenAPIHono, z } from
|
|
1
|
+
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
|
2
|
+
const ActionRequestSchema = z.object({
|
|
3
|
+
author: z.string(),
|
|
4
|
+
});
|
|
2
5
|
export function createActionRoutes(storage, hooks) {
|
|
3
6
|
const app = new OpenAPIHono();
|
|
4
7
|
app.openapi(createRoute({
|
|
5
|
-
method:
|
|
6
|
-
path:
|
|
8
|
+
method: "post",
|
|
9
|
+
path: "/publish",
|
|
10
|
+
request: {
|
|
11
|
+
body: {
|
|
12
|
+
content: {
|
|
13
|
+
"application/json": {
|
|
14
|
+
schema: ActionRequestSchema,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
7
19
|
responses: {
|
|
8
20
|
202: {
|
|
9
21
|
content: {
|
|
10
|
-
|
|
22
|
+
"application/json": {
|
|
11
23
|
schema: z.boolean(),
|
|
12
24
|
},
|
|
13
25
|
},
|
|
14
|
-
description:
|
|
26
|
+
description: "Trigger the publishing process",
|
|
15
27
|
},
|
|
16
28
|
},
|
|
17
29
|
}),
|
|
18
30
|
// TODO: Don't async, let the promises run in the background.
|
|
19
31
|
async (c) => {
|
|
20
|
-
await storage.
|
|
32
|
+
await storage.saveContent({ production: false });
|
|
21
33
|
const content = await storage.getContent();
|
|
22
34
|
const schema = await storage.getSchema();
|
|
23
35
|
try {
|
|
@@ -25,33 +37,53 @@ export function createActionRoutes(storage, hooks) {
|
|
|
25
37
|
await storage.saveLocalisationMessages(scriptResult);
|
|
26
38
|
}
|
|
27
39
|
catch (error) {
|
|
28
|
-
console.error(
|
|
40
|
+
console.error("Error executing script:", error);
|
|
29
41
|
return c.json(false);
|
|
30
42
|
}
|
|
31
43
|
return c.json(true);
|
|
32
44
|
});
|
|
33
45
|
app.openapi(createRoute({
|
|
34
|
-
method:
|
|
35
|
-
path:
|
|
46
|
+
method: "post",
|
|
47
|
+
path: "/pull",
|
|
48
|
+
request: {
|
|
49
|
+
body: {
|
|
50
|
+
content: {
|
|
51
|
+
"application/json": {
|
|
52
|
+
schema: ActionRequestSchema,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
36
57
|
responses: {
|
|
37
58
|
200: {
|
|
38
|
-
description:
|
|
59
|
+
description: "Trigger the pull process",
|
|
39
60
|
},
|
|
40
61
|
},
|
|
41
62
|
}), async (c) => {
|
|
42
|
-
|
|
63
|
+
const { author } = c.req.valid("json");
|
|
64
|
+
await hooks.onPull(author);
|
|
43
65
|
return c.json(true);
|
|
44
66
|
});
|
|
45
67
|
app.openapi(createRoute({
|
|
46
|
-
method:
|
|
47
|
-
path:
|
|
68
|
+
method: "post",
|
|
69
|
+
path: "/push",
|
|
70
|
+
request: {
|
|
71
|
+
body: {
|
|
72
|
+
content: {
|
|
73
|
+
"application/json": {
|
|
74
|
+
schema: ActionRequestSchema,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
48
79
|
responses: {
|
|
49
80
|
200: {
|
|
50
|
-
description:
|
|
81
|
+
description: "Trigger the push process",
|
|
51
82
|
},
|
|
52
83
|
},
|
|
53
84
|
}), async (c) => {
|
|
54
|
-
|
|
85
|
+
const { author } = c.req.valid("json");
|
|
86
|
+
await hooks.onPush(author);
|
|
55
87
|
return c.json(true);
|
|
56
88
|
});
|
|
57
89
|
return app;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import { EditorialConfigSchema } from "@isardsat/editorial-common";
|
|
3
|
+
export function createConfigRoutes(config) {
|
|
4
|
+
const app = new OpenAPIHono();
|
|
5
|
+
app.openapi({
|
|
6
|
+
method: "get",
|
|
7
|
+
path: "/config",
|
|
8
|
+
summary: "Get Editorial configuration",
|
|
9
|
+
responses: {
|
|
10
|
+
200: {
|
|
11
|
+
content: {
|
|
12
|
+
"application/json": {
|
|
13
|
+
schema: EditorialConfigSchema,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
description: "Editorial configuration",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
}, (c) => {
|
|
20
|
+
return c.json(config);
|
|
21
|
+
});
|
|
22
|
+
return app;
|
|
23
|
+
}
|
package/dist/routes/data.js
CHANGED
|
@@ -45,12 +45,14 @@ export function createDataRoutes(storage) {
|
|
|
45
45
|
param: { name: "itemType", in: "path" },
|
|
46
46
|
example: "newsItem",
|
|
47
47
|
}),
|
|
48
|
-
|
|
48
|
+
}),
|
|
49
|
+
query: z.object({
|
|
50
|
+
lang: z
|
|
49
51
|
.string()
|
|
50
52
|
.optional()
|
|
51
53
|
.openapi({
|
|
52
|
-
param: { name: "
|
|
53
|
-
example: "
|
|
54
|
+
param: { name: "lang", in: "query" },
|
|
55
|
+
example: "es",
|
|
54
56
|
}),
|
|
55
57
|
}),
|
|
56
58
|
},
|
|
@@ -66,8 +68,20 @@ export function createDataRoutes(storage) {
|
|
|
66
68
|
},
|
|
67
69
|
}), async (c) => {
|
|
68
70
|
const { itemType } = c.req.valid("param");
|
|
71
|
+
const { lang } = c.req.valid("query");
|
|
69
72
|
const content = await storage.getContent();
|
|
70
|
-
|
|
73
|
+
const collection = content[itemType];
|
|
74
|
+
// TODO: Formalize this process.
|
|
75
|
+
if (lang) {
|
|
76
|
+
const messages = await storage.getLocalisationMessages(lang);
|
|
77
|
+
for (const [key, message] of Object.entries(messages)) {
|
|
78
|
+
const [contentKey, typeKey, fieldKey, hash] = key.split(".");
|
|
79
|
+
if (contentKey === itemType) {
|
|
80
|
+
collection[typeKey][fieldKey] = message.defaultMessage;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return c.json(collection);
|
|
71
85
|
});
|
|
72
86
|
app.openapi(createRoute({
|
|
73
87
|
method: "get",
|
|
@@ -108,12 +122,14 @@ export function createDataRoutes(storage) {
|
|
|
108
122
|
param: { name: "id", in: "path" },
|
|
109
123
|
example: "about-us",
|
|
110
124
|
}),
|
|
111
|
-
|
|
125
|
+
}),
|
|
126
|
+
query: z.object({
|
|
127
|
+
lang: z
|
|
112
128
|
.string()
|
|
113
129
|
.optional()
|
|
114
130
|
.openapi({
|
|
115
|
-
param: { name: "
|
|
116
|
-
example: "
|
|
131
|
+
param: { name: "lang", in: "query" },
|
|
132
|
+
example: "es",
|
|
117
133
|
}),
|
|
118
134
|
}),
|
|
119
135
|
},
|
|
@@ -129,8 +145,20 @@ export function createDataRoutes(storage) {
|
|
|
129
145
|
},
|
|
130
146
|
}), async (c) => {
|
|
131
147
|
const { itemType, id } = c.req.valid("param");
|
|
148
|
+
const { lang } = c.req.valid("query");
|
|
132
149
|
const content = await storage.getContent();
|
|
133
|
-
|
|
150
|
+
const item = content[itemType][id];
|
|
151
|
+
// TODO: Formalize this process.
|
|
152
|
+
if (lang) {
|
|
153
|
+
const messages = await storage.getLocalisationMessages(lang);
|
|
154
|
+
for (const [key, message] of Object.entries(messages)) {
|
|
155
|
+
const [contentKey, typeKey, fieldKey, hash] = key.split(".");
|
|
156
|
+
if (typeKey === id) {
|
|
157
|
+
item[fieldKey] = message.defaultMessage;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return c.json(item);
|
|
134
162
|
});
|
|
135
163
|
app.openapi(createRoute({
|
|
136
164
|
method: "put",
|
package/dist/routes/files.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { OpenAPIHono } from
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
2
|
export declare function createFilesRoutes(): OpenAPIHono<import("hono").Env, {}, "/">;
|
package/dist/routes/files.js
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
|
-
import { createRoute, OpenAPIHono, z } from
|
|
2
|
-
import {
|
|
3
|
-
import { readdirSync, statSync } from
|
|
4
|
-
import { access, constants, mkdir, rename } from
|
|
5
|
-
import { basename, join, normalize } from
|
|
1
|
+
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
|
2
|
+
import { EditorialFilesResponseSchema, } from "@isardsat/editorial-common";
|
|
3
|
+
import { readdirSync, statSync } from "node:fs";
|
|
4
|
+
import { access, constants, mkdir, rename } from "node:fs/promises";
|
|
5
|
+
import { basename, join, normalize } from "node:path";
|
|
6
6
|
export function createFilesRoutes() {
|
|
7
7
|
const app = new OpenAPIHono();
|
|
8
|
-
const publicDirPath =
|
|
9
|
-
const deletedDirPath =
|
|
8
|
+
const publicDirPath = "public";
|
|
9
|
+
const deletedDirPath = "public/.deleted";
|
|
10
10
|
app.openapi(createRoute({
|
|
11
|
-
method:
|
|
12
|
-
path:
|
|
11
|
+
method: "get",
|
|
12
|
+
path: "/files",
|
|
13
13
|
responses: {
|
|
14
14
|
200: {
|
|
15
15
|
content: {
|
|
16
|
-
|
|
17
|
-
schema:
|
|
16
|
+
"application/json": {
|
|
17
|
+
schema: EditorialFilesResponseSchema,
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
|
-
description:
|
|
20
|
+
description: "Get tree of public files with total size",
|
|
21
21
|
},
|
|
22
22
|
},
|
|
23
23
|
}), async (c) => {
|
|
24
|
+
function calculateTotalSize(files) {
|
|
25
|
+
return files.reduce((total, file) => {
|
|
26
|
+
if (file.type === "file") {
|
|
27
|
+
return total + file.size;
|
|
28
|
+
}
|
|
29
|
+
else if (file.children) {
|
|
30
|
+
return total + calculateTotalSize(file.children);
|
|
31
|
+
}
|
|
32
|
+
return total;
|
|
33
|
+
}, 0);
|
|
34
|
+
}
|
|
24
35
|
function readDirectoryChildren(path) {
|
|
25
36
|
const directory = readdirSync(path);
|
|
26
37
|
return directory
|
|
27
|
-
.filter((fileName) => !fileName.startsWith(
|
|
38
|
+
.filter((fileName) => !fileName.startsWith("."))
|
|
28
39
|
.map((fileName) => {
|
|
29
40
|
const file = statSync(join(path, fileName));
|
|
30
41
|
const isDirectory = file.isDirectory();
|
|
@@ -32,24 +43,25 @@ export function createFilesRoutes() {
|
|
|
32
43
|
name: basename(fileName),
|
|
33
44
|
path: join(path, fileName),
|
|
34
45
|
size: file.size,
|
|
35
|
-
type: isDirectory ?
|
|
46
|
+
type: isDirectory ? "directory" : "file",
|
|
36
47
|
children: isDirectory
|
|
37
48
|
? readDirectoryChildren(join(path, fileName))
|
|
38
49
|
: undefined,
|
|
39
50
|
};
|
|
40
51
|
})
|
|
41
|
-
.sort((a, b) => (a.type ===
|
|
52
|
+
.sort((a, b) => (a.type === "directory" ? -1 : 0));
|
|
42
53
|
}
|
|
43
54
|
const files = readDirectoryChildren(publicDirPath);
|
|
44
|
-
|
|
55
|
+
const totalSize = calculateTotalSize(files);
|
|
56
|
+
return c.json({ files, totalSize });
|
|
45
57
|
});
|
|
46
58
|
app.openapi(createRoute({
|
|
47
|
-
method:
|
|
48
|
-
path:
|
|
59
|
+
method: "delete",
|
|
60
|
+
path: "/files",
|
|
49
61
|
request: {
|
|
50
62
|
body: {
|
|
51
63
|
content: {
|
|
52
|
-
|
|
64
|
+
"application/json": {
|
|
53
65
|
schema: z.object({
|
|
54
66
|
path: z.string(),
|
|
55
67
|
}),
|
|
@@ -61,55 +73,55 @@ export function createFilesRoutes() {
|
|
|
61
73
|
responses: {
|
|
62
74
|
200: {
|
|
63
75
|
content: {
|
|
64
|
-
|
|
76
|
+
"application/json": {
|
|
65
77
|
schema: z.boolean(),
|
|
66
78
|
},
|
|
67
79
|
},
|
|
68
|
-
description:
|
|
80
|
+
description: "",
|
|
69
81
|
},
|
|
70
82
|
400: {
|
|
71
83
|
content: {
|
|
72
|
-
|
|
84
|
+
"application/json": {
|
|
73
85
|
schema: z.object({
|
|
74
86
|
error: z.string(),
|
|
75
87
|
}),
|
|
76
88
|
},
|
|
77
89
|
},
|
|
78
|
-
description:
|
|
90
|
+
description: "Invalid file path",
|
|
79
91
|
},
|
|
80
92
|
404: {
|
|
81
93
|
content: {
|
|
82
|
-
|
|
94
|
+
"application/json": {
|
|
83
95
|
schema: z.object({
|
|
84
96
|
error: z.string(),
|
|
85
97
|
}),
|
|
86
98
|
},
|
|
87
99
|
},
|
|
88
|
-
description:
|
|
100
|
+
description: "File not found",
|
|
89
101
|
},
|
|
90
102
|
500: {
|
|
91
103
|
content: {
|
|
92
|
-
|
|
104
|
+
"application/json": {
|
|
93
105
|
schema: z.object({
|
|
94
106
|
error: z.string(),
|
|
95
107
|
}),
|
|
96
108
|
},
|
|
97
109
|
},
|
|
98
|
-
description:
|
|
110
|
+
description: "Server error",
|
|
99
111
|
},
|
|
100
112
|
},
|
|
101
113
|
}), async (c) => {
|
|
102
|
-
const { path: filePath } = c.req.valid(
|
|
114
|
+
const { path: filePath } = c.req.valid("json");
|
|
103
115
|
try {
|
|
104
116
|
const normalizedPath = normalize(filePath);
|
|
105
117
|
if (!normalizedPath.startsWith(publicDirPath)) {
|
|
106
|
-
return c.json({ error:
|
|
118
|
+
return c.json({ error: "Invalid file path" }, 400);
|
|
107
119
|
}
|
|
108
120
|
const exists = await access(filePath, constants.W_OK)
|
|
109
121
|
.then(() => true)
|
|
110
122
|
.catch(() => false);
|
|
111
123
|
if (!exists) {
|
|
112
|
-
return c.json({ error:
|
|
124
|
+
return c.json({ error: "File not found" }, 404);
|
|
113
125
|
}
|
|
114
126
|
// Move to deleted directory
|
|
115
127
|
await mkdir(deletedDirPath, { recursive: true });
|
|
@@ -117,8 +129,8 @@ export function createFilesRoutes() {
|
|
|
117
129
|
return c.json(true, 200);
|
|
118
130
|
}
|
|
119
131
|
catch (err) {
|
|
120
|
-
console.error(
|
|
121
|
-
return c.json({ error:
|
|
132
|
+
console.error("Delete failed:", err);
|
|
133
|
+
return c.json({ error: "Server error" }, 500);
|
|
122
134
|
}
|
|
123
135
|
});
|
|
124
136
|
return app;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isardsat/editorial-server",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"hono": "^4.6.20",
|
|
15
15
|
"yaml": "^2.7.0",
|
|
16
16
|
"zod": "^3.24.1",
|
|
17
|
-
"@isardsat/editorial-admin": "^6.0.
|
|
18
|
-
"@isardsat/editorial-common": "^6.0.
|
|
17
|
+
"@isardsat/editorial-admin": "^6.0.4",
|
|
18
|
+
"@isardsat/editorial-common": "^6.0.4"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@tsconfig/node22": "^22.0.0",
|