@openfin/cloud-interop-core-api 0.0.1-alpha.9be9ebc → 0.0.1-alpha.9c2e07e

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.
@@ -1,7 +1,7 @@
1
- 'use strict';
1
+ import { Buffer } from 'buffer';
2
+ import mqtt from 'mqtt';
2
3
 
3
- var mqtt = require('mqtt');
4
- var sharedUtils = require('@openfin/shared-utils');
4
+ var l=t=>{let e=t.replaceAll("-","+").replaceAll("_","/");return e.padEnd(e.length+(4-e.length%4)%4,"=")};
5
5
 
6
6
  class CloudInteropAPIError extends Error {
7
7
  code;
@@ -46,6 +46,8 @@ class EventController {
46
46
  }
47
47
  }
48
48
 
49
+ const isErrorIntentResult = (result) => 'error' in result;
50
+
49
51
  const APP_ID_DELIM = '::';
50
52
  const getRequestHeaders = (connectionParameters) => {
51
53
  const headers = {};
@@ -72,13 +74,9 @@ const getRequestHeaders = (connectionParameters) => {
72
74
  * @param source
73
75
  * @returns
74
76
  */
75
- const encodeAppIntents = (appIntents, { sessionId, sourceId }) => appIntents.map((intent) => ({
77
+ const encodeAppIntents = (appIntents, source) => appIntents.map((intent) => ({
76
78
  ...intent,
77
- apps: intent.apps.map((app) => {
78
- const id = encodeURIComponent(app.appId);
79
- const sId = encodeURIComponent(sourceId);
80
- return { ...app, appId: `${id}${APP_ID_DELIM}${sId}${APP_ID_DELIM}${sessionId}` };
81
- }),
79
+ apps: intent.apps.map((app) => ({ ...app, appId: encodeAppId(app.appId, source) })),
82
80
  }));
83
81
  /**
84
82
  * Decodes all app intents by URI decoding the parts previously encoded by `encodeAppIntents`
@@ -87,19 +85,35 @@ const encodeAppIntents = (appIntents, { sessionId, sourceId }) => appIntents.map
87
85
  */
88
86
  const decodeAppIntents = (appIntents) => appIntents.map((intent) => ({
89
87
  ...intent,
90
- apps: intent.apps.map((app) => {
91
- const [encodedAppId, encodedSourceId, sessionId] = app.appId.split(APP_ID_DELIM);
92
- const id = decodeURIComponent(encodedAppId);
93
- const sourceId = decodeURIComponent(encodedSourceId);
94
- return { ...app, appId: `${id}${APP_ID_DELIM}${sourceId}${APP_ID_DELIM}${sessionId}` };
95
- }),
88
+ apps: intent.apps.map((app) => ({ ...app, appId: decodeAppId(app.appId) })),
96
89
  }));
90
+ const encodeAppId = (appIdString, { sessionId, sourceId }) => {
91
+ const id = encodeURIComponent(appIdString);
92
+ const sId = encodeURIComponent(sourceId);
93
+ return `${id}${APP_ID_DELIM}${sId}${APP_ID_DELIM}${sessionId}`;
94
+ };
95
+ const decodeAppId = (appId) => {
96
+ const [encodedAppId, encodedSourceId, sessionId] = appId.split(APP_ID_DELIM);
97
+ const id = decodeURIComponent(encodedAppId);
98
+ const sourceId = decodeURIComponent(encodedSourceId);
99
+ return `${id}${APP_ID_DELIM}${sourceId}${APP_ID_DELIM}${sessionId}`;
100
+ };
97
101
  /**
98
- * Decodes the app id to extract the sessionId, returns '' if not able to parse
99
- * @param app
100
- * @returns
102
+ * Decodes the AppIdentifier to extract the appId, sourceId, and sessionId.
103
+ * @returns an object with:
104
+ * - appId: The appId, or the original appId if unable to parse.
105
+ * - sourceId: The sourceId, or an '' if unable to parse.
106
+ * - sessionId: The sessionId, or an '' if unable to parse.
101
107
  */
102
- const parseSessionId = (appId) => (typeof appId === 'string' ? appId : appId.appId).split(APP_ID_DELIM)?.[2]?.trim() ?? '';
108
+ const parseCloudAppId = (appId = '') => {
109
+ const originalAppString = typeof appId === 'string' ? appId : (appId.appId ?? '');
110
+ const parts = originalAppString.split(APP_ID_DELIM);
111
+ return {
112
+ appId: parts[0]?.trim() ?? originalAppString,
113
+ sourceId: parts[1]?.trim() ?? '',
114
+ sessionId: parts[2]?.trim() ?? '',
115
+ };
116
+ };
103
117
  const getSourceFromSession = (sessionDetails) => ({
104
118
  sessionId: sessionDetails.sessionId,
105
119
  sourceId: sessionDetails.sourceId,
@@ -148,13 +162,18 @@ class IntentController {
148
162
  body: JSON.stringify({ findOptions }),
149
163
  });
150
164
  if (!startResponse.ok) {
151
- throw new Error(startResponse.statusText);
165
+ throw new Error(`Error creating intent discovery record: ${startResponse.statusText}`);
152
166
  }
153
167
  // TODO: type this response?
154
168
  const json = await startResponse.json();
155
169
  this.#discovery.id = json.discoveryId;
156
170
  this.#discovery.sessionCount = json.sessionCount;
157
171
  this.#discovery.state = 'in-progress';
172
+ if (this.#discovery.sessionCount === 1) {
173
+ // since we have no other connected sessions, we can end discovery immediately
174
+ await this.#endIntentDiscovery(false);
175
+ return;
176
+ }
158
177
  // Listen out for discovery results directly sent to us
159
178
  await this.#mqttClient.subscribeAsync(`${this.#sessionDetails.sessionRootTopic}/commands/${this.#discovery.id}`);
160
179
  this.#discoveryTimeout = setTimeout(() => this.#endIntentDiscovery(), clampedTimeout);
@@ -165,10 +184,8 @@ class IntentController {
165
184
  throw new CloudInteropAPIError('Error starting intent discovery', 'ERR_STARTING_INTENT_DISCOVERY', error);
166
185
  }
167
186
  }
168
- async #endIntentDiscovery() {
187
+ async #endIntentDiscovery(mqttUnsubscribe = true) {
169
188
  if (this.#discovery.state !== 'in-progress') {
170
- // TODO: remove debug logs
171
- this.#logger('debug', 'Intent discovery not in progress');
172
189
  return;
173
190
  }
174
191
  if (this.#discoveryTimeout) {
@@ -178,10 +195,12 @@ class IntentController {
178
195
  this.#discovery.state = 'ended';
179
196
  // emit our aggregated events
180
197
  this.#events.emitEvent('aggregate-intent-details', { responses: this.#discovery.pendingIntentDetailsEvents });
181
- // gracefully end discovery
182
- await this.#mqttClient.unsubscribeAsync(`${this.#sessionDetails.sessionRootTopic}/commands/${this.#discovery.id}`).catch(() => {
183
- this.#logger('warn', `Error ending intent discovery: could not unsubscribe from discovery id ${this.#discovery.id}`);
184
- });
198
+ if (mqttUnsubscribe) {
199
+ // gracefully end discovery
200
+ await this.#mqttClient.unsubscribeAsync(`${this.#sessionDetails.sessionRootTopic}/commands/${this.#discovery.id}`).catch(() => {
201
+ this.#logger('warn', `Error ending intent discovery: could not unsubscribe from discovery id ${this.#discovery.id}`);
202
+ });
203
+ }
185
204
  await fetch(`${this.#url}/api/intents/${this.#sessionDetails.sessionId}/${this.#discovery.id}`, {
186
205
  method: 'DELETE',
187
206
  headers: getRequestHeaders(this.#connectionParams),
@@ -190,7 +209,6 @@ class IntentController {
190
209
  if (!deleteResponse.ok) {
191
210
  throw new Error(`Error ending intent discovery: ${deleteResponse.statusText}`);
192
211
  }
193
- this.#logger('debug', 'Intent discovery ended');
194
212
  })
195
213
  .catch((error) => {
196
214
  this.#logger('warn', `Error ending intent discovery: ${error}`);
@@ -199,7 +217,7 @@ class IntentController {
199
217
  this.#discovery = newDiscovery();
200
218
  }
201
219
  async raiseIntent({ raiseOptions, appId }) {
202
- const targetSessionId = parseSessionId(appId);
220
+ const targetSessionId = parseCloudAppId(appId).sessionId;
203
221
  if (!targetSessionId) {
204
222
  // TODO: should we add more info here about the format?
205
223
  throw new CloudInteropAPIError(`Invalid AppId specified, must be encoded as a cloud-session app id`, 'ERR_INVALID_TARGET_SESSION_ID');
@@ -234,6 +252,13 @@ class IntentController {
234
252
  return false;
235
253
  }
236
254
  async sendIntentResult(initiatingSessionId, result) {
255
+ if (!isErrorIntentResult(result)) {
256
+ // cloud-encode the source app id to support chained intent actions over cloud
257
+ // https://fdc3.finos.org/docs/2.0/api/spec#resolution-object -> "Use metadata about the resolving app instance to target a further intent"
258
+ const source = getSourceFromSession(this.#sessionDetails);
259
+ const encoded = encodeAppId(typeof result.source === 'string' ? result.source : result.source.appId, source);
260
+ result.source = typeof result.source === 'string' ? encoded : { ...result.source, appId: encoded };
261
+ }
237
262
  const { sessionId } = getSourceFromSession(this.#sessionDetails);
238
263
  const resultResponse = await fetch(`${this.#url}/api/intents/${initiatingSessionId}/result/${sessionId}`, {
239
264
  method: 'POST',
@@ -311,9 +336,8 @@ const BadUserNamePasswordError = 134;
311
336
  /**
312
337
  * Represents a single connection to a Cloud Interop service
313
338
  *
314
- * @export
315
- * @class CloudInteropAPI
316
- * @implements {Client}
339
+ * @public
340
+ * @class
317
341
  */
318
342
  class CloudInteropAPI {
319
343
  #cloudInteropSettings;
@@ -329,6 +353,7 @@ class CloudInteropAPI {
329
353
  #attemptingToReconnect = false;
330
354
  #events = new EventController();
331
355
  #intents;
356
+ #sessionTimer;
332
357
  constructor(cloudInteropSettings) {
333
358
  this.#cloudInteropSettings = cloudInteropSettings;
334
359
  }
@@ -341,11 +366,11 @@ class CloudInteropAPI {
341
366
  /**
342
367
  * Connects and creates a session on the Cloud Interop service
343
368
  *
344
- * @param {ConnectParameters} parameters - The parameters to use to connect
345
- * @return {*} {Promise<void>}
369
+ * @param parameters - The parameters to use to connect
370
+ * @returns Promise that resolves when connection is established
346
371
  * @memberof CloudInteropAPI
347
- * @throws {CloudInteropAPIError} - If an error occurs during connection
348
- * @throws {AuthorizationError} - If the connection is unauthorized
372
+ * @throws CloudInteropAPIError - If an error occurs during connection
373
+ * @throws AuthorizationError - If the connection is unauthorized
349
374
  */
350
375
  async connect(parameters) {
351
376
  this.#validateConnectParams(parameters);
@@ -369,6 +394,11 @@ class CloudInteropAPI {
369
394
  throw new CloudInteropAPIError(`Failed to connect to the Cloud Interop service: ${this.#cloudInteropSettings.url}`, 'ERR_CONNECT', new Error(createSessionResponse.statusText));
370
395
  }
371
396
  this.#sessionDetails = (await createSessionResponse.json());
397
+ // If local session expiry handling is enabled, start the session timer
398
+ if (this.#sessionDetails.localSessionExpiryHandling) {
399
+ this.#logger('debug', `Local session expiry handling is enabled`);
400
+ this.#startSessionTimer();
401
+ }
372
402
  const sessionRootTopic = this.#sessionDetails.sessionRootTopic;
373
403
  const clientOptions = {
374
404
  keepalive: this.#keepAliveIntervalSeconds,
@@ -398,9 +428,7 @@ class CloudInteropAPI {
398
428
  if (error instanceof mqtt.ErrorWithReasonCode) {
399
429
  switch (error.code) {
400
430
  case BadUserNamePasswordError: {
401
- await this.#disconnect(false);
402
- this.#logger('warn', `Session expired`);
403
- this.#events.emitEvent('session-expired');
431
+ this.#handleSessionExpiry();
404
432
  return;
405
433
  }
406
434
  default: {
@@ -454,9 +482,9 @@ class CloudInteropAPI {
454
482
  /**
455
483
  * Disconnects from the Cloud Interop service
456
484
  *
457
- * @return {*} {Promise<void>}
485
+ * @returns Promise that resolves when disconnected
458
486
  * @memberof CloudInteropAPI
459
- * @throws {CloudInteropAPIError} - If an error occurs during disconnection
487
+ * @throws CloudInteropAPIError - If an error occurs during disconnection
460
488
  */
461
489
  async disconnect() {
462
490
  await this.#disconnect(true);
@@ -464,9 +492,9 @@ class CloudInteropAPI {
464
492
  /**
465
493
  * Publishes a new context for the given context group to the other connected sessions
466
494
  *
467
- * @param {string} contextGroup - The context group to publish to
468
- * @param {object} context - The context to publish
469
- * @return {*} {Promise<void>}
495
+ * @param contextGroup - The context group to publish to
496
+ * @param context - The context to publish
497
+ * @returns Promise that resolves when context is published
470
498
  * @memberof CloudInteropAPI
471
499
  */
472
500
  async setContext(contextGroup, context) {
@@ -493,9 +521,9 @@ class CloudInteropAPI {
493
521
  /**
494
522
  * Starts an intent discovery operation
495
523
  *
496
- * @return {*} {Promise<void>}
524
+ * @returns Promise that resolves when intent discovery is started
497
525
  * @memberof CloudInteropAPI
498
- * @throws {CloudInteropAPIError} - If an error occurs during intent discovery
526
+ * @throws CloudInteropAPIError - If an error occurs during intent discovery
499
527
  */
500
528
  async startIntentDiscovery(options) {
501
529
  this.#throwIfNotConnected();
@@ -514,7 +542,10 @@ class CloudInteropAPI {
514
542
  return this.#intents?.sendIntentResult(initiatingSessionId, result);
515
543
  }
516
544
  parseSessionId(appId) {
517
- return parseSessionId(appId);
545
+ return parseCloudAppId(appId).sessionId;
546
+ }
547
+ parseAppId(appId) {
548
+ return parseCloudAppId(appId).appId;
518
549
  }
519
550
  addEventListener(type, callback) {
520
551
  this.#events.addEventListener(type, callback);
@@ -526,10 +557,18 @@ class CloudInteropAPI {
526
557
  this.#events.once(type, callback);
527
558
  }
528
559
  async #disconnect(fireDisconnectedEvent) {
529
- if (!this.#sessionDetails || !this.#connectionParams) {
560
+ if (!this.#sessionDetails) {
530
561
  return;
531
562
  }
532
563
  try {
564
+ if (!this.#connectionParams) {
565
+ throw new Error('Connect parameters must be provided');
566
+ }
567
+ // Cancel session timer if it's running
568
+ if (this.#sessionTimer) {
569
+ clearTimeout(this.#sessionTimer);
570
+ this.#sessionTimer = undefined;
571
+ }
533
572
  const disconnectResponse = await fetch(`${this.#cloudInteropSettings.url}/api/sessions/${this.#sessionDetails.sessionId}`, {
534
573
  method: 'DELETE',
535
574
  headers: getRequestHeaders(this.#connectionParams),
@@ -565,8 +604,13 @@ class CloudInteropAPI {
565
604
  if (contextEvent.source.sessionId === sessionDetails.sessionId) {
566
605
  return;
567
606
  }
568
- const { contextGroup, context, source, history } = contextEvent;
569
- this.#events.emitEvent('context', { contextGroup, context, source, history: { ...history, clientReceived: Date.now() } });
607
+ const { context, payload, contextGroup, channelName, source, history } = contextEvent;
608
+ this.#events.emitEvent('context', {
609
+ contextGroup: channelName || contextGroup,
610
+ context: payload || context,
611
+ source,
612
+ history: { ...history, clientReceived: Date.now() },
613
+ });
570
614
  }
571
615
  else if (topic.startsWith(`${sessionDetails.sessionRootTopic}/commands`)) {
572
616
  this.#handleCommandMessage(messageEnvelope);
@@ -623,14 +667,88 @@ class CloudInteropAPI {
623
667
  throw new Error('MQTT client not connected');
624
668
  }
625
669
  }
670
+ /**
671
+ * Extracts the expiration timestamp from a JWT token.
672
+ *
673
+ * @param token - The JWT token string
674
+ * @returns The expiration timestamp in seconds, or null if extraction fails
675
+ */
676
+ #extractExpirationFromJwt(token) {
677
+ try {
678
+ // JWT tokens have three parts separated by dots: header.payload.signature
679
+ // The exp claim is in the payload
680
+ const parts = token.split('.');
681
+ if (parts.length < 2) {
682
+ this.#logger('warn', 'Invalid JWT token format: expected at least 2 parts');
683
+ return null;
684
+ }
685
+ const payload = parts[1];
686
+ // Decode base64url encoded payload
687
+ const decodedBytes = Buffer.from(l(payload), 'base64');
688
+ const payloadJson = decodedBytes.toString('utf8');
689
+ // Parse JSON to get the exp claim
690
+ const claims = JSON.parse(payloadJson);
691
+ const exp = claims.exp;
692
+ if (exp === undefined || exp === null) {
693
+ this.#logger('warn', "JWT token does not contain 'exp' claim");
694
+ return null;
695
+ }
696
+ if (typeof exp !== 'number') {
697
+ this.#logger('warn', `JWT token 'exp' claim is not a number: ${exp}`);
698
+ return null;
699
+ }
700
+ return exp;
701
+ }
702
+ catch (error) {
703
+ this.#logger('error', `Failed to extract expiration from JWT token: ${error instanceof Error ? error.message : error}`);
704
+ return null;
705
+ }
706
+ }
707
+ /**
708
+ * Start a session timer that will expire at the time specified in the JWT token's exp claim.
709
+ * When the timer fires, it executes the same actions as the BadUserNamePasswordError case.
710
+ */
711
+ #startSessionTimer() {
712
+ if (!this.#sessionDetails?.localSessionExpiryHandling) {
713
+ return;
714
+ }
715
+ const token = this.#sessionDetails.token;
716
+ if (!token) {
717
+ this.#logger('warn', 'Cannot start session timer: token not available');
718
+ return;
719
+ }
720
+ // Extract expiration time from JWT token
721
+ const expTimestamp = this.#extractExpirationFromJwt(token);
722
+ if (expTimestamp === null) {
723
+ this.#logger('warn', 'Cannot start session timer: could not extract expiration from JWT token');
724
+ return;
725
+ }
726
+ const currentTimeSeconds = Math.floor(Date.now() / 1000);
727
+ const delaySeconds = expTimestamp - currentTimeSeconds;
728
+ if (delaySeconds <= 0) {
729
+ this.#logger('warn', 'JWT token has already expired or expires immediately');
730
+ // Execute the same actions as BadUserNamePasswordError case
731
+ this.#handleSessionExpiry();
732
+ return;
733
+ }
734
+ // Clear any existing timer
735
+ if (this.#sessionTimer) {
736
+ clearTimeout(this.#sessionTimer);
737
+ }
738
+ const expirationTimeString = new Date(expTimestamp * 1000).toISOString();
739
+ this.#logger('debug', `Starting session timer to expire in ${delaySeconds} seconds (at ${expirationTimeString})`);
740
+ this.#sessionTimer = setTimeout(async () => {
741
+ this.#handleSessionExpiry();
742
+ }, delaySeconds * 1000);
743
+ }
744
+ /**
745
+ * Handles session expiry by executing the same actions as the BadUserNamePasswordError case.
746
+ */
747
+ async #handleSessionExpiry() {
748
+ await this.#disconnect(false);
749
+ this.#logger('warn', 'Session expired');
750
+ this.#events.emitEvent('session-expired');
751
+ }
626
752
  }
627
753
 
628
- exports.AuthorizationError = AuthorizationError;
629
- exports.CloudInteropAPI = CloudInteropAPI;
630
- exports.CloudInteropAPIError = CloudInteropAPIError;
631
- Object.keys(sharedUtils).forEach(function (k) {
632
- if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
633
- enumerable: true,
634
- get: function () { return sharedUtils[k]; }
635
- });
636
- });
754
+ export { AuthorizationError, CloudInteropAPI, CloudInteropAPIError };
package/package.json CHANGED
@@ -1,231 +1,18 @@
1
1
  {
2
- "name": "@openfin/cloud-interop-core-api",
3
- "version": "0.0.1-alpha.9be9ebc",
4
- "type": "module",
5
- "description": "",
6
- "files": [
7
- "./dist/*"
8
- ],
9
- "main": "./dist/index.cjs",
10
- "browser": "./dist/index.mjs",
11
- "types": "./dist/index.d.ts",
12
- "scripts": {
13
- "build": "rimraf dist && rollup -c",
14
- "build:watch": "rollup -c --watch",
15
- "typecheck": "tsc --noEmit",
16
- "test": "jest --coverage",
17
- "lint": "eslint . --max-warnings 0",
18
- "lint:fix": "eslint . --fix --max-warnings 0"
19
- },
20
- "author": "",
21
- "license": "SEE LICENSE IN LICENSE.md",
22
- "devDependencies": {
23
- "@rollup/plugin-commonjs": "^28.0.1",
24
- "@rollup/plugin-inject": "^5.0.5",
25
- "@rollup/plugin-node-resolve": "^15.2.3",
26
- "@rollup/plugin-typescript": "^11.1.6",
27
- "@types/jest": "^29.5.14",
28
- "@types/node": "^22.7.7",
29
- "@typescript-eslint/eslint-plugin": "^7.5.0",
30
- "@typescript-eslint/parser": "^7.15.0",
31
- "eslint": "^8.57.0",
32
- "eslint-config-prettier": "^9.1.0",
33
- "eslint-plugin-check-file": "^2.8.0",
34
- "eslint-plugin-prettier": "^5.2.1",
35
- "eslint-plugin-simple-import-sort": "^12.1.1",
36
- "eslint-plugin-unicorn": "^55.0.0",
37
- "eslint-plugin-unused-imports": "^4.1.4",
38
- "jest": "^29.7.0",
39
- "prettier": "^3.3.3",
40
- "rollup": "^4.9.6",
41
- "ts-jest": "^29.2.5",
42
- "typescript": "^5.6.3"
43
- },
44
- "dependencies": {
45
- "@openfin/shared-utils": "file:../shared-utils",
46
- "mqtt": "^5.3.1"
47
- },
48
- "eslintConfig": {
49
- "env": {
50
- "browser": true,
51
- "node": true
52
- },
53
- "parser": "@typescript-eslint/parser",
54
- "parserOptions": {
55
- "ecmaVersion": "latest",
56
- "project": true,
57
- "sourceType": "module"
58
- },
59
- "extends": [
60
- "eslint:recommended",
61
- "plugin:@typescript-eslint/recommended",
62
- "plugin:@typescript-eslint/strict",
63
- "plugin:unicorn/recommended",
64
- "plugin:prettier/recommended"
65
- ],
66
- "plugins": [
67
- "prettier",
68
- "check-file",
69
- "simple-import-sort",
70
- "unused-imports"
71
- ],
72
- "rules": {
73
- "unused-imports/no-unused-imports": "warn",
74
- "unicorn/prevent-abbreviations": [
75
- "error",
76
- {
77
- "replacements": {
78
- "props": false,
79
- "prop": false,
80
- "ref": false,
81
- "args": false,
82
- "arg": false,
83
- "src": false,
84
- "dev": false,
85
- "str": false,
86
- "req": false,
87
- "res": false
88
- }
89
- }
90
- ],
91
- "@typescript-eslint/no-non-null-assertion": "error",
92
- "unicorn/no-nested-ternary": "off",
93
- "unicorn/no-array-for-each": "off",
94
- "unicorn/no-useless-undefined": "off",
95
- "unicorn/no-null": "off",
96
- "eqeqeq": [
97
- "error",
98
- "always"
99
- ],
100
- "no-alert": "error",
101
- "no-eval": "error",
102
- "prettier/prettier": "warn",
103
- "simple-import-sort/imports": [
104
- "error",
105
- {
106
- "groups": [
107
- [
108
- "^react$"
109
- ],
110
- [
111
- "^react"
112
- ],
113
- [
114
- "^next"
115
- ],
116
- [
117
- "^zod"
118
- ],
119
- [
120
- "^@radix-ui/"
121
- ],
122
- [
123
- "^[^.]"
124
- ],
125
- [
126
- "@/components/ui/.*"
127
- ],
128
- [
129
- "@/components/.*"
130
- ],
131
- [
132
- "@/config/.*"
133
- ],
134
- [
135
- "@/lib/.*"
136
- ],
137
- [
138
- "^\\.\\.(?!/?$)",
139
- "^\\.\\./?$"
140
- ],
141
- [
142
- "^\\./(?=.*/)(?!/?$)",
143
- "^\\.(?!/?$)",
144
- "^\\./?$"
145
- ],
146
- [
147
- "^.+\\.s?css$"
148
- ]
149
- ]
150
- }
151
- ],
152
- "check-file/no-index": "off",
153
- "check-file/filename-naming-convention": [
154
- "error",
155
- {
156
- "**/*.{jsx,tsx}": "KEBAB_CASE",
157
- "**/*.{js,ts}": "KEBAB_CASE"
158
- },
159
- {
160
- "ignoreMiddleExtensions": true
161
- }
162
- ],
163
- "check-file/filename-blocklist": [
164
- "error",
165
- {
166
- "**/*.spec.js": "*.test.js",
167
- "**/*.spec.jsx": "*.test.jsx",
168
- "**/*.spec.ts": "*.test.ts",
169
- "**/*.spec.tsx": "*.test.tsx"
170
- }
171
- ],
172
- "no-restricted-syntax": [
173
- "error",
174
- {
175
- "selector": "TSEnumDeclaration",
176
- "message": "Prefer string unions to enums."
177
- }
178
- ],
179
- "curly": [
180
- "error",
181
- "multi-line"
182
- ],
183
- "@typescript-eslint/consistent-type-definitions": [
184
- "error",
185
- "type"
186
- ],
187
- "@typescript-eslint/no-unused-vars": [
188
- "warn",
189
- {
190
- "argsIgnorePattern": "^_",
191
- "varsIgnorePattern": "^_"
192
- }
193
- ],
194
- "@typescript-eslint/no-explicit-any": "warn"
195
- },
196
- "ignorePatterns": [
197
- "node_modules",
198
- "out",
199
- "build",
200
- "dist",
201
- "coverage",
202
- "tests",
203
- "rollup.config.mjs",
204
- "examples"
205
- ]
206
- },
207
- "jest": {
208
- "collectCoverage": true,
209
- "collectCoverageFrom": [
210
- "src/**/*.ts"
211
- ],
212
- "coverageReporters": [
213
- "lcov",
214
- "text-summary"
215
- ],
216
- "preset": "ts-jest",
217
- "restoreMocks": true,
218
- "setupFiles": [],
219
- "testMatch": [
220
- "**/tests/*.test.ts"
221
- ],
222
- "testTimeout": 100000
223
- },
224
- "prettier": {
225
- "printWidth": 160,
226
- "semi": true,
227
- "singleQuote": true,
228
- "tabWidth": 4,
229
- "trailingComma": "all"
230
- }
2
+ "name": "@openfin/cloud-interop-core-api",
3
+ "version": "0.0.1-alpha.9c2e07e",
4
+ "type": "module",
5
+ "description": "",
6
+ "main": "./index.cjs",
7
+ "browser": "./index.mjs",
8
+ "types": "./bundle.d.ts",
9
+ "author": "",
10
+ "license": "SEE LICENSE IN LICENSE.md",
11
+ "dependencies": {
12
+ "mqtt": "^5.13.0",
13
+ "zod": "^3.24.4"
14
+ },
15
+ "optionalDependencies": {
16
+ "@rollup/rollup-linux-x64-gnu": "*"
17
+ }
231
18
  }