@adminforth/bulk-ai-flow 1.27.4 → 1.27.5

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/build.log CHANGED
@@ -14,5 +14,5 @@ custom/package.json
14
14
  custom/pnpm-lock.yaml
15
15
  custom/tsconfig.json
16
16
 
17
- sent 130,464 bytes received 191 bytes 261,310.00 bytes/sec
18
- total size is 129,741 speedup is 0.99
17
+ sent 130,414 bytes received 191 bytes 261,210.00 bytes/sec
18
+ total size is 129,691 speedup is 0.99
@@ -884,7 +884,7 @@ async function processOneRecord(recordId: string, sessionIds: string[]) {
884
884
  record.label = oldDataResult._label || record.label;
885
885
  initializeRecordData(record, oldDataResult);
886
886
  if (props.meta.isAttachFiles) {
887
- await fetchImages(record, oldDataResult);
887
+ await fetchImages(record, recordId);
888
888
  if (!checkIfDialogOpen()) {
889
889
  return;
890
890
  }
@@ -1162,16 +1162,14 @@ function normalizeEnumValue(key: string, value: any) {
1162
1162
  return match ? value : null;
1163
1163
  }
1164
1164
 
1165
- async function fetchImages(record: RecordState, oldRecord: Record<string, any>) {
1165
+ async function fetchImages(record: RecordState, recordId: string) {
1166
1166
  try {
1167
1167
  const res = await callAdminForthApi({
1168
1168
  path: `/plugin/${props.meta.pluginInstanceId}/get_images`,
1169
1169
  method: 'POST',
1170
- body: {
1171
- record: [oldRecord],
1172
- },
1170
+ body: { recordId },
1173
1171
  });
1174
- record.images = res.images?.[0] || [];
1172
+ record.images = res.images || [];
1175
1173
  touchRecords();
1176
1174
  } catch (error) {
1177
1175
  console.error('Failed to get images:', error);
@@ -884,7 +884,7 @@ async function processOneRecord(recordId: string, sessionIds: string[]) {
884
884
  record.label = oldDataResult._label || record.label;
885
885
  initializeRecordData(record, oldDataResult);
886
886
  if (props.meta.isAttachFiles) {
887
- await fetchImages(record, oldDataResult);
887
+ await fetchImages(record, recordId);
888
888
  if (!checkIfDialogOpen()) {
889
889
  return;
890
890
  }
@@ -1162,16 +1162,14 @@ function normalizeEnumValue(key: string, value: any) {
1162
1162
  return match ? value : null;
1163
1163
  }
1164
1164
 
1165
- async function fetchImages(record: RecordState, oldRecord: Record<string, any>) {
1165
+ async function fetchImages(record: RecordState, recordId: string) {
1166
1166
  try {
1167
1167
  const res = await callAdminForthApi({
1168
1168
  path: `/plugin/${props.meta.pluginInstanceId}/get_images`,
1169
1169
  method: 'POST',
1170
- body: {
1171
- record: [oldRecord],
1172
- },
1170
+ body: { recordId },
1173
1171
  });
1174
- record.images = res.images?.[0] || [];
1172
+ record.images = res.images || [];
1175
1173
  touchRecords();
1176
1174
  } catch (error) {
1177
1175
  console.error('Failed to get images:', error);
package/dist/index.d.ts CHANGED
@@ -34,5 +34,19 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
34
34
  oldRecord: any;
35
35
  fields: Record<string, any>;
36
36
  }): Promise<string | null>;
37
+ /**
38
+ * Reads one record the way the core show route does: the resource-level `show` permission first,
39
+ * then the resource's own `show.beforeDatasourceRequest` hooks so row-level scoping narrows the
40
+ * filters before the query runs.
41
+ * The returned record is the raw row, so callers which send it to the browser must pass it
42
+ * through `scopeRecordForFrontend` first.
43
+ */
44
+ private getRecordForShow;
45
+ /**
46
+ * The action dialog only ever renders the fields this plugin generates, so only those leave the
47
+ * backend, next to the primary key and the record label. backendOnly columns are dropped the same
48
+ * way the core show route drops them.
49
+ */
50
+ private scopeRecordForFrontend;
37
51
  setupEndpoints(server: IHttpServer): void;
38
52
  }
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ const getRecordsBodySchema = z.object({
17
17
  record: z.array(z.any()).nullish(),
18
18
  }).strict();
19
19
  const getImagesBodySchema = z.object({
20
- record: z.array(z.any()).nullish(),
20
+ recordId: z.union([z.string(), z.number()]),
21
21
  }).strict();
22
22
  const getOldDataBodySchema = z.object({
23
23
  recordId: z.union([z.string(), z.number()]).nullish(),
@@ -28,7 +28,7 @@ const updateFieldsBodySchema = z.object({
28
28
  saveImages: z.boolean().nullish(),
29
29
  }).strict();
30
30
  const getImageGenerationPromptsBodySchema = z.object({
31
- recordId: z.union([z.string(), z.number()]).nullish(),
31
+ recordId: z.union([z.string(), z.number()]),
32
32
  customPrompt: z.string().nullish(),
33
33
  }).strict();
34
34
  const createJobBodySchema = z.object({
@@ -907,44 +907,126 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
907
907
  return null;
908
908
  });
909
909
  }
910
+ /**
911
+ * Reads one record the way the core show route does: the resource-level `show` permission first,
912
+ * then the resource's own `show.beforeDatasourceRequest` hooks so row-level scoping narrows the
913
+ * filters before the query runs.
914
+ * The returned record is the raw row, so callers which send it to the browser must pass it
915
+ * through `scopeRecordForFrontend` first.
916
+ */
917
+ getRecordForShow(_a) {
918
+ return __awaiter(this, arguments, void 0, function* ({ adminUser, recordId, extra }) {
919
+ var _b, _c;
920
+ const meta = { requestBody: extra.body, pk: recordId };
921
+ const ctx = {
922
+ adminUser,
923
+ resource: this.resourceConfig,
924
+ meta,
925
+ source: ActionCheckSource.ShowRequest,
926
+ adminforth: this.adminforth,
927
+ };
928
+ const { allowedActions } = yield interpretResource(adminUser, this.resourceConfig, meta, ActionCheckSource.ShowRequest, this.adminforth);
929
+ const showAllowed = allowedActions[AllowedActionsEnum.show];
930
+ if (showAllowed !== true) {
931
+ return { error: typeof showAllowed === 'string' ? showAllowed : 'You are not allowed to view records in this resource' };
932
+ }
933
+ const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
934
+ const hookQuery = {
935
+ resourceId: this.resourceConfig.resourceId,
936
+ source: 'show',
937
+ filters: [Filters.EQ(primaryKeyColumn.name, recordId)],
938
+ limit: 1,
939
+ offset: 0,
940
+ sort: [],
941
+ };
942
+ for (const hook of ((_c = (_b = this.resourceConfig.hooks) === null || _b === void 0 ? void 0 : _b.show) === null || _c === void 0 ? void 0 : _c.beforeDatasourceRequest) || []) {
943
+ const filterTools = filtersTools.get(hookQuery);
944
+ hookQuery.filtersTools = filterTools;
945
+ const resp = yield hook({
946
+ resource: this.resourceConfig,
947
+ query: hookQuery,
948
+ adminUser,
949
+ //@ts-ignore
950
+ filtersTools: filterTools,
951
+ extra,
952
+ adminforth: this.adminforth,
953
+ });
954
+ if (!resp || (!resp.ok && !resp.error)) {
955
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
956
+ }
957
+ if (resp.error) {
958
+ return { error: resp.error };
959
+ }
960
+ }
961
+ const record = yield this.adminforth.resource(this.resourceConfig.resourceId).get(hookQuery.filters);
962
+ if (!record) {
963
+ return { error: 'Record not found' };
964
+ }
965
+ return { record, ctx };
966
+ });
967
+ }
968
+ /**
969
+ * The action dialog only ever renders the fields this plugin generates, so only those leave the
970
+ * backend, next to the primary key and the record label. backendOnly columns are dropped the same
971
+ * way the core show route drops them.
972
+ */
973
+ scopeRecordForFrontend(record, ctx) {
974
+ return __awaiter(this, void 0, void 0, function* () {
975
+ const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
976
+ const managedFields = this.pluginManagedFields();
977
+ const scoped = {
978
+ [primaryKeyColumn.name]: record[primaryKeyColumn.name],
979
+ _label: this.resourceConfig.recordLabel(record),
980
+ };
981
+ for (const column of this.resourceConfig.columns.filter((col) => managedFields.has(col.name))) {
982
+ if (yield resolveBoolOrFn(column.backendOnly, ctx)) {
983
+ continue;
984
+ }
985
+ scoped[column.name] = record[column.name];
986
+ }
987
+ return scoped;
988
+ });
989
+ }
910
990
  setupEndpoints(server) {
911
991
  server.endpoint({
912
992
  method: 'POST',
913
993
  path: `/plugin/${this.pluginInstanceId}/get_old_data`,
914
994
  request_schema: getOldDataBodySchema,
915
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
995
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
916
996
  const data = body;
917
997
  const recordId = data.recordId;
918
998
  if (recordId === undefined || recordId === null) {
919
999
  return { ok: false, error: "Missing recordId" };
920
1000
  }
921
- const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
922
- const record = yield this.adminforth.resource(this.resourceConfig.resourceId)
923
- .get([Filters.EQ(primaryKeyColumn.name, recordId)]);
924
- if (!record) {
925
- return { ok: false, error: "Record not found" };
1001
+ const { record, ctx, error } = yield this.getRecordForShow({
1002
+ adminUser,
1003
+ recordId,
1004
+ extra: { body, query, headers, cookies, requestUrl },
1005
+ });
1006
+ if (error) {
1007
+ return { ok: false, error };
926
1008
  }
927
- record._label = this.resourceConfig.recordLabel(record);
928
- return { ok: true, record };
1009
+ return { ok: true, record: yield this.scopeRecordForFrontend(record, ctx) };
929
1010
  })
930
1011
  });
931
1012
  server.endpoint({
932
1013
  method: 'POST',
933
1014
  path: `/plugin/${this.pluginInstanceId}/get_images`,
934
1015
  request_schema: getImagesBodySchema,
935
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
1016
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
936
1017
  const data = body;
937
- let images = [];
938
- if (data.record) {
939
- for (const record of data.record) {
940
- if (this.options.attachFiles) {
941
- images.push(yield this.options.attachFiles({ record: record }));
942
- }
943
- }
1018
+ // attachFiles runs with server privileges and usually mints download URLs, so it is only
1019
+ // ever given a record loaded here after the show check, never one supplied by the client
1020
+ const { record, error } = yield this.getRecordForShow({
1021
+ adminUser,
1022
+ recordId: data.recordId,
1023
+ extra: { body, query, headers, cookies, requestUrl },
1024
+ });
1025
+ if (error) {
1026
+ return { ok: false, error };
944
1027
  }
945
- return {
946
- images,
947
- };
1028
+ const images = this.options.attachFiles ? yield this.options.attachFiles({ record }) : [];
1029
+ return { ok: true, images };
948
1030
  })
949
1031
  });
950
1032
  server.endpoint({
@@ -1074,12 +1156,17 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1074
1156
  method: 'POST',
1075
1157
  path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
1076
1158
  request_schema: getImageGenerationPromptsBodySchema,
1077
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, headers, response }) {
1078
- var _b;
1159
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
1079
1160
  const data = body;
1080
- const Id = data.recordId || [];
1081
1161
  const customPrompt = data.customPrompt || null;
1082
- 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)]);
1162
+ const { record, error } = yield this.getRecordForShow({
1163
+ adminUser,
1164
+ recordId: data.recordId,
1165
+ extra: { body, query, headers, cookies, requestUrl },
1166
+ });
1167
+ if (error) {
1168
+ return { ok: false, error };
1169
+ }
1083
1170
  const compiledGenerationOptions = yield this.compileGenerationFieldTemplates(record, JSON.stringify({ "prompt": customPrompt }));
1084
1171
  return compiledGenerationOptions;
1085
1172
  })
@@ -1258,6 +1345,11 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1258
1345
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl, response }) {
1259
1346
  var _b, _c;
1260
1347
  const resource = this.resourceConfig;
1348
+ const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.ListRequest, this.adminforth);
1349
+ const listAllowed = allowedActions[AllowedActionsEnum.list];
1350
+ if (listAllowed !== true) {
1351
+ return { ok: false, error: typeof listAllowed === 'string' ? listAllowed : 'You are not allowed to list records in this resource' };
1352
+ }
1261
1353
  for (const hook of ((_c = (_b = resource.hooks) === null || _b === void 0 ? void 0 : _b.list) === null || _c === void 0 ? void 0 : _c.beforeDatasourceRequest) || []) {
1262
1354
  const filterTools = filtersTools.get(body);
1263
1355
  body.filtersTools = filterTools;
package/index.ts CHANGED
@@ -12,7 +12,7 @@ const getRecordsBodySchema = z.object({
12
12
  }).strict();
13
13
 
14
14
  const getImagesBodySchema = z.object({
15
- record: z.array(z.any()).nullish(),
15
+ recordId: z.union([z.string(), z.number()]),
16
16
  }).strict();
17
17
 
18
18
  const getOldDataBodySchema = z.object({
@@ -26,7 +26,7 @@ const updateFieldsBodySchema = z.object({
26
26
  }).strict();
27
27
 
28
28
  const getImageGenerationPromptsBodySchema = z.object({
29
- recordId: z.union([z.string(), z.number()]).nullish(),
29
+ recordId: z.union([z.string(), z.number()]),
30
30
  customPrompt: z.string().nullish(),
31
31
  }).strict();
32
32
 
@@ -949,25 +949,116 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
949
949
  return null;
950
950
  }
951
951
 
952
+ /**
953
+ * Reads one record the way the core show route does: the resource-level `show` permission first,
954
+ * then the resource's own `show.beforeDatasourceRequest` hooks so row-level scoping narrows the
955
+ * filters before the query runs.
956
+ * The returned record is the raw row, so callers which send it to the browser must pass it
957
+ * through `scopeRecordForFrontend` first.
958
+ */
959
+ private async getRecordForShow({ adminUser, recordId, extra }: {
960
+ adminUser: AdminUser,
961
+ recordId: any,
962
+ extra: { body: any, query: any, headers: any, cookies: any, requestUrl: string },
963
+ }): Promise<{ record?: any, ctx?: AccessCheckContext, error?: string }> {
964
+ const meta = { requestBody: extra.body, pk: recordId };
965
+ const ctx: AccessCheckContext = {
966
+ adminUser,
967
+ resource: this.resourceConfig,
968
+ meta,
969
+ source: ActionCheckSource.ShowRequest,
970
+ adminforth: this.adminforth,
971
+ };
972
+
973
+ const { allowedActions } = await interpretResource(
974
+ adminUser,
975
+ this.resourceConfig,
976
+ meta,
977
+ ActionCheckSource.ShowRequest,
978
+ this.adminforth,
979
+ );
980
+ const showAllowed = allowedActions[AllowedActionsEnum.show] as boolean | string | undefined;
981
+ if (showAllowed !== true) {
982
+ return { error: typeof showAllowed === 'string' ? showAllowed : 'You are not allowed to view records in this resource' };
983
+ }
984
+
985
+ const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
986
+ const hookQuery: any = {
987
+ resourceId: this.resourceConfig.resourceId,
988
+ source: 'show',
989
+ filters: [Filters.EQ(primaryKeyColumn.name, recordId)],
990
+ limit: 1,
991
+ offset: 0,
992
+ sort: [],
993
+ };
994
+ for (const hook of this.resourceConfig.hooks?.show?.beforeDatasourceRequest || []) {
995
+ const filterTools = filtersTools.get(hookQuery);
996
+ hookQuery.filtersTools = filterTools;
997
+ const resp = await hook({
998
+ resource: this.resourceConfig,
999
+ query: hookQuery,
1000
+ adminUser,
1001
+ //@ts-ignore
1002
+ filtersTools: filterTools,
1003
+ extra,
1004
+ adminforth: this.adminforth,
1005
+ });
1006
+ if (!resp || (!resp.ok && !resp.error)) {
1007
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
1008
+ }
1009
+ if (resp.error) {
1010
+ return { error: resp.error };
1011
+ }
1012
+ }
1013
+
1014
+ const record = await this.adminforth.resource(this.resourceConfig.resourceId).get(hookQuery.filters);
1015
+ if (!record) {
1016
+ return { error: 'Record not found' };
1017
+ }
1018
+ return { record, ctx };
1019
+ }
1020
+
1021
+ /**
1022
+ * The action dialog only ever renders the fields this plugin generates, so only those leave the
1023
+ * backend, next to the primary key and the record label. backendOnly columns are dropped the same
1024
+ * way the core show route drops them.
1025
+ */
1026
+ private async scopeRecordForFrontend(record: any, ctx: AccessCheckContext): Promise<Record<string, any>> {
1027
+ const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
1028
+ const managedFields = this.pluginManagedFields();
1029
+ const scoped: Record<string, any> = {
1030
+ [primaryKeyColumn.name]: record[primaryKeyColumn.name],
1031
+ _label: this.resourceConfig.recordLabel(record),
1032
+ };
1033
+ for (const column of this.resourceConfig.columns.filter((col) => managedFields.has(col.name))) {
1034
+ if (await resolveBoolOrFn(column.backendOnly, ctx)) {
1035
+ continue;
1036
+ }
1037
+ scoped[column.name] = record[column.name];
1038
+ }
1039
+ return scoped;
1040
+ }
1041
+
952
1042
  setupEndpoints(server: IHttpServer) {
953
1043
  server.endpoint({
954
1044
  method: 'POST',
955
1045
  path: `/plugin/${this.pluginInstanceId}/get_old_data`,
956
1046
  request_schema: getOldDataBodySchema,
957
- handler: async ({ body, response }) => {
1047
+ handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
958
1048
  const data = body as z.infer<typeof getOldDataBodySchema>;
959
1049
  const recordId = data.recordId;
960
1050
  if (recordId === undefined || recordId === null) {
961
1051
  return { ok: false, error: "Missing recordId" };
962
1052
  }
963
- const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
964
- const record = await this.adminforth.resource(this.resourceConfig.resourceId)
965
- .get([Filters.EQ(primaryKeyColumn.name, recordId)]);
966
- if (!record) {
967
- return { ok: false, error: "Record not found" };
1053
+ const { record, ctx, error } = await this.getRecordForShow({
1054
+ adminUser,
1055
+ recordId,
1056
+ extra: { body, query, headers, cookies, requestUrl },
1057
+ });
1058
+ if (error) {
1059
+ return { ok: false, error };
968
1060
  }
969
- record._label = this.resourceConfig.recordLabel(record);
970
- return { ok: true, record };
1061
+ return { ok: true, record: await this.scopeRecordForFrontend(record, ctx) };
971
1062
  }
972
1063
  });
973
1064
 
@@ -976,19 +1067,20 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
976
1067
  method: 'POST',
977
1068
  path: `/plugin/${this.pluginInstanceId}/get_images`,
978
1069
  request_schema: getImagesBodySchema,
979
- handler: async ({ body, response }) => {
1070
+ handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
980
1071
  const data = body as z.infer<typeof getImagesBodySchema>;
981
- let images = [];
982
- if(data.record){
983
- for( const record of data.record ) {
984
- if (this.options.attachFiles) {
985
- images.push(await this.options.attachFiles({ record: record }));
986
- }
987
- }
1072
+ // attachFiles runs with server privileges and usually mints download URLs, so it is only
1073
+ // ever given a record loaded here after the show check, never one supplied by the client
1074
+ const { record, error } = await this.getRecordForShow({
1075
+ adminUser,
1076
+ recordId: data.recordId,
1077
+ extra: { body, query, headers, cookies, requestUrl },
1078
+ });
1079
+ if (error) {
1080
+ return { ok: false, error };
988
1081
  }
989
- return {
990
- images,
991
- };
1082
+ const images = this.options.attachFiles ? await this.options.attachFiles({ record }) : [];
1083
+ return { ok: true, images };
992
1084
  }
993
1085
  });
994
1086
 
@@ -1130,11 +1222,17 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1130
1222
  method: 'POST',
1131
1223
  path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
1132
1224
  request_schema: getImageGenerationPromptsBodySchema,
1133
- handler: async ({ body, headers, response }) => {
1225
+ handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
1134
1226
  const data = body as z.infer<typeof getImageGenerationPromptsBodySchema>;
1135
- const Id = data.recordId || [];
1136
1227
  const customPrompt = data.customPrompt || null;
1137
- const record = await this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(this.resourceConfig.columns.find(c => c.primaryKey)?.name, Id)]);
1228
+ const { record, error } = await this.getRecordForShow({
1229
+ adminUser,
1230
+ recordId: data.recordId,
1231
+ extra: { body, query, headers, cookies, requestUrl },
1232
+ });
1233
+ if (error) {
1234
+ return { ok: false, error };
1235
+ }
1138
1236
  const compiledGenerationOptions = await this.compileGenerationFieldTemplates(record, JSON.stringify({"prompt": customPrompt}));
1139
1237
  return compiledGenerationOptions;
1140
1238
  }
@@ -1324,6 +1422,18 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
1324
1422
  handler: async ({ body, adminUser, headers, query, cookies, requestUrl, response }) => {
1325
1423
  const resource = this.resourceConfig;
1326
1424
 
1425
+ const { allowedActions } = await interpretResource(
1426
+ adminUser,
1427
+ resource,
1428
+ { requestBody: body },
1429
+ ActionCheckSource.ListRequest,
1430
+ this.adminforth,
1431
+ );
1432
+ const listAllowed = allowedActions[AllowedActionsEnum.list] as boolean | string | undefined;
1433
+ if (listAllowed !== true) {
1434
+ return { ok: false, error: typeof listAllowed === 'string' ? listAllowed : 'You are not allowed to list records in this resource' };
1435
+ }
1436
+
1327
1437
  for (const hook of resource.hooks?.list?.beforeDatasourceRequest || []) {
1328
1438
  const filterTools = filtersTools.get(body);
1329
1439
  body.filtersTools = filterTools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/bulk-ai-flow",
3
- "version": "1.27.4",
3
+ "version": "1.27.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },