@reactionary/source 0.0.41 → 0.0.48

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.
Files changed (125) hide show
  1. package/.claude/settings.local.json +28 -0
  2. package/.env-template +8 -5
  3. package/.vscode/settings.json +5 -0
  4. package/README.md +41 -0
  5. package/core/package.json +3 -1
  6. package/core/src/cache/cache.interface.ts +14 -18
  7. package/core/src/cache/memory-cache.ts +56 -0
  8. package/core/src/cache/noop-cache.ts +5 -23
  9. package/core/src/cache/redis-cache.ts +28 -38
  10. package/core/src/client/client-builder.ts +3 -3
  11. package/core/src/client/client.ts +11 -9
  12. package/core/src/decorators/reactionary.decorator.ts +80 -8
  13. package/core/src/index.ts +5 -29
  14. package/core/src/initialization.ts +43 -0
  15. package/core/src/providers/analytics.provider.ts +1 -1
  16. package/core/src/providers/base.provider.ts +61 -25
  17. package/core/src/providers/cart-payment.provider.ts +57 -0
  18. package/core/src/providers/cart.provider.ts +131 -8
  19. package/core/src/providers/category.provider.ts +9 -9
  20. package/core/src/providers/identity.provider.ts +8 -7
  21. package/core/src/providers/index.ts +12 -0
  22. package/core/src/providers/inventory.provider.ts +4 -4
  23. package/core/src/providers/price.provider.ts +7 -7
  24. package/core/src/providers/product.provider.ts +17 -5
  25. package/core/src/providers/profile.provider.ts +22 -0
  26. package/core/src/providers/search.provider.ts +4 -4
  27. package/core/src/providers/store.provider.ts +14 -0
  28. package/core/src/schemas/capabilities.schema.ts +3 -1
  29. package/core/src/schemas/models/analytics.model.ts +1 -1
  30. package/core/src/schemas/models/cart.model.ts +16 -3
  31. package/core/src/schemas/models/identifiers.model.ts +90 -22
  32. package/core/src/schemas/models/identity.model.ts +23 -7
  33. package/core/src/schemas/models/index.ts +15 -0
  34. package/core/src/schemas/models/payment.model.ts +41 -0
  35. package/core/src/schemas/models/profile.model.ts +35 -0
  36. package/core/src/schemas/models/shipping-method.model.ts +14 -0
  37. package/core/src/schemas/models/store.model.ts +11 -0
  38. package/core/src/schemas/mutations/cart-payment.mutation.ts +21 -0
  39. package/core/src/schemas/mutations/cart.mutation.ts +62 -3
  40. package/core/src/schemas/mutations/identity.mutation.ts +8 -1
  41. package/core/src/schemas/mutations/index.ts +10 -0
  42. package/core/src/schemas/mutations/profile.mutation.ts +9 -0
  43. package/core/src/schemas/queries/cart-payment.query.ts +12 -0
  44. package/core/src/schemas/queries/cart.query.ts +1 -1
  45. package/core/src/schemas/queries/identity.query.ts +1 -1
  46. package/core/src/schemas/queries/index.ts +3 -0
  47. package/core/src/schemas/queries/inventory.query.ts +4 -12
  48. package/core/src/schemas/queries/price.query.ts +1 -1
  49. package/core/src/schemas/queries/profile.query.ts +7 -0
  50. package/core/src/schemas/queries/search.query.ts +1 -1
  51. package/core/src/schemas/queries/store.query.ts +11 -0
  52. package/core/src/schemas/session.schema.ts +31 -6
  53. package/eslint.config.mjs +7 -0
  54. package/examples/next/src/app/page.tsx +4 -12
  55. package/examples/node/package.json +1 -3
  56. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +9 -8
  57. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +4 -3
  58. package/examples/node/src/basic/basic-node-setup.spec.ts +4 -5
  59. package/nx.json +1 -0
  60. package/otel/src/metrics.ts +2 -1
  61. package/otel/src/provider-instrumentation.ts +2 -1
  62. package/otel/src/tracer.ts +7 -6
  63. package/otel/src/trpc-middleware.ts +3 -2
  64. package/package.json +2 -1
  65. package/providers/algolia/src/core/initialize.ts +4 -3
  66. package/providers/algolia/src/providers/product.provider.ts +15 -13
  67. package/providers/algolia/src/providers/search.provider.ts +9 -9
  68. package/providers/algolia/src/schema/capabilities.schema.ts +1 -1
  69. package/providers/algolia/src/test/search.provider.spec.ts +10 -10
  70. package/providers/algolia/src/test/test-utils.ts +9 -4
  71. package/providers/commercetools/README.md +27 -0
  72. package/providers/commercetools/src/core/client.ts +164 -117
  73. package/providers/commercetools/src/core/initialize.ts +24 -14
  74. package/providers/commercetools/src/providers/cart-payment.provider.ts +193 -0
  75. package/providers/commercetools/src/providers/cart.provider.ts +402 -125
  76. package/providers/commercetools/src/providers/category.provider.ts +35 -35
  77. package/providers/commercetools/src/providers/identity.provider.ts +23 -75
  78. package/providers/commercetools/src/providers/index.ts +2 -0
  79. package/providers/commercetools/src/providers/inventory.provider.ts +69 -40
  80. package/providers/commercetools/src/providers/price.provider.ts +79 -47
  81. package/providers/commercetools/src/providers/product.provider.ts +36 -30
  82. package/providers/commercetools/src/providers/profile.provider.ts +61 -0
  83. package/providers/commercetools/src/providers/search.provider.ts +16 -12
  84. package/providers/commercetools/src/providers/store.provider.ts +78 -0
  85. package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
  86. package/providers/commercetools/src/schema/commercetools.schema.ts +18 -0
  87. package/providers/commercetools/src/schema/configuration.schema.ts +2 -1
  88. package/providers/commercetools/src/test/cart-payment.provider.spec.ts +145 -0
  89. package/providers/commercetools/src/test/cart.provider.spec.ts +82 -22
  90. package/providers/commercetools/src/test/category.provider.spec.ts +18 -17
  91. package/providers/commercetools/src/test/identity.provider.spec.ts +88 -0
  92. package/providers/commercetools/src/test/inventory.provider.spec.ts +41 -0
  93. package/providers/commercetools/src/test/price.provider.spec.ts +9 -8
  94. package/providers/commercetools/src/test/product.provider.spec.ts +33 -5
  95. package/providers/commercetools/src/test/profile.provider.spec.ts +49 -0
  96. package/providers/commercetools/src/test/search.provider.spec.ts +8 -7
  97. package/providers/commercetools/src/test/store.provider.spec.ts +37 -0
  98. package/providers/commercetools/src/test/test-utils.ts +7 -31
  99. package/providers/fake/src/core/initialize.ts +96 -38
  100. package/providers/fake/src/providers/analytics.provider.ts +6 -5
  101. package/providers/fake/src/providers/cart.provider.ts +66 -19
  102. package/providers/fake/src/providers/category.provider.ts +12 -12
  103. package/providers/fake/src/providers/identity.provider.ts +22 -14
  104. package/providers/fake/src/providers/index.ts +1 -0
  105. package/providers/fake/src/providers/inventory.provider.ts +13 -13
  106. package/providers/fake/src/providers/price.provider.ts +13 -13
  107. package/providers/fake/src/providers/product.provider.ts +13 -10
  108. package/providers/fake/src/providers/search.provider.ts +7 -5
  109. package/providers/fake/src/providers/store.provider.ts +47 -0
  110. package/providers/fake/src/schema/capabilities.schema.ts +4 -1
  111. package/providers/fake/src/test/cart.provider.spec.ts +18 -18
  112. package/providers/fake/src/test/category.provider.spec.ts +55 -37
  113. package/providers/fake/src/test/price.provider.spec.ts +9 -14
  114. package/providers/fake/src/test/product.provider.spec.ts +27 -0
  115. package/providers/fake/src/test/test-utils.ts +2 -28
  116. package/providers/posthog/src/core/initialize.ts +3 -3
  117. package/providers/posthog/src/schema/capabilities.schema.ts +1 -1
  118. package/trpc/src/client.ts +42 -41
  119. package/trpc/src/index.ts +4 -3
  120. package/trpc/src/integration.spec.ts +11 -11
  121. package/trpc/src/server.ts +26 -24
  122. package/trpc/src/test-utils.ts +9 -4
  123. package/trpc/src/types.ts +24 -22
  124. package/core/src/cache/cache-evaluation.interface.ts +0 -19
  125. package/examples/node/src/test-utils.ts +0 -26
