@reactionary/source 0.0.39 → 0.0.41

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 (52) hide show
  1. package/core/package.json +1 -1
  2. package/core/src/decorators/reactionary.decorator.ts +16 -0
  3. package/core/src/index.ts +2 -0
  4. package/core/src/schemas/capabilities.schema.ts +1 -1
  5. package/core/src/schemas/models/base.model.ts +5 -5
  6. package/core/src/schemas/models/cart.model.ts +1 -1
  7. package/core/src/schemas/models/identifiers.model.ts +12 -12
  8. package/core/src/schemas/models/price.model.ts +1 -1
  9. package/core/src/schemas/models/product.model.ts +2 -2
  10. package/core/src/schemas/models/search.model.ts +3 -3
  11. package/core/src/schemas/mutations/base.mutation.ts +1 -1
  12. package/core/src/schemas/mutations/cart.mutation.ts +6 -6
  13. package/core/src/schemas/mutations/inventory.mutation.ts +0 -4
  14. package/core/src/schemas/mutations/price.mutation.ts +0 -4
  15. package/core/src/schemas/mutations/product.mutation.ts +0 -4
  16. package/core/src/schemas/mutations/search.mutation.ts +0 -4
  17. package/core/src/schemas/queries/analytics.query.ts +0 -4
  18. package/core/src/schemas/queries/base.query.ts +1 -1
  19. package/core/src/schemas/queries/cart.query.ts +0 -1
  20. package/core/src/schemas/queries/inventory.query.ts +0 -4
  21. package/examples/next/src/app/page.tsx +20 -15
  22. package/examples/node/package.json +3 -1
  23. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +13 -5
  24. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +11 -1
  25. package/examples/node/src/basic/basic-node-setup.spec.ts +7 -3
  26. package/examples/node/src/test-utils.ts +26 -0
  27. package/otel/src/trace-decorator.ts +6 -5
  28. package/package.json +5 -4
  29. package/providers/algolia/package.json +1 -1
  30. package/providers/algolia/src/schema/configuration.schema.ts +1 -1
  31. package/providers/algolia/src/test/search.provider.spec.ts +29 -20
  32. package/providers/algolia/src/test/test-utils.ts +26 -0
  33. package/providers/commercetools/package.json +2 -2
  34. package/providers/commercetools/src/core/client.ts +26 -2
  35. package/providers/commercetools/src/core/initialize.ts +32 -6
  36. package/providers/commercetools/src/providers/cart.provider.ts +6 -4
  37. package/providers/commercetools/src/providers/category.provider.ts +2 -2
  38. package/providers/commercetools/src/providers/price.provider.ts +2 -1
  39. package/providers/commercetools/src/providers/search.provider.ts +33 -12
  40. package/providers/commercetools/src/schema/configuration.schema.ts +1 -1
  41. package/providers/commercetools/src/test/category.provider.spec.ts +1 -14
  42. package/providers/fake/package.json +1 -1
  43. package/providers/fake/src/core/initialize.ts +6 -8
  44. package/providers/fake/src/schema/configuration.schema.ts +3 -3
  45. package/providers/fake/src/test/category.provider.spec.ts +1 -3
  46. package/providers/posthog/package.json +1 -1
  47. package/providers/posthog/src/schema/configuration.schema.ts +1 -1
  48. package/trpc/package.json +1 -1
  49. package/trpc/src/integration.spec.ts +24 -23
  50. package/trpc/src/test-utils.ts +26 -0
  51. package/trpc/src/transparent-client.spec.ts +22 -26
  52. package/providers/algolia/src/test/product.provider.spec.ts +0 -18
@@ -1,20 +1,27 @@
1
- import { SearchResultSchema } from '@reactionary/core';
1
+ import { NoOpCache, SearchResultSchema } from '@reactionary/core';
2
2
  import { AlgoliaSearchProvider } from '../providers/search.provider';
3
+ import { createAnonymousTestSession } from './test-utils';
3
4
 
