@reactionary/source 0.0.27

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 (197) hide show
  1. package/.editorconfig +13 -0
  2. package/.github/workflows/pull-request.yml +37 -0
  3. package/.github/workflows/release.yml +49 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +6 -0
  6. package/.prettierrc +3 -0
  7. package/.verdaccio/config.yml +28 -0
  8. package/.vscode/extensions.json +9 -0
  9. package/README.md +39 -0
  10. package/core/README.md +11 -0
  11. package/core/eslint.config.mjs +23 -0
  12. package/core/package.json +8 -0
  13. package/core/project.json +33 -0
  14. package/core/src/cache/caching-strategy.ts +25 -0
  15. package/core/src/cache/redis-cache.ts +41 -0
  16. package/core/src/client/client.ts +39 -0
  17. package/core/src/index.ts +42 -0
  18. package/core/src/providers/analytics.provider.ts +10 -0
  19. package/core/src/providers/base.provider.ts +75 -0
  20. package/core/src/providers/cart.provider.ts +10 -0
  21. package/core/src/providers/identity.provider.ts +10 -0
  22. package/core/src/providers/inventory.provider.ts +11 -0
  23. package/core/src/providers/price.provider.ts +10 -0
  24. package/core/src/providers/product.provider.ts +11 -0
  25. package/core/src/providers/search.provider.ts +12 -0
  26. package/core/src/schemas/capabilities.schema.ts +13 -0
  27. package/core/src/schemas/models/analytics.model.ts +7 -0
  28. package/core/src/schemas/models/base.model.ts +19 -0
  29. package/core/src/schemas/models/cart.model.ts +17 -0
  30. package/core/src/schemas/models/currency.model.ts +187 -0
  31. package/core/src/schemas/models/identifiers.model.ts +45 -0
  32. package/core/src/schemas/models/identity.model.ts +15 -0
  33. package/core/src/schemas/models/inventory.model.ts +8 -0
  34. package/core/src/schemas/models/price.model.ts +17 -0
  35. package/core/src/schemas/models/product.model.ts +28 -0
  36. package/core/src/schemas/models/search.model.ts +35 -0
  37. package/core/src/schemas/mutations/analytics.mutation.ts +22 -0
  38. package/core/src/schemas/mutations/base.mutation.ts +7 -0
  39. package/core/src/schemas/mutations/cart.mutation.ts +30 -0
  40. package/core/src/schemas/mutations/identity.mutation.ts +18 -0
  41. package/core/src/schemas/mutations/inventory.mutation.ts +5 -0
  42. package/core/src/schemas/mutations/price.mutation.ts +5 -0
  43. package/core/src/schemas/mutations/product.mutation.ts +6 -0
  44. package/core/src/schemas/mutations/search.mutation.ts +5 -0
  45. package/core/src/schemas/queries/analytics.query.ts +5 -0
  46. package/core/src/schemas/queries/base.query.ts +7 -0
  47. package/core/src/schemas/queries/cart.query.ts +12 -0
  48. package/core/src/schemas/queries/identity.query.ts +10 -0
  49. package/core/src/schemas/queries/inventory.query.ts +9 -0
  50. package/core/src/schemas/queries/price.query.ts +12 -0
  51. package/core/src/schemas/queries/product.query.ts +18 -0
  52. package/core/src/schemas/queries/search.query.ts +12 -0
  53. package/core/src/schemas/session.schema.ts +9 -0
  54. package/core/tsconfig.json +23 -0
  55. package/core/tsconfig.lib.json +23 -0
  56. package/core/tsconfig.spec.json +28 -0
  57. package/eslint.config.mjs +46 -0
  58. package/examples/angular/e2e/example.spec.ts +9 -0
  59. package/examples/angular/eslint.config.mjs +41 -0
  60. package/examples/angular/playwright.config.ts +38 -0
  61. package/examples/angular/project.json +86 -0
  62. package/examples/angular/public/favicon.ico +0 -0
  63. package/examples/angular/src/app/app.component.html +6 -0
  64. package/examples/angular/src/app/app.component.scss +22 -0
  65. package/examples/angular/src/app/app.component.ts +14 -0
  66. package/examples/angular/src/app/app.config.ts +16 -0
  67. package/examples/angular/src/app/app.routes.ts +25 -0
  68. package/examples/angular/src/app/cart/cart.component.html +4 -0
  69. package/examples/angular/src/app/cart/cart.component.scss +14 -0
  70. package/examples/angular/src/app/cart/cart.component.ts +73 -0
  71. package/examples/angular/src/app/identity/identity.component.html +6 -0
  72. package/examples/angular/src/app/identity/identity.component.scss +18 -0
  73. package/examples/angular/src/app/identity/identity.component.ts +49 -0
  74. package/examples/angular/src/app/product/product.component.html +14 -0
  75. package/examples/angular/src/app/product/product.component.scss +11 -0
  76. package/examples/angular/src/app/product/product.component.ts +42 -0
  77. package/examples/angular/src/app/search/search.component.html +35 -0
  78. package/examples/angular/src/app/search/search.component.scss +129 -0
  79. package/examples/angular/src/app/search/search.component.ts +50 -0
  80. package/examples/angular/src/app/services/product.service.ts +35 -0
  81. package/examples/angular/src/app/services/search.service.ts +48 -0
  82. package/examples/angular/src/app/services/trpc.client.ts +27 -0
  83. package/examples/angular/src/index.html +13 -0
  84. package/examples/angular/src/main.ts +7 -0
  85. package/examples/angular/src/styles.scss +17 -0
  86. package/examples/angular/src/test-setup.ts +6 -0
  87. package/examples/angular/tsconfig.app.json +10 -0
  88. package/examples/angular/tsconfig.editor.json +6 -0
  89. package/examples/angular/tsconfig.json +32 -0
  90. package/examples/node/README.md +11 -0
  91. package/examples/node/eslint.config.mjs +22 -0
  92. package/examples/node/jest.config.ts +10 -0
  93. package/examples/node/package.json +10 -0
  94. package/examples/node/project.json +20 -0
  95. package/examples/node/src/index.ts +2 -0
  96. package/examples/node/src/initialize-algolia.spec.ts +29 -0
  97. package/examples/node/src/initialize-commercetools.spec.ts +31 -0
  98. package/examples/node/src/initialize-extended-providers.spec.ts +38 -0
  99. package/examples/node/src/initialize-mixed-providers.spec.ts +36 -0
  100. package/examples/node/src/providers/custom-algolia-product.provider.ts +18 -0
  101. package/examples/node/src/schemas/custom-product.schema.ts +8 -0
  102. package/examples/node/tsconfig.json +23 -0
  103. package/examples/node/tsconfig.lib.json +10 -0
  104. package/examples/node/tsconfig.spec.json +15 -0
  105. package/examples/trpc-node/eslint.config.mjs +3 -0
  106. package/examples/trpc-node/project.json +61 -0
  107. package/examples/trpc-node/src/assets/.gitkeep +0 -0
  108. package/examples/trpc-node/src/main.ts +55 -0
  109. package/examples/trpc-node/src/router-instance.ts +52 -0
  110. package/examples/trpc-node/tsconfig.app.json +9 -0
  111. package/examples/trpc-node/tsconfig.json +13 -0
  112. package/examples/vue/eslint.config.mjs +24 -0
  113. package/examples/vue/index.html +13 -0
  114. package/examples/vue/project.json +8 -0
  115. package/examples/vue/src/app/App.vue +275 -0
  116. package/examples/vue/src/main.ts +6 -0
  117. package/examples/vue/src/styles.scss +9 -0
  118. package/examples/vue/src/vue-shims.d.ts +5 -0
  119. package/examples/vue/tsconfig.app.json +14 -0
  120. package/examples/vue/tsconfig.json +20 -0
  121. package/examples/vue/vite.config.ts +31 -0
  122. package/jest.config.ts +6 -0
  123. package/jest.preset.js +3 -0
  124. package/migrations.json +11 -0
  125. package/nx.json +130 -0
  126. package/package.json +118 -0
  127. package/project.json +14 -0
  128. package/providers/algolia/README.md +11 -0
  129. package/providers/algolia/eslint.config.mjs +22 -0
  130. package/providers/algolia/jest.config.ts +10 -0
  131. package/providers/algolia/package.json +9 -0
  132. package/providers/algolia/project.json +33 -0
  133. package/providers/algolia/src/core/initialize.ts +20 -0
  134. package/providers/algolia/src/index.ts +7 -0
  135. package/providers/algolia/src/providers/product.provider.ts +25 -0
  136. package/providers/algolia/src/providers/search.provider.ts +125 -0
  137. package/providers/algolia/src/schema/capabilities.schema.ts +10 -0
  138. package/providers/algolia/src/schema/configuration.schema.ts +9 -0
  139. package/providers/algolia/src/schema/search.schema.ts +14 -0
  140. package/providers/algolia/src/test/product.provider.spec.ts +18 -0
  141. package/providers/algolia/src/test/search.provider.spec.ts +82 -0
  142. package/providers/algolia/tsconfig.json +23 -0
  143. package/providers/algolia/tsconfig.lib.json +10 -0
  144. package/providers/algolia/tsconfig.spec.json +15 -0
  145. package/providers/commercetools/README.md +11 -0
  146. package/providers/commercetools/eslint.config.mjs +22 -0
  147. package/providers/commercetools/jest.config.ts +10 -0
  148. package/providers/commercetools/package.json +10 -0
  149. package/providers/commercetools/project.json +33 -0
  150. package/providers/commercetools/src/core/client.ts +152 -0
  151. package/providers/commercetools/src/core/initialize.ts +40 -0
  152. package/providers/commercetools/src/index.ts +12 -0
  153. package/providers/commercetools/src/providers/cart.provider.ts +223 -0
  154. package/providers/commercetools/src/providers/identity.provider.ts +130 -0
  155. package/providers/commercetools/src/providers/inventory.provider.ts +82 -0
  156. package/providers/commercetools/src/providers/price.provider.ts +66 -0
  157. package/providers/commercetools/src/providers/product.provider.ts +90 -0
  158. package/providers/commercetools/src/providers/search.provider.ts +86 -0
  159. package/providers/commercetools/src/schema/capabilities.schema.ts +13 -0
  160. package/providers/commercetools/src/schema/configuration.schema.ts +11 -0
  161. package/providers/commercetools/src/test/product.provider.spec.ts +20 -0
  162. package/providers/commercetools/src/test/search.provider.spec.ts +18 -0
  163. package/providers/commercetools/tsconfig.json +23 -0
  164. package/providers/commercetools/tsconfig.lib.json +10 -0
  165. package/providers/commercetools/tsconfig.spec.json +15 -0
  166. package/providers/fake/README.md +7 -0
  167. package/providers/fake/eslint.config.mjs +22 -0
  168. package/providers/fake/package.json +9 -0
  169. package/providers/fake/project.json +33 -0
  170. package/providers/fake/src/core/initialize.ts +24 -0
  171. package/providers/fake/src/index.ts +8 -0
  172. package/providers/fake/src/providers/identity.provider.ts +91 -0
  173. package/providers/fake/src/providers/product.provider.ts +73 -0
  174. package/providers/fake/src/providers/search.provider.ts +142 -0
  175. package/providers/fake/src/schema/capabilities.schema.ts +10 -0
  176. package/providers/fake/src/schema/configuration.schema.ts +15 -0
  177. package/providers/fake/src/utilities/jitter.ts +14 -0
  178. package/providers/fake/tsconfig.json +20 -0
  179. package/providers/fake/tsconfig.lib.json +9 -0
  180. package/providers/posthog/README.md +7 -0
  181. package/providers/posthog/eslint.config.mjs +22 -0
  182. package/providers/posthog/package.json +11 -0
  183. package/providers/posthog/project.json +33 -0
  184. package/providers/posthog/src/core/initialize.ts +9 -0
  185. package/providers/posthog/src/index.ts +4 -0
  186. package/providers/posthog/src/schema/capabilities.schema.ts +8 -0
  187. package/providers/posthog/src/schema/configuration.schema.ts +8 -0
  188. package/providers/posthog/tsconfig.json +20 -0
  189. package/providers/posthog/tsconfig.lib.json +9 -0
  190. package/trpc/README.md +7 -0
  191. package/trpc/eslint.config.mjs +19 -0
  192. package/trpc/package.json +13 -0
  193. package/trpc/project.json +31 -0
  194. package/trpc/src/index.ts +64 -0
  195. package/trpc/tsconfig.json +13 -0
  196. package/trpc/tsconfig.lib.json +9 -0
  197. package/tsconfig.base.json +30 -0
@@ -0,0 +1,129 @@
1
+ :host {
2
+ display: grid;
3
+ gap: 0.5rem;
4
+ grid-template-columns: 300px 1fr;
5
+ color: rgb(205, 214, 244);
6
+ }
7
+
8
+ details[open] {
9
+ summary:after {
10
+ content: '-';
11
+ }
12
+ }
13
+
14
+ details {
15
+ position: relative;
16
+ background: rgb(49, 50, 68);
17
+ border-radius: 0.5rem;
18
+ }
19
+
20
+ summary {
21
+ font-weight: bold;
22
+ text-transform: capitalize;
23
+ list-style: none;
24
+ padding: 0.5rem;
25
+
26
+ &::-webkit-details-marker {
27
+ display: none;
28
+ }
29
+
30
+ &::after {
31
+ position: absolute;
32
+ top: 0.5rem;
33
+ right: 0.5rem;
34
+ content: '+';
35
+ line-height: 1;
36
+ }
37
+ }
38
+
39
+ aside {
40
+ display: grid;
41
+ grid-template-columns: 1fr;
42
+ grid-auto-rows: min-content;
43
+ gap: 0.25rem;
44
+
45
+ .content {
46
+ display: grid;
47
+ grid-template-columns: 1fr min-content min-content;
48
+ grid-auto-rows: min-content;
49
+ padding: 0.5rem;
50
+ gap: 0.5rem;
51
+
52
+ label {
53
+ grid-column: span 3;
54
+ display: grid;
55
+ grid-template-columns: subgrid;
56
+ align-items: center;
57
+ gap: 0.5rem;
58
+
59
+ input {
60
+ width: 1.5rem;
61
+ height: 1.5rem;
62
+ background: rgb(147, 153, 178);
63
+ border-radius: 0.125rem;
64
+
65
+ &:checked {
66
+ background: rgb(137, 220, 235);
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ section {
74
+ justify-content: center;
75
+ display: grid;
76
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
77
+ grid-auto-rows: min-content;
78
+ gap: 0.5rem;
79
+ }
80
+
81
+ article {
82
+ background: rgb(49, 50, 68);
83
+ border-radius: 0.25rem;
84
+ display: grid;
85
+ grid-template-columns: 1fr;
86
+ grid-template-rows: 1fr min-content;
87
+ gap: 1rem;
88
+
89
+ h3 {
90
+ line-height: 1.2;
91
+ font-size: 1rem;
92
+ text-align: center;
93
+ margin-bottom: 1rem;
94
+ }
95
+
96
+ img {
97
+ object-fit: contain;
98
+ border-radius: inherit;
99
+ max-width: 100%;
100
+ width: 100%;
101
+ }
102
+ }
103
+
104
+ footer {
105
+ grid-column: 2;
106
+ margin: 0.5rem;
107
+ gap: 0.25rem;
108
+ display: grid;
109
+ grid-template-columns: min-content min-content;
110
+ align-items: center;
111
+ justify-content: center;
112
+ }
113
+
114
+ button {
115
+ display: grid;
116
+ justify-content: center;
117
+ align-items: center;
118
+
119
+ height: 3rem;
120
+ background: rgb(49, 50, 68);
121
+ color: rgb(205, 214, 244);
122
+ aspect-ratio: 1 / 1;
123
+ border-radius: 0.25rem;
124
+
125
+ &:disabled {
126
+ opacity: 0.5;
127
+ }
128
+ }
129
+
@@ -0,0 +1,50 @@
1
+ import { Component, computed, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { SearchService } from '../services/search.service';
4
+ import { FacetValueIdentifier } from '@reactionary/core';
5
+ import { RouterModule } from '@angular/router';
6
+ import { TRPC } from '../services/trpc.client';
7
+
8
+ @Component({
9
+ selector: 'app-search',
10
+ imports: [CommonModule, RouterModule],
11
+ templateUrl: './search.component.html',
12
+ styleUrl: './search.component.scss',
13
+ })
14
+ export class SearchComponent {
15
+ protected service = inject(SearchService);
16
+ protected client = inject(TRPC);
17
+
18
+ protected hasNext = computed(() => {
19
+ return this.service.page() >= (this.service.search()?.pages || 0) - 1;
20
+ });
21
+
22
+ protected hasPrevious = computed(() => {
23
+ return !(this.service.page() > 0);
24
+ });
25
+
26
+ protected previousPage() {
27
+ this.service.page.update((old) => old - 1);
28
+ }
29
+
30
+ protected nextPage() {
31
+ this.service.page.update((old) => old + 1);
32
+ }
33
+
34
+ protected toggleFacet(value: FacetValueIdentifier) {
35
+ this.service.facets.update((old) => {
36
+ const existingIndex = old.findIndex(
37
+ (x) => JSON.stringify(x) === JSON.stringify(value)
38
+ );
39
+
40
+ if (existingIndex > -1) {
41
+ const updated = [...old];
42
+ updated.splice(existingIndex, 1);
43
+
44
+ return updated;
45
+ } else {
46
+ return [...old, value];
47
+ }
48
+ });
49
+ }
50
+ }
@@ -0,0 +1,35 @@
1
+ import { inject, Injectable, resource } from '@angular/core';
2
+ import { TRPC } from './trpc.client';
3
+ import { ActivationEnd, Router } from '@angular/router';
4
+ import { toSignal } from '@angular/core/rxjs-interop';
5
+ import { filter, map } from 'rxjs';
6
+
7
+ @Injectable({
8
+ providedIn: 'root',
9
+ })
10
+ export class ProductService {
11
+ protected client = inject(TRPC);
12
+ protected router = inject(Router);
13
+ protected slug = toSignal(
14
+ this.router.events.pipe(filter(x => x instanceof ActivationEnd), map(x => x.snapshot.params['slug'])),
15
+ { initialValue: '' }
16
+ );
17
+
18
+ public productResource = resource({
19
+ request: () => ({
20
+ slug: this.slug(),
21
+ }),
22
+ loader: async ({ request }) => {
23
+ if (request.slug) {
24
+ const results = await this.client.client.product.query([{
25
+ query: 'slug',
26
+ slug: request.slug,
27
+ }]);
28
+
29
+ return results[0];
30
+ } else {
31
+ return undefined;
32
+ }
33
+ },
34
+ });
35
+ }
@@ -0,0 +1,48 @@
1
+ import { inject, Injectable, linkedSignal, resource, signal } from '@angular/core';
2
+ import { FacetValueIdentifier, SearchResult } from '@reactionary/core';
3
+ import { TRPC } from './trpc.client';
4
+
5
+ @Injectable({
6
+ providedIn: 'root',
7
+ })
8
+ export class SearchService {
9
+ protected client = inject(TRPC);
10
+
11
+ public pageSize = signal(20);
12
+ public page = signal(0);
13
+ public term = signal('glass');
14
+ public facets = signal(new Array<FacetValueIdentifier>());
15
+
16
+ protected searchResource = resource({
17
+ request: () => ({
18
+ pageSize: this.pageSize(),
19
+ page: this.page(),
20
+ term: this.term(),
21
+ facets: this.facets(),
22
+ }),
23
+ loader: async ({ request }) => {
24
+ const result = await this.client.client.search.query([{
25
+ query: 'term',
26
+ search: {
27
+ ...request
28
+ }
29
+ }]);
30
+
31
+ return result[0];
32
+ },
33
+ });
34
+
35
+ public search = linkedSignal<
36
+ SearchResult | undefined,
37
+ SearchResult | undefined
38
+ >({
39
+ source: () => this.searchResource.value(),
40
+ computation: (source, previous) => {
41
+ if (source) {
42
+ return source;
43
+ }
44
+
45
+ return previous?.value;
46
+ },
47
+ }).asReadonly();
48
+ }
@@ -0,0 +1,27 @@
1
+ import { Injectable } from "@angular/core";
2
+ import { createTRPCClient, httpBatchLink } from "@trpc/client";
3
+
4
+ // FIXME: move the router to a buildable library, to allow importing it
5
+ // eslint-disable-next-line @nx/enforce-module-boundaries
6
+ import type { RouterType } from '../../../../trpc-node/src/router-instance';
7
+ import superjson from "superjson";
8
+
9
+ @Injectable({
10
+ providedIn: 'root',
11
+ })
12
+ export class TRPC {
13
+ public client = createTRPCClient<RouterType>({
14
+ links: [
15
+ httpBatchLink({
16
+ url: 'http://localhost:3000/trpc',
17
+ transformer: superjson,
18
+ fetch(url, options) {
19
+ return fetch(url, {
20
+ ...options,
21
+ credentials: 'include',
22
+ });
23
+ },
24
+ }),
25
+ ],
26
+ });
27
+ }
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>examples-angular</title>
6
+ <base href="/" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <link rel="icon" type="image/x-icon" href="favicon.ico" />
9
+ </head>
10
+ <body>
11
+ <app-root></app-root>
12
+ </body>
13
+ </html>
@@ -0,0 +1,7 @@
1
+ import { bootstrapApplication } from '@angular/platform-browser';
2
+ import { appConfig } from './app/app.config';
3
+ import { AppComponent } from './app/app.component';
4
+
5
+ bootstrapApplication(AppComponent, appConfig).catch((err) =>
6
+ console.error(err)
7
+ );
@@ -0,0 +1,17 @@
1
+ a,
2
+ input,
3
+ h3,
4
+ button {
5
+ all: unset;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ * {
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ body {
14
+ margin: 0;
15
+ padding: 0;
16
+ background: rgb(17, 17, 27);
17
+ }
@@ -0,0 +1,6 @@
1
+ import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
2
+
3
+ setupZoneTestEnv({
4
+ errorOnUnknownElements: true,
5
+ errorOnUnknownProperties: true,
6
+ });
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "types": ["node"]
6
+ },
7
+ "files": ["src/main.ts"],
8
+ "include": ["src/**/*.d.ts"],
9
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
10
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "include": ["src/**/*.ts"],
4
+ "compilerOptions": {},
5
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
6
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "esModuleInterop": true,
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "noImplicitOverride": true,
8
+ "noPropertyAccessFromIndexSignature": true,
9
+ "noImplicitReturns": true,
10
+ "noFallthroughCasesInSwitch": true
11
+ },
12
+ "files": [],
13
+ "include": [],
14
+ "references": [
15
+ {
16
+ "path": "./tsconfig.editor.json"
17
+ },
18
+ {
19
+ "path": "./tsconfig.app.json"
20
+ },
21
+ {
22
+ "path": "./tsconfig.spec.json"
23
+ }
24
+ ],
25
+ "extends": "../../tsconfig.base.json",
26
+ "angularCompilerOptions": {
27
+ "enableI18nLegacyMessageIdFormat": false,
28
+ "strictInjectionParameters": true,
29
+ "strictInputAccessModifiers": true,
30
+ "strictTemplates": true
31
+ }
32
+ }
@@ -0,0 +1,11 @@
1
+ # examples-node
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build examples-node` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test examples-node` to execute the unit tests via [Jest](https://jestjs.io).
@@ -0,0 +1,22 @@
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}',
13
+ '{projectRoot}/esbuild.config.{js,ts,mjs,mts}',
14
+ ],
15
+ },
16
+ ],
17
+ },
18
+ languageOptions: {
19
+ parser: await import('jsonc-eslint-parser'),
20
+ },
21
+ },
22
+ ];
@@ -0,0 +1,10 @@
1
+ export default {
2
+ displayName: 'examples-node',
3
+ preset: '../../jest.preset.js',
4
+ testEnvironment: 'node',
5
+ transform: {
6
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
+ },
8
+ moduleFileExtensions: ['ts', 'js', 'html'],
9
+ coverageDirectory: '../../coverage/examples/node',
10
+ };
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@reactionary/examples-node",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "dependencies": {
6
+ "@reactionary/provider-algolia": "0.0.1",
7
+ "@reactionary/core": "0.0.1",
8
+ "zod": "4.0.0-beta.20250430T185432"
9
+ }
10
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "examples-node",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "examples/node/src",
5
+ "projectType": "library",
6
+ "tags": [],
7
+ "targets": {
8
+ "build": {
9
+ "executor": "@nx/esbuild:esbuild",
10
+ "outputs": ["{options.outputPath}"],
11
+ "options": {
12
+ "outputPath": "dist/examples/node",
13
+ "main": "examples/node/src/index.ts",
14
+ "tsConfig": "examples/node/tsconfig.lib.json",
15
+ "assets": ["examples/node/*.md"],
16
+ "format": ["esm"]
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,2 @@
1
+ // FIXME: Convert from a library to an application. This is required due to it being a package...
2
+ export const FOO = 42;
@@ -0,0 +1,29 @@
1
+ import { buildClient } from '@reactionary/core';
2
+ import { withAlgoliaCapabilities } from '@reactionary/provider-algolia';
3
+
4
+ describe('initialize algolia', () => {
5
+ it('should be able to search against algolia', async () => {
6
+ const client = buildClient([
7
+ withAlgoliaCapabilities(
8
+ {
9
+ apiKey: process.env['ALGOLIA_API_KEY'] || '',
10
+ appId: process.env['ALGOLIA_APP_ID'] || '',
11
+ indexName: process.env['ALGOLIA_INDEX'] || '',
12
+ },
13
+ { product: true, search: true }
14
+ ),
15
+ ]);
16
+
17
+ expect(client.search).toBeDefined();
18
+
19
+ const result = await client.search.get({
20
+ term: 'glass',
21
+ page: 0,
22
+ pageSize: 10,
23
+ facets: []
24
+ });
25
+
26
+ expect(result.identifier.term).toBe('glass');
27
+ expect(result.products.length).toBeGreaterThan(0);
28
+ });
29
+ });
@@ -0,0 +1,31 @@
1
+ import { buildClient } from '@reactionary/core';
2
+ import { withCommercetoolsCapabilities } from '@reactionary/provider-commercetools';
3
+
4
+ describe('initialize commercetools', () => {
5
+ it('should be able to search against commercetools', async () => {
6
+ const client = buildClient([
7
+ withCommercetoolsCapabilities(
8
+ {
9
+ apiUrl: process.env['COMMERCETOOLS_API_URL'] || '',
10
+ authUrl: process.env['COMMERCETOOLS_AUTH_URL'] || '',
11
+ clientId: process.env['COMMERCETOOLS_CLIENT_ID'] || '',
12
+ clientSecret: process.env['COMMERCETOOLS_CLIENT_SECRET'] || '',
13
+ projectKey: process.env['COMMERCETOOLS_PROJECT_KEY'] || '',
14
+ },
15
+ { product: true, search: true }
16
+ ),
17
+ ]);
18
+
19
+ expect(client.search).toBeDefined();
20
+
21
+ const result = await client.search.get({
22
+ term: 'glass',
23
+ page: 0,
24
+ pageSize: 10,
25
+ facets: []
26
+ });
27
+
28
+ expect(result.identifier.term).toBe('glass');
29
+ expect(result.products.length).toBeGreaterThan(0);
30
+ });
31
+ });
@@ -0,0 +1,38 @@
1
+ import { buildClient, Session } from '@reactionary/core';
2
+ import { CustomAlgoliaProductProvider } from './providers/custom-algolia-product.provider';
3
+
4
+
5
+ describe('initialize extended providers', () => {
6
+ it('should be able to extend a provider with a custom schema with a default value', async () => {
7
+ const session: Session = {
8
+ id: '1234',
9
+ identity: {
10
+ id: '1234',
11
+ issued: new Date(),
12
+ expiry: new Date(),
13
+ token: '',
14
+ type: 'Anonymous'
15
+ }
16
+ }
17
+
18
+ const provider = new CustomAlgoliaProductProvider({
19
+ apiKey: process.env['ALGOLIA_API_KEY'] || '',
20
+ appId: process.env['ALGOLIA_APP_ID'] || '',
21
+ indexName: process.env['ALGOLIA_INDEX'] || '',
22
+ });
23
+
24
+ const client = buildClient([
25
+ {
26
+ product: provider
27
+ }
28
+ ]);
29
+
30
+ const product = await client.product.query([{
31
+ id: '4d28f98d-c446-446e-b59a-d9f718e5b98a',
32
+ query: 'id'
33
+ }], session);
34
+
35
+ expect(product[0].gtin).toBe('missingggg');
36
+ expect(product[0].name).toBe('SUNNAI GLASS BOWL');
37
+ });
38
+ });
@@ -0,0 +1,36 @@
1
+ import { buildClient } from '@reactionary/core';
2
+ import { withAlgoliaCapabilities } from '@reactionary/provider-algolia';
3
+ import { withCommercetoolsCapabilities } from '@reactionary/provider-commercetools';
4
+
5
+ describe('initialize mixed providers', () => {
6
+ it('should be able to handle a mixture of providers', async () => {
7
+ const client = buildClient([
8
+ withAlgoliaCapabilities(
9
+ {
10
+ apiKey: process.env['ALGOLIA_API_KEY'] || '',
11
+ appId: process.env['ALGOLIA_APP_ID'] || '',
12
+ indexName: process.env['ALGOLIA_INDEX'] || '',
13
+ },
14
+ { search: true }
15
+ ),
16
+ withCommercetoolsCapabilities(
17
+ {
18
+ apiUrl: process.env['COMMERCETOOLS_API_URL'] || '',
19
+ authUrl: process.env['COMMERCETOOLS_AUTH_URL'] || '',
20
+ clientId: process.env['COMMERCETOOLS_CLIENT_ID'] || '',
21
+ clientSecret: process.env['COMMERCETOOLS_CLIENT_SECRET'] || '',
22
+ projectKey: process.env['COMMERCETOOLS_PROJECT_KEY'] || '',
23
+ },
24
+ { product: true }
25
+ ),
26
+ ]);
27
+
28
+ const search = await client.search.get({ term: 'glass', page: 0, pageSize: 10, facets: [] });
29
+
30
+ expect(search.products.length).toBeGreaterThan(0);
31
+
32
+ const product = await client.product.get({ id: search.products[0].identifier.key });
33
+
34
+ expect(product.identifier.key).toBe(search.products[0].identifier.key);
35
+ });
36
+ });
@@ -0,0 +1,18 @@
1
+ import { AlgoliaConfiguration, AlgoliaProductProvider } from '@reactionary/provider-algolia';
2
+ import { CustomProduct, CustomProductSchema } from '../schemas/custom-product.schema';
3
+ import { ProductMutationSchema, ProductQuerySchema } from '@reactionary/core';
4
+
5
+ export class CustomAlgoliaProductProvider extends AlgoliaProductProvider<CustomProduct> {
6
+ constructor(config: AlgoliaConfiguration) {
7
+ super(config, CustomProductSchema, ProductQuerySchema, ProductMutationSchema);
8
+ }
9
+
10
+ public parse(data: any): CustomProduct {
11
+ const result = super.newModel();
12
+
13
+ result.gtin = data.ean8 ?? data.ean13 ?? data.partNumber ?? 'missingggg';
14
+ result.name = result.name.toUpperCase();
15
+
16
+ return result;
17
+ }
18
+ }
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ import { ProductSchema } from '@reactionary/core';
3
+
4
+ export const CustomProductSchema = ProductSchema.extend({
5
+ gtin: z.string().min(8),
6
+ });
7
+
8
+ export type CustomProduct = z.infer<typeof CustomProductSchema>;
@@ -0,0 +1,23 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "importHelpers": true,
8
+ "noImplicitOverride": true,
9
+ "noImplicitReturns": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "noPropertyAccessFromIndexSignature": true
12
+ },
13
+ "files": [],
14
+ "include": [],
15
+ "references": [
16
+ {
17
+ "path": "./tsconfig.lib.json"
18
+ },
19
+ {
20
+ "path": "./tsconfig.spec.json"
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "declaration": true,
6
+ "types": ["node"]
7
+ },
8
+ "include": ["src/**/*.ts"],
9
+ "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
10
+ }