@isardsat/editorial-server 6.4.3 → 6.5.0

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.
@@ -12,7 +12,9 @@ export declare function createStorage(dataDirectory: string): {
12
12
  }, import("zod").ZodTypeAny, "passthrough">>;
13
13
  singleton?: boolean | undefined;
14
14
  }>>;
15
- getContent: () => Promise<EditorialData>;
15
+ getContent: ({ production, }: {
16
+ production?: boolean;
17
+ }) => Promise<EditorialData>;
16
18
  getLocalisationMessages: (langCode: string) => Promise<any>;
17
19
  saveLocalisationMessages: (messages: any) => Promise<boolean>;
18
20
  createItem: (item: EditorialDataObjectWithType) => Promise<import("zod").objectOutputType<{
@@ -16,14 +16,14 @@ export function createStorage(dataDirectory) {
16
16
  /**
17
17
  * TODO: This should ideally cache the result of reading the file until an update occurs.
18
18
  */
19
- async function getContent() {
20
- return await readFile(dataPath, "utf-8").then((value) => JSON.parse(value));
19
+ async function getContent({ production, }) {
20
+ return await readFile(production ? dataProdPath : dataPath, "utf-8").then((value) => JSON.parse(value));
21
21
  }
22
22
  async function getLocalisationMessages(langCode) {
23
23
  return await readFile(join(dataDirectory, "locales", "messages", `${langCode}.json`), "utf-8").then((value) => JSON.parse(value));
24
24
  }
25
25
  async function saveContent({ production }) {
26
- const content = await getContent();
26
+ const content = await getContent({ production: false });
27
27
  await writeFileSafe(production ? dataProdPath : dataPath, JSON.stringify(EditorialDataSchema.parse(content), null, 2));
28
28
  return true;
29
29
  }
@@ -32,7 +32,7 @@ export function createStorage(dataDirectory) {
32
32
  return true;
33
33
  }
34
34
  async function createItem(item) {
35
- const content = await getContent();
35
+ const content = await getContent({ production: false });
36
36
  content[item.type] = content[item.type] ?? {};
37
37
  content[item.type][item.id] = EditorialDataItemSchema.parse(item);
38
38
  // TODO: Use superjson to safely encode different types.
@@ -40,7 +40,7 @@ export function createStorage(dataDirectory) {
40
40
  return item;
41
41
  }
42
42
  async function updateItem(item) {
43
- const content = await getContent();
43
+ const content = await getContent({ production: false });
44
44
  const oldItem = content[item.type][item.id];
45
45
  const newItem = EditorialDataItemSchema.parse({
46
46
  ...oldItem,
@@ -53,7 +53,7 @@ export function createStorage(dataDirectory) {
53
53
  return newItem;
54
54
  }
55
55
  async function deleteItem(item) {
56
- const content = await getContent();
56
+ const content = await getContent({ production: false });
57
57
  delete content[item.type][item.id];
58
58
  // TODO: Use superjson to safely encode different types.
59
59
  await writeFileSafe(dataPath, JSON.stringify(content, null, 2));
@@ -1,6 +1,6 @@
1
- import { copyFile, rename, writeFile } from 'fs/promises';
2
- import { tmpdir } from 'os';
3
- import { basename, dirname, join } from 'path';
1
+ import { access, constants, copyFile, rename, writeFile } from "fs/promises";
2
+ import { tmpdir } from "os";
3
+ import { basename, dirname, join } from "path";
4
4
  /**
5
5
  * This function writes a file in as atomic a way as possible. It first creates
6
6
  * a backup of the file to be written to, writes new content to a temporary
@@ -10,7 +10,13 @@ export async function writeFileSafe(file, contents) {
10
10
  const fileName = basename(file);
11
11
  const destination = join(dirname(file), `${fileName}.${Date.now()}.tmp`);
12
12
  try {
13
- await copyFile(file, join(tmpdir(), fileName));
13
+ try {
14
+ await access(file, constants.F_OK);
15
+ await copyFile(file, join(tmpdir(), fileName));
16
+ }
17
+ catch {
18
+ // File doesn't exist, skip backup
19
+ }
14
20
  await writeFile(destination, contents);
15
21
  await rename(destination, file);
16
22
  }
@@ -29,8 +29,8 @@ export function createActionRoutes(storage, hooks) {
29
29
  }),
30
30
  // TODO: Don't async, let the promises run in the background.
31
31
  async (c) => {
32
- await storage.saveContent({ production: false });
33
- const content = await storage.getContent();
32
+ await storage.saveContent({ production: true });
33
+ const content = await storage.getContent({ production: true });
34
34
  const schema = await storage.getSchema();
35
35
  try {
36
36
  const scriptResult = await hooks.onLocalize(content, schema);
@@ -23,6 +23,18 @@ export function createDataRoutes(config, storage) {
23
23
  app.openapi(createRoute({
24
24
  method: "get",
25
25
  path: "/data",
26
+ request: {
27
+ query: z.object({
28
+ lang: z
29
+ .string()
30
+ .optional()
31
+ .openapi({
32
+ param: { name: "lang", in: "query" },
33
+ example: "es_ES",
34
+ }),
35
+ preview: z.string().optional(),
36
+ }),
37
+ },
26
38
  responses: {
27
39
  200: {
28
40
  content: {
@@ -34,7 +46,8 @@ export function createDataRoutes(config, storage) {
34
46
  },
35
47
  },
36
48
  }), async (c) => {
37
- const content = await storage.getContent();
49
+ const { preview } = c.req.valid("query");
50
+ const content = await storage.getContent({ production: !preview });
38
51
  return c.json(content);
39
52
  });
40
53
  app.openapi(createRoute({
@@ -75,7 +88,7 @@ export function createDataRoutes(config, storage) {
75
88
  const { itemType } = c.req.valid("param");
76
89
  const { lang, preview } = c.req.valid("query");
77
90
  const origin = preview ? new URL(c.req.url).origin : publicFilesUrl;
78
- const content = await storage.getContent();
91
+ const content = await storage.getContent({ production: !preview });
79
92
  const schema = await storage.getSchema();
80
93
  const collection = content[itemType];
81
94
  if (!collection) {
@@ -95,6 +108,8 @@ export function createDataRoutes(config, storage) {
95
108
  for (const [key, value] of Object.entries(itemValue)) {
96
109
  if (!schema[itemType].fields[key]?.isUploadedFile)
97
110
  continue;
111
+ if (value.startsWith("http"))
112
+ continue;
98
113
  collection[itemKey][key] = `${origin}/${value}`;
99
114
  }
100
115
  }
@@ -110,6 +125,9 @@ export function createDataRoutes(config, storage) {
110
125
  example: "newsItem",
111
126
  }),
112
127
  }),
128
+ query: z.object({
129
+ preview: z.string().optional(),
130
+ }),
113
131
  },
114
132
  responses: {
115
133
  200: {
@@ -123,7 +141,8 @@ export function createDataRoutes(config, storage) {
123
141
  },
124
142
  }), async (c) => {
125
143
  const { itemType } = c.req.valid("param");
126
- const content = await storage.getContent();
144
+ const { preview } = c.req.valid("query");
145
+ const content = await storage.getContent({ production: !preview });
127
146
  return c.json(Object.keys(content[itemType]));
128
147
  });
129
148
  app.openapi(createRoute({
@@ -168,7 +187,7 @@ export function createDataRoutes(config, storage) {
168
187
  const { itemType, id } = c.req.valid("param");
169
188
  const { lang, preview } = c.req.valid("query");
170
189
  const origin = preview ? new URL(c.req.url).origin : publicFilesUrl;
171
- const content = await storage.getContent();
190
+ const content = await storage.getContent({ production: !preview });
172
191
  const schema = await storage.getSchema();
173
192
  const collection = content[itemType];
174
193
  if (!collection) {
@@ -191,6 +210,8 @@ export function createDataRoutes(config, storage) {
191
210
  for (const [key, value] of Object.entries(item)) {
192
211
  if (!schema[itemType].fields[key]?.isUploadedFile)
193
212
  continue;
213
+ if (value.startsWith("http"))
214
+ continue;
194
215
  item[key] = `${origin}/${value}`;
195
216
  }
196
217
  return c.json(item);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isardsat/editorial-server",
3
- "version": "6.4.3",
3
+ "version": "6.5.0",
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.4.3",
18
- "@isardsat/editorial-common": "^6.4.3"
17
+ "@isardsat/editorial-admin": "^6.5.0",
18
+ "@isardsat/editorial-common": "^6.5.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@tsconfig/node22": "^22.0.0",