@@ -0,0 +1,28 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npx nx build:*)",
5
+ "Bash(npx tsc:*)",
6
+ "Bash(npx nx lint:*)",
7
+ "Bash(npx nx test:*)",
8
+ "Bash(npx nx run:*)",
9
+ "Bash(npx ts-node:*)",
10
+ "Bash(npx tsx:*)",
11
+ "Bash(grep:*)",
12
+ "Bash(pnpm list:*)",
13
+ "Bash(npx nx affected:build:*)",
14
+ "Bash(npx nx affected:lint:*)",
15
+ "Bash(cat:*)",
16
+ "Bash(npx nx show projects:*)",
17
+ "Bash(npx nx g:*)",
18
+ "Bash(pnpm add:*)",
19
+ "Bash(npx nx show project:*)",
20
+ "Bash(npx nx reset:*)",
21
+ "WebSearch",
22
+ "Bash(node:*)",
23
+ "Bash(npm view:*)"
24
+ ],
25
+ "deny": [],
26
+ "ask": []
27
+ }
28
+ }
package/.env-template CHANGED
@@ -1,8 +1,11 @@
1
- COMMERCETOOLS_API_URL=https://api.europe-west1.gcp.commercetools.com
2
- COMMERCETOOLS_AUTH_URL=https://auth.europe-west1.gcp.commercetools.com
3
- COMMERCETOOLS_CLIENT_ID=
4
- COMMERCETOOLS_CLIENT_SECRET=
5
- COMMERCETOOLS_PROJECT_KEY=
1
+ CTP_PROJECT_KEY=
2
+ CTP_CLIENT_SECRET=
3
+ CTP_CLIENT_ID=
4
+ CTP_AUTH_URL=https://auth.europe-west1.gcp.commercetools.com
5
+ CTP_API_URL=https://api.europe-west1.gcp.commercetools.com
6
+ CTP_SCOPES=
7
+
8
+
6
9
 
