libshv-js 3.1.4 → 3.1.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libshv-js",
3
- "version": "3.1.4",
3
+ "version": "3.1.6",
4
4
  "description": "Typescript implementation of libshv",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
package/src/ws-client.ts CHANGED
@@ -26,6 +26,7 @@ type SubscriptionCallback = (path: string, method: string, param?: RpcValue) =>
26
26
  type RpcResponseResolver = (rpc_msg: RpcResponse) => void;
27
27
 
28
28
  type Subscription = {
29
+ subscriber: string;
29
30
  path: string;
30
31
  method: string;
31
32
  callback: SubscriptionCallback;
@@ -135,6 +136,7 @@ class WsClient {
135
136
 
136
137
  this.websocket.addEventListener('close', () => {
137
138
  this.logDebug('DISCONNECTED');
139
+ this.subscriptions.length = 0;
138
140
  this.onDisconnected();
139
141
  });
140
142
 
@@ -227,20 +229,45 @@ class WsClient {
227
229
  }
228
230
  }
229
231
 
230
- subscribe(path: string, method: string, callback: SubscriptionCallback) {
231
- this.callRpcMethod('.broker/app', 'subscribe', new ShvMap({
232
- method, path,
233
- })).catch(() => {
234
- this.logDebug(`Couldn't subscribe to ${path}, ${method}`);
235
- });
236
-
232
+ subscribe(subscriber: string, path: string, method: string, callback: SubscriptionCallback) {
233
+ if (this.subscriptions.some(val => val.subscriber === subscriber && val.path === path && val.method === method)) {
234
+ this.logDebug(`Already subscribed {$path}:${method} for subscriber ${subscriber}`);
235
+ return;
236
+ }
237
+ // If this path:method has not been subscribed on the broker, do it now
238
+ if (!this.subscriptions.some(val => val.path === path && val.method === method)) {
239
+ this.callRpcMethod('.broker/app', 'subscribe', new ShvMap({
240
+ method, path,
241
+ })).catch(() => {
242
+ this.logDebug(`Couldn't subscribe to ${path}, ${method}`);
243
+ });
244
+ }
237
245
  this.subscriptions.push({
246
+ subscriber,
238
247
  path,
239
248
  method,
240
249
  callback,
241
250
  });
242
251
  }
243
252
 
253
+ unsubscribe(subscriber: string, path: string, method: string) {
254
+ const idx = this.subscriptions.findIndex(val => val.subscriber === subscriber && val.path === path && val.method === method);
255
+ if (idx === -1) {
256
+ this.logDebug(`No such subscription ${path}:${method} for subscriber ${subscriber}`);
257
+ return;
258
+ }
259
+ this.subscriptions.splice(idx, 1);
260
+ // Unsubscribe on the broker only if there are no other subscriptions of this path:method
261
+ if (this.subscriptions.some(val => val.path === path && val.method === method)) {
262
+ return;
263
+ }
264
+ this.callRpcMethod('.broker/app', 'unsubscribe', new ShvMap({
265
+ method, path,
266
+ })).catch(() => {
267
+ this.logDebug(`Couldn't unsubscribe ${path}, ${method}`);
268
+ });
269
+ }
270
+
244
271
  close() {
245
272
  this.websocket.close();
246
273
  }
package/src/zod.ts CHANGED
@@ -2,6 +2,7 @@ import {z, type ZodType} from 'zod';
2
2
  import {IMap, Int, type RpcValue, ShvMap} from './rpcvalue';
3
3
 
4
4
  export const map = <T extends Record<string, ZodType<any, any, any>>>(schema: T) => z.custom<ShvMap<{[K in keyof T]: z.infer<T[K]>}>>((data: RpcValue) => data instanceof ShvMap && z.object(schema).safeParse(data.value).success);
5
+ export const recmap = <T extends ZodType<any, any, any>>(schema: T) => z.custom<ShvMap<Record<string, z.infer<T>>>>((data: RpcValue) => data instanceof ShvMap && z.record(z.string(), schema).safeParse(data.value).success);
5
6
  export const imap = <T extends Record<string, ZodType<any, any, any>>>(schema: T) => z.custom<IMap<{[K in keyof T]: z.infer<T[K]>}>>((data: RpcValue) => data instanceof IMap && z.object(schema).safeParse(data.value).success);
6
7
  export const int = () => z.custom<Int>((data: RpcValue) => data instanceof Int);
7
8