@openfin/cloud-interop-core-api 0.0.1-alpha.ffeba61 → 0.0.1-alpha.fff06d4

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,9 @@
1
- 'use strict';
1
+ import { Buffer } from 'buffer';
2
+ import 'fs';
3
+ import 'path';
4
+ import mqtt from 'mqtt';
2
5
 
3
- var mqtt = require('mqtt');
4
- var sharedUtils = require('@openfin/shared-utils');
6
+ var u=n=>{let e=n.replaceAll("-","+").replaceAll("_","/");return e.padEnd(e.length+(4-e.length%4)%4,"=")};
5
7
 
6
8
  class CloudInteropAPIError extends Error {
7
9
  code;
@@ -46,6 +48,8 @@ class EventController {
46
48
  }
47
49
  }
48
50
 
51
+ const isErrorIntentResult = (result) => 'error' in result;
52
+
49
53
  const APP_ID_DELIM = '::';
50
54
  const getRequestHeaders = (connectionParameters) => {
51
55
  const headers = {};
@@ -72,13 +76,9 @@ const getRequestHeaders = (connectionParameters) => {
72
76
  * @param source
73
77
  * @returns
74
78
  */
75
- const encodeAppIntents = (appIntents, { sessionId, sourceId }) => appIntents.map((intent) => ({
79
+ const encodeAppIntents = (appIntents, source) => appIntents.map((intent) => ({
76
80
  ...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
- }),
81
+ apps: intent.apps.map((app) => ({ ...app, appId: encodeAppId(app.appId, source) })),
82
82
  }));
83
83
  /**
84
84
  * Decodes all app intents by URI decoding the parts previously encoded by `encodeAppIntents`
@@ -87,19 +87,35 @@ const encodeAppIntents = (appIntents, { sessionId, sourceId }) => appIntents.map
87
87
  */
88
88
  const decodeAppIntents = (appIntents) => appIntents.map((intent) => ({
89
89
  ...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
- }),
90
+ apps: intent.apps.map((app) => ({ ...app, appId: decodeAppId(app.appId) })),
96
91
  }));
92
+ const encodeAppId = (appIdString, { sessionId, sourceId }) => {
93
+ const id = encodeURIComponent(appIdString);
94
+ const sId = encodeURIComponent(sourceId);
95
+ return `${id}${APP_ID_DELIM}${sId}${APP_ID_DELIM}${sessionId}`;
96
+ };
97
+ const decodeAppId = (appId) => {
98
+ const [encodedAppId, encodedSourceId, sessionId] = appId.split(APP_ID_DELIM);
99
+ const id = decodeURIComponent(encodedAppId);
100
+ const sourceId = decodeURIComponent(encodedSourceId);
101
+ return `${id}${APP_ID_DELIM}${sourceId}${APP_ID_DELIM}${sessionId}`;
102
+ };
97
103
  /**
98
- * Decodes the app id to extract the sessionId, returns '' if not able to parse
99
- * @param app
100
- * @returns
104
+ * Decodes the AppIdentifier to extract the appId, sourceId, and sessionId.
105
+ * @returns an object with:
106
+ * - appId: The appId, or the original appId if unable to parse.
107
+ * - sourceId: The sourceId, or an '' if unable to parse.
108
+ * - sessionId: The sessionId, or an '' if unable to parse.
101
109
  */
102
- const parseSessionId = (appId) => (typeof appId === 'string' ? appId : appId.appId).split(APP_ID_DELIM)?.[2]?.trim() ?? '';
110
+ const parseCloudAppId = (appId = '') => {
111
+ const originalAppString = typeof appId === 'string' ? appId : (appId.appId ?? '');
112
+ const parts = originalAppString.split(APP_ID_DELIM);
113
+ return {
114
+ appId: parts[0]?.trim() ?? originalAppString,
115
+ sourceId: parts[1]?.trim() ?? '',
116
+ sessionId: parts[2]?.trim() ?? '',
117
+ };
118
+ };
103
119
  const getSourceFromSession = (sessionDetails) => ({
104
120
  sessionId: sessionDetails.sessionId,
105
121
  sourceId: sessionDetails.sourceId,
@@ -148,13 +164,18 @@ class IntentController {
148
164
  body: JSON.stringify({ findOptions }),
149
165
  });
150
166
  if (!startResponse.ok) {
151
- throw new Error(startResponse.statusText);
167
+ throw new Error(`Error creating intent discovery record: ${startResponse.statusText}`);
152
168
  }
153
169
  // TODO: type this response?
154
170
  const json = await startResponse.json();
155
171
  this.#discovery.id = json.discoveryId;
156
172
  this.#discovery.sessionCount = json.sessionCount;
157
173
  this.#discovery.state = 'in-progress';
174
+ if (this.#discovery.sessionCount === 1) {
175
+ // since we have no other connected sessions, we can end discovery immediately
176
+ await this.#endIntentDiscovery(false);
177
+ return;
178
+ }
158
179
  // Listen out for discovery results directly sent to us
159
180
  await this.#mqttClient.subscribeAsync(`${this.#sessionDetails.sessionRootTopic}/commands/${this.#discovery.id}`);
160
181
  this.#discoveryTimeout = setTimeout(() => this.#endIntentDiscovery(), clampedTimeout);
@@ -165,10 +186,8 @@ class IntentController {
165
186
  throw new CloudInteropAPIError('Error starting intent discovery', 'ERR_STARTING_INTENT_DISCOVERY', error);
166
187
  }
167
188
  }
168
- async #endIntentDiscovery() {
189
+ async #endIntentDiscovery(mqttUnsubscribe = true) {
169
190
  if (this.#discovery.state !== 'in-progress') {
170
- // TODO: remove debug logs
171
- this.#logger('debug', 'Intent discovery not in progress');
172
191
  return;
173
192
  }
174
193
  if (this.#discoveryTimeout) {
@@ -178,10 +197,12 @@ class IntentController {
178
197
  this.#discovery.state = 'ended';
179
198
  // emit our aggregated events
180
199
  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
- });
200
+ if (mqttUnsubscribe) {
201
+ // gracefully end discovery
202
+ await this.#mqttClient.unsubscribeAsync(`${this.#sessionDetails.sessionRootTopic}/commands/${this.#discovery.id}`).catch(() => {
203
+ this.#logger('warn', `Error ending intent discovery: could not unsubscribe from discovery id ${this.#discovery.id}`);
204
+ });
205
+ }
185
206
  await fetch(`${this.#url}/api/intents/${this.#sessionDetails.sessionId}/${this.#discovery.id}`, {
186
207
  method: 'DELETE',
187
208
  headers: getRequestHeaders(this.#connectionParams),
@@ -190,7 +211,6 @@ class IntentController {
190
211
  if (!deleteResponse.ok) {
191
212
  throw new Error(`Error ending intent discovery: ${deleteResponse.statusText}`);
192
213
  }
193
- this.#logger('debug', 'Intent discovery ended');
194
214
  })
195
215
  .catch((error) => {
196
216
  this.#logger('warn', `Error ending intent discovery: ${error}`);
@@ -199,7 +219,7 @@ class IntentController {
199
219
  this.#discovery = newDiscovery();
200
220
  }
201
221
  async raiseIntent({ raiseOptions, appId }) {
202
- const targetSessionId = parseSessionId(appId);
222
+ const targetSessionId = parseCloudAppId(appId).sessionId;
203
223
  if (!targetSessionId) {
204
224
  // TODO: should we add more info here about the format?
205
225
  throw new CloudInteropAPIError(`Invalid AppId specified, must be encoded as a cloud-session app id`, 'ERR_INVALID_TARGET_SESSION_ID');
@@ -234,6 +254,13 @@ class IntentController {
234
254
  return false;
235
255
  }
236
256
  async sendIntentResult(initiatingSessionId, result) {
257
+ if (!isErrorIntentResult(result)) {
258
+ // cloud-encode the source app id to support chained intent actions over cloud
259
+ // https://fdc3.finos.org/docs/2.0/api/spec#resolution-object -> "Use metadata about the resolving app instance to target a further intent"
260
+ const source = getSourceFromSession(this.#sessionDetails);
261
+ const encoded = encodeAppId(typeof result.source === 'string' ? result.source : result.source.appId, source);
262
+ result.source = typeof result.source === 'string' ? encoded : { ...result.source, appId: encoded };
263
+ }
237
264
  const { sessionId } = getSourceFromSession(this.#sessionDetails);
238
265
  const resultResponse = await fetch(`${this.#url}/api/intents/${initiatingSessionId}/result/${sessionId}`, {
239
266
  method: 'POST',
@@ -311,9 +338,8 @@ const BadUserNamePasswordError = 134;
311
338
  /**
312
339
  * Represents a single connection to a Cloud Interop service
313
340
  *
314
- * @export
315
- * @class CloudInteropAPI
316
- * @implements {Client}
341
+ * @public
342
+ * @class
317
343
  */
318
344
  class CloudInteropAPI {
319
345
  #cloudInteropSettings;
@@ -329,6 +355,7 @@ class CloudInteropAPI {
329
355
  #attemptingToReconnect = false;
330
356
  #events = new EventController();
331
357
  #intents;
358
+ #sessionTimer;
332
359
  constructor(cloudInteropSettings) {
333
360
  this.#cloudInteropSettings = cloudInteropSettings;
334
361
  }
@@ -341,11 +368,11 @@ class CloudInteropAPI {
341
368
  /**
342
369
  * Connects and creates a session on the Cloud Interop service
343
370
  *
344
- * @param {ConnectParameters} parameters - The parameters to use to connect
345
- * @return {*} {Promise<void>}
371
+ * @param parameters - The parameters to use to connect
372
+ * @returns Promise that resolves when connection is established
346
373
  * @memberof CloudInteropAPI
347
- * @throws {CloudInteropAPIError} - If an error occurs during connection
348
- * @throws {AuthorizationError} - If the connection is unauthorized
374
+ * @throws CloudInteropAPIError - If an error occurs during connection
375
+ * @throws AuthorizationError - If the connection is unauthorized
349
376
  */
350
377
  async connect(parameters) {
351
378
  this.#validateConnectParams(parameters);
@@ -369,6 +396,11 @@ class CloudInteropAPI {
369
396
  throw new CloudInteropAPIError(`Failed to connect to the Cloud Interop service: ${this.#cloudInteropSettings.url}`, 'ERR_CONNECT', new Error(createSessionResponse.statusText));
370
397
  }
371
398
  this.#sessionDetails = (await createSessionResponse.json());
399
+ // If local session expiry handling is enabled, start the session timer
400
+ if (this.#sessionDetails.localSessionExpiryHandling) {
401
+ this.#logger('debug', `Local session expiry handling is enabled`);
402
+ this.#startSessionTimer();
403
+ }
372
404
  const sessionRootTopic = this.#sessionDetails.sessionRootTopic;
373
405
  const clientOptions = {
374
406
  keepalive: this.#keepAliveIntervalSeconds,
@@ -398,9 +430,7 @@ class CloudInteropAPI {
398
430
  if (error instanceof mqtt.ErrorWithReasonCode) {
399
431
  switch (error.code) {
400
432
  case BadUserNamePasswordError: {
401
- await this.#disconnect(false);
402
- this.#logger('warn', `Session expired`);
403
- this.#events.emitEvent('session-expired');
433
+ this.#handleSessionExpiry();
404
434
  return;
405
435
  }
406
436
  default: {
@@ -454,9 +484,9 @@ class CloudInteropAPI {
454
484
  /**
455
485
  * Disconnects from the Cloud Interop service
456
486
  *
457
- * @return {*} {Promise<void>}
487
+ * @returns Promise that resolves when disconnected
458
488
  * @memberof CloudInteropAPI
459
- * @throws {CloudInteropAPIError} - If an error occurs during disconnection
489
+ * @throws CloudInteropAPIError - If an error occurs during disconnection
460
490
  */
461
491
  async disconnect() {
462
492
  await this.#disconnect(true);
@@ -464,9 +494,9 @@ class CloudInteropAPI {
464
494
  /**
465
495
  * Publishes a new context for the given context group to the other connected sessions
466
496
  *
467
- * @param {string} contextGroup - The context group to publish to
468
- * @param {object} context - The context to publish
469
- * @return {*} {Promise<void>}
497
+ * @param contextGroup - The context group to publish to
498
+ * @param context - The context to publish
499
+ * @returns Promise that resolves when context is published
470
500
  * @memberof CloudInteropAPI
471
501
  */
472
502
  async setContext(contextGroup, context) {
@@ -493,9 +523,9 @@ class CloudInteropAPI {
493
523
  /**
494
524
  * Starts an intent discovery operation
495
525
  *
496
- * @return {*} {Promise<void>}
526
+ * @returns Promise that resolves when intent discovery is started
497
527
  * @memberof CloudInteropAPI
498
- * @throws {CloudInteropAPIError} - If an error occurs during intent discovery
528
+ * @throws CloudInteropAPIError - If an error occurs during intent discovery
499
529
  */
500
530
  async startIntentDiscovery(options) {
501
531
  this.#throwIfNotConnected();
@@ -514,7 +544,10 @@ class CloudInteropAPI {
514
544
  return this.#intents?.sendIntentResult(initiatingSessionId, result);
515
545
  }
516
546
  parseSessionId(appId) {
517
- return parseSessionId(appId);
547
+ return parseCloudAppId(appId).sessionId;
548
+ }
549
+ parseAppId(appId) {
550
+ return parseCloudAppId(appId).appId;
518
551
  }
519
552
  addEventListener(type, callback) {
520
553
  this.#events.addEventListener(type, callback);
@@ -526,10 +559,18 @@ class CloudInteropAPI {
526
559
  this.#events.once(type, callback);
527
560
  }
528
561
  async #disconnect(fireDisconnectedEvent) {
529
- if (!this.#sessionDetails || !this.#connectionParams) {
562
+ if (!this.#sessionDetails) {
530
563
  return;
531
564
  }
532
565
  try {
566
+ if (!this.#connectionParams) {
567
+ throw new Error('Connect parameters must be provided');
568
+ }
569
+ // Cancel session timer if it's running
570
+ if (this.#sessionTimer) {
571
+ clearTimeout(this.#sessionTimer);
572
+ this.#sessionTimer = undefined;
573
+ }
533
574
  const disconnectResponse = await fetch(`${this.#cloudInteropSettings.url}/api/sessions/${this.#sessionDetails.sessionId}`, {
534
575
  method: 'DELETE',
535
576
  headers: getRequestHeaders(this.#connectionParams),
@@ -565,8 +606,13 @@ class CloudInteropAPI {
565
606
  if (contextEvent.source.sessionId === sessionDetails.sessionId) {
566
607
  return;
567
608
  }
568
- const { contextGroup, context, source, history } = contextEvent;
569
- this.#events.emitEvent('context', { contextGroup, context, source, history: { ...history, clientReceived: Date.now() } });
609
+ const { context, payload, contextGroup, channelName, source, history } = contextEvent;
610
+ this.#events.emitEvent('context', {
611
+ contextGroup: channelName || contextGroup,
612
+ context: payload || context,
613
+ source,
614
+ history: { ...history, clientReceived: Date.now() },
615
+ });
570
616
  }
571
617
  else if (topic.startsWith(`${sessionDetails.sessionRootTopic}/commands`)) {
572
618
  this.#handleCommandMessage(messageEnvelope);
@@ -623,14 +669,88 @@ class CloudInteropAPI {
623
669
  throw new Error('MQTT client not connected');
624
670
  }
625
671
  }
672
+ /**
673
+ * Extracts the expiration timestamp from a JWT token.
674
+ *
675
+ * @param token - The JWT token string
676
+ * @returns The expiration timestamp in seconds, or null if extraction fails
677
+ */
678
+ #extractExpirationFromJwt(token) {
679
+ try {
680
+ // JWT tokens have three parts separated by dots: header.payload.signature
681
+ // The exp claim is in the payload
682
+ const parts = token.split('.');
683
+ if (parts.length < 2) {
684
+ this.#logger('warn', 'Invalid JWT token format: expected at least 2 parts');
685
+ return null;
686
+ }
687
+ const payload = parts[1];
688
+ // Decode base64url encoded payload
689
+ const decodedBytes = Buffer.from(u(payload), 'base64');
690
+ const payloadJson = decodedBytes.toString('utf8');
691
+ // Parse JSON to get the exp claim
692
+ const claims = JSON.parse(payloadJson);
693
+ const exp = claims.exp;
694
+ if (exp === undefined || exp === null) {
695
+ this.#logger('warn', "JWT token does not contain 'exp' claim");
696
+ return null;
697
+ }
698
+ if (typeof exp !== 'number') {
699
+ this.#logger('warn', `JWT token 'exp' claim is not a number: ${exp}`);
700
+ return null;
701
+ }
702
+ return exp;
703
+ }
704
+ catch (error) {
705
+ this.#logger('error', `Failed to extract expiration from JWT token: ${error instanceof Error ? error.message : error}`);
706
+ return null;
707
+ }
708
+ }
709
+ /**
710
+ * Start a session timer that will expire at the time specified in the JWT token's exp claim.
711
+ * When the timer fires, it executes the same actions as the BadUserNamePasswordError case.
712
+ */
713
+ #startSessionTimer() {
714
+ if (!this.#sessionDetails?.localSessionExpiryHandling) {
715
+ return;
716
+ }
717
+ const token = this.#sessionDetails.token;
718
+ if (!token) {
719
+ this.#logger('warn', 'Cannot start session timer: token not available');
720
+ return;
721
+ }
722
+ // Extract expiration time from JWT token
723
+ const expTimestamp = this.#extractExpirationFromJwt(token);
724
+ if (expTimestamp === null) {
725
+ this.#logger('warn', 'Cannot start session timer: could not extract expiration from JWT token');
726
+ return;
727
+ }
728
+ const currentTimeSeconds = Math.floor(Date.now() / 1000);
729
+ const delaySeconds = expTimestamp - currentTimeSeconds;
730
+ if (delaySeconds <= 0) {
731
+ this.#logger('warn', 'JWT token has already expired or expires immediately');
732
+ // Execute the same actions as BadUserNamePasswordError case
733
+ this.#handleSessionExpiry();
734
+ return;
735
+ }
736
+ // Clear any existing timer
737
+ if (this.#sessionTimer) {
738
+ clearTimeout(this.#sessionTimer);
739
+ }
740
+ const expirationTimeString = new Date(expTimestamp * 1000).toISOString();
741
+ this.#logger('debug', `Starting session timer to expire in ${delaySeconds} seconds (at ${expirationTimeString})`);
742
+ this.#sessionTimer = setTimeout(async () => {
743
+ this.#handleSessionExpiry();
744
+ }, delaySeconds * 1000);
745
+ }
746
+ /**
747
+ * Handles session expiry by executing the same actions as the BadUserNamePasswordError case.
748
+ */
749
+ async #handleSessionExpiry() {
750
+ await this.#disconnect(false);
751
+ this.#logger('warn', 'Session expired');
752
+ this.#events.emitEvent('session-expired');
753
+ }
626
754
  }
627
755
 
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
- });
756
+ export { AuthorizationError, CloudInteropAPI, CloudInteropAPIError };
package/package.json CHANGED
@@ -1,231 +1,15 @@
1
1
  {
2
- "name": "@openfin/cloud-interop-core-api",
3
- "version": "0.0.1-alpha.ffeba61",
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.fff06d4",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "./index.cjs",
7
+ "browser": "./index.mjs",
8
+ "types": "./bundle.d.ts",
9
+ "author": "support@here.io",
10
+ "license": "SEE LICENSE IN LICENSE.md",
11
+ "dependencies": {
12
+ "mqtt": "catalog:",
13
+ "zod": "catalog:"
14
+ }
231
15
  }