@flurryx/rx 0.0.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/dist/error-normalizer-DZz8HS0o.d.cts +6 -0
- package/dist/error-normalizer-DZz8HS0o.d.ts +6 -0
- package/dist/http.cjs +53 -0
- package/dist/http.cjs.map +1 -0
- package/dist/http.d.cts +6 -0
- package/dist/http.d.ts +6 -0
- package/dist/http.js +26 -0
- package/dist/http.js.map +1 -0
- package/dist/index.cjs +445 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +47 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +417 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/http.cjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/http.ts
|
|
21
|
+
var http_exports = {};
|
|
22
|
+
__export(http_exports, {
|
|
23
|
+
httpErrorNormalizer: () => httpErrorNormalizer
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(http_exports);
|
|
26
|
+
|
|
27
|
+
// src/error/http-error-normalizer.ts
|
|
28
|
+
var import_http = require("@angular/common/http");
|
|
29
|
+
var httpErrorNormalizer = (error) => {
|
|
30
|
+
if (!(error instanceof import_http.HttpErrorResponse)) {
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
code: "UNKNOWN",
|
|
34
|
+
message: String(error)
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
const errors = error.error?.errors;
|
|
39
|
+
if (Array.isArray(errors)) {
|
|
40
|
+
return errors;
|
|
41
|
+
}
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
code: error.status.toString(),
|
|
45
|
+
message: error.message
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
};
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
httpErrorNormalizer
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=http.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/http.ts","../src/error/http-error-normalizer.ts"],"sourcesContent":["export { httpErrorNormalizer } from './error/http-error-normalizer';\n","import { HttpErrorResponse } from '@angular/common/http';\nimport type { ResourceErrors } from '@flurryx/core';\nimport type { ErrorNormalizer } from './error-normalizer';\n\nexport const httpErrorNormalizer: ErrorNormalizer = (\n error: unknown\n): ResourceErrors => {\n if (!(error instanceof HttpErrorResponse)) {\n return [\n {\n code: 'UNKNOWN',\n message: String(error),\n },\n ];\n }\n\n const errors = error.error?.errors as unknown;\n if (Array.isArray(errors)) {\n return errors as ResourceErrors;\n }\n\n return [\n {\n code: error.status.toString(),\n message: error.message,\n },\n ];\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAAkC;AAI3B,IAAM,sBAAuC,CAClD,UACmB;AACnB,MAAI,EAAE,iBAAiB,gCAAoB;AACzC,WAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,OAAO,KAAK;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,OAAO;AAC5B,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM,MAAM,OAAO,SAAS;AAAA,MAC5B,SAAS,MAAM;AAAA,IACjB;AAAA,EACF;AACF;","names":[]}
|
package/dist/http.d.cts
ADDED
package/dist/http.d.ts
ADDED
package/dist/http.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/error/http-error-normalizer.ts
|
|
2
|
+
import { HttpErrorResponse } from "@angular/common/http";
|
|
3
|
+
var httpErrorNormalizer = (error) => {
|
|
4
|
+
if (!(error instanceof HttpErrorResponse)) {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
code: "UNKNOWN",
|
|
8
|
+
message: String(error)
|
|
9
|
+
}
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
const errors = error.error?.errors;
|
|
13
|
+
if (Array.isArray(errors)) {
|
|
14
|
+
return errors;
|
|
15
|
+
}
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
code: error.status.toString(),
|
|
19
|
+
message: error.message
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
};
|
|
23
|
+
export {
|
|
24
|
+
httpErrorNormalizer
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/error/http-error-normalizer.ts"],"sourcesContent":["import { HttpErrorResponse } from '@angular/common/http';\nimport type { ResourceErrors } from '@flurryx/core';\nimport type { ErrorNormalizer } from './error-normalizer';\n\nexport const httpErrorNormalizer: ErrorNormalizer = (\n error: unknown\n): ResourceErrors => {\n if (!(error instanceof HttpErrorResponse)) {\n return [\n {\n code: 'UNKNOWN',\n message: String(error),\n },\n ];\n }\n\n const errors = error.error?.errors as unknown;\n if (Array.isArray(errors)) {\n return errors as ResourceErrors;\n }\n\n return [\n {\n code: error.status.toString(),\n message: error.message,\n },\n ];\n};\n"],"mappings":";AAAA,SAAS,yBAAyB;AAI3B,IAAM,sBAAuC,CAClD,UACmB;AACnB,MAAI,EAAE,iBAAiB,oBAAoB;AACzC,WAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,OAAO,KAAK;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,OAAO;AAC5B,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM,MAAM,OAAO,SAAS;AAAA,MAC5B,SAAS,MAAM;AAAA,IACjB;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Loading: () => Loading,
|
|
24
|
+
SkipIfCached: () => SkipIfCached,
|
|
25
|
+
defaultErrorNormalizer: () => defaultErrorNormalizer,
|
|
26
|
+
syncToKeyedStore: () => syncToKeyedStore,
|
|
27
|
+
syncToStore: () => syncToStore
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/operators/sync-to-store.ts
|
|
32
|
+
var import_rxjs = require("rxjs");
|
|
33
|
+
|
|
34
|
+
// src/error/error-normalizer.ts
|
|
35
|
+
function defaultErrorNormalizer(error) {
|
|
36
|
+
if (typeof error === "object" && error !== null && "error" in error && typeof error.error === "object") {
|
|
37
|
+
const inner = error.error;
|
|
38
|
+
if (inner && Array.isArray(inner.errors)) {
|
|
39
|
+
return inner.errors;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (typeof error === "object" && error !== null && "status" in error && "message" in error) {
|
|
43
|
+
const typed = error;
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
code: String(typed.status),
|
|
47
|
+
message: typed.message
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
code: "UNKNOWN",
|
|
55
|
+
message: error.message
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
code: "UNKNOWN",
|
|
62
|
+
message: String(error)
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/operators/sync-to-store.ts
|
|
68
|
+
function syncToStore(store, key, options = { completeOnFirstEmission: true }) {
|
|
69
|
+
const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;
|
|
70
|
+
return (source) => {
|
|
71
|
+
let pipeline = source.pipe(
|
|
72
|
+
(0, import_rxjs.tap)({
|
|
73
|
+
next: (data) => {
|
|
74
|
+
store.update(key, {
|
|
75
|
+
data,
|
|
76
|
+
isLoading: false,
|
|
77
|
+
status: "Success",
|
|
78
|
+
errors: void 0
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
error: (error) => {
|
|
82
|
+
store.update(key, {
|
|
83
|
+
data: void 0,
|
|
84
|
+
isLoading: false,
|
|
85
|
+
status: "Error",
|
|
86
|
+
errors: normalizeError(error)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
if (options.completeOnFirstEmission) {
|
|
92
|
+
pipeline = pipeline.pipe((0, import_rxjs.take)(1));
|
|
93
|
+
}
|
|
94
|
+
if (options.callbackAfterComplete) {
|
|
95
|
+
pipeline = pipeline.pipe((0, import_rxjs.finalize)(options.callbackAfterComplete));
|
|
96
|
+
}
|
|
97
|
+
return pipeline;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/operators/sync-to-keyed-store.ts
|
|
102
|
+
var import_rxjs2 = require("rxjs");
|
|
103
|
+
var import_core = require("@flurryx/core");
|
|
104
|
+
function withoutKey(record, key) {
|
|
105
|
+
const next = {
|
|
106
|
+
...record
|
|
107
|
+
};
|
|
108
|
+
delete next[key];
|
|
109
|
+
return next;
|
|
110
|
+
}
|
|
111
|
+
function syncToKeyedStore(store, storeKey, resourceKey, options = {
|
|
112
|
+
completeOnFirstEmission: true
|
|
113
|
+
}) {
|
|
114
|
+
const { completeOnFirstEmission, callbackAfterComplete, mapResponse } = options;
|
|
115
|
+
const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;
|
|
116
|
+
return (source) => {
|
|
117
|
+
let pipeline = source.pipe(
|
|
118
|
+
(0, import_rxjs2.tap)({
|
|
119
|
+
next: (response) => {
|
|
120
|
+
const value = mapResponse ? mapResponse(response) : response;
|
|
121
|
+
const storeSignal = store.get(storeKey);
|
|
122
|
+
const state = storeSignal();
|
|
123
|
+
const data = state.data ?? (0, import_core.createKeyedResourceData)();
|
|
124
|
+
const nextIsLoading = {
|
|
125
|
+
...data.isLoading,
|
|
126
|
+
[resourceKey]: false
|
|
127
|
+
};
|
|
128
|
+
const nextStatus = {
|
|
129
|
+
...data.status,
|
|
130
|
+
[resourceKey]: "Success"
|
|
131
|
+
};
|
|
132
|
+
const nextData = {
|
|
133
|
+
...data,
|
|
134
|
+
entities: {
|
|
135
|
+
...data.entities,
|
|
136
|
+
[resourceKey]: value
|
|
137
|
+
},
|
|
138
|
+
isLoading: nextIsLoading,
|
|
139
|
+
status: nextStatus,
|
|
140
|
+
errors: withoutKey(data.errors, resourceKey)
|
|
141
|
+
};
|
|
142
|
+
store.update(storeKey, {
|
|
143
|
+
data: nextData,
|
|
144
|
+
isLoading: (0, import_core.isAnyKeyLoading)(nextIsLoading),
|
|
145
|
+
status: void 0,
|
|
146
|
+
errors: void 0
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
error: (error) => {
|
|
150
|
+
const storeSignal = store.get(storeKey);
|
|
151
|
+
const state = storeSignal();
|
|
152
|
+
const data = state.data ?? (0, import_core.createKeyedResourceData)();
|
|
153
|
+
const nextIsLoading = {
|
|
154
|
+
...data.isLoading,
|
|
155
|
+
[resourceKey]: false
|
|
156
|
+
};
|
|
157
|
+
const nextStatus = {
|
|
158
|
+
...data.status,
|
|
159
|
+
[resourceKey]: "Error"
|
|
160
|
+
};
|
|
161
|
+
const nextErrors = {
|
|
162
|
+
...data.errors,
|
|
163
|
+
[resourceKey]: normalizeError(error)
|
|
164
|
+
};
|
|
165
|
+
const nextData = {
|
|
166
|
+
...data,
|
|
167
|
+
isLoading: nextIsLoading,
|
|
168
|
+
status: nextStatus,
|
|
169
|
+
errors: nextErrors
|
|
170
|
+
};
|
|
171
|
+
store.update(storeKey, {
|
|
172
|
+
data: nextData,
|
|
173
|
+
isLoading: (0, import_core.isAnyKeyLoading)(nextIsLoading),
|
|
174
|
+
status: void 0,
|
|
175
|
+
errors: void 0
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
);
|
|
180
|
+
if (completeOnFirstEmission) {
|
|
181
|
+
pipeline = pipeline.pipe((0, import_rxjs2.take)(1));
|
|
182
|
+
}
|
|
183
|
+
if (callbackAfterComplete) {
|
|
184
|
+
pipeline = pipeline.pipe((0, import_rxjs2.finalize)(callbackAfterComplete));
|
|
185
|
+
}
|
|
186
|
+
return pipeline;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/decorators/skip-if-cached.ts
|
|
191
|
+
var import_rxjs3 = require("rxjs");
|
|
192
|
+
var import_core2 = require("@flurryx/core");
|
|
193
|
+
var import_core3 = require("@flurryx/core");
|
|
194
|
+
var cacheState = /* @__PURE__ */ new WeakMap();
|
|
195
|
+
function getStoreKeyMap(store, key) {
|
|
196
|
+
let storeMap = cacheState.get(store);
|
|
197
|
+
if (!storeMap) {
|
|
198
|
+
storeMap = /* @__PURE__ */ new Map();
|
|
199
|
+
cacheState.set(store, storeMap);
|
|
200
|
+
}
|
|
201
|
+
let keyMap = storeMap.get(key);
|
|
202
|
+
if (!keyMap) {
|
|
203
|
+
keyMap = /* @__PURE__ */ new Map();
|
|
204
|
+
storeMap.set(key, keyMap);
|
|
205
|
+
}
|
|
206
|
+
return keyMap;
|
|
207
|
+
}
|
|
208
|
+
function getCacheEntry(store, key, cacheKey) {
|
|
209
|
+
return getStoreKeyMap(store, key).get(cacheKey);
|
|
210
|
+
}
|
|
211
|
+
function setCacheEntry(store, key, cacheKey, entry) {
|
|
212
|
+
getStoreKeyMap(store, key).set(cacheKey, entry);
|
|
213
|
+
}
|
|
214
|
+
function clearCacheEntry(store, key, cacheKey) {
|
|
215
|
+
getStoreKeyMap(store, key).delete(cacheKey);
|
|
216
|
+
}
|
|
217
|
+
function deriveResourceKey(args) {
|
|
218
|
+
const key = args[0];
|
|
219
|
+
if (typeof key === "string" || typeof key === "number") {
|
|
220
|
+
return key;
|
|
221
|
+
}
|
|
222
|
+
return void 0;
|
|
223
|
+
}
|
|
224
|
+
function isExpired(timestamp, timeoutMs, now) {
|
|
225
|
+
if (timeoutMs === import_core3.CACHE_NO_TIMEOUT) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
if (timestamp === void 0) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return now - timestamp >= timeoutMs;
|
|
232
|
+
}
|
|
233
|
+
function getStoreContext(instance, storeKey, getStore) {
|
|
234
|
+
const store = getStore(instance);
|
|
235
|
+
if (!store) {
|
|
236
|
+
return void 0;
|
|
237
|
+
}
|
|
238
|
+
const storeSignal = store.get(storeKey);
|
|
239
|
+
if (!storeSignal) {
|
|
240
|
+
return void 0;
|
|
241
|
+
}
|
|
242
|
+
const currentState = storeSignal();
|
|
243
|
+
if (currentState === null || currentState === void 0) {
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
return { store, storeSignal, currentState };
|
|
247
|
+
}
|
|
248
|
+
function getCacheContext(store, storeKey, args, argsString, currentState) {
|
|
249
|
+
const keyedData = (0, import_core2.isKeyedResourceData)(currentState.data) ? currentState.data : void 0;
|
|
250
|
+
const resourceKey = keyedData ? deriveResourceKey(args) : void 0;
|
|
251
|
+
const isKeyedCall = keyedData !== void 0 && resourceKey !== void 0;
|
|
252
|
+
const keyedCacheKey = argsString;
|
|
253
|
+
const nonKeyedCacheKey = "__single__";
|
|
254
|
+
const runtimeCacheKey = isKeyedCall ? keyedCacheKey : nonKeyedCacheKey;
|
|
255
|
+
const keyedCacheEntry = getCacheEntry(store, storeKey, keyedCacheKey);
|
|
256
|
+
const nonKeyedCacheEntry = getCacheEntry(store, storeKey, nonKeyedCacheKey);
|
|
257
|
+
return {
|
|
258
|
+
isKeyedCall,
|
|
259
|
+
resourceKey,
|
|
260
|
+
keyedData,
|
|
261
|
+
runtimeCacheKey,
|
|
262
|
+
keyedCacheEntry,
|
|
263
|
+
nonKeyedCacheEntry
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function handleCacheErrors(store, storeKey, context, currentState) {
|
|
267
|
+
if (!context.keyedData && currentState.status === "Error") {
|
|
268
|
+
clearCacheEntry(store, storeKey, "__single__");
|
|
269
|
+
}
|
|
270
|
+
if (context.keyedData && context.resourceKey !== void 0) {
|
|
271
|
+
const status = context.keyedData.status[context.resourceKey];
|
|
272
|
+
if (status === "Error") {
|
|
273
|
+
clearCacheEntry(store, storeKey, context.runtimeCacheKey);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function handleKeyedCache(store, storeKey, context, timeoutMs, now, returnObservable) {
|
|
278
|
+
const { keyedData, resourceKey, keyedCacheEntry, runtimeCacheKey } = context;
|
|
279
|
+
if (!keyedData || resourceKey === void 0) {
|
|
280
|
+
return { hit: false };
|
|
281
|
+
}
|
|
282
|
+
const typed = keyedData;
|
|
283
|
+
const status = typed.status[resourceKey];
|
|
284
|
+
const entity = typed.entities[resourceKey];
|
|
285
|
+
const loading = typed.isLoading[resourceKey] === true;
|
|
286
|
+
const expired = isExpired(keyedCacheEntry?.timestamp, timeoutMs, now);
|
|
287
|
+
if (expired) {
|
|
288
|
+
clearCacheEntry(store, storeKey, runtimeCacheKey);
|
|
289
|
+
}
|
|
290
|
+
if (!expired && status === "Success" && entity !== void 0) {
|
|
291
|
+
if (returnObservable) {
|
|
292
|
+
return { hit: true, value: (0, import_rxjs3.of)(entity) };
|
|
293
|
+
}
|
|
294
|
+
return { hit: true };
|
|
295
|
+
}
|
|
296
|
+
if (returnObservable) {
|
|
297
|
+
if (keyedCacheEntry?.inflight$) {
|
|
298
|
+
return { hit: true, value: keyedCacheEntry.inflight$ };
|
|
299
|
+
}
|
|
300
|
+
} else if (loading) {
|
|
301
|
+
return { hit: true };
|
|
302
|
+
}
|
|
303
|
+
return { hit: false };
|
|
304
|
+
}
|
|
305
|
+
function handleNonKeyedCache(store, storeKey, context, timeoutMs, now, returnObservable, currentState, argsString, storeSignal) {
|
|
306
|
+
const { nonKeyedCacheEntry, runtimeCacheKey } = context;
|
|
307
|
+
if (returnObservable && nonKeyedCacheEntry?.args === argsString && nonKeyedCacheEntry.inflight$) {
|
|
308
|
+
return { hit: true, value: nonKeyedCacheEntry.inflight$ };
|
|
309
|
+
}
|
|
310
|
+
const hasValidCacheState = currentState?.status === "Success" || currentState?.isLoading === true;
|
|
311
|
+
if (nonKeyedCacheEntry && isExpired(nonKeyedCacheEntry.timestamp, timeoutMs, now)) {
|
|
312
|
+
clearCacheEntry(store, storeKey, runtimeCacheKey);
|
|
313
|
+
} else if (nonKeyedCacheEntry?.args === argsString && hasValidCacheState) {
|
|
314
|
+
if (returnObservable) {
|
|
315
|
+
if (nonKeyedCacheEntry.inflight$) {
|
|
316
|
+
return { hit: true, value: nonKeyedCacheEntry.inflight$ };
|
|
317
|
+
}
|
|
318
|
+
return { hit: true, value: (0, import_rxjs3.of)(storeSignal().data) };
|
|
319
|
+
}
|
|
320
|
+
return { hit: true };
|
|
321
|
+
}
|
|
322
|
+
return { hit: false };
|
|
323
|
+
}
|
|
324
|
+
function createCachedObservable(result, store, storeKey, runtimeCacheKey, argsString) {
|
|
325
|
+
return result.pipe(
|
|
326
|
+
(0, import_rxjs3.tap)({
|
|
327
|
+
next: () => {
|
|
328
|
+
setCacheEntry(store, storeKey, runtimeCacheKey, {
|
|
329
|
+
timestamp: Date.now(),
|
|
330
|
+
args: argsString
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
error: () => {
|
|
334
|
+
clearCacheEntry(store, storeKey, runtimeCacheKey);
|
|
335
|
+
}
|
|
336
|
+
}),
|
|
337
|
+
(0, import_rxjs3.finalize)(() => {
|
|
338
|
+
const entry = getCacheEntry(store, storeKey, runtimeCacheKey);
|
|
339
|
+
if (entry?.inflight$) {
|
|
340
|
+
const { inflight$: _inflight$, ...rest } = entry;
|
|
341
|
+
setCacheEntry(store, storeKey, runtimeCacheKey, rest);
|
|
342
|
+
}
|
|
343
|
+
}),
|
|
344
|
+
(0, import_rxjs3.shareReplay)({ bufferSize: 1, refCount: true })
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
function SkipIfCached(storeKey, storeGetter, returnObservable = false, timeoutMs = import_core3.DEFAULT_CACHE_TTL_MS) {
|
|
348
|
+
return function(_target, _propertyKey, descriptor) {
|
|
349
|
+
const originalMethod = descriptor.value;
|
|
350
|
+
descriptor.value = function(...args) {
|
|
351
|
+
const storeContext = getStoreContext(this, storeKey, storeGetter);
|
|
352
|
+
if (!storeContext) {
|
|
353
|
+
return originalMethod.apply(this, args);
|
|
354
|
+
}
|
|
355
|
+
const { store, storeSignal, currentState } = storeContext;
|
|
356
|
+
const argsString = JSON.stringify(args);
|
|
357
|
+
const now = Date.now();
|
|
358
|
+
const cacheContext = getCacheContext(
|
|
359
|
+
store,
|
|
360
|
+
storeKey,
|
|
361
|
+
args,
|
|
362
|
+
argsString,
|
|
363
|
+
currentState
|
|
364
|
+
);
|
|
365
|
+
handleCacheErrors(store, storeKey, cacheContext, currentState);
|
|
366
|
+
let cacheHit;
|
|
367
|
+
if (cacheContext.isKeyedCall) {
|
|
368
|
+
cacheHit = handleKeyedCache(
|
|
369
|
+
store,
|
|
370
|
+
storeKey,
|
|
371
|
+
cacheContext,
|
|
372
|
+
timeoutMs,
|
|
373
|
+
now,
|
|
374
|
+
returnObservable
|
|
375
|
+
);
|
|
376
|
+
} else {
|
|
377
|
+
cacheHit = handleNonKeyedCache(
|
|
378
|
+
store,
|
|
379
|
+
storeKey,
|
|
380
|
+
cacheContext,
|
|
381
|
+
timeoutMs,
|
|
382
|
+
now,
|
|
383
|
+
returnObservable,
|
|
384
|
+
currentState,
|
|
385
|
+
argsString,
|
|
386
|
+
storeSignal
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
if (cacheHit.hit) {
|
|
390
|
+
return cacheHit.value;
|
|
391
|
+
}
|
|
392
|
+
const result = originalMethod.apply(this, args);
|
|
393
|
+
if (!returnObservable) {
|
|
394
|
+
setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {
|
|
395
|
+
timestamp: now,
|
|
396
|
+
args: argsString
|
|
397
|
+
});
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
const inflight$ = createCachedObservable(
|
|
401
|
+
result,
|
|
402
|
+
store,
|
|
403
|
+
storeKey,
|
|
404
|
+
cacheContext.runtimeCacheKey,
|
|
405
|
+
argsString
|
|
406
|
+
);
|
|
407
|
+
setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {
|
|
408
|
+
timestamp: now,
|
|
409
|
+
args: argsString,
|
|
410
|
+
inflight$
|
|
411
|
+
});
|
|
412
|
+
return inflight$;
|
|
413
|
+
};
|
|
414
|
+
return descriptor;
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/decorators/loading.ts
|
|
419
|
+
function Loading(storeKey, storeGetter) {
|
|
420
|
+
return function(_target, _propertyKey, descriptor) {
|
|
421
|
+
const originalMethod = descriptor.value;
|
|
422
|
+
descriptor.value = function(...args) {
|
|
423
|
+
const store = storeGetter(this);
|
|
424
|
+
const resourceKey = args[0];
|
|
425
|
+
const canKey = typeof resourceKey === "string" || typeof resourceKey === "number";
|
|
426
|
+
const hasKeyed = typeof store === "object" && store !== null && "startKeyedLoading" in store && typeof store.startKeyedLoading === "function";
|
|
427
|
+
if (canKey && hasKeyed) {
|
|
428
|
+
store.startKeyedLoading(storeKey, resourceKey);
|
|
429
|
+
} else {
|
|
430
|
+
store?.startLoading(storeKey);
|
|
431
|
+
}
|
|
432
|
+
return originalMethod.apply(this, args);
|
|
433
|
+
};
|
|
434
|
+
return descriptor;
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
438
|
+
0 && (module.exports = {
|
|
439
|
+
Loading,
|
|
440
|
+
SkipIfCached,
|
|
441
|
+
defaultErrorNormalizer,
|
|
442
|
+
syncToKeyedStore,
|
|
443
|
+
syncToStore
|
|
444
|
+
});
|
|
445
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/operators/sync-to-store.ts","../src/error/error-normalizer.ts","../src/operators/sync-to-keyed-store.ts","../src/decorators/skip-if-cached.ts","../src/decorators/loading.ts"],"sourcesContent":["export {\n syncToStore,\n type SyncToStoreOptions,\n} from './operators/sync-to-store';\nexport {\n syncToKeyedStore,\n type SyncToKeyedStoreOptions,\n} from './operators/sync-to-keyed-store';\nexport { SkipIfCached } from './decorators/skip-if-cached';\nexport { Loading } from './decorators/loading';\nexport {\n defaultErrorNormalizer,\n type ErrorNormalizer,\n} from './error/error-normalizer';\n","import { finalize, Observable, take, tap } from \"rxjs\";\nimport { BaseStore } from \"@flurryx/store\";\nimport type { ResourceState } from \"@flurryx/core\";\nimport {\n defaultErrorNormalizer,\n type ErrorNormalizer,\n} from \"../error/error-normalizer\";\n\nexport interface SyncToStoreOptions {\n completeOnFirstEmission?: boolean;\n callbackAfterComplete?: () => void;\n errorNormalizer?: ErrorNormalizer;\n}\n\nexport function syncToStore<\n TEnum extends Record<string, string | number>,\n TData extends { [K in keyof TEnum]: ResourceState<unknown> }\n>(\n store: BaseStore<TEnum, TData>,\n key: keyof TEnum,\n options: SyncToStoreOptions = { completeOnFirstEmission: true }\n) {\n const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;\n\n return <R>(source: Observable<R>) => {\n let pipeline = source.pipe(\n tap({\n next: (data: R) => {\n store.update(key, {\n data,\n isLoading: false,\n status: \"Success\",\n errors: undefined,\n } as Partial<TData[typeof key]>);\n },\n error: (error: unknown) => {\n store.update(key, {\n data: undefined,\n isLoading: false,\n status: \"Error\",\n errors: normalizeError(error),\n } as Partial<TData[typeof key]>);\n },\n })\n );\n\n if (options.completeOnFirstEmission) {\n pipeline = pipeline.pipe(take(1));\n }\n\n if (options.callbackAfterComplete) {\n pipeline = pipeline.pipe(finalize(options.callbackAfterComplete));\n }\n\n return pipeline;\n };\n}\n","import type { ResourceErrors } from '@flurryx/core';\n\nexport type ErrorNormalizer = (error: unknown) => ResourceErrors;\n\nexport function defaultErrorNormalizer(error: unknown): ResourceErrors {\n if (\n typeof error === 'object' &&\n error !== null &&\n 'error' in error &&\n typeof (error as Record<string, unknown>).error === 'object'\n ) {\n const inner = (error as { error: Record<string, unknown> }).error;\n if (inner && Array.isArray(inner.errors)) {\n return inner.errors as ResourceErrors;\n }\n }\n\n if (\n typeof error === 'object' &&\n error !== null &&\n 'status' in error &&\n 'message' in error\n ) {\n const typed = error as { status: number; message: string };\n return [\n {\n code: String(typed.status),\n message: typed.message,\n },\n ];\n }\n\n if (error instanceof Error) {\n return [\n {\n code: 'UNKNOWN',\n message: error.message,\n },\n ];\n }\n\n return [\n {\n code: 'UNKNOWN',\n message: String(error),\n },\n ];\n}\n","import { finalize, Observable, take, tap } from \"rxjs\";\nimport { BaseStore } from \"@flurryx/store\";\nimport {\n createKeyedResourceData,\n isAnyKeyLoading,\n type KeyedResourceData,\n type KeyedResourceKey,\n type ResourceErrors,\n type ResourceState,\n type ResourceStatus,\n} from \"@flurryx/core\";\nimport {\n defaultErrorNormalizer,\n type ErrorNormalizer,\n} from \"../error/error-normalizer\";\nimport type { SyncToStoreOptions } from \"./sync-to-store\";\n\nexport interface SyncToKeyedStoreOptions<R, TValue> extends SyncToStoreOptions {\n mapResponse?: (response: R) => TValue;\n errorNormalizer?: ErrorNormalizer;\n}\n\nfunction withoutKey<TKey extends KeyedResourceKey, TValue>(\n record: Partial<Record<TKey, TValue>>,\n key: TKey\n): Partial<Record<TKey, TValue>> {\n const next: Partial<Record<TKey, TValue>> = {\n ...record,\n };\n delete next[key];\n return next;\n}\n\nexport function syncToKeyedStore<\n TEnum extends Record<string, string | number>,\n TStoreKey extends keyof TEnum,\n TKey extends KeyedResourceKey,\n TValue,\n R = TValue,\n TState extends ResourceState<KeyedResourceData<TKey, TValue>> = ResourceState<\n KeyedResourceData<TKey, TValue>\n >,\n TData extends {\n [K in keyof TEnum]: ResourceState<unknown>;\n } & { [K in TStoreKey]: TState } = {\n [K in keyof TEnum]: ResourceState<unknown>;\n } & { [K in TStoreKey]: TState }\n>(\n store: BaseStore<TEnum, TData>,\n storeKey: TStoreKey,\n resourceKey: TKey,\n options: SyncToKeyedStoreOptions<R, TValue> = {\n completeOnFirstEmission: true,\n }\n) {\n const { completeOnFirstEmission, callbackAfterComplete, mapResponse } =\n options;\n const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;\n\n return (source: Observable<R>) => {\n let pipeline = source.pipe(\n tap({\n next: (response: R) => {\n const value = mapResponse\n ? mapResponse(response)\n : (response as unknown as TValue);\n\n const storeSignal = store.get(storeKey);\n const state = storeSignal();\n const data = state.data ?? createKeyedResourceData<TKey, TValue>();\n\n const nextIsLoading = {\n ...data.isLoading,\n [resourceKey]: false,\n } as Partial<Record<TKey, boolean>>;\n\n const nextStatus: Partial<Record<TKey, ResourceStatus>> = {\n ...data.status,\n [resourceKey]: \"Success\",\n };\n\n const nextData: KeyedResourceData<TKey, TValue> = {\n ...data,\n entities: {\n ...data.entities,\n [resourceKey]: value,\n } as Partial<Record<TKey, TValue>>,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: withoutKey(data.errors, resourceKey),\n };\n\n store.update(storeKey, {\n data: nextData,\n isLoading: isAnyKeyLoading(nextIsLoading),\n status: undefined,\n errors: undefined,\n } as Partial<TData[typeof storeKey]>);\n },\n error: (error: unknown) => {\n const storeSignal = store.get(storeKey);\n const state = storeSignal();\n const data = state.data ?? createKeyedResourceData<TKey, TValue>();\n\n const nextIsLoading = {\n ...data.isLoading,\n [resourceKey]: false,\n } as Partial<Record<TKey, boolean>>;\n\n const nextStatus: Partial<Record<TKey, ResourceStatus>> = {\n ...data.status,\n [resourceKey]: \"Error\",\n };\n\n const nextErrors: Partial<Record<TKey, ResourceErrors>> = {\n ...data.errors,\n [resourceKey]: normalizeError(error),\n };\n\n const nextData: KeyedResourceData<TKey, TValue> = {\n ...data,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n store.update(storeKey, {\n data: nextData,\n isLoading: isAnyKeyLoading(nextIsLoading),\n status: undefined,\n errors: undefined,\n } as Partial<TData[typeof storeKey]>);\n },\n })\n );\n\n if (completeOnFirstEmission) {\n pipeline = pipeline.pipe(take(1));\n }\n\n if (callbackAfterComplete) {\n pipeline = pipeline.pipe(finalize(callbackAfterComplete));\n }\n\n return pipeline;\n };\n}\n","import { WritableSignal } from '@angular/core';\nimport { finalize, Observable, of, shareReplay, tap } from 'rxjs';\nimport type { ResourceState, StoreEnum, KeyedResourceKey } from '@flurryx/core';\nimport { isKeyedResourceData } from '@flurryx/core';\nimport { CACHE_NO_TIMEOUT, DEFAULT_CACHE_TTL_MS } from '@flurryx/core';\n\ntype StoreWithSignal<TKey extends StoreEnum> = {\n get: (key: TKey) => WritableSignal<ResourceState<unknown>> | undefined;\n};\n\ninterface CacheEntry {\n timestamp: number;\n args: string;\n inflight$?: Observable<unknown>;\n}\n\nconst cacheState = new WeakMap<\n object,\n Map<StoreEnum, Map<string, CacheEntry>>\n>();\n\nfunction getStoreKeyMap(\n store: object,\n key: StoreEnum\n): Map<string, CacheEntry> {\n let storeMap = cacheState.get(store);\n if (!storeMap) {\n storeMap = new Map();\n cacheState.set(store, storeMap);\n }\n\n let keyMap = storeMap.get(key);\n if (!keyMap) {\n keyMap = new Map();\n storeMap.set(key, keyMap);\n }\n\n return keyMap;\n}\n\nfunction getCacheEntry(\n store: object,\n key: StoreEnum,\n cacheKey: string\n): CacheEntry | undefined {\n return getStoreKeyMap(store, key).get(cacheKey);\n}\n\nfunction setCacheEntry(\n store: object,\n key: StoreEnum,\n cacheKey: string,\n entry: CacheEntry\n): void {\n getStoreKeyMap(store, key).set(cacheKey, entry);\n}\n\nfunction clearCacheEntry(\n store: object,\n key: StoreEnum,\n cacheKey: string\n): void {\n getStoreKeyMap(store, key).delete(cacheKey);\n}\n\nfunction deriveResourceKey(args: unknown[]): KeyedResourceKey | undefined {\n const key = args[0];\n if (typeof key === 'string' || typeof key === 'number') {\n return key;\n }\n return undefined;\n}\n\nfunction isExpired(\n timestamp: number | undefined,\n timeoutMs: number,\n now: number\n): boolean {\n if (timeoutMs === CACHE_NO_TIMEOUT) {\n return false;\n }\n if (timestamp === undefined) {\n return false;\n }\n return now - timestamp >= timeoutMs;\n}\n\ninterface StoreContext {\n store: object;\n storeSignal: WritableSignal<ResourceState<unknown>>;\n currentState: ResourceState<unknown>;\n}\n\nfunction getStoreContext<TTarget, TKey extends StoreEnum>(\n instance: TTarget,\n storeKey: TKey,\n getStore: (i: TTarget) => StoreWithSignal<TKey> | undefined\n): StoreContext | undefined {\n const store = getStore(instance);\n if (!store) {\n return undefined;\n }\n\n const storeSignal = store.get(storeKey);\n if (!storeSignal) {\n return undefined;\n }\n\n const currentState = storeSignal();\n if (currentState === null || currentState === undefined) {\n return undefined;\n }\n\n return { store, storeSignal, currentState };\n}\n\ninterface CacheContext {\n isKeyedCall: boolean;\n resourceKey: KeyedResourceKey | undefined;\n keyedData: ReturnType<typeof isKeyedResourceData> extends true\n ? { entities: object; isLoading: object; status: object; errors: object }\n : undefined;\n runtimeCacheKey: string;\n keyedCacheEntry: CacheEntry | undefined;\n nonKeyedCacheEntry: CacheEntry | undefined;\n}\n\nfunction getCacheContext(\n store: object,\n storeKey: StoreEnum,\n args: unknown[],\n argsString: string,\n currentState: ResourceState<unknown>\n): CacheContext {\n const keyedData = isKeyedResourceData(currentState.data)\n ? currentState.data\n : undefined;\n const resourceKey = keyedData ? deriveResourceKey(args) : undefined;\n const isKeyedCall = keyedData !== undefined && resourceKey !== undefined;\n\n const keyedCacheKey = argsString;\n const nonKeyedCacheKey = '__single__';\n const runtimeCacheKey = isKeyedCall ? keyedCacheKey : nonKeyedCacheKey;\n\n const keyedCacheEntry = getCacheEntry(store, storeKey, keyedCacheKey);\n const nonKeyedCacheEntry = getCacheEntry(store, storeKey, nonKeyedCacheKey);\n\n return {\n isKeyedCall,\n resourceKey,\n keyedData: keyedData as CacheContext['keyedData'],\n runtimeCacheKey,\n keyedCacheEntry,\n nonKeyedCacheEntry,\n };\n}\n\nfunction handleCacheErrors(\n store: object,\n storeKey: StoreEnum,\n context: CacheContext,\n currentState: ResourceState<unknown>\n): void {\n if (!context.keyedData && currentState.status === 'Error') {\n clearCacheEntry(store, storeKey, '__single__');\n }\n if (context.keyedData && context.resourceKey !== undefined) {\n const status = (\n context.keyedData as {\n status: Partial<Record<KeyedResourceKey, string>>;\n }\n ).status[context.resourceKey];\n if (status === 'Error') {\n clearCacheEntry(store, storeKey, context.runtimeCacheKey);\n }\n }\n}\n\ninterface CacheHitResult {\n hit: boolean;\n value?: Observable<unknown>;\n}\n\nfunction handleKeyedCache(\n store: object,\n storeKey: StoreEnum,\n context: CacheContext,\n timeoutMs: number,\n now: number,\n returnObservable: boolean\n): CacheHitResult {\n const { keyedData, resourceKey, keyedCacheEntry, runtimeCacheKey } = context;\n\n if (!keyedData || resourceKey === undefined) {\n return { hit: false };\n }\n\n const typed = keyedData as {\n status: Partial<Record<KeyedResourceKey, string>>;\n entities: Partial<Record<KeyedResourceKey, unknown>>;\n isLoading: Partial<Record<KeyedResourceKey, boolean>>;\n };\n\n const status = typed.status[resourceKey];\n const entity = typed.entities[resourceKey];\n const loading = typed.isLoading[resourceKey] === true;\n\n const expired = isExpired(keyedCacheEntry?.timestamp, timeoutMs, now);\n if (expired) {\n clearCacheEntry(store, storeKey, runtimeCacheKey);\n }\n\n if (!expired && status === 'Success' && entity !== undefined) {\n if (returnObservable) {\n return { hit: true, value: of(entity) };\n }\n return { hit: true };\n }\n\n if (returnObservable) {\n if (keyedCacheEntry?.inflight$) {\n return { hit: true, value: keyedCacheEntry.inflight$ };\n }\n } else if (loading) {\n return { hit: true };\n }\n\n return { hit: false };\n}\n\nfunction handleNonKeyedCache(\n store: object,\n storeKey: StoreEnum,\n context: CacheContext,\n timeoutMs: number,\n now: number,\n returnObservable: boolean,\n currentState: ResourceState<unknown>,\n argsString: string,\n storeSignal: WritableSignal<ResourceState<unknown>>\n): CacheHitResult {\n const { nonKeyedCacheEntry, runtimeCacheKey } = context;\n\n if (\n returnObservable &&\n nonKeyedCacheEntry?.args === argsString &&\n nonKeyedCacheEntry.inflight$\n ) {\n return { hit: true, value: nonKeyedCacheEntry.inflight$ };\n }\n\n const hasValidCacheState =\n currentState?.status === 'Success' || currentState?.isLoading === true;\n\n if (\n nonKeyedCacheEntry &&\n isExpired(nonKeyedCacheEntry.timestamp, timeoutMs, now)\n ) {\n clearCacheEntry(store, storeKey, runtimeCacheKey);\n } else if (nonKeyedCacheEntry?.args === argsString && hasValidCacheState) {\n if (returnObservable) {\n if (nonKeyedCacheEntry.inflight$) {\n return { hit: true, value: nonKeyedCacheEntry.inflight$ };\n }\n return { hit: true, value: of(storeSignal().data) };\n }\n return { hit: true };\n }\n\n return { hit: false };\n}\n\nfunction createCachedObservable(\n result: Observable<unknown>,\n store: object,\n storeKey: StoreEnum,\n runtimeCacheKey: string,\n argsString: string\n): Observable<unknown> {\n return result.pipe(\n tap({\n next: () => {\n setCacheEntry(store, storeKey, runtimeCacheKey, {\n timestamp: Date.now(),\n args: argsString,\n });\n },\n error: () => {\n clearCacheEntry(store, storeKey, runtimeCacheKey);\n },\n }),\n finalize(() => {\n const entry = getCacheEntry(store, storeKey, runtimeCacheKey);\n if (entry?.inflight$) {\n const { inflight$: _inflight$, ...rest } = entry;\n setCacheEntry(store, storeKey, runtimeCacheKey, rest);\n }\n }),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n}\n\nexport function SkipIfCached<TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: {\n store: StoreWithSignal<TKey>;\n }) => StoreWithSignal<TKey> | undefined,\n returnObservable?: boolean,\n timeoutMs?: number\n): MethodDecorator;\nexport function SkipIfCached<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithSignal<TKey> | undefined,\n returnObservable?: boolean,\n timeoutMs?: number\n): MethodDecorator;\nexport function SkipIfCached<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithSignal<TKey> | undefined,\n returnObservable = false,\n timeoutMs = DEFAULT_CACHE_TTL_MS\n): MethodDecorator {\n return function (\n _target: unknown,\n _propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ) {\n const originalMethod = descriptor.value as (\n this: TTarget,\n ...args: unknown[]\n ) => unknown;\n\n descriptor.value = function (this: TTarget, ...args: unknown[]) {\n const storeContext = getStoreContext(this, storeKey, storeGetter);\n if (!storeContext) {\n return originalMethod.apply(this, args);\n }\n const { store, storeSignal, currentState } = storeContext;\n\n const argsString = JSON.stringify(args);\n const now = Date.now();\n const cacheContext = getCacheContext(\n store,\n storeKey,\n args,\n argsString,\n currentState\n );\n\n handleCacheErrors(store, storeKey, cacheContext, currentState);\n\n let cacheHit: CacheHitResult;\n\n if (cacheContext.isKeyedCall) {\n cacheHit = handleKeyedCache(\n store,\n storeKey,\n cacheContext,\n timeoutMs,\n now,\n returnObservable\n );\n } else {\n cacheHit = handleNonKeyedCache(\n store,\n storeKey,\n cacheContext,\n timeoutMs,\n now,\n returnObservable,\n currentState,\n argsString,\n storeSignal\n );\n }\n\n if (cacheHit.hit) {\n return cacheHit.value;\n }\n\n const result = originalMethod.apply(this, args);\n\n if (!returnObservable) {\n setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {\n timestamp: now,\n args: argsString,\n });\n return result;\n }\n\n const inflight$ = createCachedObservable(\n result as Observable<unknown>,\n store,\n storeKey,\n cacheContext.runtimeCacheKey,\n argsString\n );\n\n setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {\n timestamp: now,\n args: argsString,\n inflight$,\n });\n\n return inflight$;\n };\n\n return descriptor;\n };\n}\n","import type { StoreEnum, KeyedResourceKey } from '@flurryx/core';\n\ntype StoreWithLoading<TKey extends StoreEnum> = {\n startLoading: (key: TKey) => void;\n};\n\nexport function Loading<TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: {\n store: StoreWithLoading<TKey>;\n }) => StoreWithLoading<TKey>\n): MethodDecorator;\nexport function Loading<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithLoading<TKey>\n): MethodDecorator;\nexport function Loading<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithLoading<TKey>\n) {\n return function (\n _target: unknown,\n _propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ) {\n const originalMethod = descriptor.value as (\n this: unknown,\n ...args: unknown[]\n ) => unknown;\n\n descriptor.value = function (this: TTarget, ...args: unknown[]) {\n const store = storeGetter(this);\n\n const resourceKey = args[0];\n const canKey =\n typeof resourceKey === 'string' || typeof resourceKey === 'number';\n const hasKeyed =\n typeof store === 'object' &&\n store !== null &&\n 'startKeyedLoading' in store &&\n typeof (store as { startKeyedLoading?: unknown }).startKeyedLoading ===\n 'function';\n\n if (canKey && hasKeyed) {\n (\n store as unknown as {\n startKeyedLoading: (\n key: TKey,\n resourceKey: KeyedResourceKey\n ) => void;\n }\n ).startKeyedLoading(storeKey, resourceKey as KeyedResourceKey);\n } else {\n store?.startLoading(storeKey);\n }\n return originalMethod.apply(this, args);\n };\n\n return descriptor;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAAgD;;;ACIzC,SAAS,uBAAuB,OAAgC;AACrE,MACE,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,OAAQ,MAAkC,UAAU,UACpD;AACA,UAAM,QAAS,MAA6C;AAC5D,QAAI,SAAS,MAAM,QAAQ,MAAM,MAAM,GAAG;AACxC,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,MACE,OAAO,UAAU,YACjB,UAAU,QACV,YAAY,SACZ,aAAa,OACb;AACA,UAAM,QAAQ;AACd,WAAO;AAAA,MACL;AAAA,QACE,MAAM,OAAO,MAAM,MAAM;AAAA,QACzB,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS,OAAO,KAAK;AAAA,IACvB;AAAA,EACF;AACF;;;ADjCO,SAAS,YAId,OACA,KACA,UAA8B,EAAE,yBAAyB,KAAK,GAC9D;AACA,QAAM,iBAAiB,QAAQ,mBAAmB;AAElD,SAAO,CAAI,WAA0B;AACnC,QAAI,WAAW,OAAO;AAAA,UACpB,iBAAI;AAAA,QACF,MAAM,CAAC,SAAY;AACjB,gBAAM,OAAO,KAAK;AAAA,YAChB;AAAA,YACA,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,QAAQ;AAAA,UACV,CAA+B;AAAA,QACjC;AAAA,QACA,OAAO,CAAC,UAAmB;AACzB,gBAAM,OAAO,KAAK;AAAA,YAChB,MAAM;AAAA,YACN,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,QAAQ,eAAe,KAAK;AAAA,UAC9B,CAA+B;AAAA,QACjC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,QAAQ,yBAAyB;AACnC,iBAAW,SAAS,SAAK,kBAAK,CAAC,CAAC;AAAA,IAClC;AAEA,QAAI,QAAQ,uBAAuB;AACjC,iBAAW,SAAS,SAAK,sBAAS,QAAQ,qBAAqB,CAAC;AAAA,IAClE;AAEA,WAAO;AAAA,EACT;AACF;;;AExDA,IAAAA,eAAgD;AAEhD,kBAQO;AAYP,SAAS,WACP,QACA,KAC+B;AAC/B,QAAM,OAAsC;AAAA,IAC1C,GAAG;AAAA,EACL;AACA,SAAO,KAAK,GAAG;AACf,SAAO;AACT;AAEO,SAAS,iBAed,OACA,UACA,aACA,UAA8C;AAAA,EAC5C,yBAAyB;AAC3B,GACA;AACA,QAAM,EAAE,yBAAyB,uBAAuB,YAAY,IAClE;AACF,QAAM,iBAAiB,QAAQ,mBAAmB;AAElD,SAAO,CAAC,WAA0B;AAChC,QAAI,WAAW,OAAO;AAAA,UACpB,kBAAI;AAAA,QACF,MAAM,CAAC,aAAgB;AACrB,gBAAM,QAAQ,cACV,YAAY,QAAQ,IACnB;AAEL,gBAAM,cAAc,MAAM,IAAI,QAAQ;AACtC,gBAAM,QAAQ,YAAY;AAC1B,gBAAM,OAAO,MAAM,YAAQ,qCAAsC;AAEjE,gBAAM,gBAAgB;AAAA,YACpB,GAAG,KAAK;AAAA,YACR,CAAC,WAAW,GAAG;AAAA,UACjB;AAEA,gBAAM,aAAoD;AAAA,YACxD,GAAG,KAAK;AAAA,YACR,CAAC,WAAW,GAAG;AAAA,UACjB;AAEA,gBAAM,WAA4C;AAAA,YAChD,GAAG;AAAA,YACH,UAAU;AAAA,cACR,GAAG,KAAK;AAAA,cACR,CAAC,WAAW,GAAG;AAAA,YACjB;AAAA,YACA,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,QAAQ,WAAW,KAAK,QAAQ,WAAW;AAAA,UAC7C;AAEA,gBAAM,OAAO,UAAU;AAAA,YACrB,MAAM;AAAA,YACN,eAAW,6BAAgB,aAAa;AAAA,YACxC,QAAQ;AAAA,YACR,QAAQ;AAAA,UACV,CAAoC;AAAA,QACtC;AAAA,QACA,OAAO,CAAC,UAAmB;AACzB,gBAAM,cAAc,MAAM,IAAI,QAAQ;AACtC,gBAAM,QAAQ,YAAY;AAC1B,gBAAM,OAAO,MAAM,YAAQ,qCAAsC;AAEjE,gBAAM,gBAAgB;AAAA,YACpB,GAAG,KAAK;AAAA,YACR,CAAC,WAAW,GAAG;AAAA,UACjB;AAEA,gBAAM,aAAoD;AAAA,YACxD,GAAG,KAAK;AAAA,YACR,CAAC,WAAW,GAAG;AAAA,UACjB;AAEA,gBAAM,aAAoD;AAAA,YACxD,GAAG,KAAK;AAAA,YACR,CAAC,WAAW,GAAG,eAAe,KAAK;AAAA,UACrC;AAEA,gBAAM,WAA4C;AAAA,YAChD,GAAG;AAAA,YACH,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,QAAQ;AAAA,UACV;AAEA,gBAAM,OAAO,UAAU;AAAA,YACrB,MAAM;AAAA,YACN,eAAW,6BAAgB,aAAa;AAAA,YACxC,QAAQ;AAAA,YACR,QAAQ;AAAA,UACV,CAAoC;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,yBAAyB;AAC3B,iBAAW,SAAS,SAAK,mBAAK,CAAC,CAAC;AAAA,IAClC;AAEA,QAAI,uBAAuB;AACzB,iBAAW,SAAS,SAAK,uBAAS,qBAAqB,CAAC;AAAA,IAC1D;AAEA,WAAO;AAAA,EACT;AACF;;;ACjJA,IAAAC,eAA2D;AAE3D,IAAAC,eAAoC;AACpC,IAAAA,eAAuD;AAYvD,IAAM,aAAa,oBAAI,QAGrB;AAEF,SAAS,eACP,OACA,KACyB;AACzB,MAAI,WAAW,WAAW,IAAI,KAAK;AACnC,MAAI,CAAC,UAAU;AACb,eAAW,oBAAI,IAAI;AACnB,eAAW,IAAI,OAAO,QAAQ;AAAA,EAChC;AAEA,MAAI,SAAS,SAAS,IAAI,GAAG;AAC7B,MAAI,CAAC,QAAQ;AACX,aAAS,oBAAI,IAAI;AACjB,aAAS,IAAI,KAAK,MAAM;AAAA,EAC1B;AAEA,SAAO;AACT;AAEA,SAAS,cACP,OACA,KACA,UACwB;AACxB,SAAO,eAAe,OAAO,GAAG,EAAE,IAAI,QAAQ;AAChD;AAEA,SAAS,cACP,OACA,KACA,UACA,OACM;AACN,iBAAe,OAAO,GAAG,EAAE,IAAI,UAAU,KAAK;AAChD;AAEA,SAAS,gBACP,OACA,KACA,UACM;AACN,iBAAe,OAAO,GAAG,EAAE,OAAO,QAAQ;AAC5C;AAEA,SAAS,kBAAkB,MAA+C;AACxE,QAAM,MAAM,KAAK,CAAC;AAClB,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU;AACtD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,UACP,WACA,WACA,KACS;AACT,MAAI,cAAc,+BAAkB;AAClC,WAAO;AAAA,EACT;AACA,MAAI,cAAc,QAAW;AAC3B,WAAO;AAAA,EACT;AACA,SAAO,MAAM,aAAa;AAC5B;AAQA,SAAS,gBACP,UACA,UACA,UAC0B;AAC1B,QAAM,QAAQ,SAAS,QAAQ;AAC/B,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,MAAM,IAAI,QAAQ;AACtC,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,YAAY;AACjC,MAAI,iBAAiB,QAAQ,iBAAiB,QAAW;AACvD,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,OAAO,aAAa,aAAa;AAC5C;AAaA,SAAS,gBACP,OACA,UACA,MACA,YACA,cACc;AACd,QAAM,gBAAY,kCAAoB,aAAa,IAAI,IACnD,aAAa,OACb;AACJ,QAAM,cAAc,YAAY,kBAAkB,IAAI,IAAI;AAC1D,QAAM,cAAc,cAAc,UAAa,gBAAgB;AAE/D,QAAM,gBAAgB;AACtB,QAAM,mBAAmB;AACzB,QAAM,kBAAkB,cAAc,gBAAgB;AAEtD,QAAM,kBAAkB,cAAc,OAAO,UAAU,aAAa;AACpE,QAAM,qBAAqB,cAAc,OAAO,UAAU,gBAAgB;AAE1E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,kBACP,OACA,UACA,SACA,cACM;AACN,MAAI,CAAC,QAAQ,aAAa,aAAa,WAAW,SAAS;AACzD,oBAAgB,OAAO,UAAU,YAAY;AAAA,EAC/C;AACA,MAAI,QAAQ,aAAa,QAAQ,gBAAgB,QAAW;AAC1D,UAAM,SACJ,QAAQ,UAGR,OAAO,QAAQ,WAAW;AAC5B,QAAI,WAAW,SAAS;AACtB,sBAAgB,OAAO,UAAU,QAAQ,eAAe;AAAA,IAC1D;AAAA,EACF;AACF;AAOA,SAAS,iBACP,OACA,UACA,SACA,WACA,KACA,kBACgB;AAChB,QAAM,EAAE,WAAW,aAAa,iBAAiB,gBAAgB,IAAI;AAErE,MAAI,CAAC,aAAa,gBAAgB,QAAW;AAC3C,WAAO,EAAE,KAAK,MAAM;AAAA,EACtB;AAEA,QAAM,QAAQ;AAMd,QAAM,SAAS,MAAM,OAAO,WAAW;AACvC,QAAM,SAAS,MAAM,SAAS,WAAW;AACzC,QAAM,UAAU,MAAM,UAAU,WAAW,MAAM;AAEjD,QAAM,UAAU,UAAU,iBAAiB,WAAW,WAAW,GAAG;AACpE,MAAI,SAAS;AACX,oBAAgB,OAAO,UAAU,eAAe;AAAA,EAClD;AAEA,MAAI,CAAC,WAAW,WAAW,aAAa,WAAW,QAAW;AAC5D,QAAI,kBAAkB;AACpB,aAAO,EAAE,KAAK,MAAM,WAAO,iBAAG,MAAM,EAAE;AAAA,IACxC;AACA,WAAO,EAAE,KAAK,KAAK;AAAA,EACrB;AAEA,MAAI,kBAAkB;AACpB,QAAI,iBAAiB,WAAW;AAC9B,aAAO,EAAE,KAAK,MAAM,OAAO,gBAAgB,UAAU;AAAA,IACvD;AAAA,EACF,WAAW,SAAS;AAClB,WAAO,EAAE,KAAK,KAAK;AAAA,EACrB;AAEA,SAAO,EAAE,KAAK,MAAM;AACtB;AAEA,SAAS,oBACP,OACA,UACA,SACA,WACA,KACA,kBACA,cACA,YACA,aACgB;AAChB,QAAM,EAAE,oBAAoB,gBAAgB,IAAI;AAEhD,MACE,oBACA,oBAAoB,SAAS,cAC7B,mBAAmB,WACnB;AACA,WAAO,EAAE,KAAK,MAAM,OAAO,mBAAmB,UAAU;AAAA,EAC1D;AAEA,QAAM,qBACJ,cAAc,WAAW,aAAa,cAAc,cAAc;AAEpE,MACE,sBACA,UAAU,mBAAmB,WAAW,WAAW,GAAG,GACtD;AACA,oBAAgB,OAAO,UAAU,eAAe;AAAA,EAClD,WAAW,oBAAoB,SAAS,cAAc,oBAAoB;AACxE,QAAI,kBAAkB;AACpB,UAAI,mBAAmB,WAAW;AAChC,eAAO,EAAE,KAAK,MAAM,OAAO,mBAAmB,UAAU;AAAA,MAC1D;AACA,aAAO,EAAE,KAAK,MAAM,WAAO,iBAAG,YAAY,EAAE,IAAI,EAAE;AAAA,IACpD;AACA,WAAO,EAAE,KAAK,KAAK;AAAA,EACrB;AAEA,SAAO,EAAE,KAAK,MAAM;AACtB;AAEA,SAAS,uBACP,QACA,OACA,UACA,iBACA,YACqB;AACrB,SAAO,OAAO;AAAA,QACZ,kBAAI;AAAA,MACF,MAAM,MAAM;AACV,sBAAc,OAAO,UAAU,iBAAiB;AAAA,UAC9C,WAAW,KAAK,IAAI;AAAA,UACpB,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,MACA,OAAO,MAAM;AACX,wBAAgB,OAAO,UAAU,eAAe;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,QACD,uBAAS,MAAM;AACb,YAAM,QAAQ,cAAc,OAAO,UAAU,eAAe;AAC5D,UAAI,OAAO,WAAW;AACpB,cAAM,EAAE,WAAW,YAAY,GAAG,KAAK,IAAI;AAC3C,sBAAc,OAAO,UAAU,iBAAiB,IAAI;AAAA,MACtD;AAAA,IACF,CAAC;AAAA,QACD,0BAAY,EAAE,YAAY,GAAG,UAAU,KAAK,CAAC;AAAA,EAC/C;AACF;AAgBO,SAAS,aACd,UACA,aACA,mBAAmB,OACnB,YAAY,mCACK;AACjB,SAAO,SACL,SACA,cACA,YACA;AACA,UAAM,iBAAiB,WAAW;AAKlC,eAAW,QAAQ,YAA4B,MAAiB;AAC9D,YAAM,eAAe,gBAAgB,MAAM,UAAU,WAAW;AAChE,UAAI,CAAC,cAAc;AACjB,eAAO,eAAe,MAAM,MAAM,IAAI;AAAA,MACxC;AACA,YAAM,EAAE,OAAO,aAAa,aAAa,IAAI;AAE7C,YAAM,aAAa,KAAK,UAAU,IAAI;AACtC,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,wBAAkB,OAAO,UAAU,cAAc,YAAY;AAE7D,UAAI;AAEJ,UAAI,aAAa,aAAa;AAC5B,mBAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF,OAAO;AACL,mBAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,UAAI,SAAS,KAAK;AAChB,eAAO,SAAS;AAAA,MAClB;AAEA,YAAM,SAAS,eAAe,MAAM,MAAM,IAAI;AAE9C,UAAI,CAAC,kBAAkB;AACrB,sBAAc,OAAO,UAAU,aAAa,iBAAiB;AAAA,UAC3D,WAAW;AAAA,UACX,MAAM;AAAA,QACR,CAAC;AACD,eAAO;AAAA,MACT;AAEA,YAAM,YAAY;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa;AAAA,QACb;AAAA,MACF;AAEA,oBAAc,OAAO,UAAU,aAAa,iBAAiB;AAAA,QAC3D,WAAW;AAAA,QACX,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;;;ACzYO,SAAS,QACd,UACA,aACA;AACA,SAAO,SACL,SACA,cACA,YACA;AACA,UAAM,iBAAiB,WAAW;AAKlC,eAAW,QAAQ,YAA4B,MAAiB;AAC9D,YAAM,QAAQ,YAAY,IAAI;AAE9B,YAAM,cAAc,KAAK,CAAC;AAC1B,YAAM,SACJ,OAAO,gBAAgB,YAAY,OAAO,gBAAgB;AAC5D,YAAM,WACJ,OAAO,UAAU,YACjB,UAAU,QACV,uBAAuB,SACvB,OAAQ,MAA0C,sBAChD;AAEJ,UAAI,UAAU,UAAU;AACtB,QACE,MAMA,kBAAkB,UAAU,WAA+B;AAAA,MAC/D,OAAO;AACL,eAAO,aAAa,QAAQ;AAAA,MAC9B;AACA,aAAO,eAAe,MAAM,MAAM,IAAI;AAAA,IACxC;AAEA,WAAO;AAAA,EACT;AACF;","names":["import_rxjs","import_rxjs","import_core"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { BaseStore } from '@flurryx/store';
|
|
3
|
+
import { ResourceState, KeyedResourceKey, KeyedResourceData, StoreEnum } from '@flurryx/core';
|
|
4
|
+
import { E as ErrorNormalizer } from './error-normalizer-DZz8HS0o.cjs';
|
|
5
|
+
export { d as defaultErrorNormalizer } from './error-normalizer-DZz8HS0o.cjs';
|
|
6
|
+
import { WritableSignal } from '@angular/core';
|
|
7
|
+
|
|
8
|
+
interface SyncToStoreOptions {
|
|
9
|
+
completeOnFirstEmission?: boolean;
|
|
10
|
+
callbackAfterComplete?: () => void;
|
|
11
|
+
errorNormalizer?: ErrorNormalizer;
|
|
12
|
+
}
|
|
13
|
+
declare function syncToStore<TEnum extends Record<string, string | number>, TData extends {
|
|
14
|
+
[K in keyof TEnum]: ResourceState<unknown>;
|
|
15
|
+
}>(store: BaseStore<TEnum, TData>, key: keyof TEnum, options?: SyncToStoreOptions): <R>(source: Observable<R>) => Observable<R>;
|
|
16
|
+
|
|
17
|
+
interface SyncToKeyedStoreOptions<R, TValue> extends SyncToStoreOptions {
|
|
18
|
+
mapResponse?: (response: R) => TValue;
|
|
19
|
+
errorNormalizer?: ErrorNormalizer;
|
|
20
|
+
}
|
|
21
|
+
declare function syncToKeyedStore<TEnum extends Record<string, string | number>, TStoreKey extends keyof TEnum, TKey extends KeyedResourceKey, TValue, R = TValue, TState extends ResourceState<KeyedResourceData<TKey, TValue>> = ResourceState<KeyedResourceData<TKey, TValue>>, TData extends {
|
|
22
|
+
[K in keyof TEnum]: ResourceState<unknown>;
|
|
23
|
+
} & {
|
|
24
|
+
[K in TStoreKey]: TState;
|
|
25
|
+
} = {
|
|
26
|
+
[K in keyof TEnum]: ResourceState<unknown>;
|
|
27
|
+
} & {
|
|
28
|
+
[K in TStoreKey]: TState;
|
|
29
|
+
}>(store: BaseStore<TEnum, TData>, storeKey: TStoreKey, resourceKey: TKey, options?: SyncToKeyedStoreOptions<R, TValue>): (source: Observable<R>) => Observable<R>;
|
|
30
|
+
|
|
31
|
+
type StoreWithSignal<TKey extends StoreEnum> = {
|
|
32
|
+
get: (key: TKey) => WritableSignal<ResourceState<unknown>> | undefined;
|
|
33
|
+
};
|
|
34
|
+
declare function SkipIfCached<TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: {
|
|
35
|
+
store: StoreWithSignal<TKey>;
|
|
36
|
+
}) => StoreWithSignal<TKey> | undefined, returnObservable?: boolean, timeoutMs?: number): MethodDecorator;
|
|
37
|
+
declare function SkipIfCached<TTarget, TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: TTarget) => StoreWithSignal<TKey> | undefined, returnObservable?: boolean, timeoutMs?: number): MethodDecorator;
|
|
38
|
+
|
|
39
|
+
type StoreWithLoading<TKey extends StoreEnum> = {
|
|
40
|
+
startLoading: (key: TKey) => void;
|
|
41
|
+
};
|
|
42
|
+
declare function Loading<TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: {
|
|
43
|
+
store: StoreWithLoading<TKey>;
|
|
44
|
+
}) => StoreWithLoading<TKey>): MethodDecorator;
|
|
45
|
+
declare function Loading<TTarget, TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: TTarget) => StoreWithLoading<TKey>): MethodDecorator;
|
|
46
|
+
|
|
47
|
+
export { ErrorNormalizer, Loading, SkipIfCached, type SyncToKeyedStoreOptions, type SyncToStoreOptions, syncToKeyedStore, syncToStore };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { BaseStore } from '@flurryx/store';
|
|
3
|
+
import { ResourceState, KeyedResourceKey, KeyedResourceData, StoreEnum } from '@flurryx/core';
|
|
4
|
+
import { E as ErrorNormalizer } from './error-normalizer-DZz8HS0o.js';
|
|
5
|
+
export { d as defaultErrorNormalizer } from './error-normalizer-DZz8HS0o.js';
|
|
6
|
+
import { WritableSignal } from '@angular/core';
|
|
7
|
+
|
|
8
|
+
interface SyncToStoreOptions {
|
|
9
|
+
completeOnFirstEmission?: boolean;
|
|
10
|
+
callbackAfterComplete?: () => void;
|
|
11
|
+
errorNormalizer?: ErrorNormalizer;
|
|
12
|
+
}
|
|
13
|
+
declare function syncToStore<TEnum extends Record<string, string | number>, TData extends {
|
|
14
|
+
[K in keyof TEnum]: ResourceState<unknown>;
|
|
15
|
+
}>(store: BaseStore<TEnum, TData>, key: keyof TEnum, options?: SyncToStoreOptions): <R>(source: Observable<R>) => Observable<R>;
|
|
16
|
+
|
|
17
|
+
interface SyncToKeyedStoreOptions<R, TValue> extends SyncToStoreOptions {
|
|
18
|
+
mapResponse?: (response: R) => TValue;
|
|
19
|
+
errorNormalizer?: ErrorNormalizer;
|
|
20
|
+
}
|
|
21
|
+
declare function syncToKeyedStore<TEnum extends Record<string, string | number>, TStoreKey extends keyof TEnum, TKey extends KeyedResourceKey, TValue, R = TValue, TState extends ResourceState<KeyedResourceData<TKey, TValue>> = ResourceState<KeyedResourceData<TKey, TValue>>, TData extends {
|
|
22
|
+
[K in keyof TEnum]: ResourceState<unknown>;
|
|
23
|
+
} & {
|
|
24
|
+
[K in TStoreKey]: TState;
|
|
25
|
+
} = {
|
|
26
|
+
[K in keyof TEnum]: ResourceState<unknown>;
|
|
27
|
+
} & {
|
|
28
|
+
[K in TStoreKey]: TState;
|
|
29
|
+
}>(store: BaseStore<TEnum, TData>, storeKey: TStoreKey, resourceKey: TKey, options?: SyncToKeyedStoreOptions<R, TValue>): (source: Observable<R>) => Observable<R>;
|
|
30
|
+
|
|
31
|
+
type StoreWithSignal<TKey extends StoreEnum> = {
|
|
32
|
+
get: (key: TKey) => WritableSignal<ResourceState<unknown>> | undefined;
|
|
33
|
+
};
|
|
34
|
+
declare function SkipIfCached<TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: {
|
|
35
|
+
store: StoreWithSignal<TKey>;
|
|
36
|
+
}) => StoreWithSignal<TKey> | undefined, returnObservable?: boolean, timeoutMs?: number): MethodDecorator;
|
|
37
|
+
declare function SkipIfCached<TTarget, TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: TTarget) => StoreWithSignal<TKey> | undefined, returnObservable?: boolean, timeoutMs?: number): MethodDecorator;
|
|
38
|
+
|
|
39
|
+
type StoreWithLoading<TKey extends StoreEnum> = {
|
|
40
|
+
startLoading: (key: TKey) => void;
|
|
41
|
+
};
|
|
42
|
+
declare function Loading<TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: {
|
|
43
|
+
store: StoreWithLoading<TKey>;
|
|
44
|
+
}) => StoreWithLoading<TKey>): MethodDecorator;
|
|
45
|
+
declare function Loading<TTarget, TKey extends StoreEnum>(storeKey: TKey, storeGetter: (instance: TTarget) => StoreWithLoading<TKey>): MethodDecorator;
|
|
46
|
+
|
|
47
|
+
export { ErrorNormalizer, Loading, SkipIfCached, type SyncToKeyedStoreOptions, type SyncToStoreOptions, syncToKeyedStore, syncToStore };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
// src/operators/sync-to-store.ts
|
|
2
|
+
import { finalize, take, tap } from "rxjs";
|
|
3
|
+
|
|
4
|
+
// src/error/error-normalizer.ts
|
|
5
|
+
function defaultErrorNormalizer(error) {
|
|
6
|
+
if (typeof error === "object" && error !== null && "error" in error && typeof error.error === "object") {
|
|
7
|
+
const inner = error.error;
|
|
8
|
+
if (inner && Array.isArray(inner.errors)) {
|
|
9
|
+
return inner.errors;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
if (typeof error === "object" && error !== null && "status" in error && "message" in error) {
|
|
13
|
+
const typed = error;
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
code: String(typed.status),
|
|
17
|
+
message: typed.message
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
code: "UNKNOWN",
|
|
25
|
+
message: error.message
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
code: "UNKNOWN",
|
|
32
|
+
message: String(error)
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/operators/sync-to-store.ts
|
|
38
|
+
function syncToStore(store, key, options = { completeOnFirstEmission: true }) {
|
|
39
|
+
const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;
|
|
40
|
+
return (source) => {
|
|
41
|
+
let pipeline = source.pipe(
|
|
42
|
+
tap({
|
|
43
|
+
next: (data) => {
|
|
44
|
+
store.update(key, {
|
|
45
|
+
data,
|
|
46
|
+
isLoading: false,
|
|
47
|
+
status: "Success",
|
|
48
|
+
errors: void 0
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
error: (error) => {
|
|
52
|
+
store.update(key, {
|
|
53
|
+
data: void 0,
|
|
54
|
+
isLoading: false,
|
|
55
|
+
status: "Error",
|
|
56
|
+
errors: normalizeError(error)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
if (options.completeOnFirstEmission) {
|
|
62
|
+
pipeline = pipeline.pipe(take(1));
|
|
63
|
+
}
|
|
64
|
+
if (options.callbackAfterComplete) {
|
|
65
|
+
pipeline = pipeline.pipe(finalize(options.callbackAfterComplete));
|
|
66
|
+
}
|
|
67
|
+
return pipeline;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/operators/sync-to-keyed-store.ts
|
|
72
|
+
import { finalize as finalize2, take as take2, tap as tap2 } from "rxjs";
|
|
73
|
+
import {
|
|
74
|
+
createKeyedResourceData,
|
|
75
|
+
isAnyKeyLoading
|
|
76
|
+
} from "@flurryx/core";
|
|
77
|
+
function withoutKey(record, key) {
|
|
78
|
+
const next = {
|
|
79
|
+
...record
|
|
80
|
+
};
|
|
81
|
+
delete next[key];
|
|
82
|
+
return next;
|
|
83
|
+
}
|
|
84
|
+
function syncToKeyedStore(store, storeKey, resourceKey, options = {
|
|
85
|
+
completeOnFirstEmission: true
|
|
86
|
+
}) {
|
|
87
|
+
const { completeOnFirstEmission, callbackAfterComplete, mapResponse } = options;
|
|
88
|
+
const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;
|
|
89
|
+
return (source) => {
|
|
90
|
+
let pipeline = source.pipe(
|
|
91
|
+
tap2({
|
|
92
|
+
next: (response) => {
|
|
93
|
+
const value = mapResponse ? mapResponse(response) : response;
|
|
94
|
+
const storeSignal = store.get(storeKey);
|
|
95
|
+
const state = storeSignal();
|
|
96
|
+
const data = state.data ?? createKeyedResourceData();
|
|
97
|
+
const nextIsLoading = {
|
|
98
|
+
...data.isLoading,
|
|
99
|
+
[resourceKey]: false
|
|
100
|
+
};
|
|
101
|
+
const nextStatus = {
|
|
102
|
+
...data.status,
|
|
103
|
+
[resourceKey]: "Success"
|
|
104
|
+
};
|
|
105
|
+
const nextData = {
|
|
106
|
+
...data,
|
|
107
|
+
entities: {
|
|
108
|
+
...data.entities,
|
|
109
|
+
[resourceKey]: value
|
|
110
|
+
},
|
|
111
|
+
isLoading: nextIsLoading,
|
|
112
|
+
status: nextStatus,
|
|
113
|
+
errors: withoutKey(data.errors, resourceKey)
|
|
114
|
+
};
|
|
115
|
+
store.update(storeKey, {
|
|
116
|
+
data: nextData,
|
|
117
|
+
isLoading: isAnyKeyLoading(nextIsLoading),
|
|
118
|
+
status: void 0,
|
|
119
|
+
errors: void 0
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
error: (error) => {
|
|
123
|
+
const storeSignal = store.get(storeKey);
|
|
124
|
+
const state = storeSignal();
|
|
125
|
+
const data = state.data ?? createKeyedResourceData();
|
|
126
|
+
const nextIsLoading = {
|
|
127
|
+
...data.isLoading,
|
|
128
|
+
[resourceKey]: false
|
|
129
|
+
};
|
|
130
|
+
const nextStatus = {
|
|
131
|
+
...data.status,
|
|
132
|
+
[resourceKey]: "Error"
|
|
133
|
+
};
|
|
134
|
+
const nextErrors = {
|
|
135
|
+
...data.errors,
|
|
136
|
+
[resourceKey]: normalizeError(error)
|
|
137
|
+
};
|
|
138
|
+
const nextData = {
|
|
139
|
+
...data,
|
|
140
|
+
isLoading: nextIsLoading,
|
|
141
|
+
status: nextStatus,
|
|
142
|
+
errors: nextErrors
|
|
143
|
+
};
|
|
144
|
+
store.update(storeKey, {
|
|
145
|
+
data: nextData,
|
|
146
|
+
isLoading: isAnyKeyLoading(nextIsLoading),
|
|
147
|
+
status: void 0,
|
|
148
|
+
errors: void 0
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
if (completeOnFirstEmission) {
|
|
154
|
+
pipeline = pipeline.pipe(take2(1));
|
|
155
|
+
}
|
|
156
|
+
if (callbackAfterComplete) {
|
|
157
|
+
pipeline = pipeline.pipe(finalize2(callbackAfterComplete));
|
|
158
|
+
}
|
|
159
|
+
return pipeline;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/decorators/skip-if-cached.ts
|
|
164
|
+
import { finalize as finalize3, of, shareReplay, tap as tap3 } from "rxjs";
|
|
165
|
+
import { isKeyedResourceData } from "@flurryx/core";
|
|
166
|
+
import { CACHE_NO_TIMEOUT, DEFAULT_CACHE_TTL_MS } from "@flurryx/core";
|
|
167
|
+
var cacheState = /* @__PURE__ */ new WeakMap();
|
|
168
|
+
function getStoreKeyMap(store, key) {
|
|
169
|
+
let storeMap = cacheState.get(store);
|
|
170
|
+
if (!storeMap) {
|
|
171
|
+
storeMap = /* @__PURE__ */ new Map();
|
|
172
|
+
cacheState.set(store, storeMap);
|
|
173
|
+
}
|
|
174
|
+
let keyMap = storeMap.get(key);
|
|
175
|
+
if (!keyMap) {
|
|
176
|
+
keyMap = /* @__PURE__ */ new Map();
|
|
177
|
+
storeMap.set(key, keyMap);
|
|
178
|
+
}
|
|
179
|
+
return keyMap;
|
|
180
|
+
}
|
|
181
|
+
function getCacheEntry(store, key, cacheKey) {
|
|
182
|
+
return getStoreKeyMap(store, key).get(cacheKey);
|
|
183
|
+
}
|
|
184
|
+
function setCacheEntry(store, key, cacheKey, entry) {
|
|
185
|
+
getStoreKeyMap(store, key).set(cacheKey, entry);
|
|
186
|
+
}
|
|
187
|
+
function clearCacheEntry(store, key, cacheKey) {
|
|
188
|
+
getStoreKeyMap(store, key).delete(cacheKey);
|
|
189
|
+
}
|
|
190
|
+
function deriveResourceKey(args) {
|
|
191
|
+
const key = args[0];
|
|
192
|
+
if (typeof key === "string" || typeof key === "number") {
|
|
193
|
+
return key;
|
|
194
|
+
}
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
function isExpired(timestamp, timeoutMs, now) {
|
|
198
|
+
if (timeoutMs === CACHE_NO_TIMEOUT) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
if (timestamp === void 0) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return now - timestamp >= timeoutMs;
|
|
205
|
+
}
|
|
206
|
+
function getStoreContext(instance, storeKey, getStore) {
|
|
207
|
+
const store = getStore(instance);
|
|
208
|
+
if (!store) {
|
|
209
|
+
return void 0;
|
|
210
|
+
}
|
|
211
|
+
const storeSignal = store.get(storeKey);
|
|
212
|
+
if (!storeSignal) {
|
|
213
|
+
return void 0;
|
|
214
|
+
}
|
|
215
|
+
const currentState = storeSignal();
|
|
216
|
+
if (currentState === null || currentState === void 0) {
|
|
217
|
+
return void 0;
|
|
218
|
+
}
|
|
219
|
+
return { store, storeSignal, currentState };
|
|
220
|
+
}
|
|
221
|
+
function getCacheContext(store, storeKey, args, argsString, currentState) {
|
|
222
|
+
const keyedData = isKeyedResourceData(currentState.data) ? currentState.data : void 0;
|
|
223
|
+
const resourceKey = keyedData ? deriveResourceKey(args) : void 0;
|
|
224
|
+
const isKeyedCall = keyedData !== void 0 && resourceKey !== void 0;
|
|
225
|
+
const keyedCacheKey = argsString;
|
|
226
|
+
const nonKeyedCacheKey = "__single__";
|
|
227
|
+
const runtimeCacheKey = isKeyedCall ? keyedCacheKey : nonKeyedCacheKey;
|
|
228
|
+
const keyedCacheEntry = getCacheEntry(store, storeKey, keyedCacheKey);
|
|
229
|
+
const nonKeyedCacheEntry = getCacheEntry(store, storeKey, nonKeyedCacheKey);
|
|
230
|
+
return {
|
|
231
|
+
isKeyedCall,
|
|
232
|
+
resourceKey,
|
|
233
|
+
keyedData,
|
|
234
|
+
runtimeCacheKey,
|
|
235
|
+
keyedCacheEntry,
|
|
236
|
+
nonKeyedCacheEntry
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function handleCacheErrors(store, storeKey, context, currentState) {
|
|
240
|
+
if (!context.keyedData && currentState.status === "Error") {
|
|
241
|
+
clearCacheEntry(store, storeKey, "__single__");
|
|
242
|
+
}
|
|
243
|
+
if (context.keyedData && context.resourceKey !== void 0) {
|
|
244
|
+
const status = context.keyedData.status[context.resourceKey];
|
|
245
|
+
if (status === "Error") {
|
|
246
|
+
clearCacheEntry(store, storeKey, context.runtimeCacheKey);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function handleKeyedCache(store, storeKey, context, timeoutMs, now, returnObservable) {
|
|
251
|
+
const { keyedData, resourceKey, keyedCacheEntry, runtimeCacheKey } = context;
|
|
252
|
+
if (!keyedData || resourceKey === void 0) {
|
|
253
|
+
return { hit: false };
|
|
254
|
+
}
|
|
255
|
+
const typed = keyedData;
|
|
256
|
+
const status = typed.status[resourceKey];
|
|
257
|
+
const entity = typed.entities[resourceKey];
|
|
258
|
+
const loading = typed.isLoading[resourceKey] === true;
|
|
259
|
+
const expired = isExpired(keyedCacheEntry?.timestamp, timeoutMs, now);
|
|
260
|
+
if (expired) {
|
|
261
|
+
clearCacheEntry(store, storeKey, runtimeCacheKey);
|
|
262
|
+
}
|
|
263
|
+
if (!expired && status === "Success" && entity !== void 0) {
|
|
264
|
+
if (returnObservable) {
|
|
265
|
+
return { hit: true, value: of(entity) };
|
|
266
|
+
}
|
|
267
|
+
return { hit: true };
|
|
268
|
+
}
|
|
269
|
+
if (returnObservable) {
|
|
270
|
+
if (keyedCacheEntry?.inflight$) {
|
|
271
|
+
return { hit: true, value: keyedCacheEntry.inflight$ };
|
|
272
|
+
}
|
|
273
|
+
} else if (loading) {
|
|
274
|
+
return { hit: true };
|
|
275
|
+
}
|
|
276
|
+
return { hit: false };
|
|
277
|
+
}
|
|
278
|
+
function handleNonKeyedCache(store, storeKey, context, timeoutMs, now, returnObservable, currentState, argsString, storeSignal) {
|
|
279
|
+
const { nonKeyedCacheEntry, runtimeCacheKey } = context;
|
|
280
|
+
if (returnObservable && nonKeyedCacheEntry?.args === argsString && nonKeyedCacheEntry.inflight$) {
|
|
281
|
+
return { hit: true, value: nonKeyedCacheEntry.inflight$ };
|
|
282
|
+
}
|
|
283
|
+
const hasValidCacheState = currentState?.status === "Success" || currentState?.isLoading === true;
|
|
284
|
+
if (nonKeyedCacheEntry && isExpired(nonKeyedCacheEntry.timestamp, timeoutMs, now)) {
|
|
285
|
+
clearCacheEntry(store, storeKey, runtimeCacheKey);
|
|
286
|
+
} else if (nonKeyedCacheEntry?.args === argsString && hasValidCacheState) {
|
|
287
|
+
if (returnObservable) {
|
|
288
|
+
if (nonKeyedCacheEntry.inflight$) {
|
|
289
|
+
return { hit: true, value: nonKeyedCacheEntry.inflight$ };
|
|
290
|
+
}
|
|
291
|
+
return { hit: true, value: of(storeSignal().data) };
|
|
292
|
+
}
|
|
293
|
+
return { hit: true };
|
|
294
|
+
}
|
|
295
|
+
return { hit: false };
|
|
296
|
+
}
|
|
297
|
+
function createCachedObservable(result, store, storeKey, runtimeCacheKey, argsString) {
|
|
298
|
+
return result.pipe(
|
|
299
|
+
tap3({
|
|
300
|
+
next: () => {
|
|
301
|
+
setCacheEntry(store, storeKey, runtimeCacheKey, {
|
|
302
|
+
timestamp: Date.now(),
|
|
303
|
+
args: argsString
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
error: () => {
|
|
307
|
+
clearCacheEntry(store, storeKey, runtimeCacheKey);
|
|
308
|
+
}
|
|
309
|
+
}),
|
|
310
|
+
finalize3(() => {
|
|
311
|
+
const entry = getCacheEntry(store, storeKey, runtimeCacheKey);
|
|
312
|
+
if (entry?.inflight$) {
|
|
313
|
+
const { inflight$: _inflight$, ...rest } = entry;
|
|
314
|
+
setCacheEntry(store, storeKey, runtimeCacheKey, rest);
|
|
315
|
+
}
|
|
316
|
+
}),
|
|
317
|
+
shareReplay({ bufferSize: 1, refCount: true })
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
function SkipIfCached(storeKey, storeGetter, returnObservable = false, timeoutMs = DEFAULT_CACHE_TTL_MS) {
|
|
321
|
+
return function(_target, _propertyKey, descriptor) {
|
|
322
|
+
const originalMethod = descriptor.value;
|
|
323
|
+
descriptor.value = function(...args) {
|
|
324
|
+
const storeContext = getStoreContext(this, storeKey, storeGetter);
|
|
325
|
+
if (!storeContext) {
|
|
326
|
+
return originalMethod.apply(this, args);
|
|
327
|
+
}
|
|
328
|
+
const { store, storeSignal, currentState } = storeContext;
|
|
329
|
+
const argsString = JSON.stringify(args);
|
|
330
|
+
const now = Date.now();
|
|
331
|
+
const cacheContext = getCacheContext(
|
|
332
|
+
store,
|
|
333
|
+
storeKey,
|
|
334
|
+
args,
|
|
335
|
+
argsString,
|
|
336
|
+
currentState
|
|
337
|
+
);
|
|
338
|
+
handleCacheErrors(store, storeKey, cacheContext, currentState);
|
|
339
|
+
let cacheHit;
|
|
340
|
+
if (cacheContext.isKeyedCall) {
|
|
341
|
+
cacheHit = handleKeyedCache(
|
|
342
|
+
store,
|
|
343
|
+
storeKey,
|
|
344
|
+
cacheContext,
|
|
345
|
+
timeoutMs,
|
|
346
|
+
now,
|
|
347
|
+
returnObservable
|
|
348
|
+
);
|
|
349
|
+
} else {
|
|
350
|
+
cacheHit = handleNonKeyedCache(
|
|
351
|
+
store,
|
|
352
|
+
storeKey,
|
|
353
|
+
cacheContext,
|
|
354
|
+
timeoutMs,
|
|
355
|
+
now,
|
|
356
|
+
returnObservable,
|
|
357
|
+
currentState,
|
|
358
|
+
argsString,
|
|
359
|
+
storeSignal
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
if (cacheHit.hit) {
|
|
363
|
+
return cacheHit.value;
|
|
364
|
+
}
|
|
365
|
+
const result = originalMethod.apply(this, args);
|
|
366
|
+
if (!returnObservable) {
|
|
367
|
+
setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {
|
|
368
|
+
timestamp: now,
|
|
369
|
+
args: argsString
|
|
370
|
+
});
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
const inflight$ = createCachedObservable(
|
|
374
|
+
result,
|
|
375
|
+
store,
|
|
376
|
+
storeKey,
|
|
377
|
+
cacheContext.runtimeCacheKey,
|
|
378
|
+
argsString
|
|
379
|
+
);
|
|
380
|
+
setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {
|
|
381
|
+
timestamp: now,
|
|
382
|
+
args: argsString,
|
|
383
|
+
inflight$
|
|
384
|
+
});
|
|
385
|
+
return inflight$;
|
|
386
|
+
};
|
|
387
|
+
return descriptor;
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/decorators/loading.ts
|
|
392
|
+
function Loading(storeKey, storeGetter) {
|
|
393
|
+
return function(_target, _propertyKey, descriptor) {
|
|
394
|
+
const originalMethod = descriptor.value;
|
|
395
|
+
descriptor.value = function(...args) {
|
|
396
|
+
const store = storeGetter(this);
|
|
397
|
+
const resourceKey = args[0];
|
|
398
|
+
const canKey = typeof resourceKey === "string" || typeof resourceKey === "number";
|
|
399
|
+
const hasKeyed = typeof store === "object" && store !== null && "startKeyedLoading" in store && typeof store.startKeyedLoading === "function";
|
|
400
|
+
if (canKey && hasKeyed) {
|
|
401
|
+
store.startKeyedLoading(storeKey, resourceKey);
|
|
402
|
+
} else {
|
|
403
|
+
store?.startLoading(storeKey);
|
|
404
|
+
}
|
|
405
|
+
return originalMethod.apply(this, args);
|
|
406
|
+
};
|
|
407
|
+
return descriptor;
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
export {
|
|
411
|
+
Loading,
|
|
412
|
+
SkipIfCached,
|
|
413
|
+
defaultErrorNormalizer,
|
|
414
|
+
syncToKeyedStore,
|
|
415
|
+
syncToStore
|
|
416
|
+
};
|
|
417
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/operators/sync-to-store.ts","../src/error/error-normalizer.ts","../src/operators/sync-to-keyed-store.ts","../src/decorators/skip-if-cached.ts","../src/decorators/loading.ts"],"sourcesContent":["import { finalize, Observable, take, tap } from \"rxjs\";\nimport { BaseStore } from \"@flurryx/store\";\nimport type { ResourceState } from \"@flurryx/core\";\nimport {\n defaultErrorNormalizer,\n type ErrorNormalizer,\n} from \"../error/error-normalizer\";\n\nexport interface SyncToStoreOptions {\n completeOnFirstEmission?: boolean;\n callbackAfterComplete?: () => void;\n errorNormalizer?: ErrorNormalizer;\n}\n\nexport function syncToStore<\n TEnum extends Record<string, string | number>,\n TData extends { [K in keyof TEnum]: ResourceState<unknown> }\n>(\n store: BaseStore<TEnum, TData>,\n key: keyof TEnum,\n options: SyncToStoreOptions = { completeOnFirstEmission: true }\n) {\n const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;\n\n return <R>(source: Observable<R>) => {\n let pipeline = source.pipe(\n tap({\n next: (data: R) => {\n store.update(key, {\n data,\n isLoading: false,\n status: \"Success\",\n errors: undefined,\n } as Partial<TData[typeof key]>);\n },\n error: (error: unknown) => {\n store.update(key, {\n data: undefined,\n isLoading: false,\n status: \"Error\",\n errors: normalizeError(error),\n } as Partial<TData[typeof key]>);\n },\n })\n );\n\n if (options.completeOnFirstEmission) {\n pipeline = pipeline.pipe(take(1));\n }\n\n if (options.callbackAfterComplete) {\n pipeline = pipeline.pipe(finalize(options.callbackAfterComplete));\n }\n\n return pipeline;\n };\n}\n","import type { ResourceErrors } from '@flurryx/core';\n\nexport type ErrorNormalizer = (error: unknown) => ResourceErrors;\n\nexport function defaultErrorNormalizer(error: unknown): ResourceErrors {\n if (\n typeof error === 'object' &&\n error !== null &&\n 'error' in error &&\n typeof (error as Record<string, unknown>).error === 'object'\n ) {\n const inner = (error as { error: Record<string, unknown> }).error;\n if (inner && Array.isArray(inner.errors)) {\n return inner.errors as ResourceErrors;\n }\n }\n\n if (\n typeof error === 'object' &&\n error !== null &&\n 'status' in error &&\n 'message' in error\n ) {\n const typed = error as { status: number; message: string };\n return [\n {\n code: String(typed.status),\n message: typed.message,\n },\n ];\n }\n\n if (error instanceof Error) {\n return [\n {\n code: 'UNKNOWN',\n message: error.message,\n },\n ];\n }\n\n return [\n {\n code: 'UNKNOWN',\n message: String(error),\n },\n ];\n}\n","import { finalize, Observable, take, tap } from \"rxjs\";\nimport { BaseStore } from \"@flurryx/store\";\nimport {\n createKeyedResourceData,\n isAnyKeyLoading,\n type KeyedResourceData,\n type KeyedResourceKey,\n type ResourceErrors,\n type ResourceState,\n type ResourceStatus,\n} from \"@flurryx/core\";\nimport {\n defaultErrorNormalizer,\n type ErrorNormalizer,\n} from \"../error/error-normalizer\";\nimport type { SyncToStoreOptions } from \"./sync-to-store\";\n\nexport interface SyncToKeyedStoreOptions<R, TValue> extends SyncToStoreOptions {\n mapResponse?: (response: R) => TValue;\n errorNormalizer?: ErrorNormalizer;\n}\n\nfunction withoutKey<TKey extends KeyedResourceKey, TValue>(\n record: Partial<Record<TKey, TValue>>,\n key: TKey\n): Partial<Record<TKey, TValue>> {\n const next: Partial<Record<TKey, TValue>> = {\n ...record,\n };\n delete next[key];\n return next;\n}\n\nexport function syncToKeyedStore<\n TEnum extends Record<string, string | number>,\n TStoreKey extends keyof TEnum,\n TKey extends KeyedResourceKey,\n TValue,\n R = TValue,\n TState extends ResourceState<KeyedResourceData<TKey, TValue>> = ResourceState<\n KeyedResourceData<TKey, TValue>\n >,\n TData extends {\n [K in keyof TEnum]: ResourceState<unknown>;\n } & { [K in TStoreKey]: TState } = {\n [K in keyof TEnum]: ResourceState<unknown>;\n } & { [K in TStoreKey]: TState }\n>(\n store: BaseStore<TEnum, TData>,\n storeKey: TStoreKey,\n resourceKey: TKey,\n options: SyncToKeyedStoreOptions<R, TValue> = {\n completeOnFirstEmission: true,\n }\n) {\n const { completeOnFirstEmission, callbackAfterComplete, mapResponse } =\n options;\n const normalizeError = options.errorNormalizer ?? defaultErrorNormalizer;\n\n return (source: Observable<R>) => {\n let pipeline = source.pipe(\n tap({\n next: (response: R) => {\n const value = mapResponse\n ? mapResponse(response)\n : (response as unknown as TValue);\n\n const storeSignal = store.get(storeKey);\n const state = storeSignal();\n const data = state.data ?? createKeyedResourceData<TKey, TValue>();\n\n const nextIsLoading = {\n ...data.isLoading,\n [resourceKey]: false,\n } as Partial<Record<TKey, boolean>>;\n\n const nextStatus: Partial<Record<TKey, ResourceStatus>> = {\n ...data.status,\n [resourceKey]: \"Success\",\n };\n\n const nextData: KeyedResourceData<TKey, TValue> = {\n ...data,\n entities: {\n ...data.entities,\n [resourceKey]: value,\n } as Partial<Record<TKey, TValue>>,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: withoutKey(data.errors, resourceKey),\n };\n\n store.update(storeKey, {\n data: nextData,\n isLoading: isAnyKeyLoading(nextIsLoading),\n status: undefined,\n errors: undefined,\n } as Partial<TData[typeof storeKey]>);\n },\n error: (error: unknown) => {\n const storeSignal = store.get(storeKey);\n const state = storeSignal();\n const data = state.data ?? createKeyedResourceData<TKey, TValue>();\n\n const nextIsLoading = {\n ...data.isLoading,\n [resourceKey]: false,\n } as Partial<Record<TKey, boolean>>;\n\n const nextStatus: Partial<Record<TKey, ResourceStatus>> = {\n ...data.status,\n [resourceKey]: \"Error\",\n };\n\n const nextErrors: Partial<Record<TKey, ResourceErrors>> = {\n ...data.errors,\n [resourceKey]: normalizeError(error),\n };\n\n const nextData: KeyedResourceData<TKey, TValue> = {\n ...data,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n store.update(storeKey, {\n data: nextData,\n isLoading: isAnyKeyLoading(nextIsLoading),\n status: undefined,\n errors: undefined,\n } as Partial<TData[typeof storeKey]>);\n },\n })\n );\n\n if (completeOnFirstEmission) {\n pipeline = pipeline.pipe(take(1));\n }\n\n if (callbackAfterComplete) {\n pipeline = pipeline.pipe(finalize(callbackAfterComplete));\n }\n\n return pipeline;\n };\n}\n","import { WritableSignal } from '@angular/core';\nimport { finalize, Observable, of, shareReplay, tap } from 'rxjs';\nimport type { ResourceState, StoreEnum, KeyedResourceKey } from '@flurryx/core';\nimport { isKeyedResourceData } from '@flurryx/core';\nimport { CACHE_NO_TIMEOUT, DEFAULT_CACHE_TTL_MS } from '@flurryx/core';\n\ntype StoreWithSignal<TKey extends StoreEnum> = {\n get: (key: TKey) => WritableSignal<ResourceState<unknown>> | undefined;\n};\n\ninterface CacheEntry {\n timestamp: number;\n args: string;\n inflight$?: Observable<unknown>;\n}\n\nconst cacheState = new WeakMap<\n object,\n Map<StoreEnum, Map<string, CacheEntry>>\n>();\n\nfunction getStoreKeyMap(\n store: object,\n key: StoreEnum\n): Map<string, CacheEntry> {\n let storeMap = cacheState.get(store);\n if (!storeMap) {\n storeMap = new Map();\n cacheState.set(store, storeMap);\n }\n\n let keyMap = storeMap.get(key);\n if (!keyMap) {\n keyMap = new Map();\n storeMap.set(key, keyMap);\n }\n\n return keyMap;\n}\n\nfunction getCacheEntry(\n store: object,\n key: StoreEnum,\n cacheKey: string\n): CacheEntry | undefined {\n return getStoreKeyMap(store, key).get(cacheKey);\n}\n\nfunction setCacheEntry(\n store: object,\n key: StoreEnum,\n cacheKey: string,\n entry: CacheEntry\n): void {\n getStoreKeyMap(store, key).set(cacheKey, entry);\n}\n\nfunction clearCacheEntry(\n store: object,\n key: StoreEnum,\n cacheKey: string\n): void {\n getStoreKeyMap(store, key).delete(cacheKey);\n}\n\nfunction deriveResourceKey(args: unknown[]): KeyedResourceKey | undefined {\n const key = args[0];\n if (typeof key === 'string' || typeof key === 'number') {\n return key;\n }\n return undefined;\n}\n\nfunction isExpired(\n timestamp: number | undefined,\n timeoutMs: number,\n now: number\n): boolean {\n if (timeoutMs === CACHE_NO_TIMEOUT) {\n return false;\n }\n if (timestamp === undefined) {\n return false;\n }\n return now - timestamp >= timeoutMs;\n}\n\ninterface StoreContext {\n store: object;\n storeSignal: WritableSignal<ResourceState<unknown>>;\n currentState: ResourceState<unknown>;\n}\n\nfunction getStoreContext<TTarget, TKey extends StoreEnum>(\n instance: TTarget,\n storeKey: TKey,\n getStore: (i: TTarget) => StoreWithSignal<TKey> | undefined\n): StoreContext | undefined {\n const store = getStore(instance);\n if (!store) {\n return undefined;\n }\n\n const storeSignal = store.get(storeKey);\n if (!storeSignal) {\n return undefined;\n }\n\n const currentState = storeSignal();\n if (currentState === null || currentState === undefined) {\n return undefined;\n }\n\n return { store, storeSignal, currentState };\n}\n\ninterface CacheContext {\n isKeyedCall: boolean;\n resourceKey: KeyedResourceKey | undefined;\n keyedData: ReturnType<typeof isKeyedResourceData> extends true\n ? { entities: object; isLoading: object; status: object; errors: object }\n : undefined;\n runtimeCacheKey: string;\n keyedCacheEntry: CacheEntry | undefined;\n nonKeyedCacheEntry: CacheEntry | undefined;\n}\n\nfunction getCacheContext(\n store: object,\n storeKey: StoreEnum,\n args: unknown[],\n argsString: string,\n currentState: ResourceState<unknown>\n): CacheContext {\n const keyedData = isKeyedResourceData(currentState.data)\n ? currentState.data\n : undefined;\n const resourceKey = keyedData ? deriveResourceKey(args) : undefined;\n const isKeyedCall = keyedData !== undefined && resourceKey !== undefined;\n\n const keyedCacheKey = argsString;\n const nonKeyedCacheKey = '__single__';\n const runtimeCacheKey = isKeyedCall ? keyedCacheKey : nonKeyedCacheKey;\n\n const keyedCacheEntry = getCacheEntry(store, storeKey, keyedCacheKey);\n const nonKeyedCacheEntry = getCacheEntry(store, storeKey, nonKeyedCacheKey);\n\n return {\n isKeyedCall,\n resourceKey,\n keyedData: keyedData as CacheContext['keyedData'],\n runtimeCacheKey,\n keyedCacheEntry,\n nonKeyedCacheEntry,\n };\n}\n\nfunction handleCacheErrors(\n store: object,\n storeKey: StoreEnum,\n context: CacheContext,\n currentState: ResourceState<unknown>\n): void {\n if (!context.keyedData && currentState.status === 'Error') {\n clearCacheEntry(store, storeKey, '__single__');\n }\n if (context.keyedData && context.resourceKey !== undefined) {\n const status = (\n context.keyedData as {\n status: Partial<Record<KeyedResourceKey, string>>;\n }\n ).status[context.resourceKey];\n if (status === 'Error') {\n clearCacheEntry(store, storeKey, context.runtimeCacheKey);\n }\n }\n}\n\ninterface CacheHitResult {\n hit: boolean;\n value?: Observable<unknown>;\n}\n\nfunction handleKeyedCache(\n store: object,\n storeKey: StoreEnum,\n context: CacheContext,\n timeoutMs: number,\n now: number,\n returnObservable: boolean\n): CacheHitResult {\n const { keyedData, resourceKey, keyedCacheEntry, runtimeCacheKey } = context;\n\n if (!keyedData || resourceKey === undefined) {\n return { hit: false };\n }\n\n const typed = keyedData as {\n status: Partial<Record<KeyedResourceKey, string>>;\n entities: Partial<Record<KeyedResourceKey, unknown>>;\n isLoading: Partial<Record<KeyedResourceKey, boolean>>;\n };\n\n const status = typed.status[resourceKey];\n const entity = typed.entities[resourceKey];\n const loading = typed.isLoading[resourceKey] === true;\n\n const expired = isExpired(keyedCacheEntry?.timestamp, timeoutMs, now);\n if (expired) {\n clearCacheEntry(store, storeKey, runtimeCacheKey);\n }\n\n if (!expired && status === 'Success' && entity !== undefined) {\n if (returnObservable) {\n return { hit: true, value: of(entity) };\n }\n return { hit: true };\n }\n\n if (returnObservable) {\n if (keyedCacheEntry?.inflight$) {\n return { hit: true, value: keyedCacheEntry.inflight$ };\n }\n } else if (loading) {\n return { hit: true };\n }\n\n return { hit: false };\n}\n\nfunction handleNonKeyedCache(\n store: object,\n storeKey: StoreEnum,\n context: CacheContext,\n timeoutMs: number,\n now: number,\n returnObservable: boolean,\n currentState: ResourceState<unknown>,\n argsString: string,\n storeSignal: WritableSignal<ResourceState<unknown>>\n): CacheHitResult {\n const { nonKeyedCacheEntry, runtimeCacheKey } = context;\n\n if (\n returnObservable &&\n nonKeyedCacheEntry?.args === argsString &&\n nonKeyedCacheEntry.inflight$\n ) {\n return { hit: true, value: nonKeyedCacheEntry.inflight$ };\n }\n\n const hasValidCacheState =\n currentState?.status === 'Success' || currentState?.isLoading === true;\n\n if (\n nonKeyedCacheEntry &&\n isExpired(nonKeyedCacheEntry.timestamp, timeoutMs, now)\n ) {\n clearCacheEntry(store, storeKey, runtimeCacheKey);\n } else if (nonKeyedCacheEntry?.args === argsString && hasValidCacheState) {\n if (returnObservable) {\n if (nonKeyedCacheEntry.inflight$) {\n return { hit: true, value: nonKeyedCacheEntry.inflight$ };\n }\n return { hit: true, value: of(storeSignal().data) };\n }\n return { hit: true };\n }\n\n return { hit: false };\n}\n\nfunction createCachedObservable(\n result: Observable<unknown>,\n store: object,\n storeKey: StoreEnum,\n runtimeCacheKey: string,\n argsString: string\n): Observable<unknown> {\n return result.pipe(\n tap({\n next: () => {\n setCacheEntry(store, storeKey, runtimeCacheKey, {\n timestamp: Date.now(),\n args: argsString,\n });\n },\n error: () => {\n clearCacheEntry(store, storeKey, runtimeCacheKey);\n },\n }),\n finalize(() => {\n const entry = getCacheEntry(store, storeKey, runtimeCacheKey);\n if (entry?.inflight$) {\n const { inflight$: _inflight$, ...rest } = entry;\n setCacheEntry(store, storeKey, runtimeCacheKey, rest);\n }\n }),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n}\n\nexport function SkipIfCached<TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: {\n store: StoreWithSignal<TKey>;\n }) => StoreWithSignal<TKey> | undefined,\n returnObservable?: boolean,\n timeoutMs?: number\n): MethodDecorator;\nexport function SkipIfCached<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithSignal<TKey> | undefined,\n returnObservable?: boolean,\n timeoutMs?: number\n): MethodDecorator;\nexport function SkipIfCached<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithSignal<TKey> | undefined,\n returnObservable = false,\n timeoutMs = DEFAULT_CACHE_TTL_MS\n): MethodDecorator {\n return function (\n _target: unknown,\n _propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ) {\n const originalMethod = descriptor.value as (\n this: TTarget,\n ...args: unknown[]\n ) => unknown;\n\n descriptor.value = function (this: TTarget, ...args: unknown[]) {\n const storeContext = getStoreContext(this, storeKey, storeGetter);\n if (!storeContext) {\n return originalMethod.apply(this, args);\n }\n const { store, storeSignal, currentState } = storeContext;\n\n const argsString = JSON.stringify(args);\n const now = Date.now();\n const cacheContext = getCacheContext(\n store,\n storeKey,\n args,\n argsString,\n currentState\n );\n\n handleCacheErrors(store, storeKey, cacheContext, currentState);\n\n let cacheHit: CacheHitResult;\n\n if (cacheContext.isKeyedCall) {\n cacheHit = handleKeyedCache(\n store,\n storeKey,\n cacheContext,\n timeoutMs,\n now,\n returnObservable\n );\n } else {\n cacheHit = handleNonKeyedCache(\n store,\n storeKey,\n cacheContext,\n timeoutMs,\n now,\n returnObservable,\n currentState,\n argsString,\n storeSignal\n );\n }\n\n if (cacheHit.hit) {\n return cacheHit.value;\n }\n\n const result = originalMethod.apply(this, args);\n\n if (!returnObservable) {\n setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {\n timestamp: now,\n args: argsString,\n });\n return result;\n }\n\n const inflight$ = createCachedObservable(\n result as Observable<unknown>,\n store,\n storeKey,\n cacheContext.runtimeCacheKey,\n argsString\n );\n\n setCacheEntry(store, storeKey, cacheContext.runtimeCacheKey, {\n timestamp: now,\n args: argsString,\n inflight$,\n });\n\n return inflight$;\n };\n\n return descriptor;\n };\n}\n","import type { StoreEnum, KeyedResourceKey } from '@flurryx/core';\n\ntype StoreWithLoading<TKey extends StoreEnum> = {\n startLoading: (key: TKey) => void;\n};\n\nexport function Loading<TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: {\n store: StoreWithLoading<TKey>;\n }) => StoreWithLoading<TKey>\n): MethodDecorator;\nexport function Loading<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithLoading<TKey>\n): MethodDecorator;\nexport function Loading<TTarget, TKey extends StoreEnum>(\n storeKey: TKey,\n storeGetter: (instance: TTarget) => StoreWithLoading<TKey>\n) {\n return function (\n _target: unknown,\n _propertyKey: string | symbol,\n descriptor: PropertyDescriptor\n ) {\n const originalMethod = descriptor.value as (\n this: unknown,\n ...args: unknown[]\n ) => unknown;\n\n descriptor.value = function (this: TTarget, ...args: unknown[]) {\n const store = storeGetter(this);\n\n const resourceKey = args[0];\n const canKey =\n typeof resourceKey === 'string' || typeof resourceKey === 'number';\n const hasKeyed =\n typeof store === 'object' &&\n store !== null &&\n 'startKeyedLoading' in store &&\n typeof (store as { startKeyedLoading?: unknown }).startKeyedLoading ===\n 'function';\n\n if (canKey && hasKeyed) {\n (\n store as unknown as {\n startKeyedLoading: (\n key: TKey,\n resourceKey: KeyedResourceKey\n ) => void;\n }\n ).startKeyedLoading(storeKey, resourceKey as KeyedResourceKey);\n } else {\n store?.startLoading(storeKey);\n }\n return originalMethod.apply(this, args);\n };\n\n return descriptor;\n };\n}\n"],"mappings":"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","names":["finalize","take","tap","tap","take","finalize","finalize","tap"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flurryx/rx",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "RxJS operators and decorators for flurryx stores",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"./http": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/http.d.ts",
|
|
24
|
+
"default": "./dist/http.js"
|
|
25
|
+
},
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/http.d.cts",
|
|
28
|
+
"default": "./dist/http.cjs"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": ["dist"],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"sideEffects": false,
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@flurryx/core": "0.0.1",
|
|
40
|
+
"@flurryx/store": "0.0.1"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@angular/core": ">=17.0.0",
|
|
44
|
+
"rxjs": ">=7.0.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"@angular/common": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|