@oondemand/oon-core-back 0.3.65 → 0.3.67

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oondemand/oon-core-back",
3
- "version": "0.3.65",
3
+ "version": "0.3.67",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/oondemand/oon-platform.git",
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
 
3
3
  const express = require("express");
4
+ const mongoose = require("mongoose");
4
5
  const GenericError = require("../../core/errors/GenericError");
5
6
  const auth = require("../../core/middlewares/auth");
6
7
  const { rbac } = require("../../core/middlewares/rbac");
7
8
  const { asyncHandler } = require("../../core/utils/helpers");
8
- const { getIntegrationModels } = require("./models");
9
+ const { getIntegrationModels, OUTBOX_STATUSES } = require("./models");
9
10
  const { getIntegrationProvider, listIntegrationProviders } = require("./registry");
10
11
  const {
11
12
  archiveIntegrationTicket,
@@ -33,6 +34,48 @@ function pagination(query = {}) {
33
34
  return { limit, page, skip: (page - 1) * limit };
34
35
  }
35
36
 
37
+ function escapeRegExp(value) {
38
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
39
+ }
40
+
41
+ function buildQueueFilter(query = {}, options = {}) {
42
+ const includeStatus = options.includeStatus !== false;
43
+ const filter = {};
44
+ for (const field of ["provider", "resource", "operation", "aggregateType", "aggregateId"]) {
45
+ if (query[field]) filter[field] = String(query[field]);
46
+ }
47
+ if (includeStatus && query.status) filter.status = String(query.status);
48
+
49
+ const search = String(query.search || "").trim().slice(0, 160);
50
+ if (search) {
51
+ const pattern = new RegExp(escapeRegExp(search), "i");
52
+ const clauses = [
53
+ { handler: pattern },
54
+ { resource: pattern },
55
+ { operation: pattern },
56
+ { aggregateType: pattern },
57
+ { aggregateId: pattern },
58
+ { idempotencyKey: pattern },
59
+ ];
60
+ if (mongoose.isValidObjectId(search)) clauses.unshift({ _id: new mongoose.Types.ObjectId(search) });
61
+ filter.$or = clauses;
62
+ }
63
+ return filter;
64
+ }
65
+
66
+ async function queueStatusSummary(Outbox, filter = {}) {
67
+ const rows = await Outbox.aggregate([
68
+ { $match: filter },
69
+ { $group: { _id: "$status", count: { $sum: 1 } } },
70
+ ]);
71
+ const statuses = Object.fromEntries(OUTBOX_STATUSES.map((status) => [status, 0]));
72
+ for (const row of rows) statuses[String(row._id)] = Number(row.count || 0);
73
+ return {
74
+ total: Object.values(statuses).reduce((sum, count) => sum + Number(count || 0), 0),
75
+ statuses,
76
+ };
77
+ }
78
+
36
79
  function requireProviderExtension(provider, method, message) {
37
80
  if (typeof provider[method] !== "function") {
38
81
  throw new GenericError(message || `O provedor ${provider.label} não oferece ${method}.`, {
@@ -144,16 +187,16 @@ function buildIntegrationRouter() {
144
187
  router.get("/queue", rbac(READ_ROLES), asyncHandler(async (req, res) => {
145
188
  const { Outbox } = getIntegrationModels();
146
189
  const { limit, page, skip } = pagination(req.query);
147
- const filter = {};
148
- for (const field of ["provider", "resource", "operation", "status", "aggregateType", "aggregateId"]) {
149
- if (req.query[field]) filter[field] = String(req.query[field]);
150
- }
151
- const [results, totalItems] = await Promise.all([
190
+ const filter = buildQueueFilter(req.query);
191
+ const summaryFilter = buildQueueFilter(req.query, { includeStatus: false });
192
+ const [results, totalItems, summary] = await Promise.all([
152
193
  Outbox.find(filter).sort({ createdAt: -1 }).skip(skip).limit(limit).lean(),
153
194
  Outbox.countDocuments(filter),
195
+ queueStatusSummary(Outbox, summaryFilter),
154
196
  ]);
155
197
  res.json({
156
198
  results: sanitizeIntegrationValue(results),
199
+ summary,
157
200
  pagination: {
158
201
  currentPage: page,
159
202
  totalItems,
@@ -222,4 +265,4 @@ function buildIntegrationRouter() {
222
265
  return router;
223
266
  }
224
267
 
225
- module.exports = { buildIntegrationRouter };
268
+ module.exports = { buildIntegrationRouter, buildQueueFilter, queueStatusSummary };
@@ -13,6 +13,21 @@ function truncate(value, limit) {
13
13
  return `${value.slice(0, limit)}…[truncado:${value.length - limit}]`;
14
14
  }
15
15
 
16
+ function binarySummary(value) {
17
+ const size = Number(value?.byteLength ?? value?.length ?? 0);
18
+ const type = value?.constructor?.name || "Binary";
19
+ return `[${type}:${size} bytes]`;
20
+ }
21
+
22
+ function bsonObjectId(value) {
23
+ if (!value || typeof value !== "object") return null;
24
+ const isObjectId = value._bsontype === "ObjectId" || value.constructor?.name === "ObjectId";
25
+ if (!isObjectId) return null;
26
+ if (typeof value.toHexString === "function") return value.toHexString();
27
+ const text = String(value);
28
+ return /^[a-f\d]{24}$/i.test(text) ? text : null;
29
+ }
30
+
16
31
  function sanitizeIntegrationValue(value, options = {}, state = { depth: 0, seen: new WeakSet() }) {
17
32
  const config = { ...DEFAULTS, ...options };
18
33
  if (value == null || typeof value === "boolean" || typeof value === "number") return value;
@@ -28,6 +43,12 @@ function sanitizeIntegrationValue(value, options = {}, state = { depth: 0, seen:
28
43
  };
29
44
  }
30
45
  if (typeof value !== "object") return truncate(String(value), config.maxStringLength);
46
+
47
+ const objectId = bsonObjectId(value);
48
+ if (objectId) return objectId;
49
+ if (Buffer.isBuffer(value) || ArrayBuffer.isView(value)) return binarySummary(value);
50
+ if (value instanceof ArrayBuffer) return binarySummary(value);
51
+
31
52
  if (state.depth >= config.maxDepth) return "[limite-de-profundidade]";
32
53
  if (state.seen.has(value)) return "[referência-circular]";
33
54
  state.seen.add(value);