insite-subscriptions-client 1.0.294 → 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.
@@ -14,25 +14,70 @@ import {
14
14
  } from "./symbols";
15
15
 
16
16
 
17
- function makeSort(sort) {
18
-
19
- const functionName = `function${performance.now().toString(36).replace(/\./g, "")}`;
17
+ type GenericItem = { _id: string } & Record<string, any>;// eslint-disable-line @typescript-eslint/no-explicit-any
18
+
19
+ type Item = GenericItem | SubscriptionMapItem;
20
+
21
+ type Updated<I extends Item = Item> = {
22
+ deleted: string[];
23
+ added: I[];
24
+ } & I[];
25
+
26
+ type SortList = Record<string, -1 | 1>;
27
+
28
+ export type Updates<I extends Item = Item> =
29
+ (
30
+ [ "c"/* create */, item: I ] |
31
+ [ "d"/* delete */, _id: string ] |
32
+ [ "i"/* initial */, items: I[], sortList?: SortList ] |
33
+ [ "u"/* update */, itemUpdates: { _id: string } & Partial<I>, isAtomicOrUpdatedFields: string[] | true ] |
34
+ null
35
+ )[] |
36
+ null;
37
+
38
+ type UpdateHandler<I extends Item = Item> = (map: SubscriptionMap<I>, updated: Updated<I>, updates: Updates<I>) => void;
39
+
40
+ declare global {
41
+ var __insite_subscription_map_sort_function: ((a: Item, b: Item) => -1 | 0 | 1) | undefined;// eslint-disable-line no-var
42
+ }
43
+
44
+ function createSortFunction(sortList: SortList) {
20
45
 
21
46
  const tempScript = document.createElement("script");
22
- tempScript.textContent = `window.${functionName} = function sort(a, b) { return ${`${Object.entries(sort).map(([ key, value ]) => value > 0 ? `a.${key} > b.${key} ? 1 : a.${key} < b.${key} ? -1 :` : `a.${key} < b.${key} ? 1 : a.${key} > b.${key} ? -1 :`).concat("0").join(" ")};`} }`;
47
+
48
+ tempScript.textContent = `window.__insite_subscription_map_sort_function = function sort(a, b) { return ${
49
+ Object.entries(sortList)
50
+ .map(([ key, value ]) => value > 0 ? `a.${key} > b.${key} ? 1 : a.${key} < b.${key} ? -1 :` : `a.${key} < b.${key} ? 1 : a.${key} > b.${key} ? -1 :`)
51
+ .concat("0")
52
+ .join(" ")
53
+ };}`;
54
+
23
55
  document.head.append(tempScript);
24
- tempScript.remove();
25
56
 
26
- const sortFunction = window[functionName];
57
+ const sortFunction = window.__insite_subscription_map_sort_function!;
27
58
 
28
- delete window[functionName];
59
+ tempScript.remove();
60
+ delete window.__insite_subscription_map_sort_function;
29
61
 
30
62
  return sortFunction;
31
63
  }
32
64
 
65
+ // function createSortFunction(sortList: SortList) {
66
+ // return new Function(// eslint-disable-line no-new-func
67
+ // "a"/* Item */,
68
+ // "b"/* Item */,
69
+ // `return ${
70
+ // Object.entries(sortList)
71
+ // .map(([ key, value ]) => value > 0 ? `a.${key} > b.${key} ? 1 : a.${key} < b.${key} ? -1 :` : `a.${key} < b.${key} ? 1 : a.${key} > b.${key} ? -1 :`)
72
+ // .concat("0")
73
+ // .join(" ")
74
+ // }`
75
+ // ) as (a: Item, b: Item) => -1 | 0 | 1;
76
+ // }
77
+
33
78
 
34
- export class SubscriptionMap extends Map {
35
- constructor(updates, onUpdate) {
79
+ export class SubscriptionMap<I extends Item = Item> extends Map<string, I> {
80
+ constructor(updates?: Updates<I>, onUpdate?: UpdateHandler<I>) {
36
81
  super();
37
82
 
38
83
  if (onUpdate)
@@ -43,19 +88,22 @@ export class SubscriptionMap extends Map {
43
88
 
44
89
  }
45
90
 
46
- #updates = new Map();
91
+ handleUpdate;
92
+
93
+ private updates = new Map();
47
94
 
48
- sortList = null;
95
+ sortList: null | SortList = null;
49
96
 
50
- sortCompareFunction = null;
97
+ sortCompareFunction: ((a: I, b: I) => number) | null = null;
51
98
 
52
- #fieldsToSort = [];
99
+ private fieldsToSort: string[] = [];
53
100
 
54
- sorted = [];
101
+ sorted: I[] = [];
55
102
 
56
103
  sort() {
57
104
 
58
- this.sorted.sort(this.sortCompareFunction);
105
+ if (this.sortCompareFunction)
106
+ this.sorted.sort(this.sortCompareFunction);
59
107
 
60
108
  }
61
109
 
@@ -63,51 +111,52 @@ export class SubscriptionMap extends Map {
63
111
  return this.handleUpdate;
64
112
  }
65
113
 
66
- [setHandleUpdateSymbol](handleUpdate) {
114
+ [setHandleUpdateSymbol](handleUpdate: UpdateHandler<I>) {
67
115
  return (this.handleUpdate = handleUpdate);
68
116
  }
69
117
 
70
- #Item;
118
+ private TheItem!: { new (map: SubscriptionMap<I>, updates: GenericItem): I };
71
119
 
72
- set Item(Item) {
73
- this.#Item = Item;
120
+ set Item(TheItem: { new (map: SubscriptionMap<I>, updates: GenericItem): I }) {
121
+ this.TheItem = TheItem;
74
122
 
75
123
  if (this.size)
76
124
  for (const [ _id, item ] of this)
77
- this.set(_id, new Item(this, item));
125
+ this.set(_id, new TheItem(this, item));
78
126
 
79
127
  }
80
128
 
81
129
  get Item() {
82
- return this.#Item;
130
+ return this.TheItem;
83
131
  }
84
132
 
85
- update(updates) {
133
+ update(updates: Updates<I>) {
86
134
 
87
- const updated = [];
88
- updated.added = [];
89
- updated.deleted = [];
135
+ const updated: Updated<I> = Object.assign([], {
136
+ added: [],
137
+ deleted: []
138
+ });
90
139
 
91
140
  if (updates) {
92
141
  let shouldSort = false;
93
142
 
94
- const Item = this.#Item;
95
- const prevUpdates = this.#updates;
143
+ const TheItem = this.TheItem;// eslint-disable-line prefer-destructuring
144
+ const prevUpdates = this.updates;
96
145
 
97
146
  for (const update of updates)
98
147
  switch (update?.[0]) {
99
148
  case "i"/* initial */: {
100
- const [ , array, sort ] = update;
149
+ const [ , array, sortList ] = update;
101
150
 
102
- if (sort) {
103
- this.sortList = sort;
104
- this.sortCompareFunction = makeSort(sort);
105
- this.#fieldsToSort = [ ...new Set(Object.keys(sort).map(key => key.replace(/\..+/, ""))) ];
151
+ if (sortList) {
152
+ this.sortList = sortList;
153
+ this.sortCompareFunction = createSortFunction(sortList);
154
+ this.fieldsToSort = [ ...new Set(Object.keys(sortList).map(key => key.replace(/\..+/, ""))) ];
106
155
  shouldSort = true;
107
156
  } else {
108
157
  this.sortList = null;
109
158
  this.sortCompareFunction = null;
110
- this.#fieldsToSort = [];
159
+ this.fieldsToSort = [];
111
160
  }
112
161
 
113
162
  if (this.size) {
@@ -120,11 +169,11 @@ export class SubscriptionMap extends Map {
120
169
  if (itemUpdates) {
121
170
  const prevItemUpdates = prevUpdates.get(_id);
122
171
 
123
- if (Item)
172
+ if (TheItem)
124
173
  item.update(itemUpdates);
125
174
  else {
126
- for (const key in prevItemUpdates)
127
- delete item[key];
175
+ for (const key in prevItemUpdates)// eslint-disable-line guard-for-in
176
+ delete item[key as keyof typeof item];
128
177
 
129
178
  Object.assign(item, itemUpdates);
130
179
  }
@@ -133,7 +182,7 @@ export class SubscriptionMap extends Map {
133
182
  updated.push(item);
134
183
  updatesMap.delete(_id);
135
184
  } else {
136
- if (Item)
185
+ if (TheItem)
137
186
  item.delete();
138
187
  else
139
188
  this.delete(_id);
@@ -143,7 +192,7 @@ export class SubscriptionMap extends Map {
143
192
  }
144
193
 
145
194
  for (const [ _id, itemUpdates ] of updatesMap) {
146
- const item = Item ? new Item(this, itemUpdates) : { ...itemUpdates };
195
+ const item = TheItem ? new TheItem(this, itemUpdates) : { ...itemUpdates };
147
196
  this.set(_id, item);
148
197
  prevUpdates.set(_id, itemUpdates);
149
198
  updated.push(item);
@@ -151,11 +200,11 @@ export class SubscriptionMap extends Map {
151
200
  }
152
201
 
153
202
  if (this.sortList)
154
- this.sorted = array.map(newItem => this.get(newItem._id));
203
+ this.sorted = array.map(newItem => this.get(newItem._id)!);
155
204
 
156
205
  } else
157
206
  for (const itemUpdates of array) {
158
- const item = Item ? new Item(this, itemUpdates) : { ...itemUpdates };
207
+ const item = (TheItem ? new TheItem(this, itemUpdates) : { ...itemUpdates }) as I;
159
208
  this.set(item._id, item);
160
209
  this.sorted.push(item);
161
210
  prevUpdates.set(item._id, itemUpdates);
@@ -168,20 +217,20 @@ export class SubscriptionMap extends Map {
168
217
 
169
218
  case "c"/* create */:
170
219
  case "u"/* update */: {
171
- let itemUpdates = update[1];
220
+ let [ , itemUpdates ] = update;
172
221
  let item = this.get(itemUpdates._id);
173
222
 
174
223
  if (item) {
175
224
  const isAtomic = update[2] === true;
176
- const updatedFields = isAtomic ? Object.keys(itemUpdates) : update[2];
225
+ const updatedFields = isAtomic ? Object.keys(itemUpdates) : update[2] as string[];
177
226
  const prevItemUpdates = prevUpdates.get(item._id);
178
227
 
179
- if (Item)
228
+ if (TheItem)
180
229
  item.update(itemUpdates);
181
230
  else {
182
231
  if (!isAtomic)
183
- for (const key in prevItemUpdates)
184
- delete item[key];
232
+ for (const key in prevItemUpdates)// eslint-disable-line guard-for-in
233
+ delete item[key as keyof typeof item];
185
234
 
186
235
  Object.assign(item, itemUpdates);
187
236
  }
@@ -189,10 +238,10 @@ export class SubscriptionMap extends Map {
189
238
  if (isAtomic)
190
239
  itemUpdates = Object.assign(prevItemUpdates, itemUpdates);
191
240
 
192
- if (this.sortList && !shouldSort && (!updatedFields || updatedFields.some(fieldName => this.#fieldsToSort.includes(fieldName))))
241
+ if (this.sortList && !shouldSort && (!updatedFields || updatedFields.some(fieldName => this.fieldsToSort.includes(fieldName))))
193
242
  shouldSort = true;
194
243
  } else {
195
- item = Item ? new Item(this, itemUpdates) : { ...itemUpdates };
244
+ item = (TheItem ? new TheItem(this, itemUpdates) : { ...itemUpdates }) as I;
196
245
  this.set(item._id, item);
197
246
  this.sorted.push(item);
198
247
  if (this.sortList)
@@ -207,11 +256,11 @@ export class SubscriptionMap extends Map {
207
256
  }
208
257
 
209
258
  case "d"/* delete */: {
210
- const _id = update[1];
259
+ const [ , _id ] = update;
211
260
  const itemToDelete = this.get(_id);
212
261
 
213
262
  if (itemToDelete) {
214
- if (Item)
263
+ if (TheItem)
215
264
  itemToDelete.delete();
216
265
  else
217
266
  this.delete(_id);
@@ -233,7 +282,7 @@ export class SubscriptionMap extends Map {
233
282
  } else
234
283
  this.clear();
235
284
 
236
- this.handleUpdate?.(this, updated, updates?.[0] && updates);
285
+ this.handleUpdate?.(this, updated, updates?.[0] ? updates : null);
237
286
 
238
287
  return this;
239
288
  }
@@ -243,7 +292,7 @@ export class SubscriptionMap extends Map {
243
292
  getAsUpdates() {
244
293
  return (
245
294
  (this.size || this.sortList) ?
246
- [ [ "i"/* initial */, [ ...this.#updates.values() ], this.sortList ] ] :
295
+ [ [ "i"/* initial */, [ ...this.updates.values() ], this.sortList ] ] :
247
296
  null
248
297
  );
249
298
  }
@@ -262,11 +311,11 @@ export class SubscriptionMap extends Map {
262
311
  clear() {
263
312
 
264
313
  super.clear();
265
- this.#updates.clear();
314
+ this.updates.clear();
266
315
  this.sorted = [];
267
316
  this.sortList = null;
268
317
  this.sortCompareFunction = null;
269
- this.#fieldsToSort = [];
318
+ this.fieldsToSort = [];
270
319
 
271
320
  }
272
321
 
@@ -287,12 +336,14 @@ export class SubscriptionMap extends Map {
287
336
  static getAsUpdatesSymbol = getAsUpdatesSymbol;
288
337
  static getAsInitialUpdatedSymbol = getAsInitialUpdatedSymbol;
289
338
  static clearSymbol = clearSymbol;
339
+ static WithSubscription: typeof SubscriptionMapWithSubscription;
340
+ static Item: typeof SubscriptionMapItem;
290
341
 
291
342
  }
292
343
 
293
344
 
294
- SubscriptionMap.WithSubscription = class SubscriptionMapWithSubscription extends SubscriptionMap {
295
- constructor(publicationName, params, onUpdate, immediately = true) {
345
+ export class SubscriptionMapWithSubscription<I extends Item = Item> extends SubscriptionMap<I> {
346
+ constructor(publicationName: string, params: unknown[], onUpdate: UpdateHandler<I>, immediately = true) {
296
347
  super(null, onUpdate);
297
348
 
298
349
  this.publicationName = publicationName;
@@ -303,12 +354,15 @@ SubscriptionMap.WithSubscription = class SubscriptionMapWithSubscription extends
303
354
 
304
355
  }
305
356
 
306
- subscription = null;
357
+ publicationName;
358
+ params;
359
+
360
+ subscription: null | Subscription = null;
307
361
 
308
362
  subscribe() {
309
363
 
310
364
  if (!this.subscription)
311
- this.subscription = new Subscription("map", this.publicationName, this.params, updates => this.update(updates));
365
+ this.subscription = new Subscription("map", this.publicationName, this.params, updates => this.update(updates as Updates<I>));
312
366
 
313
367
  }
314
368
 
@@ -329,7 +383,7 @@ SubscriptionMap.WithSubscription = class SubscriptionMapWithSubscription extends
329
383
  return this.unsubscribe;
330
384
  }
331
385
 
332
- renew(publicationName, params) {
386
+ renew(publicationName?: string, params?: unknown[]) {
333
387
 
334
388
  if (this.subscription) {
335
389
  this.unsubscribe();
@@ -366,28 +420,36 @@ SubscriptionMap.WithSubscription = class SubscriptionMapWithSubscription extends
366
420
  static renewSymbol = renewSymbol;
367
421
  static getSubscriptionSymbol = getSubscriptionSymbol;
368
422
 
369
- };
423
+ }
424
+
425
+ SubscriptionMap.WithSubscription = SubscriptionMapWithSubscription;
370
426
 
371
427
 
372
- SubscriptionMap.Item = class SubscriptionMapItem {
373
- constructor(map, updates) {
374
- this.#map = map;
428
+ export class SubscriptionMapItem {
429
+ constructor(map: SubscriptionMap, updates: GenericItem) {
430
+ this.map = map;
375
431
 
376
432
  this.update(updates);
377
433
 
378
434
  }
379
435
 
380
- #map;
436
+ _id!: string;
437
+
438
+ private map;
381
439
 
382
- update(updates) {
440
+ update(updates: GenericItem) {
383
441
  Object.assign(this, updates);
384
442
 
385
443
  }
386
444
 
387
445
  delete() {
388
446
 
389
- this.#map.delete(this._id);
447
+ this.map.delete(this._id);
390
448
 
391
449
  }
392
450
 
393
- };
451
+ }
452
+
453
+ SubscriptionMap.Item = SubscriptionMapItem;
454
+
455
+ export { Updated as SubscriptionMapUpdated };
@@ -0,0 +1,168 @@
1
+ import { Subscription } from "./Subscription";
2
+ import {
3
+ clearSymbol,
4
+ getAsInitialUpdatedSymbol,
5
+ getAsUpdatesSymbol,
6
+ getHandleUpdateSymbol,
7
+ getSubscriptionSymbol,
8
+ renewSymbol,
9
+ setHandleUpdateSymbol,
10
+ subscribeSymbol,
11
+ unsubscribeSymbol,
12
+ updateSymbol
13
+ } from "./symbols";
14
+
15
+
16
+ const handleUpdateSymbol = Symbol("handleUpdate");
17
+ const updatesSymbol = Symbol("updates");
18
+
19
+ export type Updated = Record<string, unknown>;
20
+ export type Updates = null | Record<string, unknown>;
21
+ type UpdateHandler = (object: SubscriptionObject, updated: Updated, updates: Updates) => void;
22
+
23
+
24
+ export class SubscriptionObject {
25
+ constructor(updates?: Updates, onUpdate?: UpdateHandler) {
26
+ if (onUpdate)
27
+ this[handleUpdateSymbol] = onUpdate;
28
+
29
+ if (updates)
30
+ this[updateSymbol](updates);
31
+
32
+ }
33
+
34
+ [handleUpdateSymbol]?: UpdateHandler;
35
+
36
+ [updatesSymbol]: Updates = null;
37
+
38
+ [getHandleUpdateSymbol]() {
39
+ return this[handleUpdateSymbol];
40
+ }
41
+
42
+ [setHandleUpdateSymbol](handleUpdate: UpdateHandler) {
43
+ return (this[handleUpdateSymbol] = handleUpdate);
44
+ }
45
+
46
+ [updateSymbol](updates: Updates) {
47
+ if (updates) {
48
+ for (const key in this[updatesSymbol])// eslint-disable-line guard-for-in
49
+ delete this[key];
50
+ for (const key in updates)// eslint-disable-line guard-for-in
51
+ this[key] = updates[key];
52
+ this[updatesSymbol] = updates;
53
+ } else
54
+ this[clearSymbol]();
55
+
56
+ this[handleUpdateSymbol]?.(this, this, this[updatesSymbol]);
57
+
58
+ return this;
59
+ }
60
+
61
+ [getAsUpdatesSymbol]() {
62
+ return this[updatesSymbol] && { ...this[updatesSymbol] };
63
+ }
64
+
65
+ [getAsInitialUpdatedSymbol]() {
66
+ return this.valueOf();
67
+ }
68
+
69
+ [clearSymbol]() {
70
+
71
+ for (const key in this)// eslint-disable-line guard-for-in
72
+ delete this[key];
73
+ this[updatesSymbol] = null;
74
+
75
+ }
76
+
77
+ valueOf() {
78
+ return this[updatesSymbol] && this;
79
+ }
80
+
81
+ get [Symbol.toStringTag]() {
82
+ return "SubscriptionObject";
83
+ }
84
+
85
+ [key: string]: unknown;
86
+
87
+
88
+ static updateSymbol = updateSymbol;
89
+ static getHandleUpdateSymbol = getHandleUpdateSymbol;
90
+ static setHandleUpdateSymbol = setHandleUpdateSymbol;
91
+ static getAsUpdatesSymbol = getAsUpdatesSymbol;
92
+ static getAsInitialUpdatedSymbol = getAsInitialUpdatedSymbol;
93
+ static clearSymbol = clearSymbol;
94
+ static WithSubscription: typeof SubscriptionObjectWithSubscription;
95
+
96
+ }
97
+
98
+
99
+ export class SubscriptionObjectWithSubscription extends SubscriptionObject {
100
+ constructor(publicationName: string, params: unknown[], onUpdate: UpdateHandler, immediately = true) {
101
+ super(null, onUpdate);
102
+
103
+ this.publicationName = publicationName;
104
+ this.params = params;
105
+
106
+ if (immediately)
107
+ this[subscribeSymbol]();
108
+
109
+ }
110
+
111
+ private publicationName;
112
+ private params;
113
+ private subscription: null | Subscription = null;
114
+
115
+ [subscribeSymbol]() {
116
+
117
+ if (!this.subscription)
118
+ this.subscription = new Subscription("object", this.publicationName, this.params, updates => this[updateSymbol](updates as Updates));
119
+
120
+ }
121
+
122
+ [unsubscribeSymbol]() {
123
+
124
+ if (this.subscription) {
125
+ this.subscription.cancel();
126
+ this.subscription = null;
127
+ }
128
+
129
+ }
130
+
131
+ [renewSymbol](publicationName?: string, params?: unknown[]) {
132
+
133
+ if (this.subscription) {
134
+ this[unsubscribeSymbol]();
135
+
136
+ if (publicationName)
137
+ if (Array.isArray(publicationName))
138
+ params = publicationName;
139
+ else
140
+ this.publicationName = publicationName;
141
+
142
+ if (params)
143
+ this.params = params;
144
+
145
+ this[subscribeSymbol]();
146
+ }
147
+
148
+ }
149
+
150
+ [getSubscriptionSymbol]() {
151
+ return this.subscription;
152
+ }
153
+
154
+ get [Symbol.toStringTag]() {
155
+ return "SubscriptionObjectWithSubscription";
156
+ }
157
+
158
+
159
+ static subscribeSymbol = subscribeSymbol;
160
+ static unsubscribeSymbol = unsubscribeSymbol;
161
+ static renewSymbol = renewSymbol;
162
+ static getSubscriptionSymbol = getSubscriptionSymbol;
163
+
164
+ }
165
+
166
+ SubscriptionObject.WithSubscription = SubscriptionObjectWithSubscription;
167
+
168
+ export { Updated as SubscriptionObjectUpdated };
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ export * from "./Subscription.js";
2
+ export { SubscriptionArray, SubscriptionArrayUpdated, SubscriptionArrayWithSubscription } from "./SubscriptionArray";
3
+ export * from "./SubscriptionGroup";
4
+ export { SubscriptionMap, SubscriptionMapUpdated, SubscriptionMapWithSubscription } from "./SubscriptionMap";
5
+ export { SubscriptionObject, SubscriptionObjectUpdated, SubscriptionObjectWithSubscription } from "./SubscriptionObject";
6
+ export {
7
+ clearSymbol,
8
+ getAsInitialUpdatedSymbol,
9
+ getAsUpdatesSymbol,
10
+ getHandleSubscriptionSymbol,
11
+ getHandleUpdateSymbol,
12
+ getSubscriptionSymbol,
13
+ renewSymbol,
14
+ setHandleSubscriptionSymbol,
15
+ setHandleUpdateSymbol,
16
+ subscribeSymbol,
17
+ unsubscribeSymbol,
18
+ updateSymbol
19
+ } from "./symbols";