@flowcore/sdk 1.10.3 → 1.11.2

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.
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.NotificationClient = void 0;
27
+ const dntShim = __importStar(require("../_dnt.shims.js"));
28
+ const mod_js_1 = require("../mod.js");
29
+ const logger_js_1 = require("../utils/logger.js");
30
+ const flowcore_client_js_1 = require("./flowcore-client.js");
31
+ const node_buffer_1 = require("node:buffer");
32
+ // Maximum reconnection interval in milliseconds
33
+ const MAX_RECONNECT_INTERVAL = 30_000;
34
+ /**
35
+ * Client for handling WebSocket connections to the Flowcore notification system.
36
+ * Manages connection lifecycle, authentication, and event handling.
37
+ */
38
+ class NotificationClient {
39
+ /**
40
+ * Creates a new NotificationClient instance
41
+ * @param observer - RxJS Subject for emitting notification events
42
+ * @param oidcClient - Client for handling OIDC authentication
43
+ * @param subscriptionSpec - Specification for what notifications to subscribe to
44
+ * @param options - Configuration options for the client
45
+ */
46
+ constructor(observer, oidcClient, subscriptionSpec, options) {
47
+ Object.defineProperty(this, "observer", {
48
+ enumerable: true,
49
+ configurable: true,
50
+ writable: true,
51
+ value: observer
52
+ });
53
+ Object.defineProperty(this, "oidcClient", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: oidcClient
58
+ });
59
+ Object.defineProperty(this, "subscriptionSpec", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: subscriptionSpec
64
+ });
65
+ Object.defineProperty(this, "url", {
66
+ enumerable: true,
67
+ configurable: true,
68
+ writable: true,
69
+ value: "wss://tenant.api.flowcore.io/notifications"
70
+ });
71
+ Object.defineProperty(this, "webSocket", {
72
+ enumerable: true,
73
+ configurable: true,
74
+ writable: true,
75
+ value: void 0
76
+ });
77
+ Object.defineProperty(this, "options", {
78
+ enumerable: true,
79
+ configurable: true,
80
+ writable: true,
81
+ value: void 0
82
+ });
83
+ Object.defineProperty(this, "logger", {
84
+ enumerable: true,
85
+ configurable: true,
86
+ writable: true,
87
+ value: void 0
88
+ });
89
+ Object.defineProperty(this, "eventCount", {
90
+ enumerable: true,
91
+ configurable: true,
92
+ writable: true,
93
+ value: 0
94
+ });
95
+ Object.defineProperty(this, "reconnectInterval", {
96
+ enumerable: true,
97
+ configurable: true,
98
+ writable: true,
99
+ value: void 0
100
+ });
101
+ Object.defineProperty(this, "reconnectAttempts", {
102
+ enumerable: true,
103
+ configurable: true,
104
+ writable: true,
105
+ value: 0
106
+ });
107
+ this.options = {
108
+ reconnectInterval: 1000,
109
+ ...options,
110
+ };
111
+ this.logger = options?.logger ?? logger_js_1.defaultLogger;
112
+ this.reconnectInterval = options?.reconnectInterval ?? 1000;
113
+ }
114
+ /**
115
+ * Establishes WebSocket connection and sets up event handlers
116
+ */
117
+ async connect() {
118
+ const token = await this.oidcClient.getToken();
119
+ const flowcoreClient = new flowcore_client_js_1.FlowcoreClient({
120
+ getBearerToken: () => Promise.resolve(token.accessToken),
121
+ });
122
+ const tenant = await flowcoreClient.execute(new mod_js_1.TenantFetchCommand({
123
+ tenant: this.subscriptionSpec.tenant,
124
+ }));
125
+ const dataCore = await flowcoreClient.execute(new mod_js_1.DataCoreFetchCommand({
126
+ tenantId: tenant.id,
127
+ dataCore: this.subscriptionSpec.dataCore,
128
+ }));
129
+ let flowType;
130
+ let eventType;
131
+ if (this.subscriptionSpec.flowType) {
132
+ flowType = await flowcoreClient.execute(new mod_js_1.FlowTypeFetchCommand({
133
+ dataCoreId: dataCore.id,
134
+ flowType: this.subscriptionSpec.flowType,
135
+ }));
136
+ if (this.subscriptionSpec.eventType) {
137
+ eventType = await flowcoreClient.execute(new mod_js_1.EventTypeFetchCommand({
138
+ flowTypeId: flowType?.id,
139
+ eventType: this.subscriptionSpec.eventType,
140
+ }));
141
+ }
142
+ }
143
+ this.webSocket = new dntShim.WebSocket(`${this.url}?token=${encodeURIComponent(token.accessToken)}`);
144
+ this.webSocket.onopen = () => {
145
+ this.logger.info("WebSocket connection opened.");
146
+ this.reconnectInterval = this.options.reconnectInterval;
147
+ this.reconnectAttempts = 0;
148
+ this.webSocket.send(JSON.stringify({
149
+ tenant: this.subscriptionSpec.tenant,
150
+ dataCoreId: dataCore.id,
151
+ flowTypeId: flowType?.id,
152
+ eventTypeId: eventType?.id,
153
+ }));
154
+ };
155
+ this.webSocket.onmessage = (event) => {
156
+ let parsedData;
157
+ if (event.data instanceof ArrayBuffer) {
158
+ parsedData = new TextDecoder().decode(event.data);
159
+ }
160
+ else if (node_buffer_1.Buffer.isBuffer(event.data)) {
161
+ parsedData = event.data.toString();
162
+ }
163
+ else if (Array.isArray(event.data)) {
164
+ // Handle Buffer arrays by concatenating them
165
+ parsedData = node_buffer_1.Buffer.concat(event.data).toString();
166
+ }
167
+ else {
168
+ parsedData = event.data;
169
+ }
170
+ const data = JSON.parse(parsedData);
171
+ if (data.type === "validation") {
172
+ this.logger.error(`Bad request: ${data.summary} - ${data.message} - ${data.found} - ${data.errors}`);
173
+ return;
174
+ }
175
+ const parsed = JSON.parse(data.message);
176
+ this.logger.debug(`Received event: ${parsed.pattern}`);
177
+ this.observer.next({
178
+ pattern: parsed.pattern,
179
+ data: {
180
+ tenant: parsed.data.tenantId,
181
+ eventId: parsed.data.eventId,
182
+ dataCoreId: parsed.data.dataCore,
183
+ flowType: parsed.data.aggregator,
184
+ eventType: parsed.data.eventType,
185
+ validTime: parsed.data.validTime,
186
+ },
187
+ });
188
+ this.eventCount++;
189
+ if (this.options.maxEvents && this.options.maxEvents <= this.eventCount) {
190
+ this.observer.complete();
191
+ this.eventCount = 0;
192
+ this.webSocket.close(1000, "Max events received");
193
+ }
194
+ };
195
+ this.webSocket.onclose = (event) => {
196
+ this.logger.info(`Connection closed: Code [${event.code}], Reason: ${event.reason}`);
197
+ if (event.code !== 1000) {
198
+ this.attemptReconnect();
199
+ return;
200
+ }
201
+ this.observer.complete();
202
+ };
203
+ this.webSocket.onerror = (error) => {
204
+ this.logger.error(`WebSocket encountered error: ${error}`);
205
+ this.observer.error(error);
206
+ this.webSocket.close();
207
+ };
208
+ }
209
+ /**
210
+ * Attempts to reconnect to the WebSocket server using exponential backoff
211
+ */
212
+ attemptReconnect() {
213
+ if (this.options.maxReconnects && this.reconnectAttempts >= this.options.maxReconnects) {
214
+ this.logger.error(`Max reconnect attempts ${this.reconnectAttempts}/${this.options.maxReconnects} reached. Giving up.`);
215
+ return;
216
+ }
217
+ this.reconnectAttempts++;
218
+ this.logger.info(`Attempting reconnection ${this.reconnectAttempts}${this.options.maxReconnects ? `/${this.options.maxReconnects}` : ""} in ${this.reconnectInterval} ms...`);
219
+ setTimeout(() => {
220
+ this.connect();
221
+ }, this.reconnectInterval);
222
+ this.reconnectInterval = Math.min(MAX_RECONNECT_INTERVAL, this.reconnectInterval * 2);
223
+ }
224
+ /**
225
+ * Closes the WebSocket connection
226
+ */
227
+ disconnect() {
228
+ if (this.webSocket) {
229
+ this.webSocket.close();
230
+ }
231
+ }
232
+ /**
233
+ * Overrides the base WebSocket URL for testing or different environments
234
+ * @param url - The new base URL to use
235
+ */
236
+ overrideBaseUrl(url) {
237
+ this.url = url;
238
+ }
239
+ }
240
+ exports.NotificationClient = NotificationClient;
package/script/mod.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./commands/index.js";
2
2
  export * from "./common/command.js";
