insite-subscriptions-client 1.0.295 → 2.0.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/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "insite-subscriptions-client",
3
- "version": "1.0.295",
3
+ "version": "2.0.0",
4
4
  "description": "inSite subscriptions client side",
5
5
  "type": "module",
6
- "main": "./lib/index.js",
7
- "module": "./lib/index.js",
8
- "packageManager": "bun@1.1.9",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "packageManager": "bun@1.1.26",
9
9
  "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "build": "bun .conveyer.js",
12
+ "postbuild": "tsc -p ."
11
13
  },
12
14
  "repository": {
13
15
  "type": "git",
@@ -22,14 +24,13 @@
22
24
  "author": "Eugene Nesvetaev <dev@nesvet.dev> (https://nesvet.dev/)",
23
25
  "license": "MIT",
24
26
  "dependencies": {
25
- "@nesvet/n": "^1",
26
- "eventemitter3": "^5"
27
+ "@nesvet/n": "^1.1.7",
28
+ "eventemitter3": "^5.0.1",
29
+ "insite-ws": "^2"
27
30
  },
28
31
  "devDependencies": {
29
- "@nesvet/eslint-config": "^1"
30
- },
31
- "peerDependencies": {
32
- "insite-subscriptions-server": "^1",
33
- "insite-ws": "^1"
32
+ "@nesvet/conveyer": "^2.2.4",
33
+ "@nesvet/eslint-config": "^2.0.25",
34
+ "typescript": "^5.5.4"
34
35
  }
35
36
  }
@@ -1,26 +1,18 @@
1
- //#if _SSR
2
- // import { publications } from "insite-subscriptions-server";
1
+ import type { InSiteWebSocket } from "insite-ws/client";
3
2
 
4
3
 
5
- // export const initialsMap = new Map();
6
-
7
- // export const subscriptionContext = {};
8
-
9
- // export async function Subscription(type, publicationName, args = [], handler) {
10
- // const value = await publications.get(publicationName)?.fetch(subscriptionContext, ...args);
11
-
12
- // subscriptionContext.initials.push(JSON.stringify(value));
13
-
14
- // handler(value);
4
+ declare global {
5
+ var __initials: undefined | unknown[];// eslint-disable-line no-var
6
+ }
15
7
 
16
- // }
17
8
 
9
+ let i: number;
10
+ let subscriptions: Map<number, Subscription>;
11
+ let ws: InSiteWebSocket;
18
12
 
19
- //#else
20
- let i, subscriptions, ws;
21
13
 
