@superutils/store 0.1.14

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/dist/index.js ADDED
@@ -0,0 +1,317 @@
1
+ // src/createObjectStore.ts
2
+ import { objToMap, isObj } from "@superutils/core";
3
+
4
+ // src/createStore.ts
5
+ import { isFn as isFn2 } from "@superutils/core";
6
+
7
+ // src/Store.ts
8
+ import {
9
+ deferred,
10
+ fallbackIfFails,
11
+ filter,
12
+ find,
13
+ getEntries,
14
+ getKeys,
15
+ getValues,
16
+ isArr,
17
+ isArr2D,
18
+ isDefined,
19
+ isFn,
20
+ isMap,
21
+ isPositiveNumber,
22
+ isStr,
23
+ mapJoin,
24
+ search,
25
+ sort
26
+ } from "@superutils/core";
27
+ import { BehaviorSubject, skip, Subject } from "rxjs";
28
+
29
+ // src/types/types.ts
30
+ var Store_OnErrorType = /* @__PURE__ */ ((Store_OnErrorType2) => {
31
+ Store_OnErrorType2["onChange"] = "onChange";
32
+ Store_OnErrorType2["parse"] = "parse";
33
+ Store_OnErrorType2["parse_json"] = "parse-json";
34
+ Store_OnErrorType2["stringify"] = "stringify";
35
+ Store_OnErrorType2["stringify_json"] = "stringify-json";
36
+ Store_OnErrorType2["write"] = "write";
37
+ return Store_OnErrorType2;
38
+ })(Store_OnErrorType || {});
39
+
40
+ // src/Store.ts
41
+ var forceUpdateCache$ = new Subject();
42
+ var _Store = class _Store {
43
+ constructor(name, options) {
44
+ this.initialized = false;
45
+ this.subscriptions = {
46
+ subject: void 0,
47
+ forceUpdateCache: void 0
48
+ };
49
+ this.type = "map";
50
+ this.clear = () => this.setAll(/* @__PURE__ */ new Map(), true);
51
+ this.delete = (keys) => {
52
+ if (!isArr(keys)) keys = [keys];
53
+ const data = this.getAll();
54
+ for (const k of keys) data.delete(k);
55
+ this.setAll(data, true);
56
+ return this;
57
+ };
58
+ this.filter = (...args) => filter(this.getAll(), ...args);
59
+ this.find = (predicateOrOptions) => find(this.getAll(), predicateOrOptions);
60
+ this.get = (key) => this.getAll().get(key);
61
+ this.getAll = (forceRead = false) => {
62
+ const wasInitialized = this.initialized;
63
+ if (!wasInitialized) this.init();
64
+ const readFromStorage = this.cacheDisabled || this.storage && forceRead;
65
+ if (readFromStorage) {
66
+ const data = this.read();
67
+ const shouldTrigger = forceRead || !wasInitialized && !!data.size;
68
+ shouldTrigger && this.subject$.next(data);
69
+ return data;
70
+ }
71
+ return this.subject$.value;
72
+ };
73
+ this.handleForceUpdateCache = (name) => {
74
+ const isTarget = !this.name ? false : isArr(name) ? name.includes(this.name) : isStr(name) ? name === this.name : name === true;
75
+ if (!isTarget) return;
76
+ const newData = this.read();
77
+ this.subject$.next(newData);
78
+ };
79
+ this.handleSubjectChange = (data) => {
80
+ var _a;
81
+ if (!isMap(data)) return this.subject$.next(/* @__PURE__ */ new Map());
82
+ this.write(data);
83
+ fallbackIfFails(
84
+ (_a = this.onChange) == null ? void 0 : _a.bind(this),
85
+ [data],
86
+ this.triggerOnErrorCb("onChange" /* onChange */)
87
+ );
88
+ };
89
+ this.has = (key) => this.getAll().has(key);
90
+ this.init = (initialValue, checkStorage = true) => {
91
+ var _a;
92
+ if (this.initialized) return false;
93
+ this.initialized = true;
94
+ if (checkStorage && this.name && !this.storage)
95
+ throw new Error(_Store.messages.invalidOptionsStorage);
96
+ let isEmpty = !!this.cacheDisabled;
97
+ let firstValue = initialValue;
98
+ if (!!(initialValue == null ? void 0 : initialValue.size) || !this.cacheDisabled) {
99
+ const dataStr = this.name ? (_a = this.storage) == null ? void 0 : _a.getItem(this.name) : null;
100
+ const existingValue = this.read(dataStr != null ? dataStr : null);
101
+ if (isDefined(dataStr)) firstValue = existingValue;
102
+ isEmpty = this.cacheDisabled || existingValue.size === 0;
103
+ }
104
+ (firstValue == null ? void 0 : firstValue.size) && this.subject$.next(firstValue);
105
+ this.unsubscribe();
106
+ if (!this.cacheDisabled) {
107
+ this.subscriptions.forceUpdateCache = forceUpdateCache$.subscribe(
108
+ this.handleForceUpdateCache
109
+ );
110
+ }
111
+ this.subscriptions.subject = this.subject$.pipe(skip(isEmpty ? 0 : 1)).subscribe(
112
+ !this.cacheDisabled && this.delay > 0 ? deferred(this.handleSubjectChange, this.delay, {
113
+ thisArg: this,
114
+ ...this.delayOptions
115
+ }) : this.handleSubjectChange
116
+ );
117
+ return true;
118
+ };
119
+ this.keys = () => getKeys(this.getAll());
120
+ this.map = (callback) => this.toArray().map(
121
+ ([key, value], index, entries) => callback(value, key, entries, index)
122
+ );
123
+ this.read = (dataStr = ((_b) => (_b = this.name && ((_a) => (_a = this.storage) == null ? void 0 : _a.getItem(this.name))()) != null ? _b : null)()) => {
124
+ var _a2;
125
+ const data = fallbackIfFails(
126
+ this.parse,
127
+ [dataStr],
128
+ this.triggerOnErrorCb("parse" /* parse */, void 0)
129
+ );
130
+ if (isMap(data) || !isStr(dataStr))
131
+ return (_a2 = isFn(this.parse) ? data : this.subject$.value) != null ? _a2 : /* @__PURE__ */ new Map();
132
+ return new Map(
133
+ fallbackIfFails(
134
+ () => {
135
+ const entries = JSON.parse(dataStr);
136
+ if (!isArr2D(entries))
137
+ throw new Error(_Store.messages.invalidJsonEntries);
138
+ return entries;
139
+ },
140
+ [],
141
+ this.triggerOnErrorCb("parse-json" /* parse_json */)
142
+ )
143
+ );
144
+ };
145
+ this.search = (...args) => search(this.getAll(), ...args);
146
+ this.set = (key, value) => {
147
+ const data = this.getAll();
148
+ data.set(key, isFn(value) ? value(data.get(key)) : value);
149
+ return this.setAll(data, true);
150
+ };
151
+ this.setAll = (data, replace = false) => {
152
+ if (!isMap(data)) return this;
153
+ data = replace ? data : mapJoin(this.getAll(), data);
154
+ this.subject$.next(new Map(data));
155
+ return this;
156
+ };
157
+ this.sort = (...args) => {
158
+ var _a;
159
+ const result = sort(
160
+ this.getAll(),
161
+ args[0],
162
+ args[1]
163
+ );
164
+ ((_a = args[1]) == null ? void 0 : _a.save) && this.setAll(result, true);
165
+ return result;
166
+ };
167
+ this.toArray = () => getEntries(this.getAll());
168
+ this.toJSON = (replacer, spacing = this.spaces, data = this.getAll()) => {
169
+ const str = fallbackIfFails(
170
+ this.stringify,
171
+ [data],
172
+ this.triggerOnErrorCb("stringify" /* stringify */, "")
173
+ // if fails return empty string
174
+ );
175
+ if (isStr(str)) return str;
176
+ return fallbackIfFails(
177
+ () => JSON.stringify(
178
+ Array.from(data),
179
+ replacer,
180
+ spacing
181
+ ),
182
+ [],
183
+ this.triggerOnErrorCb("stringify-json" /* stringify_json */, "")
184
+ );
185
+ };
186
+ this.toObject = (data = this.getAll()) => {
187
+ const obj = {};
188
+ if (!isMap(data)) return obj;
189
+ for (const [key, value] of data)
190
+ obj[key] = value;
191
+ return obj;
192
+ };
193
+ this.toString = (data = this.getAll()) => this.toJSON(void 0, void 0, data);
194
+ this.triggerOnErrorCb = (type, returnValue = void 0) => (err) => {
195
+ var _a;
196
+ fallbackIfFails(
197
+ (_a = this.onError) == null ? void 0 : _a.bind(this),
198
+ [err, type],
199
+ ""
200
+ );
201
+ return returnValue;
202
+ };
203
+ this.unsubscribe = () => {
204
+ var _a, _b;
205
+ (_a = this.subscriptions.forceUpdateCache) == null ? void 0 : _a.unsubscribe();
206
+ (_b = this.subscriptions.subject) == null ? void 0 : _b.unsubscribe();
207
+ this.subscriptions = {};
208
+ };
209
+ this.values = () => getValues(this.getAll());
210
+ this.write = (data) => {
211
+ var _a;
212
+ try {
213
+ !this.initialized && this.init();
214
+ data != null ? data : data = (_a = this.subject$) == null ? void 0 : _a.value;
215
+ if (!isMap(data)) return false;
216
+ const jsonStr = this.toString(data);
217
+ if (!this.name || !this.storage) return false;
218
+ this.storage.setItem(this.name, jsonStr);
219
+ return true;
220
+ } catch (err) {
221
+ this.triggerOnErrorCb("write" /* write */)(err);
222
+ return false;
223
+ }
224
+ };
225
+ const {
226
+ cacheDisabled = false,
227
+ delay,
228
+ delayOptions,
229
+ initialValue,
230
+ onError,
231
+ onChange,
232
+ parse,
233
+ spaces,
234
+ storage = fallbackIfFails(
235
+ () => globalThis.localStorage,
236
+ [],
237
+ void 0
238
+ ),
239
+ stringify
240
+ } = options != null ? options : {};
241
+ this.name = `${name != null ? name : ""}`.trim() || null;
242
+ if (this.name && !storage && !(options == null ? void 0 : options.checkStorageOnInit))
243
+ throw new Error(_Store.messages.invalidOptionsStorage);
244
+ this.cacheDisabled = !!storage && cacheDisabled;
245
+ this.delay = delay === 0 || isPositiveNumber(delay) ? delay : 300;
246
+ this.delayOptions = delayOptions;
247
+ this.onError = onError;
248
+ this.onChange = onChange;
249
+ this.parse = parse == null ? void 0 : parse.bind(this);
250
+ this.storage = storage;
251
+ this.stringify = stringify == null ? void 0 : stringify.bind(this);
252
+ this.spaces = spaces;
253
+ this.subject$ = this.cacheDisabled ? new Subject() : new BehaviorSubject(/* @__PURE__ */ new Map());
254
+ isMap(initialValue) && initialValue.size && this.init(initialValue, false);
255
+ }
256
+ get size() {
257
+ return this.getAll().size;
258
+ }
259
+ };
260
+ _Store.messages = Object.seal({
261
+ invalidJsonEntries: "Invalid JSON format. Parsed value must be a 2D array representing key-value pairs.",
262
+ invalidOptionsStorage: "options.storage: LocalStorage instance or equivalent required"
263
+ });
264
+ /**
265
+ * Trigger forced update of cached data from storage.
266
+ *
267
+ * @param name determines which cache-enabled storage instances to be updated.
268
+ * - name (`string` | `string[]`): update all instances with a specific name(s)
269
+ * - global (`true`): update all instances globally
270
+ *
271
+ * See {@link forceUpdateCache$} for more details.
272
+ */
273
+ _Store.forceUpdateCache = (name) => {
274
+ forceUpdateCache$.next(name);
275
+ };
276
+ var Store = _Store;
277
+ var Store_default = Store;
278
+
279
+ // src/createStore.ts
280
+ function createStore(name, options) {
281
+ const store = new Store_default(name, options);
282
+ Object.defineProperty(store, "context", {
283
+ configurable: false,
284
+ enumerable: false,
285
+ value: isFn2(options == null ? void 0 : options.context) ? options.context(store) : options == null ? void 0 : options.context,
286
+ writable: false
287
+ });
288
+ return store;
289
+ }
290
+ var createStore_default = createStore;
291
+
292
+ // src/createObjectStore.ts
293
+ function createObjectStore(name, options) {
294
+ const store = createStore_default(name, {
295
+ parse: (str) => objToMap(JSON.parse(str != null ? str : "{}")),
296
+ stringify: function(data) {
297
+ return JSON.stringify(this.toObject(data));
298
+ },
299
+ ...options,
300
+ initialValue: !isObj(options == null ? void 0 : options.initialValue, true) ? options == null ? void 0 : options.initialValue : objToMap(options.initialValue)
301
+ });
302
+ store.type = "object";
303
+ return store;
304
+ }
305
+
306
+ // src/index.ts
307
+ import { objToMap as objToMap2 } from "@superutils/core";
308
+ var index_default = Store_default;
309
+ export {
310
+ Store,
311
+ Store_OnErrorType,
312
+ createObjectStore,
313
+ createStore,
314
+ index_default as default,
315
+ forceUpdateCache$,
316
+ objToMap2 as objToMap
317
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "author": "Toufiqur Rahaman Chowdhury",
3
+ "description": "Generic, reactive, persistent and fully-typed Map-like data store with advanced search, filtering, and sorting capabilities.",
4
+ "dependencies": {
5
+ "@superutils/core": "^1.2.18",
6
+ "rxjs": "^7.8.2"
7
+ },
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "keywords": [
21
+ "rxjs",
22
+ "utils",
23
+ "typescript",
24
+ "react",
25
+ "hooks"
26
+ ],
27
+ "license": "MIT",
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "name": "@superutils/store",
31
+ "peerDependencies": {
32
+ "@superutils/core": "*"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "_build": "tsc -p tsconfig.json",
39
+ "_watch": "tsc -p tsconfig.json --watch",
40
+ "build": "tsup --config ../../tsup.config.js",
41
+ "dev": "npm run build -- --watch",
42
+ "start": "npm run dev",
43
+ "test": "cd ../../ && npm run test store"
44
+ },
45
+ "sideEffects": false,
46
+ "type": "module",
47
+ "types": "./dist/index.d.ts",
48
+ "version": "0.1.14",
49
+ "gitHead": "9e526ce83ac97f6ba66a06a6d2e95798a4660823"
50
+ }