@flowcore/sdk 1.10.3 → 1.11.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.
@@ -0,0 +1,239 @@
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
+ // Maximum reconnection interval in milliseconds
32
+ const MAX_RECONNECT_INTERVAL = 30_000;
33
+ /**
34
+ * Client for handling WebSocket connections to the Flowcore notification system.
35
+ * Manages connection lifecycle, authentication, and event handling.
36
+ */
37
+ class NotificationClient {
38
+ /**
39
+ * Creates a new NotificationClient instance
40
+ * @param observer - RxJS Subject for emitting notification events
41
+ * @param oidcClient - Client for handling OIDC authentication
42
+ * @param subscriptionSpec - Specification for what notifications to subscribe to
43
+ * @param options - Configuration options for the client
44
+ */
45
+ constructor(observer, oidcClient, subscriptionSpec, options) {
46
+ Object.defineProperty(this, "observer", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: observer
51
+ });
52
+ Object.defineProperty(this, "oidcClient", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: oidcClient
57
+ });
58
+ Object.defineProperty(this, "subscriptionSpec", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: subscriptionSpec
63
+ });
64
+ Object.defineProperty(this, "url", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: "wss://tenant.api.flowcore.io/notifications"
69
+ });
70
+ Object.defineProperty(this, "webSocket", {
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true,
74
+ value: void 0
75
+ });
76
+ Object.defineProperty(this, "options", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: void 0
81
+ });
82
+ Object.defineProperty(this, "logger", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: void 0
87
+ });
88
+ Object.defineProperty(this, "eventCount", {
89
+ enumerable: true,
90
+ configurable: true,
91
+ writable: true,
92
+ value: 0
93
+ });
94
+ Object.defineProperty(this, "reconnectInterval", {
95
+ enumerable: true,
96
+ configurable: true,
97
+ writable: true,
98
+ value: void 0
99
+ });
100
+ Object.defineProperty(this, "reconnectAttempts", {
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ value: 0
105
+ });
106
+ this.options = {
107
+ reconnectInterval: 1000,
108
+ ...options,
109
+ };
110
+ this.logger = options?.logger ?? logger_js_1.defaultLogger;
111
+ this.reconnectInterval = options?.reconnectInterval ?? 1000;
112
+ }
113
+ /**
114
+ * Establishes WebSocket connection and sets up event handlers
115
+ */
116
+ async connect() {
117
+ const token = await this.oidcClient.getToken();
118
+ const flowcoreClient = new flowcore_client_js_1.FlowcoreClient({
119
+ getBearerToken: () => Promise.resolve(token.accessToken),
120
+ });
121
+ const tenant = await flowcoreClient.execute(new mod_js_1.TenantFetchCommand({
122
+ tenant: this.subscriptionSpec.tenant,
123
+ }));
124
+ const dataCore = await flowcoreClient.execute(new mod_js_1.DataCoreFetchCommand({
125
+ tenantId: tenant.id,
126
+ dataCore: this.subscriptionSpec.dataCore,
127
+ }));
128
+ let flowType;
129
+ let eventType;
130
+ if (this.subscriptionSpec.flowType) {
131
+ flowType = await flowcoreClient.execute(new mod_js_1.FlowTypeFetchCommand({
132
+ dataCoreId: dataCore.id,
133
+ flowType: this.subscriptionSpec.flowType,
134
+ }));
135
+ if (this.subscriptionSpec.eventType) {
136
+ eventType = await flowcoreClient.execute(new mod_js_1.EventTypeFetchCommand({
137
+ flowTypeId: flowType?.id,
138
+ eventType: this.subscriptionSpec.eventType,
139
+ }));
140
+ }
141
+ }
142
+ this.webSocket = new dntShim.WebSocket(`${this.url}?token=${encodeURIComponent(token.accessToken)}`);
143
+ this.webSocket.onopen = () => {
144
+ this.logger.info("WebSocket connection opened.");
145
+ this.reconnectInterval = this.options.reconnectInterval;
146
+ this.reconnectAttempts = 0;
147
+ this.webSocket.send(JSON.stringify({
148
+ tenant: this.subscriptionSpec.tenant,
149
+ dataCoreId: dataCore.id,
150
+ flowTypeId: flowType?.id,
151
+ eventTypeId: eventType?.id,
152
+ }));
153
+ };
154
+ this.webSocket.onmessage = (event) => {
155
+ let parsedData;
156
+ if (event.data instanceof ArrayBuffer) {
157
+ parsedData = new TextDecoder().decode(event.data);
158
+ }
159
+ else if (Buffer.isBuffer(event.data)) {
160
+ parsedData = event.data.toString();
161
+ }
162
+ else if (Array.isArray(event.data)) {
163
+ // Handle Buffer arrays by concatenating them
164
+ parsedData = Buffer.concat(event.data).toString();
165
+ }
166
+ else {
167
+ parsedData = event.data;
168
+ }
169
+ const data = JSON.parse(parsedData);
170
+ if (data.type === "validation") {
171
+ this.logger.error(`Bad request: ${data.summary} - ${data.message} - ${data.found} - ${data.errors}`);
172
+ return;
173
+ }
174
+ const parsed = JSON.parse(data.message);
175
+ this.logger.debug(`Received event: ${parsed.pattern}`);
176
+ this.observer.next({
177
+ pattern: parsed.pattern,
178
+ data: {
179
+ tenant: parsed.data.tenantId,
180
+ eventId: parsed.data.eventId,
181
+ dataCoreId: parsed.data.dataCore,
182
+ flowType: parsed.data.aggregator,
183
+ eventType: parsed.data.eventType,
184
+ validTime: parsed.data.validTime,
185
+ },
186
+ });
187
+ this.eventCount++;
188
+ if (this.options.maxEvents && this.options.maxEvents <= this.eventCount) {
189
+ this.observer.complete();
190
+ this.eventCount = 0;
191
+ this.webSocket.close(1000, "Max events received");
192
+ }
193
+ };
194
+ this.webSocket.onclose = (event) => {
195
+ this.logger.info(`Connection closed: Code [${event.code}], Reason: ${event.reason}`);
196
+ if (event.code !== 1000) {
197
+ this.attemptReconnect();
198
+ return;
199
+ }
200
+ this.observer.complete();
201
+ };
202
+ this.webSocket.onerror = (error) => {
203
+ this.logger.error(`WebSocket encountered error: ${error}`);
204
+ this.observer.error(error);
205
+ this.webSocket.close();
206
+ };
207
+ }
208
+ /**
209
+ * Attempts to reconnect to the WebSocket server using exponential backoff
210
+ */
211
+ attemptReconnect() {
212
+ if (this.options.maxReconnects && this.reconnectAttempts >= this.options.maxReconnects) {
213
+ this.logger.error(`Max reconnect attempts ${this.reconnectAttempts}/${this.options.maxReconnects} reached. Giving up.`);
214
+ return;
215
+ }
216
+ this.reconnectAttempts++;
217
+ this.logger.info(`Attempting reconnection ${this.reconnectAttempts}${this.options.maxReconnects ? `/${this.options.maxReconnects}` : ""} in ${this.reconnectInterval} ms...`);
218
+ setTimeout(() => {
219
+ this.connect();
220
+ }, this.reconnectInterval);
221
+ this.reconnectInterval = Math.min(MAX_RECONNECT_INTERVAL, this.reconnectInterval * 2);
222
+ }
223
+ /**
224
+ * Closes the WebSocket connection
225
+ */
226
+ disconnect() {
227
+ if (this.webSocket) {
228
+ this.webSocket.close();
229
+ }
230
+ }
231
+ /**
232
+ * Overrides the base WebSocket URL for testing or different environments
233
+ * @param url - The new base URL to use
234
+ */
235
+ overrideBaseUrl(url) {
236
+ this.url = url;
237
+ }
238
+ }
239
+ 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
+ };