22
14
  export class Subscription {
23
- constructor(type, publicationName, args = [], handler, immediately = true) {
15
+ constructor(type: "array" | "map" | "object", publicationName: string, args: unknown[] = [], handler: (updates: unknown) => void, immediately = true) {
24
16
 
25
17
  if (!ws)
26
18
  throw new Error("Subscription is not binded to WS. Do Subscription.bindTo(ws) first");
@@ -47,6 +39,14 @@ export class Subscription {
47
39
 
48
40
  }
49
41
 
42
+ i;
43
+ type;
44
+ publicationName;
45
+ args;
46
+ handler;
47
+ immediately;
48
+ isActive;
49
+
50
50
  start = () => {
51
51
 
52
52
  ws.sendMessage("s-s"/* subscription subscribe */, this.type, this.publicationName, this.i, this.args, this.immediately);
@@ -66,20 +66,18 @@ export class Subscription {
66
66
  }
67
67
 
68
68
 
69
- static bindTo(_ws) {
69
+ static bindTo(_ws: InSiteWebSocket) {
70
70
  ws = _ws;
71
71
 
72
72
  i = 0;
73
73
 
74
- subscriptions =
75
- Subscription.subscriptions =
76
- new Map();
74
+ subscriptions = new Map();
77
75
 
78
- ws.on("message:s-c"/* subscription changed */, (_i, data) => {
79
- const subscription = subscriptions.get(_i);
76
+ ws.on("message:s-c"/* subscription changed */, (si: number, updates: unknown) => {
77
+ const subscription = subscriptions.get(si);
80
78
  if (subscription) {
81
79
  subscription.isActive = true;
82
- subscription.handler(data);
80
+ subscription.handler(updates);
83
81
  }
84
82
 
85
83
  });
@@ -101,6 +99,3 @@ export class Subscription {
101
99
  }
102
100
 
103
101
  }
104
-
105
-
106
- //#endif
@@ -14,38 +14,65 @@ import {
14
14
  } from "./symbols";
15
15
 
16
16
 
17
- const ascSort = (a, b) => a > b ? 1 : a < b ? -1 : 0;
18
- const descSort = (a, b) => a > b ? -1 : a < b ? 1 : 0;
17
+ /* eslint-disable @typescript-eslint/no-explicit-any */
19
18
 
20
19
 
21
- export class SubscriptionArray extends Array {
22
- constructor(updates, onUpdate) {
20
+ type Item = unknown;
21
+
22
+ type Updated<I extends Item = Item> = {
23
+ deleted: I[];
24
+ added: I[];
25
+ } & I[];
26
+
27
+ export type Updates<I extends Item = Item> =
28
+ (
29
+ [ "a"/* add */, newItem: I ] |
30
+ [ "d"/* delete */, itemToDelete: I ] |
31
+ [ "i"/* initial */, items: I[], sort?: -1 | 1 ] |
32
+ null
33
+ )[] |
34
+ null;
35
+
36
+ type UpdateHandler<I extends Item = Item> = (array: SubscriptionArray<I>, updated: Updated<I>, updates: Updates<I>) => void;
37
+
38
+ const ascSort = (a: any, b: any) => a > b ? 1 : a < b ? -1 : 0;
39
+ const descSort = (a: any, b: any) => a > b ? -1 : a < b ? 1 : 0;
40
+
41
+
42
+ export class SubscriptionArray<I extends Item = Item> extends Array<I> {
43
+ constructor(updates?: Updates<I>, onUpdate?: UpdateHandler<I>) {
23
44
  super();
24
45
 
25
- this.handleUpdate = onUpdate;
46
+ if (onUpdate)
47
+ this.handleUpdate = onUpdate;
26
48
 
27
49
  if (Array.isArray(updates))
28
50
  this.update(updates);
29
51
 
30
52
  }
31
53
 
32
- sortDirection = 0;
54
+ sorted: Item[] = [];
33
55
 
34
- sortCompareFunction = null;
56
+ handleUpdate;
57
+
58
+ sortDirection: -1 | 0 | 1 = 0;
59
+
60
+ sortCompareFunction: null | typeof ascSort | typeof descSort = null;
35
61
 
36
62
  [getHandleUpdateSymbol]() {
37
63
  return this.handleUpdate;
38
64
  }
39
65
 
40
- [setHandleUpdateSymbol](handleUpdate) {
66
+ [setHandleUpdateSymbol](handleUpdate: UpdateHandler<I>) {
41
67
  return (this.handleUpdate = handleUpdate);
42
68
  }
43
69
 
44
- update(updates) {
70
+ update(updates: Updates<I>) {
45
71
 
46
- const updated = [];
47
- updated.deleted = [];
48
- updated.added = [];
72
+ const updated: Updated<I> = Object.assign([], {
73
+ deleted: [],
74
+ added: []
75
+ });
49
76
 
50
77
  if (updates) {
51
78
  let shouldSort = false;
@@ -76,7 +103,7 @@ export class SubscriptionArray extends Array {
76
103
  }
77
104
 
78
105
  case "a"/* add */: {
79
- const newItem = update[1];
106
+ const [ , newItem ] = update;
80
107
 
81
108
  if (!this.includes(newItem)) {
82
109
  this.push(newItem);
@@ -90,7 +117,7 @@ export class SubscriptionArray extends Array {
90
117
  }
91
118
 
92
119
  case "d"/* delete */: {
93
- const itemToDelete = update[1];
120
+ const [ , itemToDelete ] = update;
94
121
 
95
122
  if (removeOne(this, itemToDelete))
96
123
  updated.deleted.push(itemToDelete);
@@ -102,13 +129,13 @@ export class SubscriptionArray extends Array {
102
129
  this.clear();
103
130
  }
104
131
 
105
- if (shouldSort)
132
+ if (shouldSort && this.sortCompareFunction)
106
133
  this.sort(this.sortCompareFunction);
107
134
 
108
135
  } else
109
136
  this.clear();
110
137
 
111
- this.handleUpdate?.(this, updated, updates?.[0] && updates);
138
+ this.handleUpdate?.(this, updated, updates?.[0] ? updates : null);
112
139
 
113
140
  return this;
114
141
  }
@@ -159,12 +186,13 @@ export class SubscriptionArray extends Array {
159
186
  static getAsUpdatesSymbol = getAsUpdatesSymbol;
160
187
  static getAsInitialUpdatedSymbol = getAsInitialUpdatedSymbol;
161
188
  static clearSymbol = clearSymbol;
189
+ static WithSubscription: typeof SubscriptionArrayWithSubscription;
162
190
 
163
191
  }
164
192
 
165
193
 
166
- SubscriptionArray.WithSubscription = class SubscriptionArrayWithSubscription extends SubscriptionArray {
167
- constructor(publicationName, params, onUpdate, immediately = true) {
194
+ export class SubscriptionArrayWithSubscription<I extends Item = Item> extends SubscriptionArray<I> {
195
+ constructor(publicationName: string, params: unknown[], onUpdate: UpdateHandler<I>, immediately = true) {
168
196
  super(null, onUpdate);
169
197
 
170
198
  this.publicationName = publicationName;
@@ -175,12 +203,14 @@ SubscriptionArray.WithSubscription = class SubscriptionArrayWithSubscription ext
175
203
 
176
204
  }
177
205
 
178
- subscription = null;
206
+ publicationName;
207
+ params;
208
+ subscription: null | Subscription = null;
179
209
 
180
210
  subscribe() {
181
211
 
182
212
  if (!this.subscription)
183
- this.subscription = new Subscription("array", this.publicationName, this.params, updates => this.update(updates));
213
+ this.subscription = new Subscription("array", this.publicationName, this.params, updates => this.update(updates as Updates<I>));
184
214
 
185
215
  }
186
216
 
@@ -201,7 +231,7 @@ SubscriptionArray.WithSubscription = class SubscriptionArrayWithSubscription ext
201
231
  return this.unsubscribe;
202
232
  }
203
233
 
204
- renew(publicationName, params) {
234
+ renew(publicationName?: string, params?: unknown[]) {
205
235
 
206
236
  if (this.subscription) {
207
237
  this.unsubscribe();
@@ -238,4 +268,8 @@ SubscriptionArray.WithSubscription = class SubscriptionArrayWithSubscription ext
238
268
  static renewSymbol = renewSymbol;
239
269
  static getSubscriptionSymbol = getSubscriptionSymbol;
240
270
 
241
- };
271
+ }
272
+
273
+ SubscriptionArray.WithSubscription = SubscriptionArrayWithSubscription;
274
+
275
+ export { Updated as SubscriptionArrayUpdated };
@@ -1,80 +1,107 @@
1
- import { debounce } from "@nesvet/n";
2
1
  import EventEmitter from "eventemitter3";
2
+ import { debounce, StatefulPromise } from "@nesvet/n";
3
3
  import { privates } from "./common";
4
4
  import { SubscriptionGroupItem } from "./SubscriptionGroupItem";
5
+ import {
6
+ Definition,
7
+ ParseValues,
8
+ SubscriptionHandle,
9
+ SubscriptionOnBeforeInit,
10
+ SubscriptionType,
11
+ TupleDefinition,
12
+ UnparsedDefinition
13
+ } from "./types";
5
14
 
6
15
 
7
- function parseDefinition(definition) {
8
- if (Array.isArray(definition)) {
16
+ /* eslint-disable @typescript-eslint/no-explicit-any */
17
+
18
+
19
+ function isTupleDefinition<T extends SubscriptionType>(definition: UnparsedDefinition<T>): definition is TupleDefinition {
20
+ return Array.isArray(definition);
21
+ }
22
+
23
+ type Target = any;
24
+
25
+ type Options = {
26
+ target?: Target;
27
+ debounce?: number;
28
+ immediately?: boolean;
29
+ };
30
+
31
+
32
+ function parseDefinition<T extends SubscriptionType>(definition: UnparsedDefinition<T>) {
33
+ if (isTupleDefinition(definition)) {
9
34
  const args = definition.slice();
10
35
 
11
- const parsed = {};
36
+ const parsed: Partial<Definition<T>> = {};
12
37
 
13
- parsed.name = args.shift();
38
+ parsed.name = args.shift() as Definition<T>["name"];
14
39
  if (typeof args[0] == "object" && !Array.isArray(args[0])) {
15
- parsed.value = args.shift();
16
- parsed.type = parsed.value.toString().match(/Subscription(Object|Array|Map)/)[1];
17
- if (parsed.type)
18
- parsed.type = parsed.type.toLowerCase();
19
- else
40
+ parsed.value = args.shift() as Definition<T>["value"];
41
+ parsed.type = parsed.value!.toString().match(/Subscription(Object|Array|Map)/)?.[1].toLowerCase() as Definition<T>["type"];
42
+ if (!parsed.type)
20
43
  throw new Error("Unknown value type");
21
44
  } else {
22
45
  if (typeof args[0] == "string")
23
- parsed.type = args.shift();
46
+ parsed.type = args.shift() as Definition<T>["type"];
24
47
  if (typeof args[0] == "string")
25
- parsed.publicationName = args.shift();
48
+ parsed.publicationName = args.shift() as Definition<T>["publicationName"];
26
49
  if (Array.isArray(args[0]))
27
- parsed.params = args.shift();
50
+ parsed.params = args.shift() as Definition<T>["params"];
28
51
  }
52
+
29
53
  if (typeof args[0] == "function")
30
- parsed.handle = args.shift();
54
+ parsed.handle = args.shift() as SubscriptionHandle<T>;
31
55
  if (typeof args[0] == "function")
32
- parsed.onBeforeInit = args.shift();
56
+ parsed.onBeforeInit = args.shift() as SubscriptionOnBeforeInit<T>;
33
57
  if (typeof args[0] == "number")
34
- parsed.debounceLimit = args.shift();
58
+ parsed.debounce = args.shift() as Definition<T>["debounce"];
35
59
  if (typeof args[0] == "boolean")
36
- parsed.preventBind = args.shift();
60
+ parsed.preventBind = args.shift() as Definition<T>["preventBind"];
37
61
 
38
- return parsed;
62
+ return parsed as Definition<T>;
39
63
  }
40
64
 
65
+ definition.type ??= "object" as T;
66
+
41
67
  return definition;
42
68
  }
43
69
 
44
- export class SubscriptionGroup extends EventEmitter {
45
- constructor(definitions, options = {}) {
46
- super();
47
-
48
- const {
70
+ export class SubscriptionGroup<DS extends UnparsedDefinition[] = any[]> extends EventEmitter {
71
+ constructor(
72
+ definitions: DS,
73
+ {
49
74
  target,
50
75
  debounce: debounceLimit = SubscriptionGroup.debounceLimit,
51
76
  immediately
52
- } = options;
77
+ }: Options = {}
78
+ ) {
79
+ super();
53
80
 
54
- this.#applyOptions({ target, debounceLimit });
81
+ this.applyOptions({ target, debounceLimit });
55
82
 
56
- this.#initPromise = new Promise(resolve => (this.#initResolve = resolve));
83
+ this.#initPromise = new StatefulPromise();
57
84
 
58
85
  this.attach(definitions, false, immediately);
59
86
 
60
87
  }
61
88
 
62
- items = [];
63
- values = [];
89
+ target?: Target;
90
+ emitUpdate!: () => void;
91
+
92
+ items = [] as unknown as Record<string, SubscriptionGroupItem> & SubscriptionGroupItem[];
93
+ values = [] as DS extends any ? (any[] & Record<string, any>) : ParseValues<DS>;
64
94
 
65
95
  isLoaded = false;
66
96
  isInited = false;
67
97
 
68
- #loadPromise;
69
- #initPromise;
70
- #unloadPromise;
71
- #loadResolve;
72
- #initResolve;
73
- #unloadResolve;
98
+ #loadPromise!: StatefulPromise<SubscriptionGroup>;
99
+ #initPromise: StatefulPromise<SubscriptionGroup>;
100
+ #unloadPromise!: StatefulPromise<SubscriptionGroup>;
74
101
 
75
- #debounceLimit = null;
102
+ #debounceLimit?: null | number = null;
76
103
 
77
- #applyOptions({ target, debounceLimit }) {
104
+ applyOptions({ target, debounceLimit }: { target?: Target; debounceLimit?: number }) {
78
105
 
79
106
  if (this.target !== target) {
80
107
  if (this.target)
@@ -101,15 +128,15 @@ export class SubscriptionGroup extends EventEmitter {
101
128
 
102
129
  }
103
130
 
104
- attach(definitions, shouldReload = this.isLoaded, immediately = true) {
131
+ attach(definitions: DS, shouldReload = this.isLoaded, immediately = true) {
105
132
  if (shouldReload)
106
133
  this.isLoaded = false;
107
134
 
108
- if (!this.#loadPromise || this.#loadPromise.isResolved)
109
- this.#loadPromise = new Promise(resolve => (this.#loadResolve = resolve));
135
+ if (!this.#loadPromise || this.#loadPromise.isFulfilled)
136
+ this.#loadPromise = new StatefulPromise();
110
137
 
111
- if (!this.#unloadPromise || this.#unloadPromise.isResolved)
112
- this.#unloadPromise = new Promise(resolve => (this.#unloadResolve = resolve));
138
+ if (!this.#unloadPromise || this.#unloadPromise.isFulfilled)
139
+ this.#unloadPromise = new StatefulPromise();
113
140
 
114
141
  return Promise.all(definitions.map(definition =>
115
142
  new SubscriptionGroupItem(parseDefinition(definition), this)
@@ -122,7 +149,7 @@ export class SubscriptionGroup extends EventEmitter {
122
149
  }));
123
150
  }
124
151
 
125
- detach(names, shouldUpdate = true) {
152
+ detach(names: string[], shouldUpdate = true) {
126
153
 
127
154
  for (const name of names)
128
155
  this.items[name]?.detach();
@@ -134,11 +161,11 @@ export class SubscriptionGroup extends EventEmitter {
134
161
 
135
162
  }
136
163
 
137
- redefine(definitions) {
164
+ redefine(definitions: DS) {
138
165
 
139
166
  const itemsToDetach = new Map(this.items.map(item => [ item.name, item ]));
140
167
  const definitionsToRedefine = [];
141
- const definitionsToAttach = [];
168
+ const definitionsToAttach = [] as unknown as DS;
142
169
 
143
170
  for (let definition of definitions) {
144
171
  definition = parseDefinition(definition);
@@ -184,7 +211,7 @@ export class SubscriptionGroup extends EventEmitter {
184
211
  this.isLoaded = true;
185
212
 
186
213
  for (const item of this.items)
187
- privates.itemLoad(item);
214
+ privates.itemLoad!(item);
188
215
 
189
216
  this.emit("load", this.values);
190
217
 
@@ -196,11 +223,10 @@ export class SubscriptionGroup extends EventEmitter {
196
223
  this.emitUpdate();
197
224
 
198
225
 
199
- this.#loadResolve(this);
200
- this.#loadPromise.isResolved = true;
226
+ this.#loadPromise.resolve(this);
201
227
 
202
- if (this.#unloadPromise.isResolved)
203
- this.#unloadPromise = new Promise(resolve => (this.#unloadResolve = resolve));
228
+ if (this.#unloadPromise.isFulfilled)
229
+ this.#unloadPromise = new StatefulPromise();
204
230
  }
205
231
 
206
232
  }
@@ -219,11 +245,11 @@ export class SubscriptionGroup extends EventEmitter {
219
245
 
220
246
 
221
247
  for (const item of this.items)
222
- privates.itemInit(item);
248
+ privates.itemInit!(item);
223
249
 
224
250
  this.emit("init", this.values);
225
251
 
226
- this.#initResolve(this);
252
+ this.#initPromise.resolve(this);
227
253
  }
228
254
 
229
255
  }
@@ -239,7 +265,7 @@ export class SubscriptionGroup extends EventEmitter {
239
265
  this.isLoaded = false;
240
266
 
241
267
  for (const item of this.items)
242
- privates.itemUnload(item);
268
+ privates.itemUnload!(item);
243
269
 
244
270
  this.emit("unload", this.values);
245
271
 
@@ -249,11 +275,10 @@ export class SubscriptionGroup extends EventEmitter {
249
275
  else
250
276
  this.emitUpdate();
251
277
 
252
- this.#unloadResolve(this);
253
- this.#unloadPromise.isResolved = true;
278
+ this.#unloadPromise.resolve(this);
254
279
 
255
- if (this.#loadPromise.isResolved)
256
- this.#loadPromise = new Promise(resolve => (this.#loadResolve = resolve));
280
+ if (this.#loadPromise.isFulfilled)
281
+ this.#loadPromise = new StatefulPromise();
257
282
  }
258
283
 
259
284
  }
@@ -283,10 +308,12 @@ export class SubscriptionGroup extends EventEmitter {
283
308
 
284
309
  static {
285
310
 
286
- privates.groupLoad = group => group.#load();
287
- privates.groupInit = group => group.#init();
288
- privates.groupUnload = group => group.#unload();
311
+ privates.groupLoad = (group: SubscriptionGroup) => group.#load();
312
+ privates.groupInit = (group: SubscriptionGroup) => group.#init();
313
+ privates.groupUnload = (group: SubscriptionGroup) => group.#unload();
289
314
 
290
315
  }
291
316
 
292
317
  }
318
+
319
+ export { Options as SubscriptionGroupOptions, Target as SubscriptionGroupTarget };