7
10
  OTEL_SERVICE_NAME=reactionary
8
11
  OTEL_LOG_LEVEL=info
@@ -0,0 +1,5 @@
1
+ {
2
+ "typescript.preferences.importModuleSpecifierEnding": "auto",
3
+ "typescript.preferences.importModuleSpecifier": "relative",
4
+ "typescript.preferences.preferTypeOnlyAutoImports": true
5
+ }
package/README.md CHANGED
@@ -37,3 +37,44 @@ The following is a short list of commonly used terms and phrases, to keep guessi
37
37
  - *Fake:* an implementation that provides a functional response, but with in a limited capacity. A fake provider may, for example, provide *Cart* functionality, but only store it in-memory and throw it away on a whim. As such it can be used for prototyping, but never for a production scenario.
38
38
  - *Product Analytics:* structured analytics that relate to how the the product is being used.
39
39
  - *Microsite:* an application of a limited scope. It may focus solely on this limited functionality, making it ideal for demonstration purposes.
40
+
41
+
42
+
43
+ ## TODO:
44
+
45
+
46
+
47
+ ### Core
48
+ - [ ] Figure a way to get a correlation id from the caller
49
+ - [ ] Maybe rework session so its not languageContext but requestContext, and this could have the correlation id in it?
50
+
51
+
52
+ ### Search
53
+ - [ ] Add support for filters, not just facets
54
+
55
+ ### Marketing
56
+ - [ ] Add marketing provider (input: (name, url, user, segments, productid, categoryid) => output { Array<Product | Category | Image | Text>}
57
+
58
+
59
+ ### Inventory
60
+ - [ ] Invent and document some notational standard for cannel-key to purpose.
61
+ - [ ] Be traced and cached
62
+
63
+ ### Profile
64
+ - [ ] Be able to register new account
65
+ - [ ] Create profile provider
66
+
67
+
68
+ ### Organization
69
+ - [ ] Create organization provider
70
+ - [ ] Create business user provider
71
+ - [ ] Create role provider
72
+
73
+ ### Cart
74
+ - [ ] Add B2B/organization identifier
75
+
76
+ ### Price
77
+ - [ ] Add list price
78
+
79
+ ### Order
80
+ - [ ] Add Order
package/core/package.json CHANGED
@@ -5,6 +5,8 @@
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
7
  "zod": "4.1.9",
8
- "@upstash/redis": "^1.34.9"
8
+ "@upstash/redis": "^1.34.9",
9
+ "@reactionary/otel": "0.0.1",
10
+ "node-object-hash": "^3.1.1"
9
11
  }
