@resolveio/server-lib 20.14.28 → 20.14.29

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.
@@ -18,5 +18,25 @@ export type AiAssistantMongoReadInput = {
18
18
  readonly?: boolean;
19
19
  };
20
20
  };
21
+ export type AiAssistantMongoAggregateInput = {
22
+ database?: string;
23
+ collection?: string;
24
+ query?: Record<string, any>;
25
+ pipeline?: Array<Record<string, any>>;
26
+ options?: {
27
+ allowDiskUse?: boolean;
28
+ maxTimeMS?: number;
29
+ limit?: number;
30
+ };
31
+ permissionView?: string;
32
+ id_client?: string;
33
+ mongo?: {
34
+ database?: string;
35
+ databases?: string[];
36
+ access?: string;
37
+ readonly?: boolean;
38
+ };
39
+ };
21
40
  export declare function loadAiTerminalMethods(methodManager: any): void;
22
41
  export declare function executeAiAssistantMongoRead(payload: AiAssistantMongoReadInput, context: any): Promise<any>;
42
+ export declare function executeAiAssistantMongoAggregate(payload: AiAssistantMongoAggregateInput, context: any): Promise<any>;
@@ -14,6 +14,17 @@ var __extends = (this && this.__extends) || (function () {
14
14
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
15
  };
16
16
  })();
17
+ var __assign = (this && this.__assign) || function () {
18
+ __assign = Object.assign || function(t) {
19
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
20
+ s = arguments[i];
21
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
+ t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
17
28
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
29
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
30
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -50,17 +61,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
50
61
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
62
  }
52
63
  };
53
- var __values = (this && this.__values) || function(o) {
54
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
55
- if (m) return m.call(o);
56
- if (o && typeof o.length === "number") return {
57
- next: function () {
58
- if (o && i >= o.length) o = void 0;
59
- return { value: o && o[i++], done: !o };
60
- }
61
- };
62
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
63
- };
64
64
  var __read = (this && this.__read) || function (o, n) {
65
65
  var m = typeof Symbol === "function" && o[Symbol.iterator];
66
66
  if (!m) return o;
@@ -77,9 +77,30 @@ var __read = (this && this.__read) || function (o, n) {
77
77
  }
78
78
  return ar;
79
79
  };
80
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
81
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
82
+ if (ar || !(i in from)) {
83
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
84
+ ar[i] = from[i];
85
+ }
86
+ }
87
+ return to.concat(ar || Array.prototype.slice.call(from));
88
+ };
89
+ var __values = (this && this.__values) || function(o) {
90
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
91
+ if (m) return m.call(o);
92
+ if (o && typeof o.length === "number") return {
93
+ next: function () {
94
+ if (o && i >= o.length) o = void 0;
95
+ return { value: o && o[i++], done: !o };
96
+ }
97
+ };
98
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
99
+ };
80
100
  Object.defineProperty(exports, "__esModule", { value: true });
81
101
  exports.loadAiTerminalMethods = loadAiTerminalMethods;
82
102
  exports.executeAiAssistantMongoRead = executeAiAssistantMongoRead;
103
+ exports.executeAiAssistantMongoAggregate = executeAiAssistantMongoAggregate;
83
104
  var fs_1 = require("fs");
84
105
  var events_1 = require("events");
85
106
  var os = require("os");
@@ -157,17 +178,21 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
157
178
  '- If the user explicitly asks to create/open/file a support ticket, end your response with a single line exactly in this format:',
158
179
  '- SUPPORT_TICKET_CREATE: <one-line summary>',
159
180
  '- Only include that line when the user clearly wants a ticket created. Do not claim a ticket is created unless you include that line.',
181
+ '- Do not end responses with tentative phrasing like "I could" or "I’m going to." Complete the request or state what is required to proceed.',
182
+ '- Use the codebase context to choose correct collections/fields/workflows and use MONGO_READ/MONGO_AGG to answer with real data when needed.',
160
183
  '- For direct questions, answer first. Ask a single follow-up only if required to run a query or resolve missing details.',
161
184
  '- If you need database data to answer, end your response with a single line exactly in this format:',
162
185
  '- MONGO_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
186
+ '- If you need grouped/aggregated data (totals by user, rankings, trends), end your response with a single line exactly in this format:',
187
+ '- MONGO_AGG: {"collection":"<name>","pipeline":[...],"options":{"allowDiskUse":true,"limit":20},"permissionView":"</route>"}',
163
188
  '- For invoice data, set permissionView to an invoice route (ex: /invoice/list or /report/invoice).',
164
189
  '- Keep queries minimal, read-only, and avoid user/credential data unless the user is a super admin.',
165
190
  '- Assume you are not a super admin unless explicitly told otherwise.',
166
191
  '- Only request data when the user has permission for that module; invoice data requires invoice view access.',
167
192
  '- If the user lacks permission, answer without data and explain how to view it in the app or request access.',
