@lightsparkdev/core 1.3.0 → 1.4.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/dist/index.js CHANGED
@@ -51,7 +51,7 @@ import {
51
51
  setLocalStorageBoolean,
52
52
  sleep,
53
53
  urlsafe_b64decode
54
- } from "./chunk-23SS5EX2.js";
54
+ } from "./chunk-NV53XYAS.js";
55
55
 
56
56
  // src/auth/LightsparkAuthException.ts
57
57
  var LightsparkAuthException = class extends LightsparkException_default {
@@ -488,7 +488,6 @@ var logger = new Logger("@lightsparkdev/core");
488
488
  import dayjs from "dayjs";
489
489
  import utc from "dayjs/plugin/utc.js";
490
490
  import { createClient } from "graphql-ws";
491
- import NodeWebSocket from "ws";
492
491
  import { Observable } from "zen-observable-ts";
493
492
  var DEFAULT_BASE_URL = "api.lightspark.com";
494
493
  dayjs.extend(utc);
@@ -502,22 +501,38 @@ var Requester = class {
502
501
  this.cryptoImpl = cryptoImpl;
503
502
  this.signingKey = signingKey;
504
503
  this.fetchImpl = fetchImpl;
504
+ this.wsClient = new Promise((resolve) => {
505
+ this.resolveWsClient = resolve;
506
+ });
507
+ void this.initWsClient(baseUrl, authProvider);
508
+ autoBind(this);
509
+ }
510
+ wsClient;
511
+ resolveWsClient = null;
512
+ async initWsClient(baseUrl, authProvider) {
513
+ if (!this.resolveWsClient) {
514
+ return this.wsClient;
515
+ }
505
516
  let websocketImpl;
506
- if (typeof WebSocket === "undefined" && typeof window === "undefined") {
507
- websocketImpl = NodeWebSocket;
517
+ if (isNode && typeof WebSocket === "undefined") {
518
+ const wsModule = await import("ws");
519
+ websocketImpl = wsModule.default;
508
520
  }
509
521
  let websocketProtocol = "wss";
510
522
  if (baseUrl.startsWith("http://")) {
511
523
  websocketProtocol = "ws";
512
524
  }
513
- this.wsClient = createClient({
525
+ const wsClient = createClient({
514
526
  url: `${websocketProtocol}://${this.stripProtocol(this.baseUrl)}/${this.schemaEndpoint}`,
515
527
  connectionParams: () => authProvider.addWsConnectionParams({}),
516
528
  webSocketImpl: websocketImpl
517
529
  });
518
- autoBind(this);
530
+ if (this.resolveWsClient) {
531
+ this.resolveWsClient(wsClient);
532
+ this.resolveWsClient = null;
533
+ }
534
+ return wsClient;
519
535
  }
520
- wsClient;
521
536
  async executeQuery(query) {
522
537
  const data = await this.makeRawRequest(
523
538
  query.queryPayload,
@@ -555,11 +570,28 @@ var Requester = class {
555
570
  };
556
571
  return new Observable((observer) => {
557
572
  logger.trace(`Requester.subscribe observer`, observer);
558
- return this.wsClient.subscribe(bodyData, {
559
- next: (data) => observer.next(data),
560
- error: (err) => observer.error(err),
561
- complete: () => observer.complete()
562
- });
573
+ let cleanup = null;
574
+ let canceled = false;
575
+ void (async () => {
576
+ try {
577
+ const wsClient = await this.wsClient;
578
+ if (!canceled) {
579
+ cleanup = wsClient.subscribe(bodyData, {
580
+ next: (data) => observer.next(data),
581
+ error: (err) => observer.error(err),
582
+ complete: () => observer.complete()
583
+ });
584
+ }
585
+ } catch (err) {
586
+ observer.error(err);
587
+ }
588
+ })();
589
+ return () => {
590
+ canceled = true;
591
+ if (cleanup) {
592
+ cleanup();
593
+ }
594
+ };
563
595
  });
564
596
  }
565
597
  async makeRawRequest(queryPayload, variables = {}, signingNodeId = void 0, skipAuth = false) {
@@ -635,9 +667,15 @@ var Requester = class {
635
667
  const responseJson = await response.json();
636
668
  const data = responseJson.data;
637
669
  if (!data) {
670
+ let firstErrorName = void 0;
671
+ if (Array.isArray(responseJson.errors) && responseJson.errors.length > 0) {
672
+ const firstError = responseJson.errors[0];
673
+ firstErrorName = firstError["extensions"]?.["error_name"];
674
+ }
638
675
  throw new LightsparkException_default(
639
676
  "RequestFailed",
640
- `Request ${operation} failed. ${JSON.stringify(responseJson.errors)}`
677
+ `Request ${operation} failed. ${JSON.stringify(responseJson.errors)}`,
678
+ { errorName: firstErrorName }
641
679
  );
642
680
  }
643
681
  return data;
@@ -62,7 +62,7 @@ __export(utils_exports, {
62
62
  isErrorWithMessage: () => isErrorWithMessage,
63
63
  isNode: () => isNode,
64
64
  isNumber: () => isNumber,
65
- isObject: () => isObject2,
65
+ isObject: () => isObject,
66
66
  isRecord: () => isRecord,
67
67
  isSDKCurrencyAmount: () => isSDKCurrencyAmount,
68
68
  isTest: () => isTest,
@@ -974,6 +974,18 @@ function localeToCurrencySymbol(locale) {
974
974
  return symbol;
975
975
  }
976
976
 
977
+ // src/utils/typeGuards.ts
978
+ function isUint8Array(value) {
979
+ return value instanceof Uint8Array;
980
+ }
981
+ function isObject(value) {
982
+ const type = typeof value;
983
+ return value != null && (type == "object" || type == "function");
984
+ }
985
+ function isRecord(value) {
986
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
987
+ }
988
+
977
989
  // src/utils/errors.ts
978
990
  var isError = (e) => {
979
991
  return Boolean(
@@ -994,31 +1006,71 @@ var isErrorMsg = (e, msg) => {
994
1006
  }
995
1007
  return false;
996
1008
  };
997
- function errorToJSON(err) {
1009
+ function normalizeObject(obj) {
1010
+ const normalized = {};
1011
+ if (isObject(obj)) {
1012
+ const props = Object.getOwnPropertyNames(obj);
1013
+ for (const prop of props) {
1014
+ const objRecord = obj;
1015
+ normalized[prop] = objRecord[prop];
1016
+ }
1017
+ }
1018
+ return normalized;
1019
+ }
1020
+ function errorToJSON(err, stringifyObjects = false) {
998
1021
  if (!err) {
999
1022
  return null;
1000
1023
  }
1001
- if (typeof err === "object" && "toJSON" in err && typeof err.toJSON === "function") {
1024
+ if (isObject(err) && "toJSON" in err && typeof err.toJSON === "function") {
1025
+ if (stringifyObjects === true) {
1026
+ return objectToJSON(err.toJSON());
1027
+ }
1002
1028
  return err.toJSON();
1003
1029
  }
1004
1030
  if (typeof err === "object" && /* This happens for certain errors like DOMException: */
1005
1031
  Object.getOwnPropertyNames(err).length === 0 && "message" in err && typeof err.message === "string") {
1006
1032
  return { message: err.message };
1007
1033
  }
1034
+ return objectToJSON(err);
1035
+ }
1036
+ function objectToJSON(obj) {
1037
+ const normalizedObj = normalizeObject(obj);
1008
1038
  return JSON.parse(
1009
- JSON.stringify(err, Object.getOwnPropertyNames(err))
1039
+ JSON.stringify(normalizedObj, (key, value) => {
1040
+ if (key === "") {
1041
+ return value;
1042
+ }
1043
+ const objProps = Object.getOwnPropertyNames(normalizedObj);
1044
+ if (!objProps.includes(key)) {
1045
+ return void 0;
1046
+ }
1047
+ if (isObject(value)) {
1048
+ return JSON.stringify(value);
1049
+ }
1050
+ return value;
1051
+ })
1010
1052
  );
1011
1053
  }
1012
1054
 
1013
1055
  // src/utils/localStorage.ts
1014
1056
  function getLocalStorageConfigItem(key) {
1015
- return getLocalStorageBoolean(key);
1057
+ const localStorageBoolean = getLocalStorageBoolean(key);
1058
+ if (localStorageBoolean == null) {
1059
+ return false;
1060
+ }
1061
+ return localStorageBoolean;
1016
1062
  }
1017
1063
  function getLocalStorageBoolean(key) {
1018
1064
  try {
1019
- return localStorage.getItem(key) === "1";
1065
+ if (localStorage.getItem(key) === "1") {
1066
+ return true;
1067
+ } else if (localStorage.getItem(key) == null) {
1068
+ return null;
1069
+ } else {
1070
+ return false;
1071
+ }
1020
1072
  } catch (e) {
1021
- return false;
1073
+ return null;
1022
1074
  }
1023
1075
  }
1024
1076
  function setLocalStorageBoolean(key, value) {
@@ -1092,11 +1144,11 @@ function baseGetTag(value) {
1092
1144
  var baseGetTag_default = baseGetTag;
1093
1145
 
1094
1146
  // ../../node_modules/lodash-es/isObject.js
1095
- function isObject(value) {
1147
+ function isObject2(value) {
1096
1148
  var type = typeof value;
1097
1149
  return value != null && (type == "object" || type == "function");
1098
1150
  }
1099
- var isObject_default = isObject;
1151
+ var isObject_default = isObject2;
1100
1152
 
1101
1153
  // ../../node_modules/lodash-es/isFunction.js
1102
1154
  var asyncTag = "[object AsyncFunction]";
@@ -1160,15 +1212,6 @@ function lsidToUUID(lsid) {
1160
1212
  return lsid.replace(/^[^:]+:(.*)$/, "$1");
1161
1213
  }
1162
1214
 
1163
- // src/utils/typeGuards.ts
1164
- function isUint8Array(value) {
1165
- return value instanceof Uint8Array;
1166
- }
1167
- function isObject2(value) {
1168
- const type = typeof value;
1169
- return value != null && (type == "object" || type == "function");
1170
- }
1171
-
1172
1215
  // src/utils/types.ts
1173
1216
  var isType = (typename) => (node) => {
1174
1217
  return node?.__typename === typename;
@@ -1176,9 +1219,6 @@ var isType = (typename) => (node) => {
1176
1219
  function notNullUndefined(value) {
1177
1220
  return value !== null && value !== void 0;
1178
1221
  }
1179
- function isRecord(value) {
1180
- return typeof value === "object" && value !== null && !Array.isArray(value);
1181
- }
1182
1222
  // Annotate the CommonJS export names for ESM import in node:
1183
1223
  0 && (module.exports = {
1184
1224
  CurrencyUnit,
@@ -1 +1 @@
1
- export { A as AppendUnitsOptions, aa as ById, al as Complete, o as CurrencyAmountArg, k as CurrencyAmountInputObj, m as CurrencyAmountObj, n as CurrencyAmountPreferenceObj, V as CurrencyCodes, T as CurrencyLocales, j as CurrencyMap, f as CurrencyUnit, g as CurrencyUnitType, ae as DeepPartial, D as DeprecatedCurrencyAmountObj, a9 as ExpandRecursively, ad as ExtractByTypename, af as JSONLiteral, ah as JSONObject, ag as JSONType, a8 as Maybe, ai as NN, ab as OmitTypename, ak as PartialBy, am as RequiredKeys, S as SDKCurrencyAmountType, U as UmaCurrency, l as UmaCurrencyAmount, z as abbrCurrencyUnit, b as b64decode, a as b64encode, O as bytesToHex, $ as clamp, i as convertCurrencyAmount, h as convertCurrencyAmountValue, R as countryCodesToCurrencyCodes, c as createSha256Hash, d as defaultCurrencyCode, _ as deleteLocalStorageItem, e as ensureArray, N as errorToJSON, B as formatCurrencyStr, w as getCurrencyAmount, Q as getCurrentLocale, L as getErrorMsg, Y as getLocalStorageBoolean, X as getLocalStorageConfigItem, P as hexToBytes, G as isBrowser, p as isCurrencyAmountInputObj, s as isCurrencyAmountObj, t as isCurrencyAmountPreferenceObj, y as isCurrencyMap, r as isDeprecatedCurrencyAmountObj, J as isError, M as isErrorMsg, K as isErrorWithMessage, H as isNode, a2 as isNumber, a7 as isObject, an as isRecord, v as isSDKCurrencyAmount, I as isTest, ac as isType, a6 as isUint8Array, q as isUmaCurrencyAmount, a0 as linearInterpolate, W as localeToCurrencyCode, F as localeToCurrencySymbol, a5 as lsidToUUID, x as mapCurrencyAmount, aj as notNullUndefined, a3 as pollUntil, a1 as round, E as separateCurrencyStrParts, Z as setLocalStorageBoolean, a4 as sleep, u as urlsafe_b64decode } from '../index-C7dqDM91.cjs';
1
+ export { A as AppendUnitsOptions, ab as ById, am as Complete, o as CurrencyAmountArg, k as CurrencyAmountInputObj, m as CurrencyAmountObj, n as CurrencyAmountPreferenceObj, V as CurrencyCodes, T as CurrencyLocales, j as CurrencyMap, f as CurrencyUnit, g as CurrencyUnitType, af as DeepPartial, D as DeprecatedCurrencyAmountObj, aa as ExpandRecursively, ae as ExtractByTypename, ag as JSONLiteral, ai as JSONObject, ah as JSONType, a9 as Maybe, aj as NN, ac as OmitTypename, al as PartialBy, an as RequiredKeys, S as SDKCurrencyAmountType, U as UmaCurrency, l as UmaCurrencyAmount, z as abbrCurrencyUnit, b as b64decode, a as b64encode, O as bytesToHex, $ as clamp, i as convertCurrencyAmount, h as convertCurrencyAmountValue, R as countryCodesToCurrencyCodes, c as createSha256Hash, d as defaultCurrencyCode, _ as deleteLocalStorageItem, e as ensureArray, N as errorToJSON, B as formatCurrencyStr, w as getCurrencyAmount, Q as getCurrentLocale, L as getErrorMsg, Y as getLocalStorageBoolean, X as getLocalStorageConfigItem, P as hexToBytes, G as isBrowser, p as isCurrencyAmountInputObj, s as isCurrencyAmountObj, t as isCurrencyAmountPreferenceObj, y as isCurrencyMap, r as isDeprecatedCurrencyAmountObj, J as isError, M as isErrorMsg, K as isErrorWithMessage, H as isNode, a2 as isNumber, a7 as isObject, a8 as isRecord, v as isSDKCurrencyAmount, I as isTest, ad as isType, a6 as isUint8Array, q as isUmaCurrencyAmount, a0 as linearInterpolate, W as localeToCurrencyCode, F as localeToCurrencySymbol, a5 as lsidToUUID, x as mapCurrencyAmount, ak as notNullUndefined, a3 as pollUntil, a1 as round, E as separateCurrencyStrParts, Z as setLocalStorageBoolean, a4 as sleep, u as urlsafe_b64decode } from '../index-DZbfPQqd.cjs';
@@ -1 +1 @@
1
- export { A as AppendUnitsOptions, aa as ById, al as Complete, o as CurrencyAmountArg, k as CurrencyAmountInputObj, m as CurrencyAmountObj, n as CurrencyAmountPreferenceObj, V as CurrencyCodes, T as CurrencyLocales, j as CurrencyMap, f as CurrencyUnit, g as CurrencyUnitType, ae as DeepPartial, D as DeprecatedCurrencyAmountObj, a9 as ExpandRecursively, ad as ExtractByTypename, af as JSONLiteral, ah as JSONObject, ag as JSONType, a8 as Maybe, ai as NN, ab as OmitTypename, ak as PartialBy, am as RequiredKeys, S as SDKCurrencyAmountType, U as UmaCurrency, l as UmaCurrencyAmount, z as abbrCurrencyUnit, b as b64decode, a as b64encode, O as bytesToHex, $ as clamp, i as convertCurrencyAmount, h as convertCurrencyAmountValue, R as countryCodesToCurrencyCodes, c as createSha256Hash, d as defaultCurrencyCode, _ as deleteLocalStorageItem, e as ensureArray, N as errorToJSON, B as formatCurrencyStr, w as getCurrencyAmount, Q as getCurrentLocale, L as getErrorMsg, Y as getLocalStorageBoolean, X as getLocalStorageConfigItem, P as hexToBytes, G as isBrowser, p as isCurrencyAmountInputObj, s as isCurrencyAmountObj, t as isCurrencyAmountPreferenceObj, y as isCurrencyMap, r as isDeprecatedCurrencyAmountObj, J as isError, M as isErrorMsg, K as isErrorWithMessage, H as isNode, a2 as isNumber, a7 as isObject, an as isRecord, v as isSDKCurrencyAmount, I as isTest, ac as isType, a6 as isUint8Array, q as isUmaCurrencyAmount, a0 as linearInterpolate, W as localeToCurrencyCode, F as localeToCurrencySymbol, a5 as lsidToUUID, x as mapCurrencyAmount, aj as notNullUndefined, a3 as pollUntil, a1 as round, E as separateCurrencyStrParts, Z as setLocalStorageBoolean, a4 as sleep, u as urlsafe_b64decode } from '../index-C7dqDM91.js';
1
+ export { A as AppendUnitsOptions, ab as ById, am as Complete, o as CurrencyAmountArg, k as CurrencyAmountInputObj, m as CurrencyAmountObj, n as CurrencyAmountPreferenceObj, V as CurrencyCodes, T as CurrencyLocales, j as CurrencyMap, f as CurrencyUnit, g as CurrencyUnitType, af as DeepPartial, D as DeprecatedCurrencyAmountObj, aa as ExpandRecursively, ae as ExtractByTypename, ag as JSONLiteral, ai as JSONObject, ah as JSONType, a9 as Maybe, aj as NN, ac as OmitTypename, al as PartialBy, an as RequiredKeys, S as SDKCurrencyAmountType, U as UmaCurrency, l as UmaCurrencyAmount, z as abbrCurrencyUnit, b as b64decode, a as b64encode, O as bytesToHex, $ as clamp, i as convertCurrencyAmount, h as convertCurrencyAmountValue, R as countryCodesToCurrencyCodes, c as createSha256Hash, d as defaultCurrencyCode, _ as deleteLocalStorageItem, e as ensureArray, N as errorToJSON, B as formatCurrencyStr, w as getCurrencyAmount, Q as getCurrentLocale, L as getErrorMsg, Y as getLocalStorageBoolean, X as getLocalStorageConfigItem, P as hexToBytes, G as isBrowser, p as isCurrencyAmountInputObj, s as isCurrencyAmountObj, t as isCurrencyAmountPreferenceObj, y as isCurrencyMap, r as isDeprecatedCurrencyAmountObj, J as isError, M as isErrorMsg, K as isErrorWithMessage, H as isNode, a2 as isNumber, a7 as isObject, a8 as isRecord, v as isSDKCurrencyAmount, I as isTest, ad as isType, a6 as isUint8Array, q as isUmaCurrencyAmount, a0 as linearInterpolate, W as localeToCurrencyCode, F as localeToCurrencySymbol, a5 as lsidToUUID, x as mapCurrencyAmount, ak as notNullUndefined, a3 as pollUntil, a1 as round, E as separateCurrencyStrParts, Z as setLocalStorageBoolean, a4 as sleep, u as urlsafe_b64decode } from '../index-DZbfPQqd.js';
@@ -50,7 +50,7 @@ import {
50
50
  setLocalStorageBoolean,
51
51
  sleep,
52
52
  urlsafe_b64decode
53
- } from "../chunk-23SS5EX2.js";
53
+ } from "../chunk-NV53XYAS.js";
54
54
  export {
55
55
  CurrencyUnit,
56
56
  abbrCurrencyUnit,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightsparkdev/core",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Lightspark JS SDK",
5
5
  "author": "Lightspark Inc.",
6
6
  "keywords": [
@@ -13,7 +13,7 @@
13
13
  "homepage": "https://github.com/lightsparkdev/js-sdk",
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "https://github.com/lightsparkdev/js-sdk.git"
16
+ "url": "git+https://github.com/lightsparkdev/js-sdk.git"
17
17
  },
18
18
  "bugs": {
19
19
  "url": "https://github.com/lightsparkdev/js-sdk/issues"
@@ -38,6 +38,7 @@
38
38
  "files": [
39
39
  "src/*",
40
40
  "dist/*",
41
+ "dist/utils/*",
41
42
  "CHANGELOG.md"
42
43
  ],
43
44
  "scripts": {
@@ -50,9 +51,10 @@
50
51
  "lint:fix": "eslint --fix .",
51
52
  "lint:watch": "esw ./src -w --ext .ts,.tsx,.js --color",
52
53
  "lint": "eslint .",
53
- "package-types": "yarn attw --pack .",
54
+ "package:checks": "yarn publint && yarn attw --pack .",
54
55
  "postversion": "yarn build",
55
- "test": "node --experimental-vm-modules $(yarn bin jest) --no-cache --runInBand --bail src/**/tests/**/*.test.ts",
56
+ "test-cmd": "node --experimental-vm-modules $(yarn bin jest) --no-cache --runInBand --bail",
57
+ "test": "yarn test-cmd -- src/**/tests/**/*.test.ts",
56
58
  "types:watch": "tsc-absolute --watch",
57
59
  "types": "tsc"
58
60
  },
@@ -82,6 +84,7 @@
82
84
  "lodash-es": "^4.17.21",
83
85
  "prettier": "3.0.3",
84
86
  "prettier-plugin-organize-imports": "^3.2.4",
87
+ "publint": "^0.3.9",
85
88
  "ts-jest": "^29.1.1",
86
89
  "tsc-absolute": "^1.0.1",
87
90
  "tsup": "^8.2.4",
@@ -5,7 +5,6 @@ import dayjs from "dayjs";
5
5
  import utc from "dayjs/plugin/utc.js";
6
6
  import type { Client as WsClient } from "graphql-ws";
7
7
  import { createClient } from "graphql-ws";
8
- import NodeWebSocket from "ws";
9
8
  import { Observable } from "zen-observable-ts";
10
9
 
11
10
  import type Query from "./Query.js";
@@ -33,7 +32,8 @@ type BodyData = {
33
32
  };
34
33
 
35
34
  class Requester {
36
- private readonly wsClient: WsClient;
35
+ private wsClient: Promise<WsClient>;
36
+ private resolveWsClient: ((value: WsClient) => void) | null = null;
37
37
  constructor(
38
38
  private readonly nodeKeyCache: NodeKeyCache,
39
39
  private readonly schemaEndpoint: string,
@@ -44,22 +44,43 @@ class Requester {
44
44
  private readonly signingKey?: SigningKey,
45
45
  private readonly fetchImpl: typeof fetch = fetch,
46
46
  ) {
47
+ this.wsClient = new Promise<WsClient>((resolve) => {
48
+ this.resolveWsClient = resolve;
49
+ });
50
+ void this.initWsClient(baseUrl, authProvider);
51
+ autoBind(this);
52
+ }
53
+
54
+ private async initWsClient(baseUrl: string, authProvider: AuthProvider) {
55
+ if (!this.resolveWsClient) {
56
+ /* If resolveWsClient is null assume already initialized: */
57
+ return this.wsClient;
58
+ }
59
+
47
60
  let websocketImpl;
48
- if (typeof WebSocket === "undefined" && typeof window === "undefined") {
49
- websocketImpl = NodeWebSocket;
61
+ if (isNode && typeof WebSocket === "undefined") {
62
+ const wsModule = await import("ws");
63
+ websocketImpl = wsModule.default;
50
64
  }
51
65
  let websocketProtocol = "wss";
52
66
  if (baseUrl.startsWith("http://")) {
53
67
  websocketProtocol = "ws";
54
68
  }
55
- this.wsClient = createClient({
69
+
70
+ const wsClient = createClient({
56
71
  url: `${websocketProtocol}://${this.stripProtocol(this.baseUrl)}/${
57
72
  this.schemaEndpoint
58
73
  }`,
59
74
  connectionParams: () => authProvider.addWsConnectionParams({}),
60
75
  webSocketImpl: websocketImpl,
61
76
  });
62
- autoBind(this);
77
+
78
+ if (this.resolveWsClient) {
79
+ this.resolveWsClient(wsClient);
80
+ this.resolveWsClient = null;
81
+ }
82
+
83
+ return wsClient;
63
84
  }
64
85
 
65
86
  public async executeQuery<T>(query: Query<T>): Promise<T | null> {
@@ -106,11 +127,31 @@ class Requester {
106
127
 
107
128
  return new Observable<{ data: T }>((observer) => {
108
129
  logger.trace(`Requester.subscribe observer`, observer);
109
- return this.wsClient.subscribe(bodyData, {
110
- next: (data) => observer.next(data as { data: T }),
111
- error: (err) => observer.error(err),
112
- complete: () => observer.complete(),
113
- });
130
+
131
+ let cleanup: (() => void) | null = null;
132
+ let canceled = false;
133
+
134
+ void (async () => {
135
+ try {
136
+ const wsClient = await this.wsClient;
137
+ if (!canceled) {
138
+ cleanup = wsClient.subscribe(bodyData, {
139
+ next: (data) => observer.next(data as { data: T }),
140
+ error: (err) => observer.error(err),
141
+ complete: () => observer.complete(),
142
+ });
143
+ }
144
+ } catch (err) {
145
+ observer.error(err);
146
+ }
147
+ })();
148
+
149
+ return () => {
150
+ canceled = true;
151
+ if (cleanup) {
152
+ cleanup();
153
+ }
154
+ };
114
155
  });
115
156
  }
116
157
 
@@ -208,9 +249,22 @@ class Requester {
208
249
  };
209
250
  const data = responseJson.data;
210
251
  if (!data) {
252
+ let firstErrorName: string | undefined = undefined;
253
+ if (
254
+ Array.isArray(responseJson.errors) &&
255
+ responseJson.errors.length > 0
256
+ ) {
257
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
258
+ const firstError = responseJson.errors[0];
259
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
260
+ firstErrorName = firstError["extensions"]?.["error_name"] as
261
+ | string
262
+ | undefined;
263
+ }
211
264
  throw new LightsparkException(
212
265
  "RequestFailed",
213
266
  `Request ${operation} failed. ${JSON.stringify(responseJson.errors)}`,
267
+ { errorName: firstErrorName },
214
268
  );
215
269
  }
216
270
  return data;