10
12
  }
@@ -1,4 +1,10 @@
1
- import { z } from 'zod';
1
+ import type { z } from 'zod';
2
+ import type { BaseModel } from '../schemas/models';
3
+
4
+ export interface CacheEntryOptions {
5
+ ttlSeconds: number;
6
+ dependencyIds: Array<string>;
7
+ }
2
8
 
3
9
  /**
4
10
  * Generic cache interface that can be implemented by different cache backends
@@ -8,31 +14,21 @@ export interface Cache {
8
14
  /**
9
15
  * Retrieves a value from cache and validates it against the provided schema
10
16
  */
11
- get<T>(key: string, schema: z.ZodType<T>): Promise<T | null>;
17
+ get<T extends BaseModel>(key: string, schema: z.ZodType<T>): Promise<T | null>;
12
18
 
13
19
  /**
14
20
  * Stores a value in cache with optional expiration time
15
21
  */
16
- put(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
17
-
18
- /**
19
- * Removes one or more keys from cache
20
- * Supports wildcard patterns (implementation dependent)
21
- */
22
- del(keys: string | string[]): Promise<void>;
23
-
24
- /**
25
- * Finds all keys matching a pattern (implementation dependent)
26
- */
27
- keys(pattern: string): Promise<string[]>;
22
+ put(key: string, value: unknown, options: CacheEntryOptions): Promise<void>;
28
23
 
29
24
  /**
30
- * Clears all cache entries or entries matching a pattern
25
+ * Removes entries from the cache based on a set of dependency
26
+ * ids
31
27
  */
32
- clear(pattern?: string): Promise<void>;
28
+ invalidate(dependencyIds: Array<string>): Promise<void>;
33
29
 
34
30
  /**
35
- * Gets basic cache statistics (implementation dependent)
31
+ * Removes all entries from cache, wiping it completely
36
32
  */
37
- getStats(): Promise<{ hits: number; misses: number; size: number }>;
33
+ clear(): Promise<void>;
38
34
  }
