@unboundcx/sdk-internal 2.1.0 → 2.2.0
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/index.js +2 -0
- package/package.json +5 -1
- package/utils/buildObjectEventV2.js +74 -0
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { InternalSocketService } from './services/socket.js';
|
|
|
9
9
|
import { InternalMasterAuthService } from './services/masterAuth.js';
|
|
10
10
|
import { InternalBrandingService } from './services/branding.js';
|
|
11
11
|
import { InternalPhoneNumbersService } from './services/phoneNumbers.js';
|
|
12
|
+
import { buildObjectEventV2 } from './utils/buildObjectEventV2.js';
|
|
12
13
|
|
|
13
14
|
export class InternalSDK {
|
|
14
15
|
constructor(sdk, buildMasterApiAuthFn) {
|
|
@@ -126,3 +127,4 @@ export { InternalSocketService } from './services/socket.js';
|
|
|
126
127
|
export { InternalMasterAuthService } from './services/masterAuth.js';
|
|
127
128
|
export { InternalBrandingService } from './services/branding.js';
|
|
128
129
|
export { InternalPhoneNumbersService } from './services/phoneNumbers.js';
|
|
130
|
+
export { buildObjectEventV2 } from './utils/buildObjectEventV2.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk-internal",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Internal SDK extension for Unbound - Provides access to internal APIs and administrative functions",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"files": [
|
|
33
33
|
"*.js",
|
|
34
34
|
"services/**/*.js",
|
|
35
|
+
"utils/**/*.js",
|
|
35
36
|
"types/**/*.d.ts",
|
|
36
37
|
"README.md",
|
|
37
38
|
"LICENSE"
|
|
@@ -43,6 +44,9 @@
|
|
|
43
44
|
},
|
|
44
45
|
"./services/*": {
|
|
45
46
|
"import": "./services/*.js"
|
|
47
|
+
},
|
|
48
|
+
"./utils/*": {
|
|
49
|
+
"import": "./utils/*.js"
|
|
46
50
|
}
|
|
47
51
|
},
|
|
48
52
|
"scripts": {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a spec-valid `objects.event.v2` envelope for non-api writers
|
|
3
|
+
* (task-router, cdr-user-status, ...) that mutate object-backed tables with
|
|
4
|
+
* raw SQL and need to emit live-update events without an HTTP round-trip
|
|
5
|
+
* through app1-api.
|
|
6
|
+
*
|
|
7
|
+
* Pure helper — no NATS/publish side effects. Callers publish the returned
|
|
8
|
+
* `{ subject, payload }` themselves via their own service's NATS client and
|
|
9
|
+
* subject-prefix handling.
|
|
10
|
+
*
|
|
11
|
+
* @param {Object} params
|
|
12
|
+
* @param {'create'|'update'|'delete'} params.action
|
|
13
|
+
* @param {string} params.objectName - plural object/table name, e.g. 'tasks'
|
|
14
|
+
* @param {string} params.accountId
|
|
15
|
+
* @param {string|number} params.recordTypeId
|
|
16
|
+
* @param {Object|null} [params.oldRow] - full pre-mutation row image; null for 'create'
|
|
17
|
+
* @param {Object|null} [params.newRow] - full post-mutation row image; null for 'delete'
|
|
18
|
+
* @param {number} [params.now] - ms timestamp used for rowVersion/ts; defaults to Date.now()
|
|
19
|
+
* @returns {{ subject: string, payload: Object }}
|
|
20
|
+
*/
|
|
21
|
+
export function buildObjectEventV2({
|
|
22
|
+
action,
|
|
23
|
+
objectName,
|
|
24
|
+
accountId,
|
|
25
|
+
recordTypeId,
|
|
26
|
+
oldRow = null,
|
|
27
|
+
newRow = null,
|
|
28
|
+
now,
|
|
29
|
+
}) {
|
|
30
|
+
const changedFields =
|
|
31
|
+
oldRow && newRow ? diffChangedFields(oldRow, newRow) : [];
|
|
32
|
+
|
|
33
|
+
const ts = now ?? Date.now();
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
subject: 'objects.event.v2',
|
|
37
|
+
payload: {
|
|
38
|
+
action,
|
|
39
|
+
objectName,
|
|
40
|
+
accountId,
|
|
41
|
+
recordTypeId,
|
|
42
|
+
oldRow,
|
|
43
|
+
newRow,
|
|
44
|
+
changedFields,
|
|
45
|
+
rowVersion: ts,
|
|
46
|
+
ts,
|
|
47
|
+
sourceCluster: process.env.CLUSTER_NAME || 'unknown',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function diffChangedFields(oldRow, newRow) {
|
|
53
|
+
const fields = new Set([...Object.keys(oldRow), ...Object.keys(newRow)]);
|
|
54
|
+
const changed = [];
|
|
55
|
+
for (const field of fields) {
|
|
56
|
+
if (!isEqualValue(oldRow[field], newRow[field])) {
|
|
57
|
+
changed.push(field);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return changed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isEqualValue(a, b) {
|
|
64
|
+
if (a === b) return true;
|
|
65
|
+
if (a == null || b == null) return a === b;
|
|
66
|
+
if (typeof a === 'object' && typeof b === 'object') {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|