4
5
  describe('Algolia Search Provider', () => {
5
- const provider = new AlgoliaSearchProvider({
6
- apiKey: process.env['ALGOLIA_API_KEY'] || '',
7
- appId: process.env['ALGOLIA_APP_ID'] || '',
8
- indexName: process.env['ALGOLIA_INDEX'] || '',
9
- }, SearchResultSchema);
6
+ const provider = new AlgoliaSearchProvider(
7
+ {
8
+ apiKey: process.env['ALGOLIA_API_KEY'] || '',
9
+ appId: process.env['ALGOLIA_APP_ID'] || '',
10
+ indexName: process.env['ALGOLIA_INDEX'] || '',
11
+ },
12
+ SearchResultSchema,
13
+ new NoOpCache()
14
+ );
15
+
16
+ const session = createAnonymousTestSession();
10
17
 
11
18
  it('should be able to get a result by term', async () => {
12
- const result = await provider.get({
19
+ const result = await provider.queryByTerm({ search: {
13
20
  term: 'glass',
14
21
  page: 0,
15
22
  pageSize: 20,
16
23
  facets: [],
17
- });
24
+ }}, session);
18
25
 
19
26
  expect(result.products.length).toBeGreaterThan(0);
20
27
  expect(result.facets.length).toBe(2);
@@ -23,18 +30,19 @@ describe('Algolia Search Provider', () => {
23
30
  });
24
31
 
25
32
  it('should be able to paginate', async () => {
26
- const firstPage = await provider.get({
33
+ const firstPage = await provider.queryByTerm({ search: {
27
34
  term: 'glass',
28
35
  page: 0,
29
36
  pageSize: 20,
30
37
  facets: [],
31
- });
32
- const secondPage = await provider.get({
38
+ }}, session);
39
+
40
+ const secondPage = await provider.queryByTerm({ search: {
33
41
  term: 'glass',
34
42
  page: 1,
35
43
  pageSize: 20,
36
44
  facets: [],
37
- });
45
+ }}, session);
38
46
 
39
47
  expect(firstPage.identifier.page).toBe(0);
40
48
  expect(secondPage.identifier.page).toBe(1);
@@ -44,18 +52,18 @@ describe('Algolia Search Provider', () => {
44
52
  });
45
53
 
46
54
  it('should be able to change page size', async () => {
47
- const smallPage = await provider.get({
55
+ const smallPage = await provider.queryByTerm({ search: {
48
56
  term: 'glass',
49
57
  page: 0,
50
58
  pageSize: 2,
51
59
  facets: [],
52
- });
53
- const largePage = await provider.get({
60
+ }}, session);
61
+ const largePage = await provider.queryByTerm({ search: {
54
62
  term: 'glass',
55
63
  page: 0,
56
64
  pageSize: 30,
57
65
  facets: [],
58
- });
66
+ }}, session);
59
67
 
60
68
  expect(smallPage.products.length).toBe(2);
61
69
  expect(smallPage.identifier.pageSize).toBe(2);
@@ -64,18 +72,19 @@ describe('Algolia Search Provider', () => {
64
72
  });
65
73
 
66
74
  it('should be able to apply facets', async () => {
67
- const initial = await provider.get({
75
+ const initial = await provider.queryByTerm({ search: {
68
76
  term: 'glass',
69
77
  page: 0,
70
78
  pageSize: 2,
71
79
  facets: [],
72
- });
73
- const filtered = await provider.get({
80
+ }}, session);
81
+
82
+ const filtered = await provider.queryByTerm({ search: {
74
83
  term: 'glass',
75
84
  page: 0,
76
85
  pageSize: 2,
77
86
  facets: [initial.facets[0].values[0].identifier],
78
- });
87
+ }}, session);
79
88
 
80
89
  expect(initial.pages).toBeGreaterThan(filtered.pages);
81
90
  });
@@ -0,0 +1,26 @@
1
+ import { Session } from "@reactionary/core";
2
+
3
+ export function createAnonymousTestSession(): Session {
4
+ return {
5
+ id: 'test-session-id',
6
+ identity: {
7
+ type: 'Anonymous',
8
+ meta: {
9
+ cache: { hit: false, key: '' },
10
+ placeholder: false,
11
+ },
12
+ id: '',
13
+ token: undefined,
14
+ issued: new Date(),
15
+ expiry: new Date(new Date().getTime() + 3600 * 1000), // 1 hour from now
16
+ },
17
+ languageContext: {
18
+ locale: 'en-US',
19
+ currencyCode: 'USD',
20
+ countryCode: 'US',
21
+ },
22
+ storeIdentifier: {
23
+ key: 'the-good-store',
24
+ },
25
+ };
26
+ }
@@ -6,8 +6,8 @@
6
6
  "dependencies": {
7
7
  "@reactionary/core": "0.0.1",
8
8
  "@reactionary/otel": "0.0.1",
9
- "zod": "4.0.0-beta.20250430T185432",
10
- "@commercetools/ts-client": "^3.2.2",
9
+ "zod": "4.1.9",
10
+ "@commercetools/ts-client": "^4.2.1",
11
11
  "@commercetools/platform-sdk": "^8.8.0"
12
12
  }
13
13
  }
@@ -2,7 +2,26 @@ import { ClientBuilder } from '@commercetools/ts-client';
2
2
  import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk';
3
3
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
4
4
 
5
- const ANONYMOUS_SCOPES = ['view_published_products', 'manage_shopping_lists', 'view_shipping_methods', 'manage_customers', 'view_product_selections', 'view_categories', 'view_project_settings', 'manage_order_edits', 'view_sessions', 'view_standalone_prices', 'manage_orders', 'view_tax_categories', 'view_cart_discounts', 'view_discount_codes', 'create_anonymous_token', 'manage_sessions', 'view_products', 'view_types'];
5
+ const ANONYMOUS_SCOPES = [
6
+ 'view_published_products',
7
+ 'manage_shopping_lists',
8
+ 'view_shipping_methods',
9
+ 'manage_customers',
10
+ 'view_product_selections',
11
+ 'view_categories',
12
+ 'view_project_settings',
13
+ 'manage_order_edits',
14
+ 'view_sessions',
15
+ 'view_standalone_prices',
16
+ 'manage_orders',
17
+ 'view_tax_categories',
18
+ 'view_cart_discounts',
19
+ 'view_discount_codes',
20
+ 'create_anonymous_token',
21
+ 'manage_sessions',
22
+ 'view_products',
23
+ 'view_types',
24
+ ];
6
25
  const GUEST_SCOPES = [...ANONYMOUS_SCOPES];
7
26
  const REGISTERED_SCOPES = [...GUEST_SCOPES];
8
27
 
@@ -119,7 +138,10 @@ export class CommercetoolsClient {
119
138
  }
120
139
 
121
140
  protected createClientWithToken(token: string) {
122
- const builder = this.createBaseClientBuilder().withExistingTokenFlow(`Bearer ${ token }`, { force: true });
141
+ const builder = this.createBaseClientBuilder().withExistingTokenFlow(
142
+ `Bearer ${token}`,
143
+ { force: true }
144
+ );
123
145
 
124
146
  return createApiBuilderFromCtpClient(builder.build());
125
147
  }
@@ -146,6 +168,8 @@ export class CommercetoolsClient {
146
168
  httpClient: fetch,
147
169
  });
148
170
 
171
+ // CT's telemetry module is currently broken and consequently not included in the above (createTelemetryMiddleware)
172
+
149
173
  return builder;
150
174
  }
151
175
  }
@@ -1,4 +1,20 @@
1
- import { CartSchema, Client, IdentitySchema, InventorySchema, PriceSchema, ProductSchema, SearchResultSchema, Cache, CategorySchema } from "@reactionary/core";
1
+ import {
2
+ CartSchema,
3
+ IdentitySchema,
4
+ InventorySchema,
5
+ PriceSchema,
6
+ ProductSchema,
7
+ SearchResultSchema,
8
+ Cache,
9
+ CategorySchema,
10
+ ProductProvider,
11
+ SearchProvider,
12
+ IdentityProvider,
13
+ CartProvider,
14
+ InventoryProvider,
15
+ PriceProvider,
16
+ CategoryProvider
17
+ } from "@reactionary/core";
2
18
  import { CommercetoolsCapabilities } from "../schema/capabilities.schema";
3
19
  import { CommercetoolsSearchProvider } from "../providers/search.provider";
4
20
  import { CommercetoolsProductProvider } from '../providers/product.provider';
@@ -9,12 +25,21 @@ import { CommercetoolsInventoryProvider } from "../providers/inventory.provider"
9
25
  import { CommercetoolsPriceProvider } from "../providers/price.provider";
10
26
  import { CommercetoolsCategoryProvider } from "../providers/category.provider";
11
27
 
12
- export function withCommercetoolsCapabilities(
28
+ type CommercetoolsClient<T extends CommercetoolsCapabilities> =
29
+ (T['cart'] extends true ? { cart: CartProvider } : object) &
30
+ (T['product'] extends true ? { product: ProductProvider } : object) &
31
+ (T['search'] extends true ? { search: SearchProvider } : object) &
32
+ (T['identity'] extends true ? { identity: IdentityProvider } : object) &
33
+ (T['category'] extends true ? { category: CategoryProvider } : object) &
34
+ (T['inventory'] extends true ? { inventory: InventoryProvider } : object) &
35
+ (T['price'] extends true ? { price: PriceProvider } : object);
36
+
37
+ export function withCommercetoolsCapabilities<T extends CommercetoolsCapabilities>(
13
38
  configuration: CommercetoolsConfiguration,
14
- capabilities: CommercetoolsCapabilities
39
+ capabilities: T
15
40
  ) {
16
- return (cache: Cache) => {
17
- const client: Partial<Client> = {};
41
+ return (cache: Cache): CommercetoolsClient<T> => {
42
+ const client: any = {};
18
43
 
19
44
  if (capabilities.product) {
20
45
  client.product = new CommercetoolsProductProvider(configuration, ProductSchema, cache);
@@ -39,8 +64,9 @@ export function withCommercetoolsCapabilities(
39
64
  if (capabilities.price) {
40
65
  client.price = new CommercetoolsPriceProvider(configuration, PriceSchema, cache);
41
66
  }
67
+
42
68
  if (capabilities.category) {
43
- client.category = new CommercetoolsCategoryProvider(configuration, CategorySchema, cache);
69
+ client.category = new CommercetoolsCategoryProvider(configuration, CategorySchema, cache);
44
70
  }
45
71
 
46
72
  return client;
@@ -1,19 +1,21 @@
1
1
  import {
2
2
  Cart,
3
3
  CartItemSchema,
4
+ CartProvider,
5
+ Cache,
6
+ Currency,
7
+ } from '@reactionary/core';
8
+ import type {
4
9
  CartMutationItemAdd,
5
10
  CartMutationItemQuantityChange,
6
11
  CartMutationItemRemove,
7
- CartProvider,
8
12
  CartQueryById,
9
13
  Session,
10
- Cache,
11
- Currency,
12
14
  } from '@reactionary/core';
13
15
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
14
16
  import { z } from 'zod';
15
17
  import { CommercetoolsClient } from '../core/client';
16
- import { Cart as CTCart } from '@commercetools/platform-sdk';
18
+ import type { Cart as CTCart } from '@commercetools/platform-sdk';
17
19
  import { traced } from '@reactionary/otel';
18
20
 
19
21
 
@@ -1,4 +1,5 @@
1
- import { CategoryProvider, Cache, Category, Session, CategoryIdentifier, PaginationOptions, createPaginatedResponseSchema, CategoryQueryById, CategoryQueryBySlug, CategoryQueryForBreadcrumb, CategoryQueryForChildCategories, CategoryQueryForTopCategories } from "@reactionary/core";
1
+ import { CategoryProvider, Cache, Category, createPaginatedResponseSchema } from "@reactionary/core";
2
+ import type { Session, CategoryQueryById, CategoryQueryBySlug, CategoryQueryForBreadcrumb, CategoryQueryForChildCategories, CategoryQueryForTopCategories } from "@reactionary/core";
2
3
  import z from "zod";
3
4
  import { CommercetoolsConfiguration } from "../schema/configuration.schema";
4
5
  import { CommercetoolsClient } from "../core/client";
@@ -35,7 +36,6 @@ export class CommercetoolsCategoryProvider<
35
36
  const response = await client.withKey({ key: payload.id.key }).get().execute();
36
37
  return this.parseSingle(response.body, session);
37
38
  } catch (error) {
38
- console.error(`Error fetching category by ID ${payload.id.key}:`, error);
39
39
  const dummyCategory = this.newModel();
40
40
  dummyCategory.meta.placeholder = true;
41
41
  dummyCategory.identifier = { key: payload.id.key };
@@ -1,4 +1,5 @@
1
- import { Price, PriceProvider, PriceQueryBySku, Session, Cache, Currency, TieredPriceSchema, MonetaryAmountSchema, TieredPrice } from '@reactionary/core';
1
+ import { Price, PriceProvider, Cache, Currency, TieredPriceSchema, TieredPrice } from '@reactionary/core';
2
+ import type { PriceQueryBySku, Session } from '@reactionary/core';
2
3
  import z from 'zod';
3
4
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
4
5
  import { CommercetoolsClient } from '../core/client';
@@ -1,26 +1,33 @@
1
- import {
2
- SearchProvider,
3
- SearchQueryByTerm,
1
+ import { SearchProvider } from '@reactionary/core';
2
+ import type {
4
3
  SearchResult,
5
4
  SearchResultProduct,
6
- Session,
7
5
  Cache,
6
+ SearchQueryByTerm,
7
+ Session,
8
8
  } from '@reactionary/core';
9
+
9
10
  import { CommercetoolsClient } from '../core/client';
10
11
  import z from 'zod';
11
12
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
13
+ import { traced } from '@reactionary/otel';
12
14
 
13
15
  export class CommercetoolsSearchProvider<
14
16
  T extends SearchResult = SearchResult
15
17
  > extends SearchProvider<T> {
16
18
  protected config: CommercetoolsConfiguration;
17
19
 
18
- constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, cache: Cache) {
20
+ constructor(
21
+ config: CommercetoolsConfiguration,
22
+ schema: z.ZodType<T>,
23
+ cache: Cache
24
+ ) {
19
25
  super(schema, cache);
20
26
 
21
27
  this.config = config;
22
28
  }
23
29
 
30
+ @traced()
24
31
  public override async queryByTerm(
25
32
  payload: SearchQueryByTerm,
26
33
  session: Session
@@ -43,9 +50,23 @@ export class CommercetoolsSearchProvider<
43
50
  return this.parseSearchResult(remote, payload, session);
44
51
  }
45
52
 
46
- protected parseSearchResult(remote: unknown, payload: SearchQueryByTerm, session: Session): T {
53
+ protected parseSearchResult(
54
+ remote: unknown,
55
+ payload: SearchQueryByTerm,
56
+ session: Session
57
+ ): T {
47
58
  const result = this.newModel();
48
- const remoteData = remote as { body: { results: Array<{ id: string; name: Record<string, string>; slug?: Record<string, string>; masterVariant: { images?: Array<{ url?: string }> } }>; total?: number } };
59
+ const remoteData = remote as {
60
+ body: {
61
+ results: Array<{
62
+ id: string;
63
+ name: Record<string, string>;
64
+ slug?: Record<string, string>;
65
+ masterVariant: { images?: Array<{ url?: string }> };
66
+ }>;
67
+ total?: number;
68
+ };
69
+ };
49
70
 
50
71
  result.identifier = payload.search;
51
72
 
@@ -54,20 +75,20 @@ export class CommercetoolsSearchProvider<
54
75
  identifier: { key: p.id },
55
76
  name: p.name[session.languageContext.locale] || p.id,
56
77
  slug: p.slug?.[session.languageContext.locale] || p.id,
57
- image: p.masterVariant.images?.[0]?.url || 'https://placehold.co/400'
78
+ image: p.masterVariant.images?.[0]?.url || 'https://placehold.co/400',
58
79
  };
59
80
 
60
81
  result.products.push(product);
61
82
  }
62
83
 
63
- result.pages = Math.ceil((remoteData.body.total || 0) / payload.search.pageSize);
84
+ result.pages = Math.ceil(
85
+ (remoteData.body.total || 0) / payload.search.pageSize
86
+ );
64
87
  result.meta = {
65
88
  cache: { hit: false, key: payload.search.term },
66
- placeholder: false
89
+ placeholder: false,
67
90
  };
68
91
 
69
92
  return this.assert(result);
70
93
  }
71
-
72
-
73
94
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
 
3
- export const CommercetoolsConfigurationSchema = z.looseInterface({
3
+ export const CommercetoolsConfigurationSchema = z.looseObject({
4
4
  projectKey: z.string(),
5
5
  authUrl: z.string(),
6
6
  apiUrl: z.string(),
@@ -1,11 +1,7 @@
1
1
  import 'dotenv/config'
2
-
3
- import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';
4
-
5
- import { CategorySchema, NoOpCache, ProductSchema, Session } from '@reactionary/core';
2
+ import { CategorySchema, NoOpCache, Session } from '@reactionary/core';
6
3
  import { CommercetoolsCategoryProvider } from '../providers/category.provider';
7
4
  import { createAnonymousTestSession, getCommercetoolsTestConfiguration } from './test-utils';
8
- import { getTracer, shutdownOtel } from '@reactionary/otel';
9
5
 
10
6
  const testData = {
11
7
  topCategories: [
@@ -168,13 +164,4 @@ describe('Commercetools Category Provider', () => {
168
164
  expect(result.meta.placeholder).toBe(true);
169
165
 
170
166
  });
171
-
172
- it('traces execution of getById', async () => {
173
- const tracer = getTracer();
174
- const span = tracer.startSpan('test-span');
175
- const result = await provider.getById({ id: { key: 'home-decor'}}, session);
176
- span.end();
177
- await shutdownOtel();
178
- });
179
-
180
167
  });
@@ -6,7 +6,7 @@
6
6
  "dependencies": {
7
7
  "@reactionary/core": "0.0.1",
8
8
  "@reactionary/otel": "0.0.1",
9
- "zod": "4.0.0-beta.20250430T185432",
9
+ "zod": "4.1.9",
10
10
  "@faker-js/faker": "^9.8.0"
11
11
  }
12
12
  }
@@ -6,13 +6,12 @@ import { FakeCapabilities } from "../schema/capabilities.schema";
6
6
  import { FakeCategoryProvider } from "../providers/category.provider";
7
7
  import { FakeCartProvider } from "../providers";
8
8
 
9
- type FakeClient<T extends FakeCapabilities> = Partial<{
10
- cart: T['cart'] extends true ? CartProvider : never;
11
- product: T['product'] extends true ? ProductProvider : never;
12
- search: T['search'] extends true ? SearchProvider : never;
13
- identity: T['identity'] extends true ? IdentityProvider : never;
14
- category: T['category'] extends true ? CategoryProvider : never;
15
- }>;
9
+ type FakeClient<T extends FakeCapabilities> =
10
+ (T['cart'] extends true ? { cart: CartProvider } : object) &
11
+ (T['product'] extends true ? { product: ProductProvider } : object) &
12
+ (T['search'] extends true ? { search: SearchProvider } : object) &
13
+ (T['identity'] extends true ? { identity: IdentityProvider } : object) &
14
+ (T['category'] extends true ? { category: CategoryProvider } : object);
16
15
 
17
16
  export function withFakeCapabilities<T extends FakeCapabilities>(configuration: FakeConfiguration, capabilities: T) {
18
17
  return (cache: ReactinaryCache): FakeClient<T> => {
@@ -30,7 +29,6 @@ export function withFakeCapabilities<T extends FakeCapabilities>(configuration:
30
29
  client.category = new FakeCategoryProvider(configuration, CategorySchema, cache);
31
30
  }
32
31
 
33
-
34
32
  if (capabilities.cart) {
35
33
  client.cart = new FakeCartProvider(configuration, CartSchema, cache);
36
34
  }
@@ -1,8 +1,8 @@
1
1
  import { z } from 'zod';
2
2
 
3
- export const FakeConfigurationSchema = z.looseInterface({
3
+ export const FakeConfigurationSchema = z.looseObject({
4
4
  jitter: z
5
- .looseInterface({
5
+ .looseObject({
6
6
  mean: z.number().min(0).max(10000),
7
7
  deviation: z.number().min(0).max(5000),
8
8
  })
@@ -10,7 +10,7 @@ export const FakeConfigurationSchema = z.looseInterface({
10
10
  mean: 0,
11
11
  deviation: 0,
12
12
  }),
13
- seeds: z.looseInterface({
13
+ seeds: z.looseObject({
14
14
  product: z.number().min(0).max(10000).default(1),
15
15
  search: z.number().min(0).max(10000).default(1),
16
16
  category: z.number().min(0).max(10000).default(1),
@@ -1,9 +1,7 @@
1
1
  import 'dotenv/config'
2
2
 
3
3
 
4
- import { CategorySchema, NoOpCache, ProductSchema, Session } from '@reactionary/core';
5
-
6
- import { getTracer, shutdownOtel } from '@reactionary/otel';
4
+ import { CategorySchema, NoOpCache, Session } from '@reactionary/core';
7
5
  import { FakeCategoryProvider } from '../providers';
8
6
  import { createAnonymousTestSession, getFakerTestConfiguration } from './test-utils';
9
7
  describe('Faker Category Provider', () => {
@@ -6,6 +6,6 @@
6
6
  "types": "./index.d.ts",
7
7
  "dependencies": {
8
8
  "@reactionary/core": "0.0.1",
9
- "zod": "4.0.0-beta.20250430T185432"
9
+ "zod": "4.1.9"
10
10
  }
11
11
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
 
3
- export const PosthogConfigurationSchema = z.looseInterface({
3
+ export const PosthogConfigurationSchema = z.looseObject({
4
4
  apiKey: z.string(),
5
5
  host: z.string(),
6
6
  });
package/trpc/package.json CHANGED
@@ -9,6 +9,6 @@
9
9
  "@reactionary/core": "0.0.1",
10
10
  "@reactionary/otel": "0.0.1",
11
11
  "superjson": "^2.2.2",
12
- "zod": "4.0.0-beta.20250430T185432"
12
+ "zod": "4.1.9"
13
13
  }
14
14
  }
@@ -1,11 +1,12 @@
1
- import { buildClient, NoOpCache, SessionSchema } from '@reactionary/core';
1
+ import { ClientBuilder, NoOpCache } from '@reactionary/core';
2
2
  import { withFakeCapabilities } from '@reactionary/provider-fake';
3
- import { createTRPCServerRouter, createTRPCContext, type TRPCRouterFromClient } from './server';
4
- import { createTRPCClient, type TRPCClientFromRouter } from './client';
3
+ import { createTRPCServerRouter, createTRPCContext } from './server';
4
+ import { createTRPCClient } from './client';
5
5
  import type { TransparentClient } from './types';
6
6
  import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
7
7
  import { createHTTPHandler } from '@trpc/server/adapters/standalone';
8
8
  import * as http from 'http';
9
+ import { createAnonymousTestSession } from './test-utils';
9
10
 
10
11
  /**
11
12
  * Integration test that actually starts an HTTP server and makes real network calls
@@ -16,29 +17,31 @@ import * as http from 'http';
16
17
  global.fetch = global.fetch || require('node-fetch');
17
18
 
18
19
  // Create the server-side client
19
- const serverClient = buildClient(
20
- [
21
- withFakeCapabilities(
22
- {
23
- jitter: { mean: 0, deviation: 0 },
24
- seeds: {
25
- product: 12345,
26
- category: 12345,
27
- cart: 12345,
28
- search: 0
20
+ const serverClient = new ClientBuilder()
21
+ .withCapability(
22
+ withFakeCapabilities(
23
+ {
24
+ jitter: {
25
+ mean: 0,
26
+ deviation: 0,
27
+ },
28
+ seeds: {
29
+ category: 1,
30
+ product: 1,
31
+ search: 1
32
+ }
29
33
  },
30
- },
31
- { search: true, product: true, identity: false, cart: true }
32
- ),
33
- ],
34
- { cache: new NoOpCache() }
35
- );
34
+ { search: true, product: true, identity: false }
35
+ )
36
+ )
37
+ .withCache(new NoOpCache())
38
+ .build();
36
39
 
37
40
  // Create TRPC router from the client (do this at module level for type inference)
38
41
  const router = createTRPCServerRouter(serverClient);
39
42
  type AppRouter = typeof router;
40
43
 
41
- describe('TRPC Integration Test - Real HTTP Server', () => {
44
+ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
42
45
  let server: http.Server;
43
46
  let serverPort: number;
44
47
  let trpcProxyClient: ReturnType<typeof createTRPCProxyClient<AppRouter>>;
@@ -96,9 +99,7 @@ describe('TRPC Integration Test - Real HTTP Server', () => {
96
99
  }
97
100
  });
98
101
 
99
- const session = SessionSchema.parse({
100
- id: '1234567890',
101
- });
102
+ const session = createAnonymousTestSession();
102
103
 
103
104
  describe('Product Provider via HTTP', () => {
104
105
  it('should fetch product by slug through real HTTP calls', async () => {
@@ -0,0 +1,26 @@
1
+ import { Session } from '@reactionary/core';
2
+
3
+ export function createAnonymousTestSession(): Session {
4
+ return {
5
+ id: 'test-session-id',
6
+ identity: {
7
+ type: 'Anonymous',
8
+ meta: {
9
+ cache: { hit: false, key: '' },
10
+ placeholder: false,
11
+ },
12
+ id: '',
13
+ token: undefined,
14
+ issued: new Date(),
15
+ expiry: new Date(new Date().getTime() + 3600 * 1000), // 1 hour from now
16
+ },
17
+ languageContext: {
18
+ locale: 'en-US',
19
+ currencyCode: 'USD',
20
+ countryCode: 'US',
21
+ },
22
+ storeIdentifier: {
23
+ key: 'the-good-store',
24
+ },
25
+ };
26
+ }