@@ -0,0 +1,56 @@
1
+ import type { BaseModel } from '../schemas/models';
2
+ import type { Cache, CacheEntryOptions } from './cache.interface';
3
+ import type z from 'zod';
4
+
5
+ /**
6
+ * Memory version of the cache. Primarily useful for local development.
7
+ * This is NOT suited for production use.
8
+ */
9
+ export class MemoryCache implements Cache {
10
+ protected entries = new Array<{ key: string; value: unknown, options: CacheEntryOptions }>();
11
+
12
+ public async get<T extends BaseModel>(key: string, schema: z.ZodType<T>): Promise<T | null> {
13
+ const c = this.entries.find((x) => x.key === key);
14
+
15
+ if (!c) {
16
+ return null;
17
+ }
18
+
19
+ const parsed = schema.parse(c.value);
20
+
21
+ parsed.meta.cache.hit = true;
22
+
23
+ return parsed;
24
+ }
25
+
26
+ public async put(
27
+ key: string,
28
+ value: unknown,
29
+ options: CacheEntryOptions
30
+ ): Promise<void> {
31
+ this.entries.push({
32
+ key,
33
+ value,
34
+ options
35
+ });
36
+
37
+ return;
38
+ }
39
+
40
+ public async invalidate(dependencyIds: Array<string>): Promise<void> {
41
+ let index = 0;
42
+ for (const entry of this.entries) {
43
+ for (const entryDependency of entry.options.dependencyIds) {
44
+ if (dependencyIds.indexOf(entryDependency) > -1) {
45
+ this.entries.splice(index, 1);
46
+ }
47
+ }
48
+
49
+ index++;
50
+ }
51
+ }
52
+
53
+ public async clear(): Promise<void> {
54
+ this.entries = [];
55
+ }
56
+ }
@@ -1,5 +1,5 @@
1
- import { Cache } from './cache.interface';
2
- import z from 'zod';
1
+ import type { Cache, CacheEntryOptions } from './cache.interface';
2
+ import type z from 'zod';
3
3
 
4
4
  /**
5
5
  * No-op cache implementation that never stores or returns data.
@@ -7,36 +7,18 @@ import z from 'zod';
7
7
  */
