@adminforth/bulk-ai-flow 1.26.10 → 1.27.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.
Files changed (3) hide show
  1. package/dist/index.js +113 -31
  2. package/index.ts +113 -30
  3. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -7,11 +7,54 @@ 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 { AdminForthFilterOperators, AdminForthPlugin, Filters } from "adminforth";
10
+ import { AdminForthFilterOperators, AdminForthPlugin, parseBody, Filters } from "adminforth";
11
11
  import { suggestIfTypo, filtersTools } from "adminforth";
12
12
  import Handlebars from 'handlebars';
13
13
  import { RateLimiter } from "adminforth";
14
14
  import { randomUUID } from "crypto";
15
+ import { z } from "zod";
16
+ const getRecordsBodySchema = z.object({
17
+ record: z.array(z.any()).nullish(),
18
+ }).strict();
19
+ const getImagesBodySchema = z.object({
20
+ record: z.array(z.any()).nullish(),
21
+ }).strict();
22
+ const getOldDataBodySchema = z.object({
23
+ recordId: z.union([z.string(), z.number()]).nullish(),
24
+ }).strict();
25
+ const updateFieldsBodySchema = z.object({
26
+ selectedIds: z.array(z.any()).nullish(),
27
+ fields: z.any(),
28
+ saveImages: z.boolean().nullish(),
29
+ }).strict();
30
+ const getImageGenerationPromptsBodySchema = z.object({
31
+ recordId: z.union([z.string(), z.number()]).nullish(),
32
+ customPrompt: z.string().nullish(),
33
+ }).strict();
34
+ const createJobBodySchema = z.object({
35
+ actionType: z.string().nullish(),
36
+ recordId: z.any().optional(),
37
+ customPrompt: z.string().nullish(),
38
+ filterFilledFields: z.boolean().nullish(),
39
+ sessionIds: z.array(z.string()).nullish(),
40
+ prompt: z.string().nullish(),
41
+ fieldName: z.string().nullish(),
42
+ fieldToRegenerate: z.string().nullish(),
43
+ action: z.string().nullish(),
44
+ }).strict();
45
+ const jobStatusBodySchema = z.object({
46
+ jobId: z.string(),
47
+ }).strict();
48
+ const updateRateLimitsBodySchema = z.object({
49
+ actionType: z.string().nullish(),
50
+ }).strict();
51
+ const compileOldImageLinkBodySchema = z.object({
52
+ image: z.string().nullish(),
53
+ columnName: z.string().nullish(),
54
+ }).strict();
55
+ const getFilteredIdsBodySchema = z.object({
56
+ filters: z.any(),
57
+ }).passthrough();
15
58
  const STUB_MODE = false;
16
59
  const jobs = new Map();
