@adminforth/import-export 1.5.4 → 1.6.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.
Files changed (3) hide show
  1. package/dist/index.js +51 -8
  2. package/index.ts +47 -8
  3. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -7,8 +7,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { AdminForthPlugin, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes, rejectApiRawFilters, interpretResource, ActionCheckSource, AllowedActionsEnum } from "adminforth";
10
+ import { AdminForthPlugin, parseBody, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes, rejectApiRawFilters, interpretResource, ActionCheckSource, AllowedActionsEnum } from "adminforth";
11
11
  import pLimit from 'p-limit';
12
+ import { z } from "zod";
13
+ const exportCsvBodySchema = z.object({
14
+ filters: z.any(),
15
+ sort: z.any(),
16
+ }).strict();
17
+ const importCsvBodySchema = z.object({
18
+ data: z.record(z.string(), z.array(z.unknown())),
19
+ }).strict();
12
20
  export default class ImportExport extends AdminForthPlugin {
13
21
  constructor(options) {
14
22
  super(options, import.meta.url);
@@ -113,8 +121,12 @@ export default class ImportExport extends AdminForthPlugin {
113
121
  server.endpoint({
114
122
  method: 'POST',
115
123
  path: `/plugin/${this.pluginInstanceId}/export-csv`,
116
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers }) {
117
- const { filters, sort } = body;
124
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, response }) {
125
+ const parsed = parseBody(exportCsvBodySchema, body, response);
126
+ if ('error' in parsed)
127
+ return parsed.error;
128
+ const payload = parsed.data;
129
+ const { filters, sort } = payload;
118
130
  if (!filters || !sort) {
119
131
  return { ok: false, error: 'Missing filters or sort in request body' };
120
132
  }
@@ -146,7 +158,14 @@ export default class ImportExport extends AdminForthPlugin {
146
158
  });
147
159
  const fields = columns.map((col) => col.name);
148
160
  const rows = data.data.map((row) => {
149
- return columns.map((col) => row[col.name]);
161
+ return columns.map((col) => {
162
+ var _a;
163
+ const value = row[col.name];
164
+ if (col.type === AdminForthDataTypes.JSON || ((_a = col.isArray) === null || _a === void 0 ? void 0 : _a.enabled)) {
165
+ return value == null ? value : JSON.stringify(value);
166
+ }
167
+ return value;
168
+ });
150
169
  });
151
170
  this.tryToAuditLogAction('export', `Export CSV with filters: ${JSON.stringify(filters)} and sort: ${JSON.stringify(sort)}. Total records: ${rows.length}`, adminUser, headers);
152
171
  return {
@@ -161,7 +180,11 @@ export default class ImportExport extends AdminForthPlugin {
161
180
  method: 'POST',
162
181
  path: `/plugin/${this.pluginInstanceId}/import-csv`,
163
182
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, query, headers, cookies, requestUrl, response }) {
164
- const { data } = body;
183
+ const parsed = parseBody(importCsvBodySchema, body, response);
184
+ if ('error' in parsed)
185
+ return parsed.error;
186
+ const payload = parsed.data;
187
+ const { data } = payload;
165
188
  if (!data || typeof data !== 'object') {
166
189
  return { ok: false, error: 'Invalid data format. Expected an object with column names as keys and arrays of values as values.' };
167
190
  }
@@ -233,7 +256,11 @@ export default class ImportExport extends AdminForthPlugin {
233
256
  method: 'POST',
234
257
  path: `/plugin/${this.pluginInstanceId}/import-csv-new-only`,
235
258
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, query, headers, cookies, requestUrl, response }) {
236
- const { data } = body;
259
+ const parsed = parseBody(importCsvBodySchema, body, response);
260
+ if ('error' in parsed)
261
+ return parsed.error;
262
+ const payload = parsed.data;
263
+ const { data } = payload;
237
264
  if (!data || typeof data !== 'object') {
238
265
  return { ok: false, error: 'Invalid data format. Expected an object with column names as keys and arrays of values as values.' };
239
266
  }
@@ -284,7 +311,11 @@ export default class ImportExport extends AdminForthPlugin {
284
311
  server.endpoint({
285
312
  method: 'POST',
286
313
  path: `/plugin/${this.pluginInstanceId}/check-records`,
287
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser }) {
314
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
315
+ const parsed = parseBody(importCsvBodySchema, body, response);
316
+ if ('error' in parsed)
317
+ return parsed.error;
318
+ const payload = parsed.data;
288
319
  const access = yield this.ensureAnyAllowed(adminUser, [
289
320
  { source: ActionCheckSource.ListRequest, action: AllowedActionsEnum.list },
290
321
  { source: ActionCheckSource.ShowRequest, action: AllowedActionsEnum.show },
@@ -292,7 +323,7 @@ export default class ImportExport extends AdminForthPlugin {
292
323
  if (!access.ok) {
293
324
  return { ok: false, error: access.error };
294
325
  }
295
- const { data } = body;
326
+ const { data } = payload;
296
327
  const primaryKeyColumn = this.resourceConfig.columns.find(col => col.primaryKey);
297
328
  const columns = this.getColumnNames(data);
298
329
  const rows = this.buildRowsFromData(data, columns, undefined, { coerceTypes: false });
@@ -355,6 +386,7 @@ export default class ImportExport extends AdminForthPlugin {
355
386
  return rows;
356
387
  }
357
388
  coerceValue(resourceCol, val) {
389
+ var _a;
358
390
  if (!resourceCol || val === '') {
359
391
  return val;
360
392
  }
@@ -368,6 +400,17 @@ export default class ImportExport extends AdminForthPlugin {
368
400
  }
369
401
  return val === 1 || val === true;
370
402
  }
403
+ if (resourceCol.type === AdminForthDataTypes.JSON || ((_a = resourceCol.isArray) === null || _a === void 0 ? void 0 : _a.enabled)) {
404
+ if (typeof val === 'string') {
405
+ try {
406
+ return JSON.parse(val);
407
+ }
408
+ catch (_b) {
409
+ return val;
410
+ }
411
+ }
412
+ return val;
413
+ }
371
414
  return val;
372
415
  }
373
416
  }
package/index.ts CHANGED
@@ -1,7 +1,17 @@
1
- import { AdminForthPlugin, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes, rejectApiRawFilters, interpretResource, ActionCheckSource, AllowedActionsEnum } from "adminforth";
1
+ import { AdminForthPlugin, parseBody, suggestIfTypo, AdminForthFilterOperators, Filters, AdminForthDataTypes, rejectApiRawFilters, interpretResource, ActionCheckSource, AllowedActionsEnum } from "adminforth";
2
2
  import type { IAdminForth, IHttpServer, AdminForthResourceColumn, AdminForthComponentDeclaration, AdminForthResource, AdminUser } from "adminforth";
3
3
  import type { PluginOptions } from './types.js';
4
4
  import pLimit from 'p-limit';
5
+ import { z } from "zod";
6
+
7
+ const exportCsvBodySchema = z.object({
8
+ filters: z.any(),
9
+ sort: z.any(),
10
+ }).strict();
11
+
12
+ const importCsvBodySchema = z.object({
13
+ data: z.record(z.string(), z.array(z.unknown())),
14
+ }).strict();
5
15
 
6
16
  export default class ImportExport extends AdminForthPlugin {
7
17
  options: PluginOptions;
@@ -127,8 +137,11 @@ export default class ImportExport extends AdminForthPlugin {
127
137
  server.endpoint({
128
138
  method: 'POST',
129
139
  path: `/plugin/${this.pluginInstanceId}/export-csv`,
130
- handler: async ({ body, adminUser, headers }) => {
131
- const { filters, sort } = body;
140
+ handler: async ({ body, adminUser, headers, response }) => {
141
+ const parsed = parseBody(exportCsvBodySchema, body, response);
142
+ if ('error' in parsed) return parsed.error;
143
+ const payload = parsed.data;
144
+ const { filters, sort } = payload;
132
145
  if (!filters || !sort) {
133
146
  return { ok: false, error: 'Missing filters or sort in request body' };
134
147
  }
@@ -168,7 +181,13 @@ export default class ImportExport extends AdminForthPlugin {
168
181
  const fields = columns.map((col) => col.name);
169
182
 
170
183
  const rows = data.data.map((row) => {
171
- return columns.map((col) => row[col.name]);
184
+ return columns.map((col) => {
185
+ const value = row[col.name];
186
+ if (col.type === AdminForthDataTypes.JSON || col.isArray?.enabled) {
187
+ return value == null ? value : JSON.stringify(value);
188
+ }
189
+ return value;
190
+ });
172
191
  });
173
192
 
174
193
  this.tryToAuditLogAction('export', `Export CSV with filters: ${JSON.stringify(filters)} and sort: ${JSON.stringify(sort)}. Total records: ${rows.length}`, adminUser, headers);
@@ -186,7 +205,10 @@ export default class ImportExport extends AdminForthPlugin {
186
205
  method: 'POST',
187
206
  path: `/plugin/${this.pluginInstanceId}/import-csv`,
188
207
  handler: async ({ body, adminUser, query, headers, cookies, requestUrl, response }) => {
189
- const { data } = body;
208
+ const parsed = parseBody(importCsvBodySchema, body, response);
209
+ if ('error' in parsed) return parsed.error;
210
+ const payload = parsed.data;
211
+ const { data } = payload;
190
212
  if (!data || typeof data !== 'object') {
191
213
  return { ok: false, error: 'Invalid data format. Expected an object with column names as keys and arrays of values as values.' };
192
214
  }
@@ -268,7 +290,10 @@ export default class ImportExport extends AdminForthPlugin {
268
290
  method: 'POST',
269
291
  path: `/plugin/${this.pluginInstanceId}/import-csv-new-only`,
270
292
  handler: async ({ body, adminUser, query, headers, cookies, requestUrl, response }) => {
271
- const { data } = body;
293
+ const parsed = parseBody(importCsvBodySchema, body, response);
294
+ if ('error' in parsed) return parsed.error;
295
+ const payload = parsed.data;
296
+ const { data } = payload;
272
297
  if (!data || typeof data !== 'object') {
273
298
  return { ok: false, error: 'Invalid data format. Expected an object with column names as keys and arrays of values as values.' };
274
299
  }
@@ -328,7 +353,10 @@ export default class ImportExport extends AdminForthPlugin {
328
353
  server.endpoint({
329
354
  method: 'POST',
330
355
  path: `/plugin/${this.pluginInstanceId}/check-records`,
331
- handler: async ({ body, adminUser }) => {
356
+ handler: async ({ body, adminUser, response }) => {
357
+ const parsed = parseBody(importCsvBodySchema, body, response);
358
+ if ('error' in parsed) return parsed.error;
359
+ const payload = parsed.data;
332
360
  const access = await this.ensureAnyAllowed(
333
361
  adminUser,
334
362
  [
@@ -340,7 +368,7 @@ export default class ImportExport extends AdminForthPlugin {
340
368
  if (!access.ok) {
341
369
  return { ok: false, error: access.error };
342
370
  }
343
- const { data } = body as { data: Record<string, unknown[]> };
371
+ const { data } = payload;
344
372
  const primaryKeyColumn = this.resourceConfig.columns.find(col => col.primaryKey);
345
373
  const columns = this.getColumnNames(data);
346
374
  const rows = this.buildRowsFromData(data, columns, undefined, { coerceTypes: false });
@@ -446,6 +474,17 @@ export default class ImportExport extends AdminForthPlugin {
446
474
  return val === 1 || val === true;
447
475
  }
448
476
 
477
+ if (resourceCol.type === AdminForthDataTypes.JSON || resourceCol.isArray?.enabled) {
478
+ if (typeof val === 'string') {
479
+ try {
480
+ return JSON.parse(val);
481
+ } catch {
482
+ return val;
483
+ }
484
+ }
485
+ return val;
486
+ }
487
+
449
488
  return val;
450
489
  }
451
490
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/import-export",
3
- "version": "1.5.4",
3
+ "version": "1.6.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -25,11 +25,11 @@
25
25
  "license": "MIT",
26
26
  "description": "CSV import/export plugin for adminforth",
27
27
  "peerDependencies": {
28
- "adminforth": "^3.6.21"
28
+ "adminforth": "^3.7.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.10.7",
32
- "adminforth": "^3.6.21",
32
+ "adminforth": "^3.7.1",
33
33
  "semantic-release": "^24.2.1",
34
34
  "semantic-release-slack-bot": "^4.0.2",
35
35
  "typescript": "^5.7.3"
@@ -60,6 +60,7 @@
60
60
  ]
61
61
  },
62
62
  "dependencies": {
63
- "p-limit": "^7.3.0"
63
+ "p-limit": "^7.3.0",
64
+ "zod": "^4.3.6"
64
65
  }
65
66
  }