@friggframework/core 2.0.0-next.84 → 2.0.0-next.86
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.
|
@@ -560,13 +560,25 @@ class IntegrationBase {
|
|
|
560
560
|
* @returns {Promise<void>}
|
|
561
561
|
*/
|
|
562
562
|
async receiveNotification(notifier, delegateString, object = null) {
|
|
563
|
-
if (delegateString !== 'CREDENTIAL_INVALIDATED') return;
|
|
564
563
|
if (!this.id) return;
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
564
|
+
|
|
565
|
+
if (delegateString === 'CREDENTIAL_INVALIDATED') {
|
|
566
|
+
console.log(
|
|
567
|
+
`[Frigg] Module ${notifier?.name || '?'} reported invalid credentials for integration ${this.id} — marking ERROR`
|
|
568
|
+
);
|
|
569
|
+
await this.updateIntegrationStatus.execute(this.id, 'ERROR');
|
|
570
|
+
this.status = 'ERROR';
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (delegateString === 'CREDENTIAL_VALIDATED') {
|
|
575
|
+
if (this.status !== 'ERROR') return;
|
|
576
|
+
console.log(
|
|
577
|
+
`[Frigg] Module ${notifier?.name || '?'} reported valid credentials for integration ${this.id} — clearing ERROR → ENABLED`
|
|
578
|
+
);
|
|
579
|
+
await this.updateIntegrationStatus.execute(this.id, 'ENABLED');
|
|
580
|
+
this.status = 'ENABLED';
|
|
581
|
+
}
|
|
570
582
|
}
|
|
571
583
|
}
|
|
572
584
|
|
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
* const updateMetrics = new UpdateProcessMetrics({ processRepository, websocketService });
|
|
29
29
|
* await updateMetrics.execute(processId, {
|
|
30
30
|
* processed: 100,
|
|
31
|
-
* success:
|
|
31
|
+
* success: 92,
|
|
32
32
|
* errors: 5,
|
|
33
|
+
* skipped: 3,
|
|
33
34
|
* errorDetails: [{ contactId: 'abc', error: 'Missing email', timestamp: '...' }]
|
|
34
35
|
* });
|
|
35
36
|
*/
|
|
@@ -54,6 +55,11 @@ class UpdateProcessMetrics {
|
|
|
54
55
|
* @param {number} [metricsUpdate.processed=0] - Records processed in this batch
|
|
55
56
|
* @param {number} [metricsUpdate.success=0] - Successful records
|
|
56
57
|
* @param {number} [metricsUpdate.errors=0] - Failed records
|
|
58
|
+
* @param {number} [metricsUpdate.skipped=0] - Intentionally-skipped
|
|
59
|
+
* records (hash-match, dedupe, loop protection, etc.). Increments
|
|
60
|
+
* `results.aggregateData.totalSkipped`. Distinct from errors so the
|
|
61
|
+
* UI can show `processed = synced + failed + skipped` without
|
|
62
|
+
* conflating intentional skips with failures.
|
|
57
63
|
* @param {Array} [metricsUpdate.errorDetails=[]] - Error details array
|
|
58
64
|
* @returns {Promise<Object>} Updated process record
|
|
59
65
|
* @throws {Error} If process not found or update fails
|
|
@@ -71,9 +77,11 @@ class UpdateProcessMetrics {
|
|
|
71
77
|
const processed = metricsUpdate.processed || 0;
|
|
72
78
|
const success = metricsUpdate.success || 0;
|
|
73
79
|
const errors = metricsUpdate.errors || 0;
|
|
80
|
+
const skipped = metricsUpdate.skipped || 0;
|
|
74
81
|
if (processed) increment['context.processedRecords'] = processed;
|
|
75
82
|
if (success) increment['results.aggregateData.totalSynced'] = success;
|
|
76
83
|
if (errors) increment['results.aggregateData.totalFailed'] = errors;
|
|
84
|
+
if (skipped) increment['results.aggregateData.totalSkipped'] = skipped;
|
|
77
85
|
|
|
78
86
|
const pushSlice = {};
|
|
79
87
|
if (
|
|
@@ -191,6 +199,7 @@ class UpdateProcessMetrics {
|
|
|
191
199
|
total: context.totalRecords || 0,
|
|
192
200
|
successCount: aggregateData.totalSynced || 0,
|
|
193
201
|
errorCount: aggregateData.totalFailed || 0,
|
|
202
|
+
skippedCount: aggregateData.totalSkipped || 0,
|
|
194
203
|
recordsPerSecond: aggregateData.recordsPerSecond || 0,
|
|
195
204
|
estimatedCompletion: context.estimatedCompletion || null,
|
|
196
205
|
timestamp: new Date().toISOString(),
|
package/modules/module.js
CHANGED
|
@@ -41,6 +41,8 @@ class Module extends Delegate {
|
|
|
41
41
|
// Module → parent delegate (typically IntegrationBase) events
|
|
42
42
|
this.DLGT_CREDENTIAL_INVALIDATED = 'CREDENTIAL_INVALIDATED';
|
|
43
43
|
this.delegateTypes.push(this.DLGT_CREDENTIAL_INVALIDATED);
|
|
44
|
+
this.DLGT_CREDENTIAL_VALIDATED = 'CREDENTIAL_VALIDATED';
|
|
45
|
+
this.delegateTypes.push(this.DLGT_CREDENTIAL_VALIDATED);
|
|
44
46
|
|
|
45
47
|
Object.assign(this, this.definition.requiredAuthMethods);
|
|
46
48
|
|
|
@@ -123,6 +125,20 @@ class Module extends Delegate {
|
|
|
123
125
|
credentialDetails
|
|
124
126
|
);
|
|
125
127
|
this.credential = persisted;
|
|
128
|
+
|
|
129
|
+
if (this.credential?.id) {
|
|
130
|
+
try {
|
|
131
|
+
await this.notify(this.DLGT_CREDENTIAL_VALIDATED, {
|
|
132
|
+
credentialId: this.credential.id,
|
|
133
|
+
moduleName: this.name,
|
|
134
|
+
});
|
|
135
|
+
} catch (err) {
|
|
136
|
+
console.error(
|
|
137
|
+
`[Frigg] Failed to propagate CREDENTIAL_VALIDATED for module ${this.name}:`,
|
|
138
|
+
err?.message || err
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
126
142
|
}
|
|
127
143
|
|
|
128
144
|
async receiveNotification(notifier, delegateString, object = null) {
|
|
@@ -151,9 +151,9 @@ class Requester extends Delegate {
|
|
|
151
151
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
152
152
|
return this._request(url, options, i + 1);
|
|
153
153
|
} else if (status === 401) {
|
|
154
|
-
if (!this.isRefreshable
|
|
154
|
+
if (!this.isRefreshable) {
|
|
155
155
|
await this.notify(this.DLGT_INVALID_AUTH);
|
|
156
|
-
} else {
|
|
156
|
+
} else if (this.refreshCount === 0) {
|
|
157
157
|
this.refreshCount++;
|
|
158
158
|
const refreshSucceeded = await this.refreshAuth();
|
|
159
159
|
if (refreshSucceeded) {
|
|
@@ -178,6 +178,11 @@ class Requester extends Delegate {
|
|
|
178
178
|
);
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
// Successful response: reset the per-instance refresh budget so
|
|
182
|
+
// a later 401 in the same Requester lifetime can attempt refresh
|
|
183
|
+
// again instead of silently falling through.
|
|
184
|
+
this.refreshCount = 0;
|
|
185
|
+
|
|
181
186
|
// parsedBody consumes the response body stream. If the server
|
|
182
187
|
// stalls mid-stream the timer (still armed) aborts it.
|
|
183
188
|
return options.returnFullRes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0-next.
|
|
4
|
+
"version": "2.0.0-next.86",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0-next.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0-next.
|
|
43
|
-
"@friggframework/test": "2.0.0-next.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0-next.86",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0-next.86",
|
|
43
|
+
"@friggframework/test": "2.0.0-next.86",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "8862a43e3aa4be518fa1b35da41b76129b617a2e"
|
|
84
84
|
}
|