@reactionary/source 0.2.19 → 0.3.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.
Files changed (93) hide show
  1. package/core/src/client/client-builder.ts +3 -7
  2. package/core/src/client/client.ts +2 -3
  3. package/core/src/decorators/reactionary.decorator.ts +2 -2
  4. package/core/src/initialization.ts +8 -3
  5. package/core/src/providers/analytics.provider.ts +75 -0
  6. package/core/src/providers/cart.provider.ts +3 -0
  7. package/core/src/providers/category.provider.ts +1 -0
  8. package/core/src/schemas/errors/invalid-input.error.ts +1 -1
  9. package/core/src/schemas/errors/invalid-output.error.ts +1 -1
  10. package/core/src/schemas/models/identifiers.model.ts +3 -0
  11. package/core/src/schemas/models/order.model.ts +2 -2
  12. package/core/src/schemas/mutations/analytics/index.ts +23 -0
  13. package/core/src/schemas/mutations/analytics/product-add-to-cart.mutation.ts +25 -0
  14. package/core/src/schemas/mutations/analytics/product-details-view.mutation.ts +14 -0
  15. package/core/src/schemas/mutations/analytics/product-summary-click.mutation.ts +26 -0
  16. package/core/src/schemas/mutations/analytics/product-summary-view.mutation.ts +25 -0
  17. package/core/src/schemas/mutations/analytics/purchase.mutation.ts +14 -0
  18. package/core/src/schemas/mutations/index.ts +1 -1
  19. package/core/src/schemas/queries/order-search.query.ts +3 -0
  20. package/core/src/schemas/session.schema.ts +20 -9
  21. package/core/src/test/client-builder.spec.ts +60 -0
  22. package/core/src/zod-utils.ts +3 -1
  23. package/documentation/{1-purpose.md → docs/1-purpose.md} +4 -0
  24. package/documentation/docs/8-tracking.md +9 -0
  25. package/documentation/docs/providers/analytics.provider.md +297 -0
  26. package/documentation/docs/providers/base.provider.md +118 -0
  27. package/documentation/docs/providers/cart.provider.md +305 -0
  28. package/documentation/docs/providers/category.provider.md +244 -0
  29. package/documentation/docs/providers/checkout.provider.md +315 -0
  30. package/documentation/docs/providers/identity.provider.md +194 -0
  31. package/documentation/docs/providers/inventory.provider.md +162 -0
  32. package/documentation/docs/providers/order-search.provider.md +155 -0
  33. package/documentation/docs/providers/order.provider.md +160 -0
  34. package/documentation/docs/providers/price.provider.md +197 -0
  35. package/documentation/docs/providers/product-search.provider.md +265 -0
  36. package/documentation/docs/providers/product.provider.md +204 -0
  37. package/documentation/docs/providers/profile.provider.md +283 -0
  38. package/documentation/docs/providers/store.provider.md +146 -0
  39. package/documentation/docs/schemas/schemas.md +1862 -0
  40. package/documentation/docusaurus.config.js +33 -0
  41. package/documentation/scripts/generate.ts +52 -0
  42. package/documentation/sidebars.js +8 -0
  43. package/documentation/src/css/custom.css +3 -0
  44. package/documentation/src/pages/index.js +12 -0
  45. package/eslint.config.mjs +1 -1
  46. package/examples/node/package.json +6 -6
  47. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +0 -2
  48. package/package.json +19 -5
  49. package/providers/algolia/project.json +1 -1
  50. package/providers/algolia/src/core/initialize.ts +5 -0
  51. package/providers/algolia/src/providers/analytics.provider.ts +112 -0
  52. package/providers/algolia/src/providers/index.ts +1 -0
  53. package/providers/commercetools/project.json +1 -1
  54. package/providers/commercetools/src/providers/profile.provider.ts +1 -4
  55. package/providers/fake/project.json +1 -1
  56. package/providers/fake/src/providers/analytics.provider.ts +5 -0
  57. package/providers/fake/src/providers/checkout.provider.ts +5 -2
  58. package/providers/fake/src/providers/product.provider.ts +18 -8
  59. package/providers/fake/src/test/cart.provider.spec.ts +0 -2
  60. package/providers/fake/src/test/category.provider.spec.ts +3 -3
  61. package/providers/fake/src/test/checkout.provider.spec.ts +3 -7
  62. package/providers/google-analytics/README.md +11 -0
  63. package/providers/google-analytics/eslint.config.mjs +25 -0
  64. package/providers/google-analytics/package.json +18 -0
  65. package/providers/google-analytics/project.json +33 -0
  66. package/providers/google-analytics/src/core/initialize.ts +16 -0
  67. package/providers/google-analytics/src/index.ts +4 -0
  68. package/providers/google-analytics/src/providers/analytics.provider.ts +162 -0
  69. package/providers/google-analytics/src/schema/capabilities.schema.ts +10 -0
  70. package/providers/google-analytics/src/schema/configuration.schema.ts +9 -0
  71. package/providers/google-analytics/src/test/analytics.provider.spec.ts +93 -0
  72. package/providers/google-analytics/tsconfig.json +24 -0
  73. package/providers/google-analytics/tsconfig.lib.json +23 -0
  74. package/providers/google-analytics/tsconfig.spec.json +28 -0
  75. package/providers/google-analytics/vite.config.ts +26 -0
  76. package/providers/google-analytics/vitest.config.mts +21 -0
  77. package/providers/medusa/package.json +3 -10
  78. package/providers/medusa/project.json +1 -1
  79. package/providers/medusa/src/providers/profile.provider.ts +5 -15
  80. package/providers/medusa/src/test/test-utils.ts +0 -1
  81. package/providers/medusa/tsconfig.json +3 -0
  82. package/providers/medusa/tsconfig.lib.json +16 -1
  83. package/providers/meilisearch/project.json +1 -1
  84. package/providers/posthog/project.json +1 -1
  85. package/tsconfig.base.json +4 -1
  86. package/core/src/schemas/mutations/analytics.mutation.ts +0 -23
  87. package/providers/algolia/src/test/test-utils.ts +0 -31
  88. /package/documentation/{2-getting-started.md → docs/2-getting-started.md} +0 -0
  89. /package/documentation/{3-querying-and-changing-data.md → docs/3-querying-and-changing-data.md} +0 -0
  90. /package/documentation/{4-product-data.md → docs/4-product-data.md} +0 -0
  91. /package/documentation/{5-cart-and-checkout.md → docs/5-cart-and-checkout.md} +0 -0
  92. /package/documentation/{6-product-search.md → docs/6-product-search.md} +0 -0
  93. /package/documentation/{7-marketing.md → docs/7-marketing.md} +0 -0
