@centia-io/sdk 0.0.53 → 0.0.55

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.
@@ -94,12 +94,14 @@
94
94
  const generatePkceChallenge = async () => {
95
95
  const generateRandomString = () => {
96
96
  const array = new Uint32Array(28);
97
- crypto.getRandomValues(array);
97
+ if (globalThis.crypto?.getRandomValues) crypto.getRandomValues(array);
98
+ else for (let i = 0; i < array.length; i++) array[i] = Math.random() * 4294967295 >>> 0;
98
99
  return Array.from(array, (dec) => ("0" + dec.toString(16)).substr(-2)).join("");
99
100
  };
100
- const sha256 = (plain) => {
101
+ const sha256 = async (plain) => {
101
102
  const data = new TextEncoder().encode(plain);
102
- return crypto.subtle.digest("SHA-256", data);
103
+ if (globalThis.crypto?.subtle) return crypto.subtle.digest("SHA-256", data);
104
+ return sha256Fallback(data);
103
105
  };
104
106
  const base64urlEncode = (str) => {
105
107
  return btoa(String.fromCharCode.apply(null, [...new Uint8Array(str)])).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -117,6 +119,128 @@
117
119
  codeChallenge: await pkceChallengeFromVerifier(codeVerifier)
118
120
  };
119
121
  };
122
+ /**
123
+ * Pure JS SHA-256 fallback for insecure contexts (HTTP) where crypto.subtle is unavailable.
124
+ */
125
+ const sha256Fallback = (data) => {
126
+ const K = [
127
+ 1116352408,
128
+ 1899447441,
129
+ 3049323471,
130
+ 3921009573,
131
+ 961987163,
132
+ 1508970993,
133
+ 2453635748,
134
+ 2870763221,
135
+ 3624381080,
136
+ 310598401,
137
+ 607225278,
138
+ 1426881987,
139
+ 1925078388,
140
+ 2162078206,
141
+ 2614888103,
142
+ 3248222580,
143
+ 3835390401,
144
+ 4022224774,
145
+ 264347078,
146
+ 604807628,
147
+ 770255983,
148
+ 1249150122,
149
+ 1555081692,
150
+ 1996064986,
151
+ 2554220882,
152
+ 2821834349,
153
+ 2952996808,
154
+ 3210313671,
155
+ 3336571891,
156
+ 3584528711,
157
+ 113926993,
158
+ 338241895,
159
+ 666307205,
160
+ 773529912,
161
+ 1294757372,
162
+ 1396182291,
163
+ 1695183700,
164
+ 1986661051,
165
+ 2177026350,
166
+ 2456956037,
167
+ 2730485921,
168
+ 2820302411,
169
+ 3259730800,
170
+ 3345764771,
171
+ 3516065817,
172
+ 3600352804,
173
+ 4094571909,
174
+ 275423344,
175
+ 430227734,
176
+ 506948616,
177
+ 659060556,
178
+ 883997877,
179
+ 958139571,
180
+ 1322822218,
181
+ 1537002063,
182
+ 1747873779,
183
+ 1955562222,
184
+ 2024104815,
185
+ 2227730452,
186
+ 2361852424,
187
+ 2428436474,
188
+ 2756734187,
189
+ 3204031479,
190
+ 3329325298
191
+ ];
192
+ const rotr = (n, x) => x >>> n | x << 32 - n;
193
+ const ch = (x, y, z) => x & y ^ ~x & z;
194
+ const maj = (x, y, z) => x & y ^ x & z ^ y & z;
195
+ const sigma0 = (x) => rotr(2, x) ^ rotr(13, x) ^ rotr(22, x);
196
+ const sigma1 = (x) => rotr(6, x) ^ rotr(11, x) ^ rotr(25, x);
197
+ const gamma0 = (x) => rotr(7, x) ^ rotr(18, x) ^ x >>> 3;
198
+ const gamma1 = (x) => rotr(17, x) ^ rotr(19, x) ^ x >>> 10;
199
+ const bitLen = data.length * 8;
200
+ const padded = Array.from(data);
201
+ padded.push(128);
202
+ while (padded.length % 64 !== 56) padded.push(0);
203
+ for (let i = 56; i >= 0; i -= 8) padded.push(i >= 32 ? 0 : bitLen >>> i & 255);
204
+ let h0 = 1779033703, h1 = 3144134277, h2 = 1013904242, h3 = 2773480762;
205
+ let h4 = 1359893119, h5 = 2600822924, h6 = 528734635, h7 = 1541459225;
206
+ for (let offset = 0; offset < padded.length; offset += 64) {
207
+ const W = new Array(64);
208
+ for (let i = 0; i < 16; i++) W[i] = padded[offset + i * 4] << 24 | padded[offset + i * 4 + 1] << 16 | padded[offset + i * 4 + 2] << 8 | padded[offset + i * 4 + 3];
209
+ for (let i = 16; i < 64; i++) W[i] = gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16] | 0;
210
+ let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
211
+ for (let i = 0; i < 64; i++) {
212
+ const t1 = h + sigma1(e) + ch(e, f, g) + K[i] + W[i] | 0;
213
+ const t2 = sigma0(a) + maj(a, b, c) | 0;
214
+ h = g;
215
+ g = f;
216
+ f = e;
217
+ e = d + t1 | 0;
218
+ d = c;
219
+ c = b;
220
+ b = a;
221
+ a = t1 + t2 | 0;
222
+ }
223
+ h0 = h0 + a | 0;
224
+ h1 = h1 + b | 0;
225
+ h2 = h2 + c | 0;
226
+ h3 = h3 + d | 0;
227
+ h4 = h4 + e | 0;
228
+ h5 = h5 + f | 0;
229
+ h6 = h6 + g | 0;
230
+ h7 = h7 + h | 0;
231
+ }
232
+ const result = /* @__PURE__ */ new ArrayBuffer(32);
233
+ const view = new DataView(result);
234
+ view.setUint32(0, h0);
235
+ view.setUint32(4, h1);
236
+ view.setUint32(8, h2);
237
+ view.setUint32(12, h3);
238
+ view.setUint32(16, h4);
239
+ view.setUint32(20, h5);
240
+ view.setUint32(24, h6);
241
+ view.setUint32(28, h7);
242
+ return result;
243
+ };
120
244
  const isTokenExpired = (token) => {
121
245
  let isJwtExpired = false;
122
246
  const { exp } = jwtDecode(token);
@@ -741,35 +865,94 @@
741
865
  */
742
866
  var Ws = class {
743
867
  constructor(options) {
744
- this.options = options;
745
- this.options.wsClient = this.options?.wsClient ?? WebSocket;
868
+ this.ws = null;
869
+ this.listeners = {};
870
+ this.closed = false;
871
+ this.options = {
872
+ reconnect: true,
873
+ reconnectInterval: 3e3,
874
+ ...options
875
+ };
876
+ this.options.wsClient = this.options.wsClient ?? WebSocket;
746
877
  }
747
878
  connect() {
748
- const me = this;
879
+ this.closed = false;
880
+ this.doConnect();
881
+ }
882
+ disconnect() {
883
+ this.closed = true;
884
+ this.ws?.close();
885
+ this.ws = null;
886
+ }
887
+ subscribe(sub) {
888
+ this.send({
889
+ type: "subscription",
890
+ ...sub
891
+ });
892
+ }
893
+ send(data) {
894
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) throw new Error("WebSocket is not connected");
895
+ this.ws.send(typeof data === "string" ? data : JSON.stringify(data));
896
+ }
897
+ on(event, listener) {
898
+ if (!this.listeners[event]) this.listeners[event] = [];
899
+ this.listeners[event].push(listener);
900
+ return () => this.off(event, listener);
901
+ }
902
+ off(event, listener) {
903
+ const arr = this.listeners[event];
904
+ if (!arr) return;
905
+ const idx = arr.indexOf(listener);
906
+ if (idx !== -1) arr.splice(idx, 1);
907
+ }
908
+ get connected() {
909
+ return this.ws?.readyState === WebSocket.OPEN;
910
+ }
911
+ emit(event, data) {
912
+ const arr = this.listeners[event];
913
+ if (!arr) return;
914
+ for (const fn of arr) fn(data);
915
+ }
916
+ doConnect() {
749
917
  const { accessToken } = getTokens();
750
- const connect = () => {
751
- let queryString = `?token=` + accessToken;
752
- if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
753
- const WSClass = this.options.wsClient;
754
- const ws = new WSClass(this.options.host + `/` + queryString);
755
- ws.onopen = function() {
756
- console.log("WebSocket connected!");
757
- };
758
- ws.onmessage = function(event) {
759
- me.options.callBack(event.data);
760
- };
761
- ws.onclose = function(event) {
762
- if (accessToken !== "") {
763
- console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
764
- setTimeout(connect, 3e3);
765
- }
766
- };
767
- ws.onerror = function(err) {
768
- console.error("WebSocket error observed:", err);
769
- ws.close();
770
- };
918
+ if (!accessToken) return;
919
+ let url = this.options.host + "/?token=" + encodeURIComponent(accessToken);
920
+ if (this.options.rels) url += "&rels=" + encodeURIComponent(this.options.rels);
921
+ const WSClass = this.options.wsClient;
922
+ const ws = new WSClass(url);
923
+ this.ws = ws;
924
+ ws.onopen = () => {
925
+ this.emit("open", void 0);
926
+ };
927
+ ws.onmessage = (event) => {
928
+ let msg;
929
+ try {
930
+ msg = JSON.parse(typeof event.data === "string" ? event.data : event.data.toString());
931
+ } catch {
932
+ return;
933
+ }
934
+ switch (msg.type) {
935
+ case "batch":
936
+ this.emit("batch", msg);
937
+ break;
938
+ case "subscription_ack":
939
+ this.emit("subscription_ack", msg);
940
+ break;
941
+ case "error":
942
+ this.emit("error", msg);
943
+ break;
944
+ }
945
+ };
946
+ ws.onclose = (event) => {
947
+ this.emit("close", {
948
+ code: event.code,
949
+ reason: event.reason
950
+ });
951
+ if (!this.closed && this.options.reconnect) setTimeout(() => this.doConnect(), this.options.reconnectInterval);
952
+ };
953
+ ws.onerror = () => {
954
+ ws.close();
771
955
  };
772
- if (accessToken !== "") connect();
773
956
  }
774
957
  };
775
958
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centia-io/sdk",
3
- "version": "0.0.53",
3
+ "version": "0.0.55",
4
4
  "description": "Centia-io TypeScript SDK",
5
5
  "author": "Martin Høgh",
6
6
  "license": "MIT",