@oondemand/oon-core-back 0.5.6 → 0.6.1
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 +2 -3
- package/src/api/core.routes.js +0 -2
- package/src/boot/createApp.js +0 -7
- package/src/boot/database.js +0 -34
- package/src/boot/loadCentral.js +0 -6
- package/src/capabilities/pdfRendering.js +9 -9
- package/src/core/define.js +1 -6
- package/src/core/models/Sistema.js +2 -10
- package/src/core/registry.js +0 -8
- package/src/deploy/render.js +0 -2
- package/src/deploy/templates/secret.yaml +0 -2
- package/src/index.js +2 -16
- package/src/manifest/appManifest.js +5 -22
- package/bin/integration-worker.js +0 -31
- package/src/modules/integrations/index.js +0 -26
- package/src/modules/integrations/models.js +0 -112
- package/src/modules/integrations/registry.js +0 -171
- package/src/modules/integrations/routes.js +0 -343
- package/src/modules/integrations/runtime/inbox.js +0 -134
- package/src/modules/integrations/runtime/lease.js +0 -94
- package/src/modules/integrations/runtime/outbox.js +0 -199
- package/src/modules/integrations/runtime/sync.js +0 -85
- package/src/modules/integrations/runtime/tracking.js +0 -89
- package/src/modules/integrations/runtime/utils.js +0 -71
- package/src/modules/integrations/runtime.js +0 -10
- package/src/modules/integrations/sanitizer.js +0 -96
- package/src/modules/integrations/worker.js +0 -56
- package/src/modules/omie/client.js +0 -282
- package/src/modules/omie/definitions.js +0 -212
- package/src/modules/omie/index.js +0 -33
- package/src/modules/omie/models.js +0 -377
- package/src/modules/omie/provider.js +0 -529
|
@@ -1,56 +0,0 @@
|
|
|
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 };
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const axios = require("axios");
|
|
4
|
-
const GenericError = require("../../core/errors/GenericError");
|
|
5
|
-
const {
|
|
6
|
-
sanitizeIntegrationError,
|
|
7
|
-
sanitizeIntegrationValue,
|
|
8
|
-
} = require("../integrations/sanitizer");
|
|
9
|
-
|
|
10
|
-
const RETRYABLE_HTTP = new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
11
|
-
|
|
12
|
-
class OmieApiError extends GenericError {
|
|
13
|
-
constructor(message, options = {}) {
|
|
14
|
-
super(message, {
|
|
15
|
-
statusCode: options.statusCode || 502,
|
|
16
|
-
details: options.details,
|
|
17
|
-
cause: options.cause,
|
|
18
|
-
});
|
|
19
|
-
this.name = "OmieApiError";
|
|
20
|
-
this.code = options.code || "OMIE_API_ERROR";
|
|
21
|
-
this.retryable = options.retryable !== false;
|
|
22
|
-
this.response = options.response;
|
|
23
|
-
this.trace = options.trace;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function getPath(value, path, fallback) {
|
|
28
|
-
if (!path) return value ?? fallback;
|
|
29
|
-
const result = String(path).split(".").filter(Boolean).reduce(
|
|
30
|
-
(current, part) => (current == null ? undefined : current[part]),
|
|
31
|
-
value,
|
|
32
|
-
);
|
|
33
|
-
return result === undefined ? fallback : result;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function resolveTemplate(value, scope = {}) {
|
|
37
|
-
if (Array.isArray(value)) return value.map((item) => resolveTemplate(item, scope));
|
|
38
|
-
if (!value || typeof value !== "object") {
|
|
39
|
-
if (typeof value !== "string" || !value.startsWith("$")) return value;
|
|
40
|
-
const [root, ...parts] = value.slice(1).split(".");
|
|
41
|
-
return getPath(scope[root], parts.join("."));
|
|
42
|
-
}
|
|
43
|
-
if (Object.prototype.hasOwnProperty.call(value, "$value")) return value.$value;
|
|
44
|
-
if (Object.prototype.hasOwnProperty.call(value, "$path")) {
|
|
45
|
-
const [root, ...parts] = String(value.$path).replace(/^\$/, "").split(".");
|
|
46
|
-
return getPath(scope[root], parts.join("."), value.default);
|
|
47
|
-
}
|
|
48
|
-
return Object.fromEntries(
|
|
49
|
-
Object.entries(value).map(([key, item]) => [key, resolveTemplate(item, scope)]),
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function normalizeEndpoint(baseUrl, endpoint) {
|
|
54
|
-
const base = String(baseUrl || "").trim().replace(/\/+$/, "");
|
|
55
|
-
const value = String(endpoint || "").trim();
|
|
56
|
-
if (!base || !value) {
|
|
57
|
-
throw new OmieApiError("A chamada Omie exige baseUrl e endpoint declarados pela Central.", {
|
|
58
|
-
statusCode: 422,
|
|
59
|
-
retryable: false,
|
|
60
|
-
code: "OMIE_CALL_INVALID",
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
const absolute = /^https?:\/\//i.test(value) ? value : `${base}/${value.replace(/^\/+/, "")}`;
|
|
64
|
-
let parsed;
|
|
65
|
-
try {
|
|
66
|
-
parsed = new URL(absolute);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
throw new OmieApiError("Endpoint Omie inválido.", {
|
|
69
|
-
statusCode: 422,
|
|
70
|
-
retryable: false,
|
|
71
|
-
code: "OMIE_ENDPOINT_INVALID",
|
|
72
|
-
cause: error,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
if (!["https:", "http:"].includes(parsed.protocol)) {
|
|
76
|
-
throw new OmieApiError("Endpoint Omie deve usar HTTP ou HTTPS.", {
|
|
77
|
-
statusCode: 422,
|
|
78
|
-
retryable: false,
|
|
79
|
-
code: "OMIE_ENDPOINT_PROTOCOL",
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return parsed.toString();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function responseError(body, statusCode) {
|
|
86
|
-
const code = body?.faultcode ?? body?.code ?? body?.codigo_status;
|
|
87
|
-
const description = body?.faultstring ?? body?.description ?? body?.descricao_status;
|
|
88
|
-
if (statusCode >= 200 && statusCode < 300 && !description) return null;
|
|
89
|
-
if (statusCode >= 200 && statusCode < 300 && String(code ?? "0") === "0") return null;
|
|
90
|
-
return new OmieApiError(description || `Omie retornou HTTP ${statusCode}.`, {
|
|
91
|
-
statusCode,
|
|
92
|
-
code: String(code || "OMIE_RESPONSE_ERROR"),
|
|
93
|
-
retryable: RETRYABLE_HTTP.has(Number(statusCode)),
|
|
94
|
-
response: sanitizeIntegrationValue(body),
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function normalizedStringList(value) {
|
|
99
|
-
const values = Array.isArray(value) ? value : value === undefined || value === null ? [] : [value];
|
|
100
|
-
return values.map((item) => String(item).trim()).filter(Boolean);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function isConfiguredEmptyResult(callDefinition = {}, body = {}) {
|
|
104
|
-
const code = String(body?.faultcode ?? body?.code ?? body?.codigo_status ?? "").trim();
|
|
105
|
-
const description = String(
|
|
106
|
-
body?.faultstring ?? body?.description ?? body?.descricao_status ?? "",
|
|
107
|
-
).trim();
|
|
108
|
-
const codes = normalizedStringList(callDefinition.emptyResultFaultCodes);
|
|
109
|
-
const messages = normalizedStringList(callDefinition.emptyResultMessages);
|
|
110
|
-
return (code && codes.includes(code))
|
|
111
|
-
|| (description && messages.some((message) => description.includes(message)));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function retryableTransportError(error) {
|
|
115
|
-
const statusCode = Number(error?.response?.status || error?.statusCode || 0);
|
|
116
|
-
return RETRYABLE_HTTP.has(statusCode)
|
|
117
|
-
|| ["ECONNABORTED", "ECONNRESET", "ETIMEDOUT", "EAI_AGAIN"].includes(error?.code)
|
|
118
|
-
|| error?.name === "AbortError";
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function wait(ms) {
|
|
122
|
-
return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async function resolveCallParam(callDefinition, input = {}, context = {}) {
|
|
126
|
-
const declared = typeof callDefinition.param === "function"
|
|
127
|
-
? await callDefinition.param({ input, context, cursor: context.cursor })
|
|
128
|
-
: callDefinition.param;
|
|
129
|
-
return resolveTemplate(declared ?? [{}], {
|
|
130
|
-
input,
|
|
131
|
-
context,
|
|
132
|
-
cursor: context.cursor,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function createOmieClient(options = {}) {
|
|
137
|
-
const credentials = options.credentials || {};
|
|
138
|
-
const appKey = String(credentials.appKey || "").trim();
|
|
139
|
-
const appSecret = String(credentials.appSecret || "").trim();
|
|
140
|
-
const baseUrl = String(credentials.baseUrl || options.baseUrl || "").trim();
|
|
141
|
-
const timeoutMs = Math.max(100, Number(options.timeoutMs || 30_000));
|
|
142
|
-
const maxAttempts = Math.max(1, Number(options.maxAttempts || 3));
|
|
143
|
-
const retryInitialMs = Math.max(0, Number(options.retryInitialMs ?? 500));
|
|
144
|
-
const transport = options.transport || (async ({ url, body, timeout }) => {
|
|
145
|
-
const response = await axios.post(url, body, {
|
|
146
|
-
timeout,
|
|
147
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
148
|
-
validateStatus: () => true,
|
|
149
|
-
});
|
|
150
|
-
return { status: response.status, data: response.data };
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
if (!appKey || !appSecret) {
|
|
154
|
-
throw new OmieApiError("Credenciais Omie não configuradas.", {
|
|
155
|
-
statusCode: 422,
|
|
156
|
-
retryable: false,
|
|
157
|
-
code: "OMIE_CREDENTIALS_MISSING",
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function execute(callDefinition, input = {}, context = {}) {
|
|
162
|
-
if (!callDefinition || typeof callDefinition !== "object") {
|
|
163
|
-
throw new OmieApiError("Definição de chamada Omie inválida.", {
|
|
164
|
-
statusCode: 422,
|
|
165
|
-
retryable: false,
|
|
166
|
-
code: "OMIE_CALL_INVALID",
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
const url = normalizeEndpoint(baseUrl, callDefinition.endpoint);
|
|
170
|
-
const call = String(callDefinition.call || "").trim();
|
|
171
|
-
if (!call) {
|
|
172
|
-
throw new OmieApiError("A Central deve declarar a operação/call Omie.", {
|
|
173
|
-
statusCode: 422,
|
|
174
|
-
retryable: false,
|
|
175
|
-
code: "OMIE_CALL_MISSING",
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
const resolvedParam = await resolveCallParam(callDefinition, input, context);
|
|
179
|
-
const body = {
|
|
180
|
-
call,
|
|
181
|
-
app_key: appKey,
|
|
182
|
-
app_secret: appSecret,
|
|
183
|
-
param: Array.isArray(resolvedParam) ? resolvedParam : [resolvedParam],
|
|
184
|
-
};
|
|
185
|
-
const callMaxAttempts = Math.max(1, Number(callDefinition.maxAttempts ?? maxAttempts));
|
|
186
|
-
let lastError;
|
|
187
|
-
|
|
188
|
-
for (let attempt = 1; attempt <= callMaxAttempts; attempt += 1) {
|
|
189
|
-
const startedAt = Date.now();
|
|
190
|
-
const trace = {
|
|
191
|
-
endpoint: callDefinition.endpoint,
|
|
192
|
-
call,
|
|
193
|
-
attempt,
|
|
194
|
-
request: sanitizeIntegrationValue({ call, param: body.param }),
|
|
195
|
-
};
|
|
196
|
-
try {
|
|
197
|
-
const response = await transport({
|
|
198
|
-
url,
|
|
199
|
-
body,
|
|
200
|
-
timeout: Number(callDefinition.timeoutMs || timeoutMs),
|
|
201
|
-
attempt,
|
|
202
|
-
});
|
|
203
|
-
const status = Number(response?.status || 200);
|
|
204
|
-
const data = response?.data ?? {};
|
|
205
|
-
const emptyResult = isConfiguredEmptyResult(callDefinition, data);
|
|
206
|
-
trace.httpStatus = status;
|
|
207
|
-
trace.response = sanitizeIntegrationValue(data);
|
|
208
|
-
trace.durationMs = Date.now() - startedAt;
|
|
209
|
-
trace.emptyResult = emptyResult;
|
|
210
|
-
if (!emptyResult) {
|
|
211
|
-
const normalized = responseError(data, status);
|
|
212
|
-
if (normalized) throw normalized;
|
|
213
|
-
}
|
|
214
|
-
trace.status = "success";
|
|
215
|
-
context.recordRequest?.(trace);
|
|
216
|
-
return { data, trace, emptyResult };
|
|
217
|
-
} catch (error) {
|
|
218
|
-
const normalized = error instanceof OmieApiError
|
|
219
|
-
? error
|
|
220
|
-
: new OmieApiError(error?.message || "Falha ao chamar a API Omie.", {
|
|
221
|
-
statusCode: Number(error?.response?.status || 502),
|
|
222
|
-
retryable: retryableTransportError(error),
|
|
223
|
-
code: error?.code || "OMIE_TRANSPORT_ERROR",
|
|
224
|
-
response: sanitizeIntegrationValue(error?.response?.data || {}),
|
|
225
|
-
cause: error,
|
|
226
|
-
});
|
|
227
|
-
trace.status = "error";
|
|
228
|
-
trace.durationMs = Date.now() - startedAt;
|
|
229
|
-
trace.error = sanitizeIntegrationError(normalized);
|
|
230
|
-
context.recordRequest?.(trace);
|
|
231
|
-
normalized.trace = trace;
|
|
232
|
-
lastError = normalized;
|
|
233
|
-
if (!normalized.retryable || attempt >= callMaxAttempts) throw normalized;
|
|
234
|
-
const delay = Math.min(5_000, retryInitialMs * (2 ** (attempt - 1)));
|
|
235
|
-
await wait(delay);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
throw lastError;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function paginate(callDefinition, input = {}, context = {}) {
|
|
242
|
-
const pagination = callDefinition.pagination || {};
|
|
243
|
-
const items = [];
|
|
244
|
-
let page = Number(input.page || pagination.startPage || 1);
|
|
245
|
-
let totalPages = page;
|
|
246
|
-
let lastResponse = {};
|
|
247
|
-
do {
|
|
248
|
-
const pageInput = {
|
|
249
|
-
...input,
|
|
250
|
-
page,
|
|
251
|
-
pageSize: Number(input.pageSize || pagination.pageSize || 100),
|
|
252
|
-
};
|
|
253
|
-
const result = await execute(callDefinition, pageInput, context);
|
|
254
|
-
lastResponse = result.data;
|
|
255
|
-
const pageItems = getPath(lastResponse, pagination.itemsPath, []);
|
|
256
|
-
if (!Array.isArray(pageItems)) {
|
|
257
|
-
throw new OmieApiError(`itemsPath inválido na chamada ${callDefinition.call}.`, {
|
|
258
|
-
statusCode: 422,
|
|
259
|
-
retryable: false,
|
|
260
|
-
code: "OMIE_ITEMS_PATH_INVALID",
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
items.push(...pageItems);
|
|
264
|
-
totalPages = Number(getPath(lastResponse, pagination.totalPagesPath, page)) || page;
|
|
265
|
-
page += 1;
|
|
266
|
-
} while (page <= totalPages && (!pagination.maxPages || page <= Number(pagination.maxPages)));
|
|
267
|
-
return { items, response: lastResponse, totalPages };
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return { execute, paginate };
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
module.exports = {
|
|
274
|
-
OmieApiError,
|
|
275
|
-
createOmieClient,
|
|
276
|
-
getPath,
|
|
277
|
-
isConfiguredEmptyResult,
|
|
278
|
-
normalizeEndpoint,
|
|
279
|
-
resolveCallParam,
|
|
280
|
-
resolveTemplate,
|
|
281
|
-
responseError,
|
|
282
|
-
};
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const registry = require("../../core/registry");
|
|
4
|
-
const GenericError = require("../../core/errors/GenericError");
|
|
5
|
-
const { normalizeKey } = require("../integrations/registry");
|
|
6
|
-
|
|
7
|
-
const LIST_MODES = new Set(["import", "full", "incremental", "individual"]);
|
|
8
|
-
const DIRECTIONS = new Set(["inbound", "outbound", "bidirectional"]);
|
|
9
|
-
const CONFLICT_POLICIES = new Set(["remote-wins", "local-wins", "skip", "error"]);
|
|
10
|
-
|
|
11
|
-
function cloneDeclarative(value) {
|
|
12
|
-
if (Array.isArray(value)) return value.map(cloneDeclarative);
|
|
13
|
-
if (!value || typeof value !== "object") return value;
|
|
14
|
-
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneDeclarative(item)]));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function normalizeCall(key, definition = {}) {
|
|
18
|
-
const callKey = normalizeKey(key, "identificador da chamada Omie");
|
|
19
|
-
if (!definition.endpoint || !definition.call) {
|
|
20
|
-
throw new GenericError(
|
|
21
|
-
`A chamada Omie ${callKey} deve declarar endpoint e call.`,
|
|
22
|
-
{ statusCode: 422 },
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
...cloneDeclarative(definition),
|
|
27
|
-
key: callKey,
|
|
28
|
-
label: String(definition.label || callKey),
|
|
29
|
-
connectionTest: definition.connectionTest === true,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function normalizeList(definition = {}, index = 0) {
|
|
34
|
-
const key = normalizeKey(definition.key, `identificador da lista Omie ${index + 1}`);
|
|
35
|
-
const mode = String(definition.mode || "full").toLowerCase();
|
|
36
|
-
const direction = String(definition.direction || "inbound").toLowerCase();
|
|
37
|
-
const conflict = String(definition.policies?.conflict || "remote-wins").toLowerCase();
|
|
38
|
-
if (!LIST_MODES.has(mode)) {
|
|
39
|
-
throw new GenericError(`Modo inválido na lista Omie ${key}: ${mode}.`, { statusCode: 422 });
|
|
40
|
-
}
|
|
41
|
-
if (!DIRECTIONS.has(direction)) {
|
|
42
|
-
throw new GenericError(`Direção inválida na lista Omie ${key}: ${direction}.`, { statusCode: 422 });
|
|
43
|
-
}
|
|
44
|
-
if (!CONFLICT_POLICIES.has(conflict)) {
|
|
45
|
-
throw new GenericError(`Política de conflito inválida na lista Omie ${key}: ${conflict}.`, {
|
|
46
|
-
statusCode: 422,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
if (definition.filter !== undefined && typeof definition.filter !== "function") {
|
|
50
|
-
throw new GenericError(`O filtro da lista Omie ${key} deve ser uma função.`, {
|
|
51
|
-
statusCode: 422,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
if (!definition.call) {
|
|
55
|
-
throw new GenericError(`A lista Omie ${key} deve referenciar uma chamada declarada.`, {
|
|
56
|
-
statusCode: 422,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
if (!definition.target?.model || !definition.target?.externalKey) {
|
|
60
|
-
throw new GenericError(
|
|
61
|
-
`A lista Omie ${key} deve declarar target.model e target.externalKey.`,
|
|
62
|
-
{ statusCode: 422 },
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
...cloneDeclarative(definition),
|
|
67
|
-
key,
|
|
68
|
-
label: String(definition.label || key),
|
|
69
|
-
description: String(definition.description || ""),
|
|
70
|
-
call: normalizeKey(definition.call, `chamada da lista ${key}`),
|
|
71
|
-
mode,
|
|
72
|
-
direction,
|
|
73
|
-
order: Number(definition.order ?? (index + 1) * 10),
|
|
74
|
-
includeInFullSync: definition.includeInFullSync !== false,
|
|
75
|
-
policies: {
|
|
76
|
-
create: definition.policies?.create !== false,
|
|
77
|
-
update: definition.policies?.update !== false,
|
|
78
|
-
inactivate: definition.policies?.inactivate === true,
|
|
79
|
-
conflict,
|
|
80
|
-
...(definition.policies || {}),
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function normalizeWebhook(definition = {}, index = 0) {
|
|
86
|
-
const eventType = String(definition.eventType || "*").trim();
|
|
87
|
-
if (!eventType) {
|
|
88
|
-
throw new GenericError(`Webhook Omie ${index + 1} sem eventType.`, { statusCode: 422 });
|
|
89
|
-
}
|
|
90
|
-
const actions = Array.isArray(definition.actions) ? definition.actions : [];
|
|
91
|
-
actions.forEach((action, actionIndex) => {
|
|
92
|
-
if (!action?.handler) {
|
|
93
|
-
throw new GenericError(
|
|
94
|
-
`A ação ${actionIndex + 1} do webhook ${eventType} deve declarar handler.`,
|
|
95
|
-
{ statusCode: 422 },
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
return {
|
|
100
|
-
...cloneDeclarative(definition),
|
|
101
|
-
eventType,
|
|
102
|
-
resource: String(definition.resource || ""),
|
|
103
|
-
actions,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function collectOmieDefinitions() {
|
|
108
|
-
const result = {
|
|
109
|
-
calls: {},
|
|
110
|
-
lists: [],
|
|
111
|
-
webhooks: [],
|
|
112
|
-
handlers: {},
|
|
113
|
-
instances: [],
|
|
114
|
-
legacy: {},
|
|
115
|
-
};
|
|
116
|
-
for (const declaration of registry.listOmieMappings()) {
|
|
117
|
-
if (typeof declaration.toOmie === "function") {
|
|
118
|
-
const legacyKey = normalizeKey(declaration.name, "mapping Omie legado");
|
|
119
|
-
result.legacy[legacyKey] = {
|
|
120
|
-
key: legacyKey,
|
|
121
|
-
label: String(declaration.label || declaration.name || legacyKey),
|
|
122
|
-
toOmie: declaration.toOmie,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
for (const [key, call] of Object.entries(declaration.calls || {})) {
|
|
126
|
-
const normalized = normalizeCall(key, call);
|
|
127
|
-
if (result.calls[normalized.key]) {
|
|
128
|
-
throw new GenericError(`Chamada Omie duplicada: ${normalized.key}.`, { statusCode: 422 });
|
|
129
|
-
}
|
|
130
|
-
result.calls[normalized.key] = normalized;
|
|
131
|
-
}
|
|
132
|
-
for (const list of declaration.lists || []) result.lists.push(normalizeList(list, result.lists.length));
|
|
133
|
-
for (const webhook of declaration.webhooks || []) {
|
|
134
|
-
result.webhooks.push(normalizeWebhook(webhook, result.webhooks.length));
|
|
135
|
-
}
|
|
136
|
-
for (const [handler, implementation] of Object.entries(declaration.handlers || {})) {
|
|
137
|
-
if (typeof implementation !== "function") {
|
|
138
|
-
throw new GenericError(`Handler Omie ${handler} deve ser uma função.`, { statusCode: 422 });
|
|
139
|
-
}
|
|
140
|
-
if (result.handlers[handler]) {
|
|
141
|
-
throw new GenericError(`Handler Omie duplicado: ${handler}.`, { statusCode: 422 });
|
|
142
|
-
}
|
|
143
|
-
result.handlers[handler] = implementation;
|
|
144
|
-
}
|
|
145
|
-
for (const instance of declaration.instances || []) {
|
|
146
|
-
result.instances.push({
|
|
147
|
-
id: normalizeKey(instance.id || instance.instanceId || "default", "instância Omie"),
|
|
148
|
-
label: String(instance.label || instance.id || "Omie"),
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const listKeys = new Set();
|
|
154
|
-
for (const list of result.lists) {
|
|
155
|
-
if (listKeys.has(list.key)) {
|
|
156
|
-
throw new GenericError(`Lista Omie duplicada: ${list.key}.`, { statusCode: 422 });
|
|
157
|
-
}
|
|
158
|
-
listKeys.add(list.key);
|
|
159
|
-
if (!result.calls[list.call]) {
|
|
160
|
-
throw new GenericError(
|
|
161
|
-
`A lista Omie ${list.key} referencia a chamada inexistente ${list.call}.`,
|
|
162
|
-
{ statusCode: 422 },
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return result;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function describeOmieDefinitions(definitions = collectOmieDefinitions()) {
|
|
170
|
-
return {
|
|
171
|
-
calls: Object.values(definitions.calls).map((call) => ({
|
|
172
|
-
key: call.key,
|
|
173
|
-
label: call.label,
|
|
174
|
-
endpoint: call.endpoint,
|
|
175
|
-
call: call.call,
|
|
176
|
-
paginated: Boolean(call.pagination),
|
|
177
|
-
connectionTest: call.connectionTest,
|
|
178
|
-
})),
|
|
179
|
-
lists: definitions.lists.map((list) => ({
|
|
180
|
-
key: list.key,
|
|
181
|
-
label: list.label,
|
|
182
|
-
description: list.description,
|
|
183
|
-
call: list.call,
|
|
184
|
-
mode: list.mode,
|
|
185
|
-
direction: list.direction,
|
|
186
|
-
targetModel: list.target.model,
|
|
187
|
-
externalKey: list.target.externalKey,
|
|
188
|
-
filtered: typeof list.filter === "function",
|
|
189
|
-
policies: list.policies,
|
|
190
|
-
schedule: list.schedule || null,
|
|
191
|
-
order: list.order,
|
|
192
|
-
})),
|
|
193
|
-
webhooks: definitions.webhooks.map((webhook) => ({
|
|
194
|
-
eventType: webhook.eventType,
|
|
195
|
-
resource: webhook.resource,
|
|
196
|
-
actions: webhook.actions.map((action) => ({ handler: action.handler })),
|
|
197
|
-
})),
|
|
198
|
-
instances: definitions.instances,
|
|
199
|
-
legacyMappings: Object.values(definitions.legacy || {}).map((mapping) => ({
|
|
200
|
-
key: mapping.key,
|
|
201
|
-
label: mapping.label,
|
|
202
|
-
})),
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
module.exports = {
|
|
207
|
-
collectOmieDefinitions,
|
|
208
|
-
describeOmieDefinitions,
|
|
209
|
-
normalizeCall,
|
|
210
|
-
normalizeList,
|
|
211
|
-
normalizeWebhook,
|
|
212
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const client = require("./client");
|
|
4
|
-
const definitions = require("./definitions");
|
|
5
|
-
const models = require("./models");
|
|
6
|
-
const provider = require("./provider");
|
|
7
|
-
|
|
8
|
-
const omie = {
|
|
9
|
-
sync(input = {}) {
|
|
10
|
-
return provider.enqueueOmieCall(input);
|
|
11
|
-
},
|
|
12
|
-
enqueue(input = {}) {
|
|
13
|
-
return provider.enqueueOmieCall(input);
|
|
14
|
-
},
|
|
15
|
-
async call(input = {}, options = {}) {
|
|
16
|
-
const declaredCall = input.callKey || input.mapping || input.name;
|
|
17
|
-
const normalized = definitions.collectOmieDefinitions();
|
|
18
|
-
return provider.executeConfiguredCall(
|
|
19
|
-
normalized,
|
|
20
|
-
declaredCall,
|
|
21
|
-
input.payload || input.input || {},
|
|
22
|
-
{ ...options, instanceId: input.instanceId || options.instanceId },
|
|
23
|
-
);
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
module.exports = {
|
|
28
|
-
...client,
|
|
29
|
-
...definitions,
|
|
30
|
-
...models,
|
|
31
|
-
...provider,
|
|
32
|
-
omie,
|
|
33
|
-
};
|