@@ -0,0 +1,33 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+ title: 'My Project',
5
+ tagline: 'Documentation',
6
+ url: 'https://your-site.com',
7
+ baseUrl: '/',
8
+ onBrokenLinks: 'throw',
9
+ staticDirectories: [path.resolve(__dirname, 'static')],
10
+ i18n: {
11
+ defaultLocale: 'en',
12
+ locales: ['en'],
13
+ },
14
+ markdown: {
15
+ format: 'md',
16
+ },
17
+ presets: [
18
+ [
19
+ 'classic',
20
+ {
21
+ docs: {
22
+ path: path.resolve(__dirname, 'docs'),
23
+ routeBasePath: '/',
24
+ sidebarPath: path.resolve(__dirname, 'sidebars.js'),
25
+ },
26
+ blog: false,
27
+ theme: {
28
+ customCss: path.resolve(__dirname, 'src/css/custom.css'),
29
+ },
30
+ },
31
+ ],
32
+ ],
33
+ };
@@ -0,0 +1,52 @@
1
+ import { zod2md } from 'zod2md';
2
+ import { writeFileSync } from 'fs';
3
+ import * as td from 'typedoc';
4
+ import type { TypeDocOptions } from 'typedoc';
5
+ import type { PluginOptions as MarkdownPluginOptions } from 'typedoc-plugin-markdown';
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+
9
+ type TypedocWithMarkdownOptions = TypeDocOptions & MarkdownPluginOptions;
10
+
11
+ const projects = [
12
+ {
13
+ entry: 'core/src/schemas/index.ts',
14
+ title: 'Schemas',
15
+ output: 'documentation/docs/schemas/schemas.md',
16
+ },
17
+ ];
18
+
19
+ async function main() {
20
+ for (const project of projects) {
21
+ const markdown = await zod2md({
22
+ entry: project.entry,
23
+ title: `${project.title} Schemas`,
24
+ tsconfig: './core/tsconfig.lib.json',
25
+ });
26
+ writeFileSync(project.output, markdown);
27
+ }
28
+
29
+ const typedocConfig = {
30
+ entryPoints: ['core/src/providers/*.provider.ts'],
31
+ tsconfig: 'core/tsconfig.lib.json',
32
+ plugin: ['typedoc-plugin-markdown'],
33
+ out: 'documentation/docs/providers',
34
+ outputFileStrategy: 'modules',
35
+ categorizeByGroup: true,
36
+ readme: 'none',
37
+ membersWithOwnFile: [],
38
+ modulesFileName: undefined,
39
+ } satisfies TypedocWithMarkdownOptions;
40
+ const app = await td.Application.bootstrapWithPlugins(typedocConfig);
41
+
42
+ const project = await app.convert();
43
+ if (project) {
44
+ await app.generateOutputs(project);
45
+
46
+ await fs.rm(path.join('documentation/docs/providers', 'README.md'), {
47
+ force: true,
48
+ });
49
+ }
50
+ }
51
+
52
+ main();
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ docs: [
3
+ {
4
+ type: 'autogenerated',
5
+ dirName: '.',
6
+ },
7
+ ],
8
+ };
@@ -0,0 +1,3 @@
1
+ :root {
2
+ --ifm-color-primary: #2e8555;
3
+ }
@@ -0,0 +1,12 @@
1
+ import Layout from '@theme/Layout';
2
+
3
+ export default function Home() {
4
+ return (
5
+ <Layout title="Home">
6
+ <main style={{ padding: '2rem' }}>
7
+ <h1>Welcome to My Docs</h1>
8
+ <p>Get started by reading the <a href="/docs/intro">introduction</a>.</p>
9
+ </main>
10
+ </Layout>
11
+ );
12
+ }
package/eslint.config.mjs CHANGED
@@ -9,7 +9,7 @@ export default [
9
9
  '**/dist',
10
10
  '**/vite.config.*.timestamp*',
11
11
  '**/vitest.config.*.timestamp*',
12
- '**/vitest.config.ts'
12
+ '**/vitest.config.ts',
13
13
  ],