168
- '- For counts, totals, or time-range metrics, always use MONGO_READ. Do not guess or return 0 without data.',
169
- '- Before issuing MONGO_READ, verify the collection name and key fields by checking collection/model definitions in the current app (look for "collectionName:" and date fields like date_created/date_completed/createdAt). Do not invent collection names.',
170
- '- Use MONGO_READ only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
193
+ '- For simple counts or time-range totals, use MONGO_READ (includeTotal). For breakdowns, rankings, or sums grouped by a field, use MONGO_AGG.',
194
+ '- Before issuing MONGO_READ or MONGO_AGG, verify the collection name and key fields by checking collection/model definitions in the current app (look for "collectionName:" and date fields like date_created/date_completed/createdAt). Do not invent collection names.',
195
+ '- Use MONGO_READ/MONGO_AGG only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
171
196
  '- When referencing data, summarize it in bullets and avoid raw JSON or dumps.',
172
197
  '- Keep responses concise and use low reasoning effort.'
173
198
  ].join('\n');
@@ -452,6 +477,24 @@ function loadAiTerminalMethods(methodManager) {
452
477
  });
453
478
  }
454
479
  },
480
+ aiAssistantMongoAggregate: {
481
+ check: new simpl_schema_1.default({
482
+ payload: {
483
+ type: Object,
484
+ blackbox: true
485
+ }
486
+ }),
487
+ function: function (payload) {
488
+ return __awaiter(this, void 0, void 0, function () {
489
+ return __generator(this, function (_a) {
490
+ switch (_a.label) {
491
+ case 0: return [4 /*yield*/, executeAiAssistantMongoAggregate(payload, this)];
492
+ case 1: return [2 /*return*/, _a.sent()];
493
+ }
494
+ });
495
+ });
496
+ }
497
+ },
455
498
  aiCoderTerminalDeployTest: {
456
499
  check: new simpl_schema_1.default({
457
500
  id_conversation: {
@@ -903,6 +946,74 @@ function executeAiAssistantMongoRead(payload, context) {
903
946
  });
904
947
  });
905
948
  }