3
3
  export * from "./common/flowcore-client.js";
4
+ export * from "./common/notification-client.js";
4
5
  export * from "./contracts/index.js";
5
6
  export * from "./exceptions/index.js";
6
7
  export * from "./utils/parse-response-helper.js";
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kCAAkC,CAAA"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kCAAkC,CAAA"}
package/script/mod.js CHANGED
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./commands/index.js"), exports);
18
18
  __exportStar(require("./common/command.js"), exports);
19
19
  __exportStar(require("./common/flowcore-client.js"), exports);
20
+ __exportStar(require("./common/notification-client.js"), exports);
20
21
  __exportStar(require("./contracts/index.js"), exports);
21
22
  __exportStar(require("./exceptions/index.js"), exports);
22
23
  __exportStar(require("./utils/parse-response-helper.js"), exports);
@@ -0,0 +1,8 @@
1
+ export type Logger = {
2
+ debug: (message: string, meta?: Record<string, unknown>) => void;
3
+ info: (message: string, meta?: Record<string, unknown>) => void;
4
+ warn: (message: string, meta?: Record<string, unknown>) => void;
5
+ error: (message: string | Error, meta?: Record<string, unknown>) => void;
6
+ };
7
+ export declare const defaultLogger: Logger;
8
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAChE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAC/D,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAC/D,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CACzE,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,MAa3B,CAAA"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultLogger = void 0;
4
+ exports.defaultLogger = {
5
+ debug: (message, meta) => {
6
+ console.debug(message, meta);
7
+ },
8
+ info: (message, meta) => {
9
+ console.info(message, meta);
10
+ },
11
+ warn: (message, meta) => {
12
+ console.warn(message, meta);
13
+ },
14
+ error: (message, meta) => {
15
+ console.error(message, meta);
16
+ },
17
+ };