14
14
  },
15
15
  {
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@reactionary/examples-node",
3
- "version": "0.2.19",
3
+ "version": "0.3.1",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
- "@reactionary/core": "0.2.19",
8
- "@reactionary/provider-commercetools": "0.2.19",
9
- "@reactionary/provider-algolia": "0.2.19",
10
- "@reactionary/provider-medusa": "0.2.19",
11
- "@reactionary/provider-meilisearch": "0.2.19"
7
+ "@reactionary/core": "0.3.1",
8
+ "@reactionary/provider-commercetools": "0.3.1",
9
+ "@reactionary/provider-algolia": "0.3.1",
10
+ "@reactionary/provider-medusa": "0.3.1",
11
+ "@reactionary/provider-meilisearch": "0.3.1"
12
12
  },
13
13
  "type": "module"
14
14
  }
@@ -1,7 +1,5 @@
1
1
  import type {
2
2
  Cache,
3
- ProductQueryById,
4
- ProductQueryBySlug,
5
3
  RequestContext} from '@reactionary/core';
6
4
  import {
7
5
  ClientBuilder,
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@reactionary/source",
3
- "version": "0.2.19",
3
+ "version": "0.3.1",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "dependencies": {
7
7
  "@commercetools/platform-sdk": "^8.16.0",
8
8
  "@commercetools/ts-client": "^4.2.1",
9
+ "@commercetools/ts-sdk-apm": "^4.0.0",
10
+ "@docusaurus/core": "^3.9.2",
11
+ "@docusaurus/preset-classic": "^3.9.2",
9
12
  "@faker-js/faker": "^9.8.0",
10
13
  "@medusajs/js-sdk": "^2.13.0",
11
14
  "@opentelemetry/api": "^1.9.0",
@@ -19,7 +22,6 @@
19
22
  "meilisearch": "^0.55.0",
20
23
  "node-object-hash": "^3.1.1",
21
24
  "posthog-node": "^5.24.0",
22
- "search-insights": "^2.17.3",
23
25
  "zod": "4.1.9"
24
26
  },
25
27
  "devDependencies": {
@@ -44,15 +46,23 @@
44
46
  "@types/debug": "^4.1.12",
45
47
  "@types/node": "^24.0.0",
46
48
  "@typescript-eslint/utils": "^8.33.1",
49
+ "@vitest/coverage-v8": "^4.0.0",
50
+ "docusaurus-plugin-typedoc": "^1.4.2",
51
+ "esbuild": "^0.19.2",
52
+ "jsonc-eslint-parser": "^2.1.0",
47
53
  "nx": "22.4.5",
48
- "prettier": "^2.6.2",
54
+ "prettier": "~3.6.2",
49
55
  "ts-node": "10.9.1",
50
56
  "tslib": "^2.3.0",
57
+ "typedoc": "^0.28.16",
58
+ "typedoc-plugin-markdown": "^4.9.0",
51
59
  "typescript": "5.9.3",
52
60
  "typescript-eslint": "^8.33.1",
61
+ "verdaccio": "^6.0.5",
53
62
  "vite": "7.1.9",
54
63
  "vite-tsconfig-paths": "^5.1.4",
55
- "vitest": "^4.0.9"
64
+ "vitest": "^4.0.9",
65
+ "zod2md": "^0.2.5"
56
66
  },
57
67
  "nx": {
58
68
  "includedScripts": []
@@ -62,5 +72,9 @@
62
72
  "provenance": false
63
73
  },
64
74
  "packageManager": "pnpm@8.15.9+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81",
65
- "scripts": {}
75
+ "scripts": {
76
+ "docs:start": "docusaurus start --config documentation/docusaurus.config.js",
77
+ "docs:build": "docusaurus build --config documentation/docusaurus.config.js",
78
+ "docs:generate": "node ./documentation/scripts/generate.ts"
79
+ }
66
80
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "provider-algolia",
2
+ "name": "algolia",
3
3
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
4
  "sourceRoot": "providers/algolia/src",
5
5
  "projectType": "library",
@@ -2,6 +2,7 @@ import type { Cache, ClientFromCapabilities, RequestContext } from "@reactionary
2
2
  import { AlgoliaSearchProvider } from "../providers/product-search.provider.js";
3
3
  import type { AlgoliaCapabilities } from "../schema/capabilities.schema.js";
4
4
  import type { AlgoliaConfiguration } from "../schema/configuration.schema.js";
5
+ import { AlgoliaAnalyticsProvider } from "../providers/analytics.provider.js";
5
6
 
6
7
  export function withAlgoliaCapabilities<T extends AlgoliaCapabilities>(configuration: AlgoliaConfiguration, capabilities: T) {
7
8
  return (cache: Cache, context: RequestContext): ClientFromCapabilities<T> => {
@@ -11,6 +12,10 @@ export function withAlgoliaCapabilities<T extends AlgoliaCapabilities>(configura
11
12
  client.productSearch = new AlgoliaSearchProvider(configuration, cache, context);
12
13
  }
13
14
 
15
+ if (capabilities.analytics) {
16
+ client.analytics = new AlgoliaAnalyticsProvider(cache, context, configuration);
17
+ }
18
+
14
19
  return client;
15
20
  };
16
21
  }
@@ -0,0 +1,112 @@
1
+ import {
2
+ AnalyticsProvider,
3
+ type AnalyticsMutationProductAddToCartEvent,
4
+ type AnalyticsMutationProductSummaryClickEvent,
5
+ type AnalyticsMutationProductSummaryViewEvent,
6
+ type AnalyticsMutationPurchaseEvent,
7
+ type Cache,
8
+ type RequestContext,
9
+ } from '@reactionary/core';
10
+ import {
11
+ insightsClient,
12
+ type InsightsClient,
13
+ type ViewedObjectIDs,
14
+ type ClickedObjectIDsAfterSearch,
15
+ type AddedToCartObjectIDsAfterSearch,
16
+ type PurchasedObjectIDs,
17
+ } from 'algoliasearch';
18
+ import type { AlgoliaConfiguration } from '../schema/configuration.schema.js';
19
+ import type { AlgoliaProductSearchIdentifier } from '../schema/search.schema.js';
20
+
21
+ export class AlgoliaAnalyticsProvider extends AnalyticsProvider {
22
+ protected client: InsightsClient;
23
+ protected config: AlgoliaConfiguration;
24
+
25
+ constructor(
26
+ cache: Cache,
27
+ requestContext: RequestContext,
28
+ config: AlgoliaConfiguration
29
+ ) {
30
+ super(cache, requestContext);
31
+
32
+ this.config = config;
33
+ this.client = insightsClient(this.config.appId, this.config.apiKey);
34
+ }
35
+
36
+ protected override async processProductAddToCart(
37
+ event: AnalyticsMutationProductAddToCartEvent
38
+ ) {
39
+ if (event.source && event.source.type === 'search') {
40
+ const algoliaEvent = {
41
+ eventName: 'addToCart',
42
+ eventType: 'conversion',
43
+ eventSubtype: 'addToCart',
44
+ index: this.config.indexName,
45
+ objectIDs: [event.product.key],
46
+ userToken: this.context.session.identityContext.personalizationKey,
47
+ queryID: (event.source.identifier as AlgoliaProductSearchIdentifier)
48
+ .key,
49
+ } satisfies AddedToCartObjectIDsAfterSearch;
50
+
51
+ this.client.pushEvents({
52
+ events: [algoliaEvent],
53
+ });
54
+ }
55
+ }
56
+
57
+ protected override async processProductSummaryClick(
58
+ event: AnalyticsMutationProductSummaryClickEvent
59
+ ) {
60
+ if (event.source && event.source.type === 'search') {
61
+ const algoliaEvent = {
62
+ eventName: 'click',
63
+ eventType: 'click',
64
+ index: this.config.indexName,
65
+ objectIDs: [event.product.key],
66
+ userToken: this.context.session.identityContext.personalizationKey,
67
+ positions: [event.position],
68
+ queryID: (event.source.identifier as AlgoliaProductSearchIdentifier)
69
+ .key,
70
+ } satisfies ClickedObjectIDsAfterSearch;
71
+
72
+ this.client.pushEvents({
73
+ events: [algoliaEvent],
74
+ });
75
+ }
76
+ }
77
+
78
+ protected override async processProductSummaryView(
79
+ event: AnalyticsMutationProductSummaryViewEvent
80
+ ) {
81
+ if (event.source && event.source.type === 'search') {
82
+ const algoliaEvent = {
83
+ eventName: 'view',
84
+ eventType: 'view',
85
+ index: this.config.indexName,
86
+ objectIDs: event.products.map((x) => x.key),
87
+ userToken: this.context.session.identityContext.personalizationKey,
88
+ } satisfies ViewedObjectIDs;
89
+
90
+ this.client.pushEvents({
91
+ events: [algoliaEvent],
92
+ });
93
+ }
94
+ }
95
+
96
+ protected override async processPurchase(
97
+ event: AnalyticsMutationPurchaseEvent
98
+ ): Promise<void> {
99
+ const algoliaEvent = {
100
+ eventName: 'purchase',
101
+ eventType: 'conversion',
102
+ eventSubtype: 'purchase',
103
+ index: this.config.indexName,
104
+ objectIDs: event.order.items.map((x) => x.identifier.key),
105
+ userToken: this.context.session.identityContext.personalizationKey,
106
+ } satisfies PurchasedObjectIDs;
107
+
108
+ this.client.pushEvents({
109
+ events: [algoliaEvent],
110
+ });
111
+ }
112
+ }
@@ -1 +1,2 @@
1
+ export * from './analytics.provider.js';
1
2
  export * from './product-search.provider.js';
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "provider-commercetools",
2
+ "name": "commercetools",
3
3
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
4
  "sourceRoot": "providers/commercetools/src",
5
5
  "projectType": "library",
@@ -237,10 +237,7 @@ export class CommercetoolsProfileProvider extends ProfileProvider {
237
237
  if (addressToMakeDefault.id === customer.defaultBillingAddressId) {
238
238
  return error<InvalidInputError>({
239
239
  type: 'InvalidInput',
240
- error: {
241
- field: 'addressIdentifier',
242
- message: 'Cannot set shipping address as default billing address',
243
- }
240
+ error: 'Cannot set shipping address as default billing address'
244
241
  });
245
242
  }
246
243
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "provider-fake",
2
+ "name": "fake",
3
3
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
4
  "sourceRoot": "providers/fake/src",
5
5
  "projectType": "library",
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ AnalyticsMutation,
2
3
  Cache,
3
4
  RequestContext} from '@reactionary/core';
4
5
  import {
@@ -15,4 +16,8 @@ export class FakeAnalyticsProvider extends AnalyticsProvider {
15
16
 
16
17
  this.config = config;
17
18
  }
19
+
20
+ public override async track(event: AnalyticsMutation): Promise<void> {
21
+ // No-op
22
+ }
18
23
  }
@@ -29,9 +29,12 @@ import {
29
29
  CheckoutMutationFinalizeCheckoutSchema,
30
30
  success,
31
31
  type CheckoutIdentifier,
32
+ PaymentMethodSchema,
33
+ ShippingMethodSchema,
32
34
  } from '@reactionary/core';
33
35
  import type { FakeConfiguration } from '../schema/configuration.schema.js';
34
36
  import { base, en, Faker } from '@faker-js/faker';
37
+ import z from 'zod';
35
38
 
36
39
  export class FakeCheckoutProvider extends CheckoutProvider {
37
40
  protected config: FakeConfiguration;
@@ -90,7 +93,7 @@ export class FakeCheckoutProvider extends CheckoutProvider {
90
93
 
91
94
  @Reactionary({
92
95
  inputSchema: CheckoutQueryForAvailableShippingMethodsSchema,
93
- outputSchema: CheckoutSchema,
96
+ outputSchema: z.array(ShippingMethodSchema),
94
97
  })
95
98
  public override async getAvailableShippingMethods(
96
99
  payload: CheckoutQueryForAvailableShippingMethods
@@ -116,7 +119,7 @@ export class FakeCheckoutProvider extends CheckoutProvider {
116
119
 
117
120
  @Reactionary({
118
121
  inputSchema: CheckoutQueryForAvailablePaymentMethodsSchema,
119
- outputSchema: CheckoutSchema,
122
+ outputSchema: z.array(PaymentMethodSchema),
120
123
  })
121
124
  public override async getAvailablePaymentMethods(
122
125
  payload: CheckoutQueryForAvailablePaymentMethods
@@ -14,7 +14,7 @@ import {
14
14
  type Result,
15
15
  error,
16
16
  success,
17
- type NotFoundError
17
+ type NotFoundError,
18
18
  } from '@reactionary/core';
19
19
  import type z from 'zod';
20
20
  import type { FakeConfiguration } from '../schema/configuration.schema.js';
@@ -23,7 +23,11 @@ import { base, en, Faker } from '@faker-js/faker';
23
23
  export class FakeProductProvider extends ProductProvider {
24
24
  protected config: FakeConfiguration;
25
25
 
26
- constructor(config: FakeConfiguration, cache: ReactinaryCache, context: RequestContext) {
26
+ constructor(
27
+ config: FakeConfiguration,
28
+ cache: ReactinaryCache,
29
+ context: RequestContext
30
+ ) {
27
31
  super(cache, context);
28
32
 
29
33
  this.config = config;
@@ -31,7 +35,11 @@ export class FakeProductProvider extends ProductProvider {
31
35
 
32
36
  @Reactionary({
33
37
  inputSchema: ProductQueryByIdSchema,
34
- outputSchema: ProductSchema
38
+ outputSchema: ProductSchema,
39
+ cache: true,
40
+ cacheTimeToLiveInSeconds: 300,
41
+ currencyDependentCaching: false,
42
+ localeDependentCaching: true,
35
43
  })
36
44
  public override async getById(
37
45
  payload: ProductQueryById
@@ -41,7 +49,7 @@ export class FakeProductProvider extends ProductProvider {
41
49
 
42
50
  @Reactionary({
43
51
  inputSchema: ProductQueryBySlugSchema,
44
- outputSchema: ProductSchema
52
+ outputSchema: ProductSchema,
45
53
  })
46
54
  public override async getBySlug(
47
55
  payload: ProductQueryBySlug
@@ -53,7 +61,9 @@ export class FakeProductProvider extends ProductProvider {
53
61
  inputSchema: ProductQueryBySKUSchema,
54
62
  outputSchema: ProductSchema,
55
63
  })
56
- public override async getBySKU(payload: ProductQueryBySKU): Promise<Result<Product>> {
64
+ public override async getBySKU(
65
+ payload: ProductQueryBySKU
66
+ ): Promise<Result<Product>> {
57
67
  return success(this.parseSingle(payload.variant.sku));
58
68
  }
59
69
 
@@ -79,12 +89,12 @@ export class FakeProductProvider extends ProductProvider {
79
89
  ean: '',
80
90
  gtin: '',
81
91
  identifier: {
82
- sku: ''
92
+ sku: '',
83
93
  },
84
94
  images: [],
85
95
  name: '',
86
96
  options: [],
87
- upc: ''
97
+ upc: '',
88
98
  },
89
99
  description: generator.commerce.productDescription(),
90
100
  manufacturer: '',
@@ -93,7 +103,7 @@ export class FakeProductProvider extends ProductProvider {
93
103
  published: true,
94
104
  sharedAttributes: [],
95
105
  variants: [],
96
- } satisfies Product
106
+ } satisfies Product;
97
107
 
98
108
  return result;
99
109
  }
@@ -72,8 +72,6 @@ describe('Fake Cart Provider', () => {
72
72
  expect(updatedCart.value.items.length).toBe(1);
73
73
  expect(updatedCart.value.items[0].variant.sku).toBe(testData.skuWithoutTiers);
74
74
  expect(updatedCart.value.items[0].quantity).toBe(3);
75
- expect(updatedCart.value.items[0].price.totalPrice.value).toBe(cart.value.items[0].price.totalPrice.value * 3);
76
- expect(updatedCart.value.items[0].price.unitPrice.value).toBe(cart.value.items[0].price.unitPrice.value);
77
75
  });
78
76
 
79
77
  it('should be able to remove an item from a cart', async () => {
@@ -158,16 +158,16 @@ describe('Faker Category Provider', () => {
158
158
  expect(result.value.text).not.toBe('');
159
159
  });
160
160
 
161
- it('returns a placeholder if you search for a category that does not exist', async () => {
161
+ it('returns a not found error for categories that do not exist', async () => {
162
162
  const result = await provider.getById({
163
163
  id: { key: 'non-existent-category' },
164
164
  });
165
165
 
166
- if (!result.success) {
166
+ if (result.success) {
167
167
  assert.fail();
168
168
  }
169
169
 
170
- expect(result.value.identifier.key).toBe('non-existent-category');
170
+ expect(result.error.type).toBe('NotFound');
171
171
  });
172
172
 
173
173
  describe('caching', () => {
@@ -1,15 +1,11 @@
1
1
  import 'dotenv/config';
2
2
  import type { RequestContext } from '@reactionary/core';
3
3
  import {
4
- CartSchema,
5
- IdentitySchema,
6
4
  NoOpCache,
7
5
  createInitialRequestContext,
8
6
  } from '@reactionary/core';
9
7
  import { getFakerTestConfiguration } from './test-utils.js';
10
- import { FakeCartProvider } from '../providers/cart.provider.js';
11
- import { FakeIdentityProvider } from '../providers/index.js';
12
- import { describe, expect, it, beforeAll, beforeEach, assert } from 'vitest';
8
+ import { describe, expect, it, beforeEach, assert } from 'vitest';
13
9
  import { FakeCheckoutProvider } from '../providers/checkout.provider.js';
14
10
 
15
11
  describe('Fake Checkout Provider', () => {
@@ -200,7 +196,7 @@ describe('Fake Checkout Provider', () => {
200
196
  });
201
197
 
202
198
  if (!result.success) {
203
- assert.fail();
199
+ assert.fail(JSON.stringify(result.error));
204
200
  }
205
201
 
206
202
  expect(result.value.length).toBeGreaterThan(0);
@@ -214,7 +210,7 @@ describe('Fake Checkout Provider', () => {
214
210
  });
215
211
 
216
212
  if (!result.success) {
217
- assert.fail();
213
+ assert.fail(JSON.stringify(result.error));
218
214
  }
219
215
 
220
216
  expect(result.value.length).toBeGreaterThan(0);
@@ -0,0 +1,11 @@
1
+ # google-analytics
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build google-analytics` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test google-analytics` to execute the unit tests via [Vitest](https://vitest.dev/).
@@ -0,0 +1,25 @@
1
+ import baseConfig from '../../eslint.config.mjs';
2
+
3
+ export default [
4
+ ...baseConfig,
5
+ {
6
+ files: ['**/*.json'],
7
+ rules: {
8
+ '@nx/dependency-checks': [
9
+ 'error',
10
+ {
11
+ ignoredFiles: [
12
+ '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
13
+ '{projectRoot}/esbuild.config.{js,ts,mjs,mts}',
14
+ '{projectRoot}/vite.config.{js,ts,mjs,mts}',
15
+ '{projectRoot}/**/*.spec.ts',
16
+ ],
17
+ ignoredDependencies: ['vitest', '@nx/vite'],
18
+ },
19
+ ],
20
+ },
21
+ languageOptions: {
22
+ parser: await import('jsonc-eslint-parser'),
23
+ },
24
+ },
25
+ ];
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@reactionary/google-analytics",
3
+ "version": "0.0.1",
4
+ "main": "index.js",
5
+ "types": "src/index.d.ts",
6
+ "dependencies": {
7
+ "@reactionary/core": "0.0.1",
8
+ "zod": "4.1.9"
9
+ },
10
+ "devDependencies": {
11
+ "vitest": "*",
12
+ "@vitest/ui": "*",
13
+ "@vitest/coverage-v8": "*",
14
+ "vite-tsconfig-paths": "*"
15
+ },
16
+ "type": "module",
17
+ "sideEffects": false
18
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "google-analytics",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "providers/google-analytics/src",
5
+ "projectType": "library",
6
+ "release": {
7
+ "version": {
8
+ "manifestRootsToUpdate": ["dist/{projectRoot}"],
9
+ "currentVersionResolver": "git-tag",
10
+ "fallbackCurrentVersionResolver": "disk"
11
+ }
12
+ },
13
+ "tags": [],
14
+ "targets": {
15
+ "build": {
16
+ "executor": "@nx/esbuild:esbuild",
17
+ "outputs": ["{options.outputPath}"],
18
+ "options": {
19
+ "outputPath": "dist/providers/google-analytics",
20
+ "main": "providers/google-analytics/src/index.ts",
21
+ "tsConfig": "providers/google-analytics/tsconfig.lib.json",
22
+ "assets": ["providers/google-analytics/*.md"],
23
+ "format": ["esm"],
24
+ "bundle": false
25
+ }
26
+ },
27
+ "nx-release-publish": {
28
+ "options": {
29
+ "packageRoot": "dist/{projectRoot}"
30
+ }
31
+ }
32
+ }
33
+ }