949
+ function executeAiAssistantMongoAggregate(payload, context) {
950
+ return __awaiter(this, void 0, void 0, function () {
951
+ var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, documents, sanitizedDocuments;
952
+ var _c;
953
+ return __generator(this, function (_d) {
954
+ switch (_d.label) {
955
+ case 0:
956
+ input = payload || {};
957
+ collection = normalizeOptionalString(input.collection);
958
+ if (!collection) {
959
+ throw new Error('AI assistant mongo aggregate: Collection is required.');
960
+ }
961
+ return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
962
+ case 1:
963
+ _a = _d.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
964
+ if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
965
+ throw new Error('AI assistant mongo aggregate: Access denied.');
966
+ }
967
+ customerId = normalizeOptionalString((_c = user === null || user === void 0 ? void 0 : user.other) === null || _c === void 0 ? void 0 : _c.id_customer);
968
+ dbName = resolveAssistantDatabaseName(input.database, input.mongo);
969
+ db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
970
+ baseQuery = normalizeMongoQuery(input.query);
971
+ if (!isSuperAdmin && (collection === 'users' || collection === 'user-versions')) {
972
+ userId = normalizeOptionalString(user === null || user === void 0 ? void 0 : user._id);
973
+ if (!userId) {
974
+ throw new Error('AI assistant mongo aggregate: Access denied.');
975
+ }
976
+ baseQuery = {
977
+ $and: [baseQuery, { _id: userId }]
978
+ };
979
+ }
980
+ normalizedClient = normalizeOptionalString(input.id_client);
981
+ if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 3];
982
+ return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
983
+ case 2:
984
+ _b = _d.sent();
985
+ return [3 /*break*/, 4];
986
+ case 3:
987
+ _b = false;
988
+ _d.label = 4;
989
+ case 4:
990
+ shouldScopeByClient = _b;
991
+ clientScopedQuery = shouldScopeByClient
992
+ ? applyClientScopeFilter(baseQuery, normalizedClient, isSuperAdmin)
993
+ : baseQuery;
994
+ scopedQuery = applyCustomerScopeFilter(clientScopedQuery, collection, customerId, isSuperAdmin);
995
+ normalizedPipeline = normalizeAssistantAggregatePipeline(input.pipeline);
996
+ pipelineWithScope = buildAssistantAggregatePipeline(scopedQuery, normalizedPipeline);
997
+ normalizedOptions = normalizeAssistantAggregateOptions(input.options);
998
+ limitedPipeline = applyAssistantAggregateLimit(pipelineWithScope, normalizedOptions.limit);
999
+ if (containsForbiddenMongoOperators(limitedPipeline)) {
1000
+ throw new Error('AI assistant mongo aggregate: Pipeline contains restricted operators.');
1001
+ }
1002
+ return [4 /*yield*/, db.collection(collection)
1003
+ .aggregate(limitedPipeline, normalizedOptions.aggregateOptions)
1004
+ .toArray()];
1005
+ case 5:
1006
+ documents = _d.sent();
1007
+ sanitizedDocuments = isSuperAdmin
1008
+ ? documents
1009
+ : documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
1010
+ return [2 /*return*/, {
1011
+ documents: sanitizedDocuments
1012
+ }];
1013
+ }
1014
+ });
1015
+ });
1016
+ }
906
1017
  function ensureAssistantReadAccess(context, permissionView, collection) {
907
1018
  return __awaiter(this, void 0, void 0, function () {
908
1019
  var idUser, user, isSuperAdmin, normalizedPermission, normalizedCollection;
@@ -979,6 +1090,76 @@ function normalizeAssistantFindOptions(options) {
979
1090
  includeTotal: normalized.includeTotal === true
980
1091
  };
981
1092
  }
1093
+ function normalizeAssistantAggregatePipeline(pipeline) {
1094
+ if (!Array.isArray(pipeline)) {
1095
+ return [];
1096
+ }
1097
+ return pipeline.filter(function (stage) { return stage && typeof stage === 'object' && !Array.isArray(stage); });
1098
+ }
1099
+ function buildAssistantAggregatePipeline(query, pipeline) {
1100
+ var _a;
1101
+ var scopedPipeline = Array.isArray(pipeline) ? __spreadArray([], __read(pipeline), false) : [];
1102
+ if (!query || !Object.keys(query).length) {
1103
+ return scopedPipeline;
1104
+ }
1105
+ if (scopedPipeline.length && ((_a = scopedPipeline[0]) === null || _a === void 0 ? void 0 : _a.$geoNear) && typeof scopedPipeline[0].$geoNear === 'object') {
1106
+ var geoNearStage = __assign({}, scopedPipeline[0].$geoNear);
1107
+ var existingQuery = geoNearStage.query && typeof geoNearStage.query === 'object' ? geoNearStage.query : {};
1108
+ geoNearStage.query = { $and: [existingQuery, query] };
1109
+ return __spreadArray([{ $geoNear: geoNearStage }], __read(scopedPipeline.slice(1)), false);
1110
+ }
1111
+ return __spreadArray([{ $match: query }], __read(scopedPipeline), false);
1112
+ }
1113
+ function normalizeAssistantAggregateOptions(options) {
1114
+ var normalized = options || {};
1115
+ var allowDiskUse = normalized.allowDiskUse === true ? true : undefined;
1116
+ var maxTimeMS = typeof normalized.maxTimeMS === 'number' && normalized.maxTimeMS > 0
1117
+ ? (0, common_1.round)(normalized.maxTimeMS)
1118
+ : undefined;
1119
+ var limit = typeof normalized.limit === 'number'
1120
+ ? Math.min(Math.max((0, common_1.round)(normalized.limit), 0), AI_ASSISTANT_MONGO_MAX_LIMIT)
1121
+ : undefined;
1122
+ var aggregateOptions = {};
1123
+ if (allowDiskUse !== undefined) {
1124
+ aggregateOptions.allowDiskUse = allowDiskUse;
1125
+ }
1126
+ if (maxTimeMS !== undefined) {
1127
+ aggregateOptions.maxTimeMS = maxTimeMS;
1128
+ }
1129
+ return {
1130
+ aggregateOptions: aggregateOptions,
1131
+ limit: limit
1132
+ };
1133
+ }
1134
+ function findAggregateLimit(pipeline) {
1135
+ for (var i = 0; i < pipeline.length; i += 1) {
1136
+ var stage = pipeline[i];
1137
+ if (!stage || typeof stage !== 'object') {
1138
+ continue;
1139
+ }
1140
+ var limit = stage.$limit;
1141
+ if (typeof limit === 'number' && Number.isFinite(limit)) {
1142
+ return limit;
1143
+ }
1144
+ }
1145
+ return null;
1146
+ }
1147
+ function applyAssistantAggregateLimit(pipeline, limit) {
1148
+ var normalizedPipeline = Array.isArray(pipeline) ? __spreadArray([], __read(pipeline), false) : [];
1149
+ var maxLimit = AI_ASSISTANT_MONGO_MAX_LIMIT;
1150
+ var requestedLimit = typeof limit === 'number' && limit > 0
1151
+ ? Math.min(limit, maxLimit)
1152
+ : AI_ASSISTANT_MONGO_DEFAULT_LIMIT;
1153
+ var existingLimit = findAggregateLimit(normalizedPipeline);
1154
+ if (existingLimit === null) {
1155
+ normalizedPipeline.push({ $limit: requestedLimit });
1156
+ return normalizedPipeline;
1157
+ }
1158
+ if (existingLimit > maxLimit) {
1159
+ normalizedPipeline.push({ $limit: maxLimit });
1160
+ }
1161
+ return normalizedPipeline;
1162
+ }
982
1163
  function normalizeMongoQuery(query) {
983
1164
  var normalized = query && typeof query === 'object' ? query : {};
984
1165
  if (containsForbiddenMongoOperators(normalized)) {