17
60
  export default class BulkAiFlowPlugin extends AdminForthPlugin {
@@ -771,18 +814,21 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
771
814
  server.endpoint({
772
815
  method: 'POST',
773
816
  path: `/plugin/${this.pluginInstanceId}/get_records`,
774
- handler: (body) => __awaiter(this, void 0, void 0, function* () {
775
- var _a;
776
- if (!Array.isArray((_a = body.body) === null || _a === void 0 ? void 0 : _a.record)) {
817
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
818
+ const parsed = parseBody(getRecordsBodySchema, body, response);
819
+ if ('error' in parsed)
820
+ return parsed.error;
821
+ const data = parsed.data;
822
+ if (!Array.isArray(data.record)) {
777
823
  return { records: [] };
778
824
  }
779
825
  let records = [];
780
826
  const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
781
- records = yield this.adminforth.resource(this.resourceConfig.resourceId).list([Filters.IN(primaryKeyColumn.name, body.body.record)]);
827
+ records = yield this.adminforth.resource(this.resourceConfig.resourceId).list([Filters.IN(primaryKeyColumn.name, data.record)]);
782
828
  for (const [index, record] of records.entries()) {
783
829
  records[index]._label = this.resourceConfig.recordLabel(records[index]);
784
830
  }
785
- const order = Object.fromEntries(body.body.record.map((id, i) => [id, i]));
831
+ const order = Object.fromEntries(data.record.map((id, i) => [id, i]));
786
832
  const sortedRecords = records.sort((a, b) => order[a.id] - order[b.id]);
787
833
  return {
788
834
  records: sortedRecords,
@@ -792,8 +838,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
792
838
  server.endpoint({
793
839
  method: 'POST',
794
840
  path: `/plugin/${this.pluginInstanceId}/get_old_data`,
795
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
796
- const recordId = body.recordId;
841
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
842
+ const parsed = parseBody(getOldDataBodySchema, body, response);
843
+ if ('error' in parsed)
844
+ return parsed.error;
845
+ const data = parsed.data;
846
+ const recordId = data.recordId;
797
847
  if (recordId === undefined || recordId === null) {
798
848
  return { ok: false, error: "Missing recordId" };
799
849
  }
@@ -810,10 +860,14 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
810
860
  server.endpoint({
811
861
  method: 'POST',
812
862
  path: `/plugin/${this.pluginInstanceId}/get_images`,
813
- handler: (body) => __awaiter(this, void 0, void 0, function* () {
863
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
864
+ const parsed = parseBody(getImagesBodySchema, body, response);
865
+ if ('error' in parsed)
866
+ return parsed.error;
867
+ const data = parsed.data;
814
868
  let images = [];
815
- if (body.body.record) {
816
- for (const record of body.body.record) {
869
+ if (data.record) {
870
+ for (const record of data.record) {
817
871
  if (this.options.attachFiles) {
818
872
  images.push(yield this.options.attachFiles({ record: record }));
819
873
  }
@@ -827,15 +881,19 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
827
881
  server.endpoint({
828
882
  method: 'POST',
829
883
  path: `/plugin/${this.pluginInstanceId}/update_fields`,
830
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers }) {
884
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, response }) {
885
+ const parsed = parseBody(updateFieldsBodySchema, body, response);
886
+ if ('error' in parsed)
887
+ return parsed.error;
888
+ const data = parsed.data;
831
889
  let isAllowedToSave = { ok: true, error: '' };
832
890
  if (this.options.isAllowedToSave) {
833
891
  isAllowedToSave = yield this.options.isAllowedToSave({ record: {}, adminUser: adminUser, resource: this.resourceConfig });
834
892
  }
835
893
  if (isAllowedToSave.ok !== false) {
836
- const selectedIds = body.selectedIds || [];
837
- const fieldsToUpdate = body.fields || {};
838
- const saveImages = body.saveImages;
894
+ const selectedIds = data.selectedIds || [];
895
+ const fieldsToUpdate = data.fields || {};
896
+ const saveImages = data.saveImages;
839
897
  const outputImageFields = [];
840
898
  if (this.options.generateImages) {
841
899
  for (const [key, value] of Object.entries(this.options.generateImages)) {
@@ -928,10 +986,14 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
928
986
  server.endpoint({
929
987
  method: 'POST',
930
988
  path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
931
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, headers }) {
989
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, headers, response }) {
932
990
  var _b;
933
- const Id = body.recordId || [];
934
- const customPrompt = body.customPrompt || null;
991
+ const parsed = parseBody(getImageGenerationPromptsBodySchema, body, response);
992
+ if ('error' in parsed)
993
+ return parsed.error;
994
+ const data = parsed.data;
995
+ const Id = data.recordId || [];
996
+ const customPrompt = data.customPrompt || null;
935
997
  const record = yield this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ((_b = this.resourceConfig.columns.find(c => c.primaryKey)) === null || _b === void 0 ? void 0 : _b.name, Id)]);
936
998
  const compiledGenerationOptions = yield this.compileGenerationFieldTemplates(record, JSON.stringify({ "prompt": customPrompt }));
937
999
  return compiledGenerationOptions;
@@ -951,8 +1013,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
951
1013
  server.endpoint({
952
1014
  method: 'POST',
953
1015
  path: `/plugin/${this.pluginInstanceId}/create-job`,
954
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers }) {
955
- const { actionType, recordId, customPrompt, filterFilledFields, sessionIds } = body;
1016
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, response }) {
1017
+ const parsed = parseBody(createJobBodySchema, body, response);
1018
+ if ('error' in parsed)
1019
+ return parsed.error;
1020
+ const data = parsed.data;
1021
+ const { actionType, recordId, customPrompt, filterFilledFields, sessionIds } = data;
956
1022
  if (this.options.rateLimits) {
957
1023
  if (sessionIds && sessionIds.length > 0) {
958
1024
  for (const sessionId of sessionIds) {
@@ -988,15 +1054,15 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
988
1054
  this.analyze_image(jobId, recordId, adminUser, headers, customPrompt, filterFilledFields);
989
1055
  break;
990
1056
  case 'regenerate_images':
991
- if (!body.prompt || !body.fieldName) {
1057
+ if (!data.prompt || !data.fieldName) {
992
1058
  jobs.set(jobId, { status: "failed", error: "Missing prompt or field name" });
993
1059
  break;
994
1060
  }
995
- this.regenerateImage(jobId, recordId, body.fieldName, body.prompt, adminUser, headers);
1061
+ this.regenerateImage(jobId, recordId, data.fieldName, data.prompt, adminUser, headers);
996
1062
  break;
997
1063
  case 'regenerate_cell':
998
- const fieldToRegenerate = body.fieldToRegenerate;
999
- this.regenerateCell(jobId, fieldToRegenerate, recordId, body.action, body.prompt);
1064
+ const fieldToRegenerate = data.fieldToRegenerate;
1065
+ this.regenerateCell(jobId, fieldToRegenerate, recordId, data.action, data.prompt);
1000
1066
  break;
1001
1067
  default:
1002
1068
  jobs.set(jobId, { status: "failed", error: "Unknown action type" });
@@ -1011,7 +1077,11 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1011
1077
  method: 'POST',
1012
1078
  path: `/plugin/${this.pluginInstanceId}/get-job-status`,
1013
1079
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, response }) {
1014
- const jobId = body.jobId;
1080
+ const parsed = parseBody(jobStatusBodySchema, body, response);
1081
+ if ('error' in parsed)
1082
+ return parsed.error;
1083
+ const data = parsed.data;
1084
+ const jobId = data.jobId;
1015
1085
  if (!jobId) {
1016
1086
  response.setStatus(400);
1017
1087
  return {
@@ -1043,9 +1113,13 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1043
1113
  server.endpoint({
1044
1114
  method: 'POST',
1045
1115
  path: `/plugin/${this.pluginInstanceId}/update-rate-limits`,
1046
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers }) {
1116
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, response }) {
1047
1117
  var _b, _c, _d;
1048
- const actionType = body.actionType;
1118
+ const parsed = parseBody(updateRateLimitsBodySchema, body, response);
1119
+ if ('error' in parsed)
1120
+ return parsed.error;
1121
+ const data = parsed.data;
1122
+ const actionType = data.actionType;
1049
1123
  const sessionId = randomUUID();
1050
1124
  this.sessionIds.add(sessionId);
1051
1125
  if (actionType === 'analyze' && ((_b = this.options.rateLimits) === null || _b === void 0 ? void 0 : _b.fillFieldsFromImages)) {
@@ -1070,10 +1144,14 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1070
1144
  server.endpoint({
1071
1145
  method: 'POST',
1072
1146
  path: `/plugin/${this.pluginInstanceId}/compile_old_image_link`,
1073
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers }) {
1147
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, response }) {
1074
1148
  var _b, _c;
1075
- const image = body.image;
1076
- const columnName = body.columnName;
1149
+ const parsed = parseBody(compileOldImageLinkBodySchema, body, response);
1150
+ if ('error' in parsed)
1151
+ return parsed.error;
1152
+ const data = parsed.data;
1153
+ const image = data.image;
1154
+ const columnName = data.columnName;
1077
1155
  if (!image) {
1078
1156
  return { ok: false, error: "Can't find image url" };
1079
1157
  }
@@ -1099,8 +1177,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1099
1177
  server.endpoint({
1100
1178
  method: 'POST',
1101
1179
  path: `/plugin/${this.pluginInstanceId}/get_filtered_ids`,
1102
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
1180
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl, response }) {
1103
1181
  var _b, _c;
1182
+ const parsed = parseBody(getFilteredIdsBodySchema, body, response);
1183
+ if ('error' in parsed)
1184
+ return parsed.error;
1185
+ const data = parsed.data;
1104
1186
  const resource = this.resourceConfig;
1105
1187
  for (const hook of ((_c = (_b = resource.hooks) === null || _b === void 0 ? void 0 : _b.list) === null || _c === void 0 ? void 0 : _c.beforeDatasourceRequest) || []) {
1106
1188
  const filterTools = filtersTools.get(body);
package/index.ts CHANGED
@@ -1,10 +1,63 @@
1
- import { AdminForthFilterOperators, AdminForthPlugin, Filters } from "adminforth";
1
+ import { AdminForthFilterOperators, AdminForthPlugin, parseBody, Filters } from "adminforth";
2
2
  import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResource } from "adminforth";
3
3
  import { suggestIfTypo, filtersTools } from "adminforth";
4
4
  import type { PluginOptions } from './types.js';
5
5
  import Handlebars from 'handlebars';
6
6
  import { RateLimiter } from "adminforth";
7
7
  import { randomUUID } from "crypto";
8
+ import { z } from "zod";
9
+
10
+ const getRecordsBodySchema = z.object({
11
+ record: z.array(z.any()).nullish(),
12
+ }).strict();
13
+
14
+ const getImagesBodySchema = z.object({
15
+ record: z.array(z.any()).nullish(),
16
+ }).strict();
17
+
18
+ const getOldDataBodySchema = z.object({
19
+ recordId: z.union([z.string(), z.number()]).nullish(),
20
+ }).strict();
21
+
22
+ const updateFieldsBodySchema = z.object({
23
+ selectedIds: z.array(z.any()).nullish(),
24
+ fields: z.any(),
25
+ saveImages: z.boolean().nullish(),
26
+ }).strict();
27
+
28
+ const getImageGenerationPromptsBodySchema = z.object({
29
+ recordId: z.union([z.string(), z.number()]).nullish(),
30
+ customPrompt: z.string().nullish(),
31
+ }).strict();
32
+
33
+ const createJobBodySchema = z.object({
34
+ actionType: z.string().nullish(),
35
+ recordId: z.any().optional(),
36
+ customPrompt: z.string().nullish(),
37
+ filterFilledFields: z.boolean().nullish(),
38
+ sessionIds: z.array(z.string()).nullish(),
39
+ prompt: z.string().nullish(),
40
+ fieldName: z.string().nullish(),
41
+ fieldToRegenerate: z.string().nullish(),
42
+ action: z.string().nullish(),
43
+ }).strict();
44
+
45
+ const jobStatusBodySchema = z.object({
46
+ jobId: z.string(),
47
+ }).strict();
48
+
49
+ const updateRateLimitsBodySchema = z.object({
50
+ actionType: z.string().nullish(),
51
+ }).strict();
52
+
53
+ const compileOldImageLinkBodySchema = z.object({
54
+ image: z.string().nullish(),
55
+ columnName: z.string().nullish(),
56
+ }).strict();
57
+
58
+ const getFilteredIdsBodySchema = z.object({
59
+ filters: z.any(),
60
+ }).passthrough();
8
61
  const STUB_MODE = false;
9
62
  const jobs = new Map();
10
63
  export default class BulkAiFlowPlugin extends AdminForthPlugin {
@@ -779,17 +832,20 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
779
832
  server.endpoint({
780
833
  method: 'POST',
781
834
  path: `/plugin/${this.pluginInstanceId}/get_records`,
782
- handler: async ( body ) => {
783
- if (!Array.isArray(body.body?.record)) {
835
+ handler: async ({ body, response }) => {
836
+ const parsed = parseBody(getRecordsBodySchema, body, response);
837
+ if ('error' in parsed) return parsed.error;
838
+ const data = parsed.data;
839
+ if (!Array.isArray(data.record)) {
784
840
  return { records: [] };
785
841
  }
786
842
  let records = [];
787
843
  const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
788
- records = await this.adminforth.resource(this.resourceConfig.resourceId).list([Filters.IN(primaryKeyColumn.name, body.body.record)]);
844
+ records = await this.adminforth.resource(this.resourceConfig.resourceId).list([Filters.IN(primaryKeyColumn.name, data.record)]);
789
845
  for( const [index, record] of records.entries() ) {
790
846
  records[index]._label = this.resourceConfig.recordLabel(records[index]);
791
847
  }
792
- const order = Object.fromEntries(body.body.record.map((id, i) => [id, i]));
848
+ const order = Object.fromEntries(data.record.map((id, i) => [id, i]));
793
849
 
794
850
  const sortedRecords = records.sort(
795
851
  (a, b) => order[a.id] - order[b.id]
@@ -804,8 +860,11 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
804
860
  server.endpoint({
805
861
  method: 'POST',
806
862
  path: `/plugin/${this.pluginInstanceId}/get_old_data`,
807
- handler: async ({ body }) => {
808
- const recordId = body.recordId;
863
+ handler: async ({ body, response }) => {
864
+ const parsed = parseBody(getOldDataBodySchema, body, response);
865
+ if ('error' in parsed) return parsed.error;
866
+ const data = parsed.data;
867
+ const recordId = data.recordId;
809
868
  if (recordId === undefined || recordId === null) {
810
869
  return { ok: false, error: "Missing recordId" };
811
870
  }
@@ -824,10 +883,13 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
824
883
  server.endpoint({
825
884
  method: 'POST',
826
885
  path: `/plugin/${this.pluginInstanceId}/get_images`,
827
- handler: async ( body ) => {
886
+ handler: async ({ body, response }) => {
887
+ const parsed = parseBody(getImagesBodySchema, body, response);
888
+ if ('error' in parsed) return parsed.error;
889
+ const data = parsed.data;
828
890
  let images = [];
829
- if(body.body.record){
830
- for( const record of body.body.record ) {
891
+ if(data.record){
892
+ for( const record of data.record ) {
831
893
  if (this.options.attachFiles) {
832
894
  images.push(await this.options.attachFiles({ record: record }));
833
895
  }
@@ -843,15 +905,18 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
843
905
  server.endpoint({
844
906
  method: 'POST',
845
907
  path: `/plugin/${this.pluginInstanceId}/update_fields`,
846
- handler: async ({ body, adminUser, headers }) => {
908
+ handler: async ({ body, adminUser, headers, response }) => {
909
+ const parsed = parseBody(updateFieldsBodySchema, body, response);
910
+ if ('error' in parsed) return parsed.error;
911
+ const data = parsed.data;
847
912
  let isAllowedToSave: any = { ok: true, error: '' };
848
913
  if(this.options.isAllowedToSave) {
849
914
  isAllowedToSave = await this.options.isAllowedToSave({ record: {}, adminUser: adminUser, resource: this.resourceConfig });
850
915
  }
851
916
  if (isAllowedToSave.ok !== false) {
852
- const selectedIds = body.selectedIds || [];
853
- const fieldsToUpdate = body.fields || {};
854
- const saveImages = body.saveImages;
917
+ const selectedIds = data.selectedIds || [];
918
+ const fieldsToUpdate = data.fields || {};
919
+ const saveImages = data.saveImages;
855
920
  const outputImageFields = [];
856
921
  if (this.options.generateImages) {
857
922
  for (const [key, value] of Object.entries(this.options.generateImages)) {
@@ -950,9 +1015,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
950
1015
  server.endpoint({
951
1016
  method: 'POST',
952
1017
  path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
953
- handler: async ({ body, headers }) => {
954
- const Id = body.recordId || [];
955
- const customPrompt = body.customPrompt || null;
1018
+ handler: async ({ body, headers, response }) => {
1019
+ const parsed = parseBody(getImageGenerationPromptsBodySchema, body, response);
1020
+ if ('error' in parsed) return parsed.error;
1021
+ const data = parsed.data;
1022
+ const Id = data.recordId || [];
1023
+ const customPrompt = data.customPrompt || null;
956
1024
  const record = await this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(this.resourceConfig.columns.find(c => c.primaryKey)?.name, Id)]);
957
1025
  const compiledGenerationOptions = await this.compileGenerationFieldTemplates(record, JSON.stringify({"prompt": customPrompt}));
958
1026
  return compiledGenerationOptions;
@@ -976,8 +1044,11 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
976
1044
  server.endpoint({
977
1045
  method: 'POST',
978
1046
  path: `/plugin/${this.pluginInstanceId}/create-job`,
979
- handler: async ({ body, adminUser, headers }) => {
980
- const { actionType, recordId, customPrompt, filterFilledFields, sessionIds } = body;
1047
+ handler: async ({ body, adminUser, headers, response }) => {
1048
+ const parsed = parseBody(createJobBodySchema, body, response);
1049
+ if ('error' in parsed) return parsed.error;
1050
+ const data = parsed.data;
1051
+ const { actionType, recordId, customPrompt, filterFilledFields, sessionIds } = data;
981
1052
  if (this.options.rateLimits) {
982
1053
  if (sessionIds && sessionIds.length > 0) {
983
1054
  for (const sessionId of sessionIds) {
@@ -1011,15 +1082,15 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1011
1082
  this.analyze_image(jobId, recordId, adminUser, headers, customPrompt, filterFilledFields);
1012
1083
  break;
1013
1084
  case 'regenerate_images':
1014
- if (!body.prompt || !body.fieldName) {
1085
+ if (!data.prompt || !data.fieldName) {
1015
1086
  jobs.set(jobId, { status: "failed", error: "Missing prompt or field name" });
1016
1087
  break;
1017
1088
  }
1018
- this.regenerateImage(jobId, recordId, body.fieldName, body.prompt, adminUser, headers);
1089
+ this.regenerateImage(jobId, recordId, data.fieldName, data.prompt, adminUser, headers);
1019
1090
  break;
1020
1091
  case 'regenerate_cell':
1021
- const fieldToRegenerate = body.fieldToRegenerate;
1022
- this.regenerateCell(jobId, fieldToRegenerate, recordId, body.action, body.prompt);
1092
+ const fieldToRegenerate = data.fieldToRegenerate;
1093
+ this.regenerateCell(jobId, fieldToRegenerate, recordId, data.action, data.prompt);
1023
1094
  break;
1024
1095
  default:
1025
1096
  jobs.set(jobId, { status: "failed", error: "Unknown action type" });
@@ -1036,7 +1107,10 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1036
1107
  method: 'POST',
1037
1108
  path: `/plugin/${this.pluginInstanceId}/get-job-status`,
1038
1109
  handler: async ({ body, adminUser, headers, response }) => {
1039
- const jobId = body.jobId;
1110
+ const parsed = parseBody(jobStatusBodySchema, body, response);
1111
+ if ('error' in parsed) return parsed.error;
1112
+ const data = parsed.data;
1113
+ const jobId = data.jobId;
1040
1114
  if (!jobId) {
1041
1115
  response.setStatus(400);
1042
1116
 
@@ -1073,8 +1147,11 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1073
1147
  server.endpoint({
1074
1148
  method: 'POST',
1075
1149
  path: `/plugin/${this.pluginInstanceId}/update-rate-limits`,
1076
- handler: async ({ body, adminUser, headers }) => {
1077
- const actionType = body.actionType;
1150
+ handler: async ({ body, adminUser, headers, response }) => {
1151
+ const parsed = parseBody(updateRateLimitsBodySchema, body, response);
1152
+ if ('error' in parsed) return parsed.error;
1153
+ const data = parsed.data;
1154
+ const actionType = data.actionType;
1078
1155
  const sessionId = randomUUID();
1079
1156
  this.sessionIds.add(sessionId);
1080
1157
  if (actionType === 'analyze' && this.options.rateLimits?.fillFieldsFromImages) {
@@ -1101,9 +1178,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1101
1178
  server.endpoint({
1102
1179
  method: 'POST',
1103
1180
  path: `/plugin/${this.pluginInstanceId}/compile_old_image_link`,
1104
- handler: async ({ body, adminUser, headers }) => {
1105
- const image = body.image;
1106
- const columnName = body.columnName;
1181
+ handler: async ({ body, adminUser, headers, response }) => {
1182
+ const parsed = parseBody(compileOldImageLinkBodySchema, body, response);
1183
+ if ('error' in parsed) return parsed.error;
1184
+ const data = parsed.data;
1185
+ const image = data.image;
1186
+ const columnName = data.columnName;
1107
1187
  if (!image) {
1108
1188
  return { ok: false, error: "Can't find image url" };
1109
1189
  }
@@ -1131,7 +1211,10 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1131
1211
  server.endpoint({
1132
1212
  method: 'POST',
1133
1213
  path: `/plugin/${this.pluginInstanceId}/get_filtered_ids`,
1134
- handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
1214
+ handler: async ({ body, adminUser, headers, query, cookies, requestUrl, response }) => {
1215
+ const parsed = parseBody(getFilteredIdsBodySchema, body, response);
1216
+ if ('error' in parsed) return parsed.error;
1217
+ const data = parsed.data;
1135
1218
  const resource = this.resourceConfig;
1136
1219
 
1137
1220
  for (const hook of resource.hooks?.list?.beforeDatasourceRequest || []) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/bulk-ai-flow",
3
- "version": "1.26.10",
3
+ "version": "1.27.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -25,17 +25,18 @@
25
25
  "description": "Bulk AI workflow plugin for AdminForth for batch field generation and image processing",
26
26
  "devDependencies": {
27
27
  "@types/node": "latest",
28
- "adminforth": "^3.6.21",
28
+ "adminforth": "^3.7.1",
29
29
  "semantic-release": "^24.2.1",
30
30
  "semantic-release-slack-bot": "^4.0.2",
31
31
  "typescript": "^5.7.3"
32
32
  },
33
33
  "dependencies": {
34
34
  "@types/handlebars": "^4.0.40",
35
- "handlebars": "^4.7.8"
35
+ "handlebars": "^4.7.8",
36
+ "zod": "^4.3.6"
36
37
  },
37
38
  "peerDependencies": {
38
- "adminforth": "^3.6.21"
39
+ "adminforth": "^3.7.1"
39
40
  },
40
41
  "release": {
41
42
  "plugins": [