@oondemand/oon-core-back 0.3.55 → 0.3.57
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/bin/integration-worker.js +31 -0
- package/package.json +3 -2
- package/src/boot/createApp.js +9 -9
- package/src/boot/database.js +25 -15
- package/src/index.js +6 -1
- package/src/modules/integrations/index.js +26 -0
- package/src/modules/integrations/models.js +111 -0
- package/src/modules/integrations/registry.js +154 -0
- package/src/modules/integrations/routes.js +167 -0
- package/src/modules/integrations/runtime/inbox.js +123 -0
- package/src/modules/integrations/runtime/lease.js +94 -0
- package/src/modules/integrations/runtime/outbox.js +199 -0
- package/src/modules/integrations/runtime/sync.js +85 -0
- package/src/modules/integrations/runtime/tracking.js +89 -0
- package/src/modules/integrations/runtime/utils.js +71 -0
- package/src/modules/integrations/runtime.js +10 -0
- package/src/modules/integrations/sanitizer.js +75 -0
- package/src/modules/integrations/worker.js +56 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const SENSITIVE_KEY = /(authorization|cookie|password|passwd|secret|token|api[-_]?key|app[-_]?key|app[-_]?secret|private[-_]?key|credential|senha)/i;
|
|
4
|
+
const DEFAULTS = {
|
|
5
|
+
maxDepth: 6,
|
|
6
|
+
maxArrayItems: 20,
|
|
7
|
+
maxObjectKeys: 100,
|
|
8
|
+
maxStringLength: 4000,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function truncate(value, limit) {
|
|
12
|
+
if (value.length <= limit) return value;
|
|
13
|
+
return `${value.slice(0, limit)}…[truncado:${value.length - limit}]`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sanitizeIntegrationValue(value, options = {}, state = { depth: 0, seen: new WeakSet() }) {
|
|
17
|
+
const config = { ...DEFAULTS, ...options };
|
|
18
|
+
if (value == null || typeof value === "boolean" || typeof value === "number") return value;
|
|
19
|
+
if (typeof value === "bigint") return String(value);
|
|
20
|
+
if (typeof value === "string") return truncate(value, config.maxStringLength);
|
|
21
|
+
if (value instanceof Date) return value.toISOString();
|
|
22
|
+
if (value instanceof Error) {
|
|
23
|
+
return {
|
|
24
|
+
name: value.name,
|
|
25
|
+
message: truncate(String(value.message || value), config.maxStringLength),
|
|
26
|
+
code: value.code,
|
|
27
|
+
statusCode: value.statusCode || value.response?.status,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (typeof value !== "object") return truncate(String(value), config.maxStringLength);
|
|
31
|
+
if (state.depth >= config.maxDepth) return "[limite-de-profundidade]";
|
|
32
|
+
if (state.seen.has(value)) return "[referência-circular]";
|
|
33
|
+
state.seen.add(value);
|
|
34
|
+
|
|
35
|
+
const nextState = { depth: state.depth + 1, seen: state.seen };
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
const items = value
|
|
38
|
+
.slice(0, config.maxArrayItems)
|
|
39
|
+
.map((item) => sanitizeIntegrationValue(item, config, nextState));
|
|
40
|
+
if (value.length > config.maxArrayItems) {
|
|
41
|
+
items.push({ _truncated: value.length - config.maxArrayItems });
|
|
42
|
+
}
|
|
43
|
+
return items;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const output = {};
|
|
47
|
+
const entries = Object.entries(value).slice(0, config.maxObjectKeys);
|
|
48
|
+
for (const [key, item] of entries) {
|
|
49
|
+
output[key] = SENSITIVE_KEY.test(key)
|
|
50
|
+
? "[REDACTED]"
|
|
51
|
+
: sanitizeIntegrationValue(item, config, nextState);
|
|
52
|
+
}
|
|
53
|
+
if (Object.keys(value).length > config.maxObjectKeys) {
|
|
54
|
+
output._truncatedKeys = Object.keys(value).length - config.maxObjectKeys;
|
|
55
|
+
}
|
|
56
|
+
return output;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function sanitizeIntegrationError(error, options = {}) {
|
|
60
|
+
const sanitized = sanitizeIntegrationValue(error, options);
|
|
61
|
+
if (typeof sanitized === "string") return { message: sanitized };
|
|
62
|
+
return {
|
|
63
|
+
name: sanitized?.name || error?.name || "Error",
|
|
64
|
+
message: sanitized?.message || String(error?.message || error || "Falha desconhecida."),
|
|
65
|
+
code: sanitized?.code || error?.code,
|
|
66
|
+
statusCode: sanitized?.statusCode || error?.statusCode || error?.response?.status,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
DEFAULT_SANITIZE_OPTIONS: DEFAULTS,
|
|
72
|
+
SENSITIVE_KEY,
|
|
73
|
+
sanitizeIntegrationError,
|
|
74
|
+
sanitizeIntegrationValue,
|
|
75
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { loadCentral } = require("../../boot/loadCentral");
|
|
4
|
+
const { connectDB } = require("../../boot/database");
|
|
5
|
+
const { listIntegrationProviders } = require("./registry");
|
|
6
|
+
const { processIntegrationQueue, processWebhookInbox } = require("./runtime");
|
|
7
|
+
|
|
8
|
+
function delay(ms) {
|
|
9
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function drainOnce(options = {}) {
|
|
13
|
+
const providers = options.provider
|
|
14
|
+
? [{ key: String(options.provider).trim().toLowerCase() }]
|
|
15
|
+
: listIntegrationProviders();
|
|
16
|
+
const results = [];
|
|
17
|
+
for (const provider of providers) {
|
|
18
|
+
const [queue, events] = await Promise.all([
|
|
19
|
+
processIntegrationQueue({ ...options, provider: provider.key, limit: options.batchSize || options.limit || 20 }),
|
|
20
|
+
processWebhookInbox({ ...options, provider: provider.key, limit: options.webhookBatchSize || 20 }),
|
|
21
|
+
]);
|
|
22
|
+
results.push({ provider: provider.key, queue, events });
|
|
23
|
+
}
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function runIntegrationWorker(options = {}) {
|
|
28
|
+
const cwd = options.cwd || process.cwd();
|
|
29
|
+
loadCentral(cwd);
|
|
30
|
+
await connectDB();
|
|
31
|
+
const once = options.once === true;
|
|
32
|
+
const intervalMs = Math.max(
|
|
33
|
+
1000,
|
|
34
|
+
Number(options.intervalMs || process.env.OON_INTEGRATION_WORKER_INTERVAL_MS || 15_000),
|
|
35
|
+
);
|
|
36
|
+
let stopping = false;
|
|
37
|
+
const stop = () => { stopping = true; };
|
|
38
|
+
process.once("SIGTERM", stop);
|
|
39
|
+
process.once("SIGINT", stop);
|
|
40
|
+
|
|
41
|
+
do {
|
|
42
|
+
const results = await drainOnce(options);
|
|
43
|
+
if (options.logger !== false) {
|
|
44
|
+
const processed = results.reduce(
|
|
45
|
+
(sum, item) => sum + item.queue.processed + item.events.processed,
|
|
46
|
+
0,
|
|
47
|
+
);
|
|
48
|
+
if (processed) console.log(`[integration-worker] processados=${processed}`);
|
|
49
|
+
}
|
|
50
|
+
if (!once && !stopping) await delay(intervalMs);
|
|
51
|
+
} while (!once && !stopping);
|
|
52
|
+
|
|
53
|
+
return { stopped: true };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { drainOnce, runIntegrationWorker };
|