@reactionary/core 0.0.30 → 0.0.31
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/index.js +232 -36
- package/package.json +2 -2
- package/src/cache/cache-evaluation.interface.d.ts +17 -0
- package/src/cache/cache.interface.d.ts +36 -0
- package/src/cache/noop-cache.d.ts +18 -0
- package/src/cache/redis-cache.d.ts +13 -9
- package/src/client/client.d.ts +6 -1
- package/src/index.d.ts +3 -1
- package/src/providers/analytics.provider.d.ts +3 -0
- package/src/providers/base.provider.d.ts +13 -2
- package/src/providers/cart.provider.d.ts +3 -0
- package/src/providers/identity.provider.d.ts +3 -0
- package/src/providers/inventory.provider.d.ts +3 -0
- package/src/providers/price.provider.d.ts +3 -0
- package/src/providers/product.provider.d.ts +3 -0
- package/src/providers/search.provider.d.ts +3 -0
- package/src/cache/caching-strategy.d.ts +0 -13
package/index.js
CHANGED
|
@@ -1,47 +1,95 @@
|
|
|
1
|
-
// core/src/cache/caching-strategy.ts
|
|
2
|
-
var BaseCachingStrategy = class {
|
|
3
|
-
get(query, session) {
|
|
4
|
-
const q = query;
|
|
5
|
-
return {
|
|
6
|
-
key: q.sku,
|
|
7
|
-
cacheDurationInSeconds: 300,
|
|
8
|
-
canCache: true
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
|
|
13
1
|
// core/src/cache/redis-cache.ts
|
|
14
2
|
import { Redis } from "@upstash/redis";
|
|
15
3
|
var RedisCache = class {
|
|
16
|
-
constructor(
|
|
17
|
-
this.strategy = strategy;
|
|
4
|
+
constructor() {
|
|
18
5
|
this.redis = Redis.fromEnv();
|
|
19
6
|
}
|
|
20
|
-
async get(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
7
|
+
async get(key, schema) {
|
|
8
|
+
if (!key) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const unvalidated = await this.redis.get(key);
|
|
12
|
+
const parsed = schema.safeParse(unvalidated);
|
|
13
|
+
if (parsed.success) {
|
|
14
|
+
return parsed.data;
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
async put(key, value, ttlSeconds) {
|
|
19
|
+
if (!key) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const options = ttlSeconds ? { ex: ttlSeconds } : void 0;
|
|
23
|
+
await this.redis.set(key, value, options);
|
|
24
|
+
}
|
|
25
|
+
async del(keys) {
|
|
26
|
+
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
27
|
+
for (const key of keyArray) {
|
|
28
|
+
if (key.includes("*")) {
|
|
29
|
+
const matchingKeys = await this.redis.keys(key);
|
|
30
|
+
if (matchingKeys.length > 0) {
|
|
31
|
+
await this.redis.del(...matchingKeys);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
await this.redis.del(key);
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
|
-
return result;
|
|
31
37
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
async keys(pattern) {
|
|
39
|
+
return await this.redis.keys(pattern);
|
|
40
|
+
}
|
|
41
|
+
async clear(pattern) {
|
|
42
|
+
const searchPattern = pattern || "*";
|
|
43
|
+
const keys = await this.redis.keys(searchPattern);
|
|
44
|
+
if (keys.length > 0) {
|
|
45
|
+
await this.redis.del(...keys);
|
|
36
46
|
}
|
|
37
47
|
}
|
|
48
|
+
async getStats() {
|
|
49
|
+
const keys = await this.redis.keys("*");
|
|
50
|
+
return {
|
|
51
|
+
hits: 0,
|
|
52
|
+
// Would need to track this separately
|
|
53
|
+
misses: 0,
|
|
54
|
+
// Would need to track this separately
|
|
55
|
+
size: keys.length
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// core/src/cache/noop-cache.ts
|
|
61
|
+
var NoOpCache = class {
|
|
62
|
+
async get(_key, _schema) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
async put(_key, _value, _ttlSeconds) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
async del(_keys) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
async keys(_pattern) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
async clear(_pattern) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
async getStats() {
|
|
78
|
+
return {
|
|
79
|
+
hits: 0,
|
|
80
|
+
misses: 0,
|
|
81
|
+
size: 0
|
|
82
|
+
};
|
|
83
|
+
}
|
|
38
84
|
};
|
|
39
85
|
|
|
40
86
|
// core/src/client/client.ts
|
|
41
|
-
function buildClient(
|
|
87
|
+
function buildClient(providerFactories, options = {}) {
|
|
42
88
|
let client = {};
|
|
89
|
+
const sharedCache = options.cache || new RedisCache();
|
|
43
90
|
const mergedAnalytics = [];
|
|
44
|
-
for (const
|
|
91
|
+
for (const factory of providerFactories) {
|
|
92
|
+
const provider = factory(sharedCache);
|
|
45
93
|
client = {
|
|
46
94
|
...client,
|
|
47
95
|
...provider
|
|
@@ -51,7 +99,14 @@ function buildClient(providers) {
|
|
|
51
99
|
}
|
|
52
100
|
}
|
|
53
101
|
client.analytics = mergedAnalytics;
|
|
54
|
-
|
|
102
|
+
const completeClient = {
|
|
103
|
+
...client,
|
|
104
|
+
cache: sharedCache
|
|
105
|
+
};
|
|
106
|
+
return completeClient;
|
|
107
|
+
}
|
|
108
|
+
function createCache() {
|
|
109
|
+
return new RedisCache();
|
|
55
110
|
}
|
|
56
111
|
|
|
57
112
|
// otel/src/trpc-middleware.ts
|
|
@@ -286,12 +341,14 @@ function createProviderInstrumentation(providerName) {
|
|
|
286
341
|
}
|
|
287
342
|
|
|
288
343
|
// core/src/providers/base.provider.ts
|
|
344
|
+
import * as crypto from "crypto";
|
|
289
345
|
var BaseProvider = class {
|
|
290
|
-
constructor(schema, querySchema, mutationSchema) {
|
|
346
|
+
constructor(schema, querySchema, mutationSchema, cache) {
|
|
291
347
|
this.schema = schema;
|
|
292
348
|
this.querySchema = querySchema;
|
|
293
349
|
this.mutationSchema = mutationSchema;
|
|
294
350
|
this.instrumentation = createProviderInstrumentation(this.constructor.name);
|
|
351
|
+
this.cache = cache;
|
|
295
352
|
}
|
|
296
353
|
/**
|
|
297
354
|
* Validates that the final domain model constructed by the provider
|
|
@@ -317,11 +374,44 @@ var BaseProvider = class {
|
|
|
317
374
|
"query",
|
|
318
375
|
async (span) => {
|
|
319
376
|
span.setAttribute("provider.query.count", queries.length);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
377
|
+
let cacheHits = 0;
|
|
378
|
+
let cacheMisses = 0;
|
|
379
|
+
const results = [];
|
|
380
|
+
for (const query of queries) {
|
|
381
|
+
let result = null;
|
|
382
|
+
const cacheInfo = this.getCacheEvaluation(query, session);
|
|
383
|
+
if (cacheInfo.canCache && cacheInfo.key) {
|
|
384
|
+
try {
|
|
385
|
+
result = await this.cache.get(cacheInfo.key, this.schema);
|
|
386
|
+
if (result) {
|
|
387
|
+
cacheHits++;
|
|
388
|
+
span.setAttribute("provider.cache.hit", true);
|
|
389
|
+
}
|
|
390
|
+
} catch (error) {
|
|
391
|
+
console.warn(`Cache get error for ${this.constructor.name}:`, error);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!result) {
|
|
395
|
+
const singleResult = await this.fetch([query], session);
|
|
396
|
+
result = singleResult[0];
|
|
397
|
+
cacheMisses++;
|
|
398
|
+
if (result && cacheInfo.canCache && cacheInfo.key) {
|
|
399
|
+
try {
|
|
400
|
+
await this.cache.put(cacheInfo.key, result, cacheInfo.cacheDurationInSeconds);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
console.warn(`Cache put error for ${this.constructor.name}:`, error);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (result) {
|
|
407
|
+
this.assert(result);
|
|
408
|
+
results.push(result);
|
|
409
|
+
}
|
|
323
410
|
}
|
|
324
411
|
span.setAttribute("provider.result.count", results.length);
|
|
412
|
+
span.setAttribute("provider.cache.hits", cacheHits);
|
|
413
|
+
span.setAttribute("provider.cache.misses", cacheMisses);
|
|
414
|
+
span.setAttribute("provider.cache.hit_ratio", cacheHits / (cacheHits + cacheMisses));
|
|
325
415
|
return results;
|
|
326
416
|
},
|
|
327
417
|
{ queryCount: queries.length }
|
|
@@ -343,34 +433,139 @@ var BaseProvider = class {
|
|
|
343
433
|
{ mutationCount: mutations.length }
|
|
344
434
|
);
|
|
345
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* Provider-specific cache evaluation logic.
|
|
438
|
+
* Returns information about how this query should be cached.
|
|
439
|
+
* Override this method to enable caching with custom keys and TTL.
|
|
440
|
+
* Default implementation returns no caching.
|
|
441
|
+
*/
|
|
442
|
+
getCacheEvaluation(query, session) {
|
|
443
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
444
|
+
const userId = session.identity?.id || "anonymous";
|
|
445
|
+
const queryHash = crypto.createHash("md5").update(JSON.stringify(query)).digest("hex").substring(0, 12);
|
|
446
|
+
const key = `${providerName}:${userId}:${queryHash}`;
|
|
447
|
+
return {
|
|
448
|
+
key,
|
|
449
|
+
cacheDurationInSeconds: 0,
|
|
450
|
+
canCache: false
|
|
451
|
+
};
|
|
452
|
+
}
|
|
346
453
|
};
|
|
347
454
|
|
|
348
455
|
// core/src/providers/analytics.provider.ts
|
|
456
|
+
import * as crypto2 from "crypto";
|
|
349
457
|
var AnalyticsProvider = class extends BaseProvider {
|
|
458
|
+
getCacheEvaluation(query, _session) {
|
|
459
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
460
|
+
const relevantFields = {
|
|
461
|
+
type: typeof query === "object" && query !== null && "type" in query ? query.type : void 0,
|
|
462
|
+
dateRange: typeof query === "object" && query !== null && "dateRange" in query ? query.dateRange : void 0,
|
|
463
|
+
filters: typeof query === "object" && query !== null && "filters" in query ? query.filters : void 0
|
|
464
|
+
};
|
|
465
|
+
const analyticsHash = crypto2.createHash("md5").update(JSON.stringify(relevantFields)).digest("hex").substring(0, 12);
|
|
466
|
+
const key = `${providerName}:analytics:${analyticsHash}`;
|
|
467
|
+
return {
|
|
468
|
+
key,
|
|
469
|
+
cacheDurationInSeconds: 0,
|
|
470
|
+
canCache: false
|
|
471
|
+
};
|
|
472
|
+
}
|
|
350
473
|
};
|
|
351
474
|
|
|
352
475
|
// core/src/providers/cart.provider.ts
|
|
476
|
+
import * as crypto3 from "crypto";
|
|
353
477
|
var CartProvider = class extends BaseProvider {
|
|
478
|
+
getCacheEvaluation(query, session) {
|
|
479
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
480
|
+
const userId = session.identity?.id || "anonymous";
|
|
481
|
+
const queryHash = crypto3.createHash("md5").update(JSON.stringify(query)).digest("hex").substring(0, 12);
|
|
482
|
+
const key = `${providerName}:cart:${userId}:${queryHash}`;
|
|
483
|
+
return {
|
|
484
|
+
key,
|
|
485
|
+
cacheDurationInSeconds: 0,
|
|
486
|
+
canCache: false
|
|
487
|
+
};
|
|
488
|
+
}
|
|
354
489
|
};
|
|
355
490
|
|
|
356
491
|
// core/src/providers/identity.provider.ts
|
|
357
492
|
var IdentityProvider = class extends BaseProvider {
|
|
493
|
+
getCacheEvaluation(_query, session) {
|
|
494
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
495
|
+
const userId = session.identity?.id;
|
|
496
|
+
const key = userId ? `${providerName}:identity:${userId}` : `${providerName}:identity:anonymous`;
|
|
497
|
+
return {
|
|
498
|
+
key,
|
|
499
|
+
cacheDurationInSeconds: 0,
|
|
500
|
+
canCache: false
|
|
501
|
+
};
|
|
502
|
+
}
|
|
358
503
|
};
|
|
359
504
|
|
|
360
505
|
// core/src/providers/inventory.provider.ts
|
|
361
506
|
var InventoryProvider = class extends BaseProvider {
|
|
507
|
+
getCacheEvaluation(query, _session) {
|
|
508
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
509
|
+
const key = `${providerName}:inventory:${query.sku}`;
|
|
510
|
+
return {
|
|
511
|
+
key,
|
|
512
|
+
cacheDurationInSeconds: 0,
|
|
513
|
+
canCache: false
|
|
514
|
+
};
|
|
515
|
+
}
|
|
362
516
|
};
|
|
363
517
|
|
|
364
518
|
// core/src/providers/price.provider.ts
|
|
519
|
+
import * as crypto4 from "crypto";
|
|
365
520
|
var PriceProvider = class extends BaseProvider {
|
|
521
|
+
getCacheEvaluation(query, _session) {
|
|
522
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
523
|
+
const skuHash = crypto4.createHash("md5").update(JSON.stringify(query.sku)).digest("hex").substring(0, 12);
|
|
524
|
+
const key = `${providerName}:price:${skuHash}`;
|
|
525
|
+
return {
|
|
526
|
+
key,
|
|
527
|
+
cacheDurationInSeconds: 0,
|
|
528
|
+
canCache: false
|
|
529
|
+
};
|
|
530
|
+
}
|
|
366
531
|
};
|
|
367
532
|
|
|
368
533
|
// core/src/providers/product.provider.ts
|
|
534
|
+
import * as crypto5 from "crypto";
|
|
369
535
|
var ProductProvider = class extends BaseProvider {
|
|
536
|
+
getCacheEvaluation(query, _session) {
|
|
537
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
538
|
+
let key;
|
|
539
|
+
if (query.query === "slug") {
|
|
540
|
+
key = `${providerName}:product:slug:${query.slug}`;
|
|
541
|
+
} else if (query.query === "id") {
|
|
542
|
+
key = `${providerName}:product:id:${query.id}`;
|
|
543
|
+
} else {
|
|
544
|
+
const queryHash = crypto5.createHash("md5").update(JSON.stringify(query)).digest("hex").substring(0, 12);
|
|
545
|
+
key = `${providerName}:product:${queryHash}`;
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
key,
|
|
549
|
+
cacheDurationInSeconds: 300,
|
|
550
|
+
// Products are moderately stable - 5 minutes
|
|
551
|
+
canCache: true
|
|
552
|
+
};
|
|
553
|
+
}
|
|
370
554
|
};
|
|
371
555
|
|
|
372
556
|
// core/src/providers/search.provider.ts
|
|
557
|
+
import * as crypto6 from "crypto";
|
|
373
558
|
var SearchProvider = class extends BaseProvider {
|
|
559
|
+
getCacheEvaluation(query, _session) {
|
|
560
|
+
const providerName = this.constructor.name.toLowerCase();
|
|
561
|
+
const searchHash = crypto6.createHash("md5").update(JSON.stringify(query.search)).digest("hex").substring(0, 12);
|
|
562
|
+
const key = `${providerName}:search:${searchHash}`;
|
|
563
|
+
return {
|
|
564
|
+
key,
|
|
565
|
+
cacheDurationInSeconds: 0,
|
|
566
|
+
canCache: false
|
|
567
|
+
};
|
|
568
|
+
}
|
|
374
569
|
};
|
|
375
570
|
|
|
376
571
|
// core/src/schemas/capabilities.schema.ts
|
|
@@ -828,7 +1023,6 @@ var SearchQueryByTermSchema = BaseQuerySchema.extend({
|
|
|
828
1023
|
var SearchQuerySchema = z25.union([SearchQueryByTermSchema]);
|
|
829
1024
|
export {
|
|
830
1025
|
AnalyticsProvider,
|
|
831
|
-
BaseCachingStrategy,
|
|
832
1026
|
BaseModelSchema,
|
|
833
1027
|
BaseMutationSchema,
|
|
834
1028
|
BaseProvider,
|
|
@@ -863,6 +1057,7 @@ export {
|
|
|
863
1057
|
InventorySchema,
|
|
864
1058
|
MetaSchema,
|
|
865
1059
|
MonetaryAmountSchema,
|
|
1060
|
+
NoOpCache,
|
|
866
1061
|
PriceIdentifierSchema,
|
|
867
1062
|
PriceMutationSchema,
|
|
868
1063
|
PriceProvider,
|
|
@@ -890,5 +1085,6 @@ export {
|
|
|
890
1085
|
SearchResultProductSchema,
|
|
891
1086
|
SearchResultSchema,
|
|
892
1087
|
SessionSchema,
|
|
893
|
-
buildClient
|
|
1088
|
+
buildClient,
|
|
1089
|
+
createCache
|
|
894
1090
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache evaluation result that determines how and if a query should be cached
|
|
3
|
+
*/
|
|
4
|
+
export interface CacheEvaluation {
|
|
5
|
+
/**
|
|
6
|
+
* The cache key to use for storing/retrieving the value
|
|
7
|
+
*/
|
|
8
|
+
key: string;
|
|
9
|
+
/**
|
|
10
|
+
* How long to cache the value in seconds
|
|
11
|
+
*/
|
|
12
|
+
cacheDurationInSeconds: number;
|
|
13
|
+
/**
|
|
14
|
+
* Whether this query result can be cached
|
|
15
|
+
*/
|
|
16
|
+
canCache: boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Generic cache interface that can be implemented by different cache backends
|
|
4
|
+
* (Redis, memory, file-based, etc.)
|
|
5
|
+
*/
|
|
6
|
+
export interface Cache {
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves a value from cache and validates it against the provided schema
|
|
9
|
+
*/
|
|
10
|
+
get<T>(key: string, schema: z.ZodType<T>): Promise<T | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Stores a value in cache with optional expiration time
|
|
13
|
+
*/
|
|
14
|
+
put(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Removes one or more keys from cache
|
|
17
|
+
* Supports wildcard patterns (implementation dependent)
|
|
18
|
+
*/
|
|
19
|
+
del(keys: string | string[]): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Finds all keys matching a pattern (implementation dependent)
|
|
22
|
+
*/
|
|
23
|
+
keys(pattern: string): Promise<string[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Clears all cache entries or entries matching a pattern
|
|
26
|
+
*/
|
|
27
|
+
clear(pattern?: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Gets basic cache statistics (implementation dependent)
|
|
30
|
+
*/
|
|
31
|
+
getStats(): Promise<{
|
|
32
|
+
hits: number;
|
|
33
|
+
misses: number;
|
|
34
|
+
size: number;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Cache } from './cache.interface';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* No-op cache implementation that never stores or returns data.
|
|
5
|
+
* Useful for testing or when caching should be disabled.
|
|
6
|
+
*/
|
|
7
|
+
export declare class NoOpCache implements Cache {
|
|
8
|
+
get<T>(_key: string, _schema: z.ZodType<T>): Promise<T | null>;
|
|
9
|
+
put(_key: string, _value: unknown, _ttlSeconds?: number): Promise<void>;
|
|
10
|
+
del(_keys: string | string[]): Promise<void>;
|
|
11
|
+
keys(_pattern: string): Promise<string[]>;
|
|
12
|
+
clear(_pattern?: string): Promise<void>;
|
|
13
|
+
getStats(): Promise<{
|
|
14
|
+
hits: number;
|
|
15
|
+
misses: number;
|
|
16
|
+
size: number;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { Redis } from '@upstash/redis';
|
|
2
|
-
import {
|
|
3
|
-
import { BaseQuery } from '../schemas/queries/base.query';
|
|
4
|
-
import { Session } from '../schemas/session.schema';
|
|
5
|
-
import { BaseModel } from '../schemas/models/base.model';
|
|
2
|
+
import { Cache } from './cache.interface';
|
|
6
3
|
import z from 'zod';
|
|
7
|
-
export declare class RedisCache {
|
|
8
|
-
protected strategy: CachingStrategy;
|
|
4
|
+
export declare class RedisCache implements Cache {
|
|
9
5
|
protected redis: Redis;
|
|
10
|
-
constructor(
|
|
11
|
-
get<T
|
|
12
|
-
put(
|
|
6
|
+
constructor();
|
|
7
|
+
get<T>(key: string, schema: z.ZodType<T>): Promise<T | null>;
|
|
8
|
+
put(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
|
|
9
|
+
del(keys: string | string[]): Promise<void>;
|
|
10
|
+
keys(pattern: string): Promise<string[]>;
|
|
11
|
+
clear(pattern?: string): Promise<void>;
|
|
12
|
+
getStats(): Promise<{
|
|
13
|
+
hits: number;
|
|
14
|
+
misses: number;
|
|
15
|
+
size: number;
|
|
16
|
+
}>;
|
|
13
17
|
}
|
package/src/client/client.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { IdentityProvider } from '../providers/identity.provider';
|
|
|
5
5
|
import { CartProvider } from "../providers/cart.provider";
|
|
6
6
|
import { PriceProvider } from "../providers/price.provider";
|
|
7
7
|
import { InventoryProvider } from "../providers/inventory.provider";
|
|
8
|
+
import { Cache } from "../cache/cache.interface";
|
|
8
9
|
export interface Client {
|
|
9
10
|
product: ProductProvider;
|
|
10
11
|
search: SearchProvider;
|
|
@@ -15,4 +16,8 @@ export interface Client {
|
|
|
15
16
|
price: PriceProvider;
|
|
16
17
|
inventory: InventoryProvider;
|
|
17
18
|
}
|
|
18
|
-
export
|
|
19
|
+
export interface BuildClientOptions {
|
|
20
|
+
cache?: Cache;
|
|
21
|
+
}
|
|
22
|
+
export declare function buildClient<T extends Partial<Client>>(providerFactories: Array<(cache: Cache) => T>, options?: BuildClientOptions): Required<T>;
|
|
23
|
+
export declare function createCache(): Cache;
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export * from './cache/
|
|
1
|
+
export * from './cache/cache.interface';
|
|
2
|
+
export * from './cache/cache-evaluation.interface';
|
|
2
3
|
export * from './cache/redis-cache';
|
|
4
|
+
export * from './cache/noop-cache';
|
|
3
5
|
export * from './client/client';
|
|
4
6
|
export * from './providers/analytics.provider';
|
|
5
7
|
export * from './providers/base.provider';
|
|
@@ -2,5 +2,8 @@ import { AnalyticsEvent } from '../schemas/models/analytics.model';
|
|
|
2
2
|
import { AnalyticsMutation } from '../schemas/mutations/analytics.mutation';
|
|
3
3
|
import { AnalyticsQuery } from '../schemas/queries/analytics.query';
|
|
4
4
|
import { BaseProvider } from './base.provider';
|
|
5
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
|
+
import { Session } from '../schemas/session.schema';
|
|
5
7
|
export declare abstract class AnalyticsProvider<T extends AnalyticsEvent = AnalyticsEvent, Q extends AnalyticsQuery = AnalyticsQuery, M extends AnalyticsMutation = AnalyticsMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(query: Q, _session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -3,6 +3,9 @@ import { Session } from '../schemas/session.schema';
|
|
|
3
3
|
import { BaseQuery } from '../schemas/queries/base.query';
|
|
4
4
|
import { BaseMutation } from '../schemas/mutations/base.mutation';
|
|
5
5
|
import { BaseModel } from '../schemas/models/base.model';
|
|
6
|
+
import { createProviderInstrumentation } from '@reactionary/otel';
|
|
7
|
+
import { Cache } from '../cache/cache.interface';
|
|
8
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
9
|
/**
|
|
7
10
|
* Base capability provider, responsible for mutations (changes) and queries (fetches)
|
|
8
11
|
* for a given business object domain.
|
|
@@ -11,8 +14,9 @@ export declare abstract class BaseProvider<T extends BaseModel = BaseModel, Q ex
|
|
|
11
14
|
readonly schema: z.ZodType<T>;
|
|
12
15
|
readonly querySchema: z.ZodType<Q, Q>;
|
|
13
16
|
readonly mutationSchema: z.ZodType<M, M>;
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
protected instrumentation: ReturnType<typeof createProviderInstrumentation>;
|
|
18
|
+
protected cache: Cache;
|
|
19
|
+
constructor(schema: z.ZodType<T>, querySchema: z.ZodType<Q, Q>, mutationSchema: z.ZodType<M, M>, cache: Cache);
|
|
16
20
|
/**
|
|
17
21
|
* Validates that the final domain model constructed by the provider
|
|
18
22
|
* fulfills the schema as defined. This will throw an exception.
|
|
@@ -44,4 +48,11 @@ export declare abstract class BaseProvider<T extends BaseModel = BaseModel, Q ex
|
|
|
44
48
|
* capabilities.
|
|
45
49
|
*/
|
|
46
50
|
protected abstract process(mutations: M[], session: Session): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Provider-specific cache evaluation logic.
|
|
53
|
+
* Returns information about how this query should be cached.
|
|
54
|
+
* Override this method to enable caching with custom keys and TTL.
|
|
55
|
+
* Default implementation returns no caching.
|
|
56
|
+
*/
|
|
57
|
+
protected getCacheEvaluation(query: Q, session: Session): CacheEvaluation;
|
|
47
58
|
}
|
|
@@ -2,5 +2,8 @@ import { CartQuery } from "../schemas/queries/cart.query";
|
|
|
2
2
|
import { CartMutation } from "../schemas/mutations/cart.mutation";
|
|
3
3
|
import { BaseProvider } from "./base.provider";
|
|
4
4
|
import { Cart } from "../schemas/models/cart.model";
|
|
5
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
|
+
import { Session } from '../schemas/session.schema';
|
|
5
7
|
export declare abstract class CartProvider<T extends Cart = Cart, Q extends CartQuery = CartQuery, M extends CartMutation = CartMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(query: Q, session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -2,5 +2,8 @@ import { Identity } from "../schemas/models/identity.model";
|
|
|
2
2
|
import { IdentityQuery } from "../schemas/queries/identity.query";
|
|
3
3
|
import { IdentityMutation } from "../schemas/mutations/identity.mutation";
|
|
4
4
|
import { BaseProvider } from "./base.provider";
|
|
5
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
|
+
import { Session } from '../schemas/session.schema';
|
|
5
7
|
export declare abstract class IdentityProvider<T extends Identity = Identity, Q extends IdentityQuery = IdentityQuery, M extends IdentityMutation = IdentityMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(_query: Q, session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -2,5 +2,8 @@ import { Inventory } from '../schemas/models/inventory.model';
|
|
|
2
2
|
import { InventoryQuery } from '../schemas/queries/inventory.query';
|
|
3
3
|
import { InventoryMutation } from '../schemas/mutations/inventory.mutation';
|
|
4
4
|
import { BaseProvider } from './base.provider';
|
|
5
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
|
+
import { Session } from '../schemas/session.schema';
|
|
5
7
|
export declare abstract class InventoryProvider<T extends Inventory = Inventory, Q extends InventoryQuery = InventoryQuery, M extends InventoryMutation = InventoryMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(query: Q, _session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -2,5 +2,8 @@ import { Price } from '../schemas/models/price.model';
|
|
|
2
2
|
import { PriceMutation } from '../schemas/mutations/price.mutation';
|
|
3
3
|
import { PriceQuery } from '../schemas/queries/price.query';
|
|
4
4
|
import { BaseProvider } from './base.provider';
|
|
5
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
|
+
import { Session } from '../schemas/session.schema';
|
|
5
7
|
export declare abstract class PriceProvider<T extends Price = Price, Q extends PriceQuery = PriceQuery, M extends PriceMutation = PriceMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(query: Q, _session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -2,5 +2,8 @@ import { Product } from '../schemas/models/product.model';
|
|
|
2
2
|
import { ProductMutation } from '../schemas/mutations/product.mutation';
|
|
3
3
|
import { ProductQuery } from '../schemas/queries/product.query';
|
|
4
4
|
import { BaseProvider } from './base.provider';
|
|
5
|
+
import { Session } from '../schemas/session.schema';
|
|
6
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
5
7
|
export declare abstract class ProductProvider<T extends Product = Product, Q extends ProductQuery = ProductQuery, M extends ProductMutation = ProductMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(query: Q, _session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -2,5 +2,8 @@ import { SearchResult } from '../schemas/models/search.model';
|
|
|
2
2
|
import { SearchQuery } from '../schemas/queries/search.query';
|
|
3
3
|
import { SearchMutation } from '../schemas/mutations/search.mutation';
|
|
4
4
|
import { BaseProvider } from './base.provider';
|
|
5
|
+
import { CacheEvaluation } from '../cache/cache-evaluation.interface';
|
|
6
|
+
import { Session } from '../schemas/session.schema';
|
|
5
7
|
export declare abstract class SearchProvider<T extends SearchResult = SearchResult, Q extends SearchQuery = SearchQuery, M extends SearchMutation = SearchMutation> extends BaseProvider<T, Q, M> {
|
|
8
|
+
protected getCacheEvaluation(query: Q, _session: Session): CacheEvaluation;
|
|
6
9
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { BaseQuery } from "../schemas/queries/base.query";
|
|
2
|
-
import { Session } from "../schemas/session.schema";
|
|
3
|
-
export interface CachingStrategyEvaluation {
|
|
4
|
-
key: string;
|
|
5
|
-
cacheDurationInSeconds: number;
|
|
6
|
-
canCache: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface CachingStrategy {
|
|
9
|
-
get(query: BaseQuery, session: Session): CachingStrategyEvaluation;
|
|
10
|
-
}
|
|
11
|
-
export declare class BaseCachingStrategy implements CachingStrategy {
|
|
12
|
-
get(query: BaseQuery, session: Session): CachingStrategyEvaluation;
|
|
13
|
-
}
|