8
8
  export class NoOpCache implements Cache {
9
9
  public async get<T>(_key: string, _schema: z.ZodType<T>): Promise<T | null> {
10
- // Always return null - never a cache hit
11
10
  return null;
12
11
  }
13
12
 
14
- public async put(_key: string, _value: unknown, _ttlSeconds?: number): Promise<void> {
15
- // No-op - silently ignore cache write requests
13
+ public async put(_key: string, _value: unknown, options: CacheEntryOptions): Promise<void> {
16
14
  return;
17
15
  }
18
16
 
19
- public async del(_keys: string | string[]): Promise<void> {
20
- // No-op - silently ignore delete requests
17
+ public async invalidate(dependencyIds: Array<string>): Promise<void> {
21
18
  return;
22
19
  }
23
20
 
24
- public async keys(_pattern: string): Promise<string[]> {
25
- // Always return empty array
26
- return [];
27
- }
28
-
29
- public async clear(_pattern?: string): Promise<void> {
30
- // No-op - silently ignore clear requests
21
+ public async clear(): Promise<void> {
31
22
  return;
32
23
  }
33
-
34
- public async getStats(): Promise<{ hits: number; misses: number; size: number }> {
35
- // Always return zeros
36
- return {
37
- hits: 0,
38
- misses: 0,
39
- size: 0
40
- };
41
- }
42
24
  }
@@ -1,6 +1,6 @@
1
1
  import { Redis } from '@upstash/redis';
2
- import { Cache } from './cache.interface';
3
- import z from 'zod';
2
+ import type { Cache, CacheEntryOptions } from './cache.interface';
3
+ import type z from 'zod';
4
4
 
5
5
  export class RedisCache implements Cache {
6
6
  protected redis: Redis;
@@ -13,62 +13,52 @@ export class RedisCache implements Cache {
13
13
  if (!key) {
14
14
  return null;
15
15
  }
16
-
16
+
17
17
  const unvalidated = await this.redis.get(key);
18
18
  const parsed = schema.safeParse(unvalidated);
19
19
 
20
20
  if (parsed.success) {
21
21
  return parsed.data;
22
22
  }
23
-
23
+
24
24
  return null;
25
25
  }
26
26
 
27
- public async put(key: string, value: unknown, ttlSeconds?: number): Promise<void> {
27
+ public async put(
28
+ key: string,
29
+ value: unknown,
30
+ options: CacheEntryOptions
31
+ ): Promise<void> {
28
32
  if (!key) {
29
33
  return;
30
34
  }
31
35
 
32
- const options = ttlSeconds ? { ex: ttlSeconds } : undefined;
33
- await this.redis.set(key, value, options);
34
- }
36
+ const serialized = JSON.stringify(value);
37
+ const multi = this.redis.multi();
35
38
 
36
- public async del(keys: string | string[]): Promise<void> {
37
- const keyArray = Array.isArray(keys) ? keys : [keys];
38
-
39
- for (const key of keyArray) {
40
- if (key.includes('*')) {
41
- // Handle wildcard patterns
42
- const matchingKeys = await this.redis.keys(key);
43
- if (matchingKeys.length > 0) {
44
- await this.redis.del(...matchingKeys);
45
- }
46
- } else {
47
- // Delete specific key
48
- await this.redis.del(key);
49
- }
39
+ multi.set(key, serialized, { ex: options.ttlSeconds });
40
+
41
+ for (const depId of options.dependencyIds) {
42
+ multi.sadd(`dep:${depId}`, key);
50
43
  }
51
- }
52
44
 
53
- public async keys(pattern: string): Promise<string[]> {
54
- return await this.redis.keys(pattern);
45
+ await multi.exec();
55
46
  }
56
47
 
57
- public async clear(pattern?: string): Promise<void> {
58
- const searchPattern = pattern || '*';
59
- const keys = await this.redis.keys(searchPattern);
60
- if (keys.length > 0) {
61
- await this.redis.del(...keys);
48
+ public async invalidate(dependencyIds: Array<string>): Promise<void> {
49
+ for (const id of dependencyIds) {
50
+ const depKey = `dep:${id}`;
51
+ const keys = await this.redis.smembers(depKey);
52
+
53
+ if (keys.length > 0) {
54
+ await this.redis.del(...keys);
55
+ }
56
+
57
+ await this.redis.del(depKey);
62
58
  }
63
59
  }
64
60
 
65
- public async getStats(): Promise<{ hits: number; misses: number; size: number }> {
66
- // Basic cache statistics (could be enhanced with actual Redis metrics)
67
- const keys = await this.redis.keys('*');
68
- return {
69
- hits: 0, // Would need to track this separately
70
- misses: 0, // Would need to track this separately
71
- size: keys.length
72
- };
61
+ public async clear(): Promise<void> {
62
+ // Not sure about supporting this on Redis.
73
63
  }
74
64
  }
@@ -1,7 +1,7 @@
1
- import { Cache } from "../cache/cache.interface";
1
+ import type { Cache } from "../cache/cache.interface";
2
2
  import { NoOpCache } from "../cache/noop-cache";
3
- import { Client } from "./client";
4
- import { AnalyticsProvider } from "../providers/analytics.provider";
3
+ import type { Client } from "./client";
4
+ import type { AnalyticsProvider } from "../providers/analytics.provider";
5
5
 
6
6
  type CapabilityFactory<T> = (cache: Cache) => T;
7
7
 
@@ -1,13 +1,14 @@
1
- import { AnalyticsProvider } from "../providers/analytics.provider";
2
- import { ProductProvider } from "../providers/product.provider";
3
- import { SearchProvider } from "../providers/search.provider";
4
- import { IdentityProvider } from '../providers/identity.provider';
5
- import { CartProvider } from "../providers/cart.provider";
6
- import { PriceProvider } from "../providers/price.provider";
7
- import { InventoryProvider } from "../providers/inventory.provider";
8
- import { Cache } from "../cache/cache.interface";
1
+ import type { AnalyticsProvider } from "../providers/analytics.provider";
2
+ import type { ProductProvider } from "../providers/product.provider";
3
+ import type { SearchProvider } from "../providers/search.provider";
4
+ import type { IdentityProvider } from '../providers/identity.provider';
5
+ import type { CartProvider } from "../providers/cart.provider";
6
+ import type { PriceProvider } from "../providers/price.provider";
7
+ import type { InventoryProvider } from "../providers/inventory.provider";
8
+ import type { Cache } from "../cache/cache.interface";
9
9
  import { RedisCache } from "../cache/redis-cache";
10
- import { CategoryProvider } from "../providers/category.provider";
10
+ import type { CategoryProvider } from "../providers/category.provider";
11
+ import type { CartPaymentProvider } from "../providers";
11
12
 
12
13
  export interface Client {
13
14
  product: ProductProvider,
@@ -15,6 +16,7 @@ export interface Client {
15
16
  identity: IdentityProvider,
16
17
  cache: Cache,
17
18
  cart: CartProvider,
19
+ cartPayment: CartPaymentProvider,
18
20
  analytics: Array<AnalyticsProvider>,
19
21
  price: PriceProvider,
20
22
  inventory: InventoryProvider,
@@ -1,16 +1,88 @@
1
- export function Reactionary(options: unknown): MethodDecorator {
1
+ import type { BaseProvider } from '../providers';
2
+ import { getTracer, SpanKind } from '@reactionary/otel';
3
+
4
+ /**
5
+ * The options associated with annotating a provider function and marking
6
+ * it as a reactionary entrypoint to be called
7
+ */
8
+ export class ReactionaryDecoratorOptions {
9
+ /**
10
+ * Whether or not the query is eligible for caching. Queries that depend
11
+ * heavily on personalization, for example, are likely to be a poor fit
12
+ * for caching.
13
+ */
14
+ public cache = false;
15
+
16
+ /**
17
+ * Whether or not the cache entry should be variable based on the locale
18
+ * of the context in which it is querried.
19
+ */
20
+ public localeDependentCaching = false;
21
+
22
+ /**
23
+ * Whether or not the cache entry should be variable based on the currency
24
+ * of the context in which it is querried.
25
+ */
26
+ public currencyDependentCaching = false;
27
+
28
+ /**
29
+ * The number of seconds which a cache entry should be considered valid for the
30
+ * given query.
31
+ */
32
+ public cacheTimeToLiveInSeconds = 60;
33
+
34
+ };
35
+
36
+ /**
37
+ * Decorator for provider functions to provide functionality such as caching, tracing and type-checked
38
+ * assertion through Zod. It should only be used with publically accessible queries or mutations on
39
+ * providers.
40
+ */
41
+ export function Reactionary(options: Partial<ReactionaryDecoratorOptions>) {
2
42
  return function (
3
- target: any,
43
+ target: BaseProvider,
4
44
  propertyKey: string | symbol,
5
45
  descriptor: PropertyDescriptor
6
46
  ): PropertyDescriptor {
7
47
  const original = descriptor.value;
8
-
9
- descriptor.value = function (...args: any[]) {
10
- console.log('calling through reactionary decoration!');
11
- return original.apply(this, args);
48
+ const scope = `${target.constructor.name}.${propertyKey.toString()}`;
49
+ const configuration = { ...new ReactionaryDecoratorOptions(), ...options };
50
+
51
+ if (!original) {
52
+ throw new Error(
53
+ '@Reactionary decorator may only be applied to methods on classes extending BaseProvider.'
54
+ );
55
+ }
56
+
57
+ descriptor.value = async function (this: BaseProvider, ...args: any[]) {
58
+ const tracer = getTracer();
59
+
60
+ return tracer.startActiveSpan(
61
+ propertyKey.toString(),
62
+ { kind: SpanKind.SERVER },
63
+ async (span) => {
64
+ const cacheKey = this.generateCacheKeyForQuery(scope, args[0]);
65
+
66
+ const fromCache = await this.cache.get(cacheKey, this.schema);
67
+ let result = fromCache;
68
+
69
+ if (!result) {
70
+ result = await original.apply(this, args);
71
+
72
+ const dependencyIds = this.generateDependencyIdsForModel(result);
73
+
74
+ this.cache.put(cacheKey, result, {
75
+ ttlSeconds: configuration.cacheTimeToLiveInSeconds,
76
+ dependencyIds: dependencyIds
77
+ });
78
+ }
79
+
80
+ span.end();
81
+ return this.assert(result as any);
82
+ }
83
+ );
12
84
  };
13
-
85
+
14
86
  return descriptor;
15
87
  };
16
- }
88
+ }
package/core/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from './cache/cache.interface';
2
- export * from './cache/cache-evaluation.interface';
3
2
  export * from './cache/redis-cache';
3
+ export * from './cache/memory-cache';
4
4
  export * from './cache/noop-cache';
5
5
 
6
6
  export * from './client/client';
@@ -8,36 +8,12 @@ export * from './client/client-builder';
8
8
 
9
9
  export * from './decorators/reactionary.decorator';
10
10
 
11
- export * from './providers/analytics.provider';
12
- export * from './providers/base.provider';
13
- export * from './providers/cart.provider';
14
- export * from './providers/identity.provider';
15
- export * from './providers/inventory.provider';
16
- export * from './providers/price.provider';
17
- export * from './providers/product.provider';
18
- export * from './providers/search.provider';
19
- export * from './providers/category.provider';
11
+ export * from './providers/'
20
12
 
21
13
  export * from './schemas/capabilities.schema';
22
14
  export * from './schemas/session.schema';
23
15
 
24
- export * from './schemas/models/base.model';
25
- export * from './schemas/models/cart.model';
26
- export * from './schemas/models/currency.model';
27
- export * from './schemas/models/identifiers.model';
28
- export * from './schemas/models/identity.model';
29
- export * from './schemas/models/inventory.model';
30
- export * from './schemas/models/price.model';
31
- export * from './schemas/models/product.model';
32
- export * from './schemas/models/search.model';
33
- export * from './schemas/models/category.model';
34
-
35
- export * from './schemas/mutations/base.mutation';
36
- export * from './schemas/mutations/cart.mutation';
37
- export * from './schemas/mutations/identity.mutation';
38
- export * from './schemas/mutations/inventory.mutation';
39
- export * from './schemas/mutations/price.mutation';
40
- export * from './schemas/mutations/product.mutation';
41
- export * from './schemas/mutations/search.mutation';
42
-
16
+ export * from './schemas/models/';
17
+ export * from './schemas/mutations/';
43
18
  export * from './schemas/queries';
19
+ export * from './initialization';
@@ -0,0 +1,43 @@
1
+ import type { RequestContext } from "./schemas/session.schema";
2
+
3
+ export function createInitialRequestContext(): RequestContext {
4
+ return {
5
+ id: '',
6
+ identity: {
7
+ type: 'Anonymous',
8
+ meta: {
9
+ cache: { hit: false, key: '' },
10
+ placeholder: false,
11
+ },
12
+ id: { userId: 'anonymous' },
13
+ token: undefined,
14
+ issued: new Date(),
15
+ expiry: new Date(new Date().getTime() + 3600 * 1000),
16
+ logonId: '',
17
+ createdAt: '',
18
+ updatedAt: '',
19
+ keyring: [],
20
+ currentService: undefined,
21
+ },
22
+ languageContext: {
23
+ locale: 'en-US',
24
+ currencyCode: 'USD',
25
+ },
26
+ storeIdentifier: {
27
+ key: 'the-good-store',
28
+ },
29
+ taxJurisdiction: {
30
+ countryCode: 'US',
31
+ stateCode: '',
32
+ countyCode: '',
33
+ cityCode: '',
34
+ },
35
+ session: {},
36
+
37
+ correlationId: '',
38
+ isBot: false,
39
+ clientIp: '',
40
+ userAgent: '',
41
+ referrer: '',
42
+ };
43
+ }
@@ -1,4 +1,4 @@
1
- import { AnalyticsEvent } from '../schemas/models/analytics.model';
1
+ import type { AnalyticsEvent } from '../schemas/models/analytics.model';
2
2
  import { BaseProvider } from './base.provider';
3
3
 
4
4
  export abstract class AnalyticsProvider<