@superutils/rx 0.1.1
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/LICENSE +0 -0
- package/README.md +3 -0
- package/dist/browser/index.min.js +4 -0
- package/dist/browser/index.min.js.map +1 -0
- package/dist/index.cjs +651 -0
- package/dist/index.d.cts +730 -0
- package/dist/index.d.ts +730 -0
- package/dist/index.js +636 -0
- package/package.json +53 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
BehaviorSubject: () => import_rxjs.BehaviorSubject,
|
|
34
|
+
DataStorage: () => DataStorage,
|
|
35
|
+
IGNORE_UPDATE_SYMBOL: () => IGNORE_UPDATE_SYMBOL,
|
|
36
|
+
IntervalRunner: () => IntervalRunner,
|
|
37
|
+
IntervalSubject: () => IntervalSubject,
|
|
38
|
+
Subject: () => import_rxjs.Subject,
|
|
39
|
+
Subscription: () => import_rxjs.Subscription,
|
|
40
|
+
asPromise: () => asPromise,
|
|
41
|
+
copyRxSubject: () => copyRxSubject,
|
|
42
|
+
forceUpdateCache$: () => forceUpdateCache$,
|
|
43
|
+
isObservable: () => import_rxjs.isObservable,
|
|
44
|
+
isSubjectLike: () => isSubjectLike2,
|
|
45
|
+
isSubscriptionLike: () => isSubscriptionLike,
|
|
46
|
+
skip: () => import_rxjs.skip,
|
|
47
|
+
unsubscribeAll: () => unsubscribeAll
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(index_exports);
|
|
50
|
+
|
|
51
|
+
// src/asPromise.ts
|
|
52
|
+
var import_core = require("@superutils/core");
|
|
53
|
+
var import_promise = __toESM(require("@superutils/promise"), 1);
|
|
54
|
+
|
|
55
|
+
// src/rxjs.ts
|
|
56
|
+
var import_rxjs = require("rxjs");
|
|
57
|
+
|
|
58
|
+
// src/asPromise.ts
|
|
59
|
+
var asPromise = (subject, expectedValue, timeoutOrOptions) => {
|
|
60
|
+
if (!(0, import_core.isSubjectLike)(subject) && !(0, import_rxjs.isObservable)(subject))
|
|
61
|
+
return import_promise.default.reject(
|
|
62
|
+
new Error("subject must be an instance of BehaviorSubject")
|
|
63
|
+
);
|
|
64
|
+
let subscription;
|
|
65
|
+
const options = (0, import_core.isObj)(timeoutOrOptions) ? timeoutOrOptions : { timeout: timeoutOrOptions };
|
|
66
|
+
options.timeout = (0, import_core.isPositiveNumber)(options.timeout) ? options.timeout : import_promise.TIMEOUT_MAX;
|
|
67
|
+
const promise = import_promise.default.timeout(
|
|
68
|
+
{
|
|
69
|
+
...options,
|
|
70
|
+
onTimeout: async () => {
|
|
71
|
+
const { onTimeout, timeoutMsg } = options;
|
|
72
|
+
const msg = await (0, import_core.fallbackIfFails)(onTimeout, [], void 0);
|
|
73
|
+
return msg != null ? msg : (0, import_core.isError)(timeoutMsg) ? timeoutMsg : new Error(
|
|
74
|
+
timeoutMsg != null ? timeoutMsg : "request timed out before an expected value is received"
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
new import_promise.default((resolve) => {
|
|
79
|
+
subscription = subject.subscribe((value) => {
|
|
80
|
+
const shouldResolve = value === expectedValue || expectedValue === void 0 || (0, import_core.isFn)(expectedValue) && (0, import_core.fallbackIfFails)(expectedValue, [value], false);
|
|
81
|
+
shouldResolve && resolve(value);
|
|
82
|
+
});
|
|
83
|
+
})
|
|
84
|
+
);
|
|
85
|
+
promise.onFinalize.push(() => {
|
|
86
|
+
var _a;
|
|
87
|
+
(_a = subscription == null ? void 0 : subscription.unsubscribe) == null ? void 0 : _a.call(subscription);
|
|
88
|
+
});
|
|
89
|
+
return promise;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/copyRxSubject.ts
|
|
93
|
+
var import_core5 = require("@superutils/core");
|
|
94
|
+
|
|
95
|
+
// src/isSubjectLike.ts
|
|
96
|
+
var import_core2 = require("@superutils/core");
|
|
97
|
+
var isSubjectLike2 = (x, withValue = false) => (0, import_core2.isSubjectLike)(x, withValue);
|
|
98
|
+
var isSubjectLike_default = isSubjectLike2;
|
|
99
|
+
|
|
100
|
+
// src/unsubscribeAll.ts
|
|
101
|
+
var import_core4 = require("@superutils/core");
|
|
102
|
+
|
|
103
|
+
// src/isSubscriptionLike.ts
|
|
104
|
+
var import_core3 = require("@superutils/core");
|
|
105
|
+
var isSubscriptionLike = (value, strict = false) => {
|
|
106
|
+
if (value instanceof import_rxjs.Subscription) return true;
|
|
107
|
+
const sub = value;
|
|
108
|
+
return !strict && !!sub && (0, import_core3.isBool)(sub.closed) && (0, import_core3.isFn)(sub.unsubscribe);
|
|
109
|
+
};
|
|
110
|
+
var isSubscriptionLike_default = isSubscriptionLike;
|
|
111
|
+
|
|
112
|
+
// src/unsubscribeAll.ts
|
|
113
|
+
var unsubscribeAll = (unsub = {}, onError) => {
|
|
114
|
+
if (!unsub) return;
|
|
115
|
+
try {
|
|
116
|
+
if ((0, import_core4.isFn)(unsub)) return unsub();
|
|
117
|
+
if (isSubscriptionLike_default(unsub)) return unsub.unsubscribe();
|
|
118
|
+
Object.values(unsub).forEach(
|
|
119
|
+
(value) => unsubscribeAll(value, onError)
|
|
120
|
+
);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
onError == null ? void 0 : onError(err);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var unsubscribeAll_default = unsubscribeAll;
|
|
126
|
+
|
|
127
|
+
// src/copyRxSubject.ts
|
|
128
|
+
var IGNORE_UPDATE_SYMBOL = /* @__PURE__ */ Symbol("ignore-rx-update");
|
|
129
|
+
function copyRxSubject(source$, copy$, valueModifier, options) {
|
|
130
|
+
var _a;
|
|
131
|
+
copy$ = isSubjectLike_default(copy$) ? copy$ : new import_rxjs.BehaviorSubject(void 0);
|
|
132
|
+
options = {
|
|
133
|
+
...copyRxSubject.defaults,
|
|
134
|
+
...options != null ? options : {}
|
|
135
|
+
};
|
|
136
|
+
const sourceArr = isSubjectLike_default(source$) ? [source$] : (0, import_core5.isArr)(source$) ? source$ : [source$];
|
|
137
|
+
const cache = new Map(
|
|
138
|
+
sourceArr.map((subject, i) => [
|
|
139
|
+
i,
|
|
140
|
+
isSubjectLike_default(subject) ? subject.value : subject
|
|
141
|
+
// fixed value provided
|
|
142
|
+
])
|
|
143
|
+
);
|
|
144
|
+
const triggerChange = () => {
|
|
145
|
+
const currentValue = (0, import_core5.isArr)(source$) ? [...cache.values()] : cache.get(0);
|
|
146
|
+
if (!(0, import_core5.isFn)(valueModifier)) return copy$.next(currentValue);
|
|
147
|
+
const modifiedValue = (0, import_core5.fallbackIfFails)(
|
|
148
|
+
valueModifier,
|
|
149
|
+
[currentValue, void 0, copy$],
|
|
150
|
+
(err) => {
|
|
151
|
+
var _a2;
|
|
152
|
+
(0, import_core5.fallbackIfFails)(
|
|
153
|
+
(_a2 = options.onError) == null ? void 0 : _a2.bind(options.thisArg),
|
|
154
|
+
[err],
|
|
155
|
+
void 0
|
|
156
|
+
);
|
|
157
|
+
return IGNORE_UPDATE_SYMBOL;
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
modifiedValue !== IGNORE_UPDATE_SYMBOL && copy$.next(modifiedValue);
|
|
161
|
+
};
|
|
162
|
+
const triggerChangeDeferred = (0, import_core5.isPositiveNumber)(options.delay) ? (0, import_core5.deferred)(triggerChange, options.delay, options) : triggerChange;
|
|
163
|
+
const subscriptions = sourceArr.map((subject, i) => {
|
|
164
|
+
if (!isSubjectLike_default(subject) || subject.closed) return;
|
|
165
|
+
return (subject instanceof import_rxjs.BehaviorSubject ? subject.pipe(
|
|
166
|
+
(0, import_rxjs.skip)(1)
|
|
167
|
+
// skip initial value
|
|
168
|
+
) : subject).subscribe((newValue) => {
|
|
169
|
+
cache.set(i, newValue);
|
|
170
|
+
triggerChangeDeferred();
|
|
171
|
+
});
|
|
172
|
+
}).filter(Boolean);
|
|
173
|
+
const unsubscribeOrg = (_a = copy$ == null ? void 0 : copy$.unsubscribe) == null ? void 0 : _a.bind(copy$);
|
|
174
|
+
copy$.unsubscribe = (...args) => {
|
|
175
|
+
unsubscribeOrg == null ? void 0 : unsubscribeOrg(...args);
|
|
176
|
+
unsubscribeAll(subscriptions);
|
|
177
|
+
cache.clear();
|
|
178
|
+
};
|
|
179
|
+
triggerChange();
|
|
180
|
+
return copy$;
|
|
181
|
+
}
|
|
182
|
+
copyRxSubject.defaults = {
|
|
183
|
+
delay: 0,
|
|
184
|
+
throttle: false
|
|
185
|
+
};
|
|
186
|
+
copyRxSubject.IGNORE_UPDATE_SYMBOL = IGNORE_UPDATE_SYMBOL;
|
|
187
|
+
|
|
188
|
+
// src/data-storage/DataStorage.ts
|
|
189
|
+
var import_core6 = require("@superutils/core");
|
|
190
|
+
var forceUpdateCache$ = new import_rxjs.Subject();
|
|
191
|
+
var DataStorage = class {
|
|
192
|
+
/**
|
|
193
|
+
* A wrapper for reading and writing to LocalStorage (browser) or JSON files (NodeJS),
|
|
194
|
+
* providing a Map-like interface with advanced features like search, filtering, and sorting.
|
|
195
|
+
*
|
|
196
|
+
* #### Notes:
|
|
197
|
+
* - **Performance**: `DataStorage` is optimized for small to medium datasets.
|
|
198
|
+
* - For datasets > 1MB, consider increasing the `delay` option to reduce write frequency.
|
|
199
|
+
* - It is **NOT** recommended for datasets larger than 3MB due to synchronous serialization costs.
|
|
200
|
+
* - **RxJS Integration**: Built on RxJS for reactive data handling, though no prior RxJS knowledge is required.
|
|
201
|
+
* - **Storage Behavior**:
|
|
202
|
+
* - If `name` is omitted, the instance operates in-memory only and data is not persisted to storage.
|
|
203
|
+
* - If `cacheDisabled` is `true`, data is not kept in memory; every read/write operation accesses the underlying
|
|
204
|
+
* storage directly.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* #### Browser Usage
|
|
208
|
+
* ```javascript
|
|
209
|
+
* import { DataStorage } from '@superutils/rx'
|
|
210
|
+
* import fetch from '@superutils/fetch'
|
|
211
|
+
*
|
|
212
|
+
* const storage = new DataStorage('products')
|
|
213
|
+
* const { products } = await fetch('[DUMMYJSON-DOT-COM]/products')
|
|
214
|
+
* // save all items to storage
|
|
215
|
+
* storage.setAll(
|
|
216
|
+
* new Map(products.map(p => [p.id, p])), // convert to Map
|
|
217
|
+
* )
|
|
218
|
+
*
|
|
219
|
+
* // print product with id `1`
|
|
220
|
+
* console.log(storage.get(1))
|
|
221
|
+
*
|
|
222
|
+
* // search for items
|
|
223
|
+
* const searchResult = storage.search({
|
|
224
|
+
* query: { availabilityStatus: 'low' }
|
|
225
|
+
* })
|
|
226
|
+
* console.log(searchResult)
|
|
227
|
+
* ```
|
|
228
|
+
* @example
|
|
229
|
+
* #### NodeJS Usage
|
|
230
|
+
* ```javascript
|
|
231
|
+
* import { DataStorage } from '@superutils/rx'
|
|
232
|
+
* import fetch from '@superutils/fetch'
|
|
233
|
+
* import { LocalStorage } from 'node-localstorage'
|
|
234
|
+
*
|
|
235
|
+
* // Add localStorage alternative for NodeJS that reads and writes to JSON files.
|
|
236
|
+
* // This is not necessary for browsers.
|
|
237
|
+
* globalThis.localStorage = new LocalStorage('./data', 1e7)
|
|
238
|
+
*
|
|
239
|
+
* const storage = new DataStorage('products')
|
|
240
|
+
* const { products } = await fetch('[DUMMYJSON-DOT-COM]/products')
|
|
241
|
+
* // save all items to storage
|
|
242
|
+
* storage.setAll(
|
|
243
|
+
* new Map(products.map(p => [p.id, p])), // convert to Map
|
|
244
|
+
* )
|
|
245
|
+
*
|
|
246
|
+
* // print product with id `1`
|
|
247
|
+
* console.log(storage.get(1))
|
|
248
|
+
*
|
|
249
|
+
* // search for items
|
|
250
|
+
* const searchResult = storage.search({
|
|
251
|
+
* query: { availabilityStatus: 'low' }
|
|
252
|
+
* })
|
|
253
|
+
* console.log(searchResult)
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* #### Advanced: `onChange` and RxJS subject
|
|
258
|
+
*
|
|
259
|
+
* Internally, `DataStorage` uses RxJS subject which is exposed as `subject` property.
|
|
260
|
+
* You can use this to subscribe to changes and do additional operations such as logging or sanitization etc.
|
|
261
|
+
*
|
|
262
|
+
* Alternatively, you can also set the `onChange` callback which is triggered whenever the subject changes and
|
|
263
|
+
* does not require maintaining a subscription or knowledge of RxJS subject.
|
|
264
|
+
*
|
|
265
|
+
* ```javascript
|
|
266
|
+
* import { DataStorage } from '@superutils/rx'
|
|
267
|
+
*
|
|
268
|
+
* const storage = new DataStorage('my-data')
|
|
269
|
+
* const sub = storage.subject.subscribe(data => {
|
|
270
|
+
* // Write to the database whenever data changes
|
|
271
|
+
* console.log('Saving to database...', data)
|
|
272
|
+
* })
|
|
273
|
+
* // unsubscribe from subject
|
|
274
|
+
* setTimeout(()=> sub.unsbuscribe(), 1000)
|
|
275
|
+
*
|
|
276
|
+
* // add an entry to storage
|
|
277
|
+
* storage.set('bob', { age: 99, id: 'bob', name: 'Bob' })
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
constructor(name, options) {
|
|
281
|
+
/** Debounce and throttle related options */
|
|
282
|
+
// readonly deferOptions
|
|
283
|
+
this.initialized = false;
|
|
284
|
+
this.subscriptions = {
|
|
285
|
+
subject: void 0,
|
|
286
|
+
forceUpdateCache: void 0
|
|
287
|
+
};
|
|
288
|
+
this.clear = () => {
|
|
289
|
+
this.setAll(/* @__PURE__ */ new Map(), true);
|
|
290
|
+
return this;
|
|
291
|
+
};
|
|
292
|
+
this.delete = (keys) => {
|
|
293
|
+
if (!(0, import_core6.isArr)(keys)) keys = [keys];
|
|
294
|
+
const data = this.getAll();
|
|
295
|
+
for (const k of keys) data.delete(k);
|
|
296
|
+
this.setAll(data, true);
|
|
297
|
+
return this;
|
|
298
|
+
};
|
|
299
|
+
this.find = (predicateOrOptions) => (0, import_core6.find)(this.getAll(), predicateOrOptions);
|
|
300
|
+
this.filter = (predicate, limit, asArray, result) => (0, import_core6.filter)(this.getAll(), predicate, limit, asArray, result);
|
|
301
|
+
this.get = (key) => this.getAll().get(key);
|
|
302
|
+
this.getAll = (forceRead = false) => {
|
|
303
|
+
var _a;
|
|
304
|
+
const wasInitialized = this.initialized;
|
|
305
|
+
if (!wasInitialized) this.init();
|
|
306
|
+
const readFromStorage = this.cacheDisabled || this.name && forceRead;
|
|
307
|
+
if (readFromStorage) {
|
|
308
|
+
const data = this.read();
|
|
309
|
+
const shouldTrigger = forceRead || !wasInitialized && !!data.size;
|
|
310
|
+
shouldTrigger && this.subject.next(data);
|
|
311
|
+
return data;
|
|
312
|
+
}
|
|
313
|
+
return (_a = this.subject) == null ? void 0 : _a.value;
|
|
314
|
+
};
|
|
315
|
+
this.has = (key) => this.getAll().has(key);
|
|
316
|
+
this.init = (initialValue) => {
|
|
317
|
+
var _a, _b;
|
|
318
|
+
if (this.initialized) return false;
|
|
319
|
+
this.initialized = true;
|
|
320
|
+
this.subject instanceof import_rxjs.BehaviorSubject && this.subject.next(this.read());
|
|
321
|
+
unsubscribeAll_default(this.subscriptions);
|
|
322
|
+
if (!this.cacheDisabled) {
|
|
323
|
+
this.subscriptions.forceUpdateCache = forceUpdateCache$.subscribe(
|
|
324
|
+
(refresh) => {
|
|
325
|
+
const doRefresh = !this.name ? false : (0, import_core6.isArr)(refresh) ? refresh.includes(this.name) : (0, import_core6.isStr)(refresh) ? refresh === this.name : refresh === true;
|
|
326
|
+
if (!doRefresh) return;
|
|
327
|
+
const newData = this.read();
|
|
328
|
+
this.subject.next(newData);
|
|
329
|
+
}
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
!((_b = (_a = this.subject) == null ? void 0 : _a.value) == null ? void 0 : _b.size) && (0, import_core6.isMap)(initialValue) && !!(initialValue == null ? void 0 : initialValue.size) && this.setAll(initialValue);
|
|
333
|
+
const piped = this.subject.pipe(
|
|
334
|
+
(0, import_rxjs.skip)(this.cacheDisabled || !!(initialValue == null ? void 0 : initialValue.size) ? 0 : 1)
|
|
335
|
+
);
|
|
336
|
+
let handleChange = (data) => {
|
|
337
|
+
if (!(0, import_core6.isMap)(data)) return this.subject.next(/* @__PURE__ */ new Map());
|
|
338
|
+
this.write(data);
|
|
339
|
+
(0, import_core6.fallbackIfFails)(
|
|
340
|
+
async () => {
|
|
341
|
+
var _a2;
|
|
342
|
+
return await ((_a2 = this.onChange) == null ? void 0 : _a2.call(this, data));
|
|
343
|
+
},
|
|
344
|
+
[],
|
|
345
|
+
this.triggerOnError("onChange")
|
|
346
|
+
);
|
|
347
|
+
};
|
|
348
|
+
if (this.delay > 0)
|
|
349
|
+
handleChange = (0, import_core6.deferred)(handleChange, this.delay, this.delayOptions);
|
|
350
|
+
this.subscriptions.subject = piped.subscribe(handleChange);
|
|
351
|
+
return true;
|
|
352
|
+
};
|
|
353
|
+
this.keys = () => (0, import_core6.getKeys)(this.getAll());
|
|
354
|
+
this.map = (callback) => this.toArray().map(
|
|
355
|
+
([key, value], index, data) => callback(value, key, data, index)
|
|
356
|
+
);
|
|
357
|
+
this.read = () => {
|
|
358
|
+
var _a, _b;
|
|
359
|
+
const dataStr = (_b = (_a = this.storage) == null ? void 0 : _a.getItem(this.name)) != null ? _b : "[]";
|
|
360
|
+
const data = (0, import_core6.isFn)(this.parse) && (0, import_core6.fallbackIfFails)(
|
|
361
|
+
this.parse,
|
|
362
|
+
[dataStr],
|
|
363
|
+
this.triggerOnError("parse")
|
|
364
|
+
);
|
|
365
|
+
if ((0, import_core6.isMap)(data)) return data;
|
|
366
|
+
return new Map(
|
|
367
|
+
(0, import_core6.fallbackIfFails)(
|
|
368
|
+
() => JSON.parse(dataStr),
|
|
369
|
+
[],
|
|
370
|
+
this.triggerOnError("parse-json")
|
|
371
|
+
)
|
|
372
|
+
);
|
|
373
|
+
};
|
|
374
|
+
this.search = (options) => (0, import_core6.search)(this.getAll(), options);
|
|
375
|
+
this.set = (key, value) => {
|
|
376
|
+
this.setAll(/* @__PURE__ */ new Map([[key, value]]), false);
|
|
377
|
+
return this;
|
|
378
|
+
};
|
|
379
|
+
this.setAll = (data = /* @__PURE__ */ new Map(), replace = false) => {
|
|
380
|
+
if (!(0, import_core6.isMap)(data)) return this;
|
|
381
|
+
data = replace ? data : (0, import_core6.mapJoin)(this.getAll(), data);
|
|
382
|
+
this.subject.next(new Map(data));
|
|
383
|
+
return this;
|
|
384
|
+
};
|
|
385
|
+
this.sort = ((nameOrComparator, options) => {
|
|
386
|
+
const result = (0, import_core6.sort)(
|
|
387
|
+
this.getAll(),
|
|
388
|
+
nameOrComparator,
|
|
389
|
+
options
|
|
390
|
+
);
|
|
391
|
+
(options == null ? void 0 : options.save) && this.setAll(result, true);
|
|
392
|
+
return result;
|
|
393
|
+
});
|
|
394
|
+
this.toArray = () => (0, import_core6.getEntries)(this.getAll());
|
|
395
|
+
this.toJSON = (replacer, spacing = this.spaces, data = this.getAll()) => {
|
|
396
|
+
const arr = Array.from(data);
|
|
397
|
+
const str = (0, import_core6.fallbackIfFails)(
|
|
398
|
+
() => {
|
|
399
|
+
var _a;
|
|
400
|
+
return (_a = this.stringify) == null ? void 0 : _a.call(this, data);
|
|
401
|
+
},
|
|
402
|
+
[],
|
|
403
|
+
this.triggerOnError("stringify")
|
|
404
|
+
);
|
|
405
|
+
if ((0, import_core6.isStr)(str)) return str;
|
|
406
|
+
return (0, import_core6.fallbackIfFails)(
|
|
407
|
+
() => JSON.stringify(arr, replacer, spacing),
|
|
408
|
+
[],
|
|
409
|
+
this.triggerOnError("stringify-json")
|
|
410
|
+
);
|
|
411
|
+
};
|
|
412
|
+
this.toString = (data) => this.toJSON(void 0, void 0, data);
|
|
413
|
+
this.triggerOnError = (type) => (err) => {
|
|
414
|
+
this.onError && (0, import_core6.fallbackIfFails)(this.onError, [err, type], "");
|
|
415
|
+
};
|
|
416
|
+
this.unsubscribe = () => unsubscribeAll_default(this.subscriptions);
|
|
417
|
+
this.values = () => [...this.getAll().values()];
|
|
418
|
+
this.write = (data) => {
|
|
419
|
+
try {
|
|
420
|
+
!this.initialized && this.init();
|
|
421
|
+
data != null ? data : data = this.subject.value;
|
|
422
|
+
if (!this.name || !this.storage || !(0, import_core6.isMap)(data)) return false;
|
|
423
|
+
this.storage.setItem(this.name, this.toString(data));
|
|
424
|
+
return true;
|
|
425
|
+
} catch (err) {
|
|
426
|
+
this.triggerOnError("write")(err);
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
const {
|
|
431
|
+
cacheDisabled = false,
|
|
432
|
+
delay,
|
|
433
|
+
delayOptions,
|
|
434
|
+
initialValue,
|
|
435
|
+
onError,
|
|
436
|
+
onChange,
|
|
437
|
+
parse,
|
|
438
|
+
spaces,
|
|
439
|
+
storage,
|
|
440
|
+
stringify
|
|
441
|
+
} = options != null ? options : {};
|
|
442
|
+
this.delay = cacheDisabled ? 0 : delay === 0 || (0, import_core6.isPositiveNumber)(delay) ? delay : 300;
|
|
443
|
+
this.name = `${name != null ? name : ""}`.trim();
|
|
444
|
+
this.onError = onError;
|
|
445
|
+
this.onChange = onChange;
|
|
446
|
+
this.parse = parse;
|
|
447
|
+
this.storage = storage === null ? null : storage != null ? storage : (0, import_core6.fallbackIfFails)(
|
|
448
|
+
() => globalThis.localStorage,
|
|
449
|
+
[],
|
|
450
|
+
void 0
|
|
451
|
+
);
|
|
452
|
+
if (this.name && !this.storage)
|
|
453
|
+
throw new Error(
|
|
454
|
+
"options.storage: LocalStorage instance or equivalent required"
|
|
455
|
+
);
|
|
456
|
+
this.cacheDisabled = !!this.storage && cacheDisabled;
|
|
457
|
+
this.stringify = stringify;
|
|
458
|
+
this.spaces = spaces;
|
|
459
|
+
this.subject = this.cacheDisabled ? new import_rxjs.Subject() : new import_rxjs.BehaviorSubject(void 0);
|
|
460
|
+
this.delayOptions = delayOptions;
|
|
461
|
+
(0, import_core6.isMap)(initialValue) && initialValue.size && this.init(initialValue);
|
|
462
|
+
}
|
|
463
|
+
get size() {
|
|
464
|
+
return this.getAll().size;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
/**
|
|
468
|
+
* Trigger forced update of cached data from storage.
|
|
469
|
+
*
|
|
470
|
+
* @param name determines which storage instances to be updated.
|
|
471
|
+
* - name (`string` | `string[]`): update all instances with a specific name(s)
|
|
472
|
+
* - global (`true`): update all instances globally
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```javascript
|
|
476
|
+
* import { DataStorage } from '@superutils/rx'
|
|
477
|
+
*
|
|
478
|
+
* // Update all DataStorage instances with specific name(s)
|
|
479
|
+
* const name = 'products'
|
|
480
|
+
* DataStorage.forceUpdateCache([name])
|
|
481
|
+
*
|
|
482
|
+
* // Update every single instance of DataStorage that uses storage (has a "name")
|
|
483
|
+
* DataStorage.forceUpdateCache(true)
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
DataStorage.forceUpdateCache = (name) => {
|
|
487
|
+
forceUpdateCache$.next(name);
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// src/IntervalSubject.ts
|
|
491
|
+
var IntervalSubject = class extends import_rxjs.BehaviorSubject {
|
|
492
|
+
constructor(autoStart, _delay = 1e3, initialValue = 0, incrementBy = 1) {
|
|
493
|
+
super(initialValue);
|
|
494
|
+
this.autoStart = autoStart;
|
|
495
|
+
this._delay = _delay;
|
|
496
|
+
this.initialValue = initialValue;
|
|
497
|
+
this.incrementBy = incrementBy;
|
|
498
|
+
this._running = false;
|
|
499
|
+
this.pause = () => {
|
|
500
|
+
clearInterval(this._intervalId);
|
|
501
|
+
this._running = false;
|
|
502
|
+
return this;
|
|
503
|
+
};
|
|
504
|
+
this.resume = () => this.start();
|
|
505
|
+
this.start = () => {
|
|
506
|
+
if (!this._running) {
|
|
507
|
+
this._running = true;
|
|
508
|
+
this._intervalId = setInterval(
|
|
509
|
+
() => this.next(this.value + this.incrementBy),
|
|
510
|
+
this._delay
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
return this;
|
|
514
|
+
};
|
|
515
|
+
this.stop = () => {
|
|
516
|
+
this.pause();
|
|
517
|
+
this.next(0);
|
|
518
|
+
return this;
|
|
519
|
+
};
|
|
520
|
+
this.autoStart && this.start();
|
|
521
|
+
}
|
|
522
|
+
get delay() {
|
|
523
|
+
return this._delay;
|
|
524
|
+
}
|
|
525
|
+
set delay(newDelay) {
|
|
526
|
+
if (!this._running) this._delay = newDelay;
|
|
527
|
+
}
|
|
528
|
+
get running() {
|
|
529
|
+
return this._running;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// src/IntervalRunner.ts
|
|
534
|
+
var import_core7 = require("@superutils/core");
|
|
535
|
+
var IntervalRunner = class {
|
|
536
|
+
constructor(taskFn, taskArgs, intervalMs, sequential = true, preExecute = true) {
|
|
537
|
+
this.taskFn = taskFn;
|
|
538
|
+
this.taskArgs = taskArgs;
|
|
539
|
+
this.sequential = sequential;
|
|
540
|
+
this.preExecute = preExecute;
|
|
541
|
+
this.minIntervalMs = 1e3;
|
|
542
|
+
this.runCount = 0;
|
|
543
|
+
this.started = false;
|
|
544
|
+
this.clearInterval = () => {
|
|
545
|
+
this.sequential ? clearTimeout(this.idInterval) : clearInterval(this.idInterval);
|
|
546
|
+
this.idInterval = void 0;
|
|
547
|
+
};
|
|
548
|
+
this.executeTask = async (once = false) => {
|
|
549
|
+
var _a;
|
|
550
|
+
let err;
|
|
551
|
+
let result;
|
|
552
|
+
if (this.sequential || once) this.clearInterval();
|
|
553
|
+
try {
|
|
554
|
+
++this.runCount;
|
|
555
|
+
await ((_a = this.onBeforeExec) == null ? void 0 : _a.call(this, this.runCount, once));
|
|
556
|
+
result = await this.taskFn.apply(void 0, this.taskArgs);
|
|
557
|
+
this.lastResult = result;
|
|
558
|
+
} catch (_err) {
|
|
559
|
+
err = _err;
|
|
560
|
+
}
|
|
561
|
+
(0, import_core7.fallbackIfFails)(
|
|
562
|
+
this.onResult,
|
|
563
|
+
[err != null ? err : null, result, this.runCount, once],
|
|
564
|
+
void 0
|
|
565
|
+
);
|
|
566
|
+
if (!once && this.sequential && this.intervalMs$.value > this.minIntervalMs) {
|
|
567
|
+
this.idInterval = setTimeout(
|
|
568
|
+
this.executeTask,
|
|
569
|
+
this.intervalMs$.value
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
return this.lastResult;
|
|
573
|
+
};
|
|
574
|
+
/** Execute the task function regardless of the interval runner state */
|
|
575
|
+
this.executeOnce = async () => await this.executeTask(true);
|
|
576
|
+
/** Check if interval is running*/
|
|
577
|
+
this.isStarted = () => this.started;
|
|
578
|
+
/**
|
|
579
|
+
* Restart interval
|
|
580
|
+
*
|
|
581
|
+
* @param resetRunCount (optional) whether to reset run count
|
|
582
|
+
*
|
|
583
|
+
* @returns {Boolean} indicates whether restart was successful
|
|
584
|
+
*/
|
|
585
|
+
this.restart = (resetRunCount = false) => {
|
|
586
|
+
if (!this.onResult) return false;
|
|
587
|
+
this.stop(resetRunCount);
|
|
588
|
+
this.start(this.onResult, this.onBeforeExec);
|
|
589
|
+
return true;
|
|
590
|
+
};
|
|
591
|
+
/**
|
|
592
|
+
* @summary set `onResult` & `onBeforeExec` callbacks and start execution.
|
|
593
|
+
*
|
|
594
|
+
* If it's already running, the callbacks will be used on the next execution.
|
|
595
|
+
*
|
|
596
|
+
* In order to start using callbacks immediately, invoke the `intervalRunner.stop()` function first.
|
|
597
|
+
*
|
|
598
|
+
* @returns {Boolean} indicates whether starting interveral waa successful
|
|
599
|
+
*/
|
|
600
|
+
this.start = (onResult, onBeforeExec) => {
|
|
601
|
+
if (!onResult) return false;
|
|
602
|
+
this.onResult = onResult;
|
|
603
|
+
this.onBeforeExec = onBeforeExec;
|
|
604
|
+
if (this.started) return false;
|
|
605
|
+
this.started = true;
|
|
606
|
+
let delayMs;
|
|
607
|
+
this.subscription = this.intervalMs$.subscribe((newDelayMs) => {
|
|
608
|
+
var _a;
|
|
609
|
+
if (delayMs === newDelayMs && newDelayMs !== void 0) return;
|
|
610
|
+
delayMs = Math.max((_a = newDelayMs != null ? newDelayMs : delayMs) != null ? _a : 0, this.minIntervalMs);
|
|
611
|
+
this.clearInterval();
|
|
612
|
+
const preExec = this.lastResult === void 0 && this.preExecute;
|
|
613
|
+
preExec && this.executeTask().catch(import_core7.noop);
|
|
614
|
+
this.idInterval = !this.sequential ? setInterval(this.executeTask, delayMs) : !preExec ? setTimeout(this.executeTask, delayMs) : void 0;
|
|
615
|
+
});
|
|
616
|
+
return true;
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* Stop interval runner
|
|
620
|
+
*
|
|
621
|
+
* @param resetRunCount (optional) whether to reset the run counter
|
|
622
|
+
*/
|
|
623
|
+
this.stop = (resetRunCount = false) => {
|
|
624
|
+
var _a, _b;
|
|
625
|
+
if (resetRunCount) this.runCount = 0;
|
|
626
|
+
this.started = false;
|
|
627
|
+
(_b = (_a = this.subscription) == null ? void 0 : _a.unsubscribe) == null ? void 0 : _b.call(_a);
|
|
628
|
+
this.clearInterval();
|
|
629
|
+
return this;
|
|
630
|
+
};
|
|
631
|
+
this.intervalMs$ = intervalMs instanceof import_rxjs.BehaviorSubject ? intervalMs : new import_rxjs.BehaviorSubject(intervalMs);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
635
|
+
0 && (module.exports = {
|
|
636
|
+
BehaviorSubject,
|
|
637
|
+
DataStorage,
|
|
638
|
+
IGNORE_UPDATE_SYMBOL,
|
|
639
|
+
IntervalRunner,
|
|
640
|
+
IntervalSubject,
|
|
641
|
+
Subject,
|
|
642
|
+
Subscription,
|
|
643
|
+
asPromise,
|
|
644
|
+
copyRxSubject,
|
|
645
|
+
forceUpdateCache$,
|
|
646
|
+
isObservable,
|
|
647
|
+
isSubjectLike,
|
|
648
|
+
isSubscriptionLike,
|
|
649
|
+
skip,
|
|
650
|
+
unsubscribeAll
|
|
651
|
+
});
|