@isardsat/editorial-server 6.4.4 → 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) {
@@ -112,6 +125,9 @@ export function createDataRoutes(config, storage) {
112
125
  example: "newsItem",
113
126
  }),
114
127
  }),
128
+ query: z.object({
129
+ preview: z.string().optional(),
130
+ }),
115
131
  },
116
132
  responses: {
117
133
  200: {
@@ -125,7 +141,8 @@ export function createDataRoutes(config, storage) {
125
141
  },
126
142
  }), async (c) => {
127
143
  const { itemType } = c.req.valid("param");
128
- const content = await storage.getContent();
144
+ const { preview } = c.req.valid("query");
145
+ const content = await storage.getContent({ production: !preview });
129
146
  return c.json(Object.keys(content[itemType]));
130
147
  });
131
148
  app.openapi(createRoute({
@@ -170,7 +187,7 @@ export function createDataRoutes(config, storage) {
170
187
  const { itemType, id } = c.req.valid("param");
171
188
  const { lang, preview } = c.req.valid("query");
172
189
  const origin = preview ? new URL(c.req.url).origin : publicFilesUrl;
173
- const content = await storage.getContent();
190
+ const content = await storage.getContent({ production: !preview });
174
191
  const schema = await storage.getSchema();
175
192
  const collection = content[itemType];
176
193
  if (!collection) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isardsat/editorial-server",
3
- "version": "6.4.4",
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.4",
18
- "@isardsat/editorial-common": "^6.4.4"
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",