@aws/nx-plugin 0.1.6 → 0.2.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 (126) hide show
  1. package/LICENSE-THIRD-PARTY +1554 -3241
  2. package/generators.json +1 -13
  3. package/package.json +14 -14
  4. package/src/cloudscape-website/app/README.md +84 -48
  5. package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +168 -233
  6. package/src/cloudscape-website/app/files/app/README.md.template +44 -0
  7. package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
  8. package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
  9. package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
  10. package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
  11. package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
  12. package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
  13. package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +79 -144
  14. package/src/cloudscape-website/app/generator.js +90 -74
  15. package/src/cloudscape-website/app/generator.js.map +1 -1
  16. package/src/cloudscape-website/app/schema.d.ts +3 -5
  17. package/src/cloudscape-website/app/schema.json +1 -24
  18. package/src/cloudscape-website/cognito-auth/README.md +53 -32
  19. package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +162 -124
  20. package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
  21. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
  22. package/src/cloudscape-website/cognito-auth/generator.js +130 -47
  23. package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
  24. package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
  25. package/src/cloudscape-website/cognito-auth/schema.json +7 -1
  26. package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +20 -15
  27. package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
  28. package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
  29. package/src/cloudscape-website/runtime-config/generator.js +4 -2
  30. package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
  31. package/src/infra/app/README.md +71 -46
  32. package/src/infra/app/__snapshots__/generator.spec.ts.snap +184 -305
  33. package/src/infra/app/files/app/README.md.template +76 -0
  34. package/src/infra/app/files/app/src/main.ts.template +18 -0
  35. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
  36. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
  37. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
  38. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
  39. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
  40. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
  41. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
  42. package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
  43. package/src/infra/app/generator.js +36 -7
  44. package/src/infra/app/generator.js.map +1 -1
  45. package/src/infra/app/schema.d.ts +10 -1
  46. package/src/infra/app/schema.json +16 -8
  47. package/src/trpc/backend/README.md +102 -80
  48. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +42 -19
  49. package/src/trpc/backend/files/backend/README.md.template +33 -0
  50. package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
  51. package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
  52. package/src/trpc/backend/files/schema/README.md.template +33 -0
  53. package/src/trpc/backend/generator.js +30 -44
  54. package/src/trpc/backend/generator.js.map +1 -1
  55. package/src/trpc/backend/schema.d.ts +3 -1
  56. package/src/trpc/backend/schema.json +8 -13
  57. package/src/trpc/react/README.md +46 -66
  58. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
  59. package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
  60. package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
  61. package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
  62. package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
  63. package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
  64. package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
  65. package/src/trpc/react/generator.js +124 -25
  66. package/src/trpc/react/generator.js.map +1 -1
  67. package/src/trpc/react/schema.json +2 -2
  68. package/src/ts/lib/__snapshots__/generator.spec.ts.snap +47 -93
  69. package/src/ts/lib/eslint.d.ts +1 -2
  70. package/src/ts/lib/eslint.js +62 -21
  71. package/src/ts/lib/eslint.js.map +1 -1
  72. package/src/ts/lib/files/README.md.template +33 -0
  73. package/src/ts/lib/generator.js +44 -5
  74. package/src/ts/lib/generator.js.map +1 -1
  75. package/src/ts/lib/schema.d.ts +1 -4
  76. package/src/ts/lib/schema.json +2 -21
  77. package/src/ts/lib/ts-project-utils.js +3 -18
  78. package/src/ts/lib/ts-project-utils.js.map +1 -1
  79. package/src/ts/lib/vitest.js +12 -0
  80. package/src/ts/lib/vitest.js.map +1 -1
  81. package/src/utils/ast.d.ts +13 -0
  82. package/src/utils/ast.js +102 -0
  83. package/src/utils/ast.js.map +1 -0
  84. package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
  85. package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
  86. package/src/utils/files/common/constructs/src/index.ts.template +2 -1
  87. package/src/utils/files/common/readme/README.md.template +33 -0
  88. package/src/utils/files/common/types/src/runtime-config.ts.template +2 -13
  89. package/src/utils/format.d.ts +1 -1
  90. package/src/utils/format.js +2 -2
  91. package/src/utils/format.js.map +1 -1
  92. package/src/utils/names.d.ts +2 -0
  93. package/src/utils/names.js +27 -0
  94. package/src/utils/names.js.map +1 -0
  95. package/src/utils/npm-scope.js.map +1 -1
  96. package/src/utils/paths.js.map +1 -1
  97. package/src/utils/shared-constructs.js +37 -4
  98. package/src/utils/shared-constructs.js.map +1 -1
  99. package/src/utils/test.d.ts +2 -0
  100. package/src/utils/test.js +19 -0
  101. package/src/utils/test.js.map +1 -0
  102. package/src/utils/versions.d.ts +15 -9
  103. package/src/utils/versions.js +14 -8
  104. package/src/utils/versions.js.map +1 -1
  105. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
  106. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
  107. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
  108. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
  109. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
  110. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
  111. package/src/gitlab/generator.d.ts +0 -8
  112. package/src/gitlab/generator.js +0 -16
  113. package/src/gitlab/generator.js.map +0 -1
  114. package/src/gitlab/schema.d.ts +0 -9
  115. package/src/gitlab/schema.json +0 -52
  116. package/src/infra/app/files/src/main.ts.template +0 -37
  117. package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
  118. package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
  119. package/src/ts/cjs-to-esm/generator.d.ts +0 -12
  120. package/src/ts/cjs-to-esm/generator.js +0 -189
  121. package/src/ts/cjs-to-esm/generator.js.map +0 -1
  122. package/src/ts/cjs-to-esm/schema.d.ts +0 -9
  123. package/src/ts/cjs-to-esm/schema.json +0 -28
  124. /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
  125. /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
  126. /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
@@ -1,7 +1,8 @@
1
1
  # tRPC React Generator
2
2
 
3
3
  ## Overview
4
- This generator adds tRPC client integration to your React application, enabling type-safe API calls to your tRPC backend. It sets up all necessary configuration for connecting to your tRPC backend, including AWS IAM authentication support and proper error handling. The integration provides full end-to-end type safety between your frontend and backend.
4
+
5
+ This generator adds tRPC client integration to your React application, enabling type-safe API calls to your tRPC backend. It sets up all necessary configuration for connecting to your tRPC backends, including AWS IAM authentication support and proper error handling. The integration provides full end-to-end type safety between your frontend and tRPC backend(s).
5
6
 
6
7
  ## Prerequisites
7
8
 
@@ -12,14 +13,13 @@ Before using this generator, ensure your React application has:
12
13
  3. A working tRPC backend (generated using the tRPC backend generator)
13
14
 
14
15
  Example of required `main.tsx` structure:
16
+
15
17
  ```tsx
16
18
  import { StrictMode } from 'react';
17
19
  import * as ReactDOM from 'react-dom/client';
18
20
  import App from './app/app';
19
21
 
20
- const root = ReactDOM.createRoot(
21
- document.getElementById('root') as HTMLElement
22
- );
22
+ const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
23
23
  root.render(
24
24
  <StrictMode>
25
25
  <App />
@@ -34,12 +34,14 @@ You can generate the tRPC React integration in two ways:
34
34
  ### 1. Using VSCode IDE
35
35
 
36
36
  First, install the NX Console extension for VSCode:
37
+
37
38
  1. Open VSCode
38
39
  2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
39
40
  3. Search for "Nx Console"
40
41
  4. Install [Nx Console](https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console)
41
42
 
42
43
  Then add tRPC to your React application:
44
+
43
45
  1. Open the NX Console in VSCode
44
46
  2. Click on "Generate"
45
47
  3. Search for "trpc#react"
@@ -49,11 +51,13 @@ Then add tRPC to your React application:
49
51
  ### 2. Using CLI
50
52
 
51
53
  Add tRPC to your React application:
54
+
52
55
  ```bash
53
56
  nx g @aws/nx-plugin:trpc#react --frontendProjectName=my-app --backendProjectName=my-api --auth=IAM
54
57
  ```
55
58
 
56
59
  You can also perform a dry-run to see what files would be generated without actually creating them:
60
+
57
61
  ```bash
58
62
  nx g @aws/nx-plugin:trpc#react --frontendProjectName=my-app --backendProjectName=my-api --auth=IAM --dry-run
59
63
  ```
@@ -62,13 +66,13 @@ Both methods will add tRPC client integration to your React application with all
62
66
 
63
67
  ## Input Parameters
64
68
 
65
- | Parameter | Type | Default | Description |
66
- |-----------|------|---------|-------------|
67
- | frontendProjectName* | string | - | The name of your React application project (required). |
68
- | backendProjectName* | string | - | The name of your tRPC backend project (required). |
69
- | auth* | string | "IAM" | Authentication strategy. Options: "IAM", "None" |
69
+ | Parameter | Type | Default | Description |
70
+ | --------------------- | ------ | ------- | ------------------------------------------------------ |
71
+ | frontendProjectName\* | string | - | The name of your React application project (required). |
72
+ | backendProjectName\* | string | - | The name of your tRPC backend project (required). |
73
+ | auth\* | string | "IAM" | Authentication strategy. Options: "IAM", "None" |
70
74
 
71
- *Required parameter
75
+ \*Required parameter
72
76
 
73
77
  ## Expected Output
74
78
 
@@ -77,13 +81,18 @@ The generator creates the following structure in your React application:
77
81
  ```
78
82
  src/
79
83
  ├── components/
80
- │ └── TRPCClientProvider/
81
- │ └── index.tsx # tRPC client configuration and provider
84
+ │ └── TrpcClients/
85
+ │ └── index.tsx
86
+ │ └── IsolatedTrpcProvider.tsx # Supports add connections to multiple tRPC APIs
87
+ │ └── TrpcApis.tsx # Object containing all of your trpc API connections
88
+ │ └── TrpcClientProviders.tsx # Sets up the trpc clients and bindings to your backend schema(s)
82
89
  └── hooks/
83
- └── useTrpc.tsx # Custom hook for using tRPC client
90
+ └── useSigV4.tsx # Custom hook for signing HTTP(s) requests with SigV4 (IAM only)
91
+ └── use<ApiName>.tsx # Adds a hook for the given backend API. ApiName will resolve to the name of the api.
84
92
  ```
85
93
 
86
94
  Additionally, it:
95
+
87
96
  1. Installs required dependencies:
88
97
  - @trpc/client
89
98
  - @trpc/react-query
@@ -94,13 +103,13 @@ Additionally, it:
94
103
 
95
104
  ### Using the tRPC Hook
96
105
 
97
- The generator provides a `useTrpc` hook that gives you access to the type-safe tRPC client:
106
+ The generator provides a `use<ApiName>` hook that gives you access to the type-safe tRPC client:
98
107
 
99
108
  ```tsx
100
- import { useTrpc } from './hooks/useTrpc';
109
+ import { useMyApi } from './hooks/useMyApi';
101
110
 
102
111
  function MyComponent() {
103
- const trpc = useTrpc();
112
+ const trpc = useMyApi();
104
113
 
105
114
  // Example query
106
115
  const { data, isLoading } = trpc.users.list.useQuery();
@@ -111,17 +120,13 @@ function MyComponent() {
111
120
  const handleCreate = () => {
112
121
  mutation.mutate({
113
122
  name: 'John Doe',
114
- email: 'john@example.com'
123
+ email: 'john@example.com',
115
124
  });
116
125
  };
117
126
 
118
127
  if (isLoading) return <div>Loading...</div>;
119
128
 
120
- return (
121
- <div>
122
- {/* Your component JSX */}
123
- </div>
124
- );
129
+ return <div>{/* Your component JSX */}</div>;
125
130
  }
126
131
  ```
127
132
 
@@ -145,11 +150,7 @@ function MyComponent() {
145
150
  );
146
151
  }
147
152
 
148
- return (
149
- <div>
150
- {/* Your component JSX */}
151
- </div>
152
- );
153
+ return <div>{/* Your component JSX */}</div>;
153
154
  }
154
155
  ```
155
156
 
@@ -173,7 +174,7 @@ function UserList() {
173
174
 
174
175
  return (
175
176
  <ul>
176
- {users.data.map(user => (
177
+ {users.data.map((user) => (
177
178
  <li key={user.id}>{user.name}</li>
178
179
  ))}
179
180
  </ul>
@@ -187,7 +188,7 @@ Use optimistic updates for better user experience:
187
188
 
188
189
  ```tsx
189
190
  function UserList() {
190
- const trpc = useTrpc();
191
+ const trpc = useUsers();
191
192
  const utils = trpc.useUtils();
192
193
 
193
194
  const deleteMutation = trpc.users.delete.useMutation({
@@ -199,26 +200,22 @@ function UserList() {
199
200
  const previousUsers = utils.users.list.getData();
200
201
 
201
202
  // Optimistically remove the user
202
- utils.users.list.setData(undefined, (old) =>
203
- old?.filter(user => user.id !== userId)
204
- );
203
+ utils.users.list.setData(undefined, (old) => old?.filter((user) => user.id !== userId));
205
204
 
206
205
  return { previousUsers };
207
206
  },
208
207
  onError: (err, userId, context) => {
209
208
  // Restore previous data on error
210
209
  utils.users.list.setData(undefined, context?.previousUsers);
211
- }
210
+ },
212
211
  });
213
212
 
214
213
  return (
215
214
  <ul>
216
- {users.map(user => (
215
+ {users.map((user) => (
217
216
  <li key={user.id}>
218
217
  {user.name}
219
- <button onClick={() => deleteMutation.mutate(user.id)}>
220
- Delete
221
- </button>
218
+ <button onClick={() => deleteMutation.mutate(user.id)}>Delete</button>
222
219
  </li>
223
220
  ))}
224
221
  </ul>
@@ -232,7 +229,7 @@ Prefetch data for better performance:
232
229
 
233
230
  ```tsx
234
231
  function UserList() {
235
- const trpc = useTrpc();
232
+ const trpc = useUsers();
236
233
 
237
234
  // Prefetch user details on hover
238
235
  const prefetchUser = async (userId: string) => {
@@ -241,14 +238,9 @@ function UserList() {
241
238
 
242
239
  return (
243
240
  <ul>
244
- {users.map(user => (
245
- <li
246
- key={user.id}
247
- onMouseEnter={() => prefetchUser(user.id)}
248
- >
249
- <Link to={`/users/${user.id}`}>
250
- {user.name}
251
- </Link>
241
+ {users.map((user) => (
242
+ <li key={user.id} onMouseEnter={() => prefetchUser(user.id)}>
243
+ <Link to={`/users/${user.id}`}>{user.name}</Link>
252
244
  </li>
253
245
  ))}
254
246
  </ul>
@@ -262,14 +254,9 @@ Handle pagination with infinite queries:
262
254
 
263
255
  ```tsx
264
256
  function UserList() {
265
- const trpc = useTrpc();
257
+ const trpc = useUsers();
266
258
 
267
- const {
268
- data,
269
- fetchNextPage,
270
- hasNextPage,
271
- isFetchingNextPage
272
- } = trpc.users.list.useInfiniteQuery(
259
+ const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = trpc.users.list.useInfiniteQuery(
273
260
  { limit: 10 },
274
261
  {
275
262
  getNextPageParam: (lastPage) => lastPage.nextCursor,
@@ -278,17 +265,10 @@ function UserList() {
278
265
 
279
266
  return (
280
267
  <div>
281
- {data?.pages.map((page) => (
282
- page.users.map(user => (
283
- <UserCard key={user.id} user={user} />
284
- ))
285
- ))}
268
+ {data?.pages.map((page) => page.users.map((user) => <UserCard key={user.id} user={user} />))}
286
269
 
287
270
  {hasNextPage && (
288
- <button
289
- onClick={() => fetchNextPage()}
290
- disabled={isFetchingNextPage}
291
- >
271
+ <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
292
272
  {isFetchingNextPage ? 'Loading...' : 'Load More'}
293
273
  </button>
294
274
  )}
@@ -303,16 +283,16 @@ The integration provides complete end-to-end type safety. Your IDE will provide
303
283
 
304
284
  ```tsx
305
285
  function UserForm() {
306
- const trpc = useTrpc();
307
-
286
+ const trpc = useUsers();
287
+
308
288
  // ✅ Input is fully typed
309
289
  const createUser = trpc.users.create.useMutation();
310
-
290
+
311
291
  const handleSubmit = (data: CreateUserInput) => {
312
292
  // ✅ Type error if input doesn't match schema
313
293
  createUser.mutate(data);
314
294
  };
315
-
295
+
316
296
  return <form onSubmit={handleSubmit}>{/* ... */}</form>;
317
297
  }
318
298
  ```
@@ -1,85 +1,124 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`trpc react generator > should generate trpc react files > TRPCClientProvider.tsx 1`] = `
3
+ exports[`trpc react generator > should generate trpc react files > TrpcClients-IsolatedTrpcProvider.tsx 1`] = `
4
4
  "import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
5
- import { httpBatchLink } from '@trpc/react-query';
6
- import { useContext, useState, FC } from 'react';
7
- import { useTrpc } from '../../hooks/useTrpc';
8
- import { RuntimeConfigContext } from '../RuntimeConfig';
9
-
10
- const TRPCClientProvider: FC<any> = ({ children }) => {
11
- const trpc = useTrpc();
12
- const runtimeContext = useContext(RuntimeConfigContext);
13
- const [queryClient] = useState(() => new QueryClient());
14
-
15
- const [trpcClient] = useState(() =>
16
- trpc.createClient({
17
- links: [
18
- httpBatchLink({
19
- url: runtimeContext?.trpcApis?.['TestApi']!,
20
- }),
21
- ],
22
- })
23
- );
5
+ import { createTRPCReact } from '@trpc/react-query';
6
+ import {
7
+ httpBatchLink,
8
+ httpLink,
9
+ HTTPBatchLinkOptions,
10
+ HTTPLinkOptions,
11
+ splitLink,
12
+ } from '@trpc/client';
13
+ import { useState, FC, createContext, useMemo, PropsWithChildren } from 'react';
24
14
 
25
- return (
26
- <trpc.Provider client={trpcClient} queryClient={queryClient}>
27
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
28
- </trpc.Provider>
29
- );
30
- };
15
+ import { AnyTRPCRouter } from '@trpc/server';
31
16
 
32
- export default TRPCClientProvider;
33
- "
34
- `;
17
+ export interface IsolatedTrpcClientProviderProps extends PropsWithChildren {
18
+ readonly apiUrl: string;
19
+ }
35
20
 
36
- exports[`trpc react generator > should generate trpc react files > useTrpc.tsx 1`] = `
37
- "import type { AppRouter } from 'backend';
38
- import { createTRPCReact } from '@trpc/react-query';
21
+ export const createIsolatedTrpcClientProvider = <
22
+ TAppRouter extends AnyTRPCRouter,
23
+ TContext,
24
+ >() => {
25
+ const isolatedTrpcContext = createContext(null as any);
26
+ const trpc = createTRPCReact<TAppRouter, TContext>({
27
+ context: isolatedTrpcContext,
28
+ });
29
+
30
+ const IsolatedTrpcClientProvider: FC<IsolatedTrpcClientProviderProps> = ({
31
+ apiUrl,
32
+ children,
33
+ }) => {
34
+ const [queryClient] = useState(() => new QueryClient());
35
+
36
+ const trpcClient = useMemo(() => {
37
+ const linkOptions: HTTPLinkOptions<any> & HTTPBatchLinkOptions<any> = {
38
+ url: apiUrl,
39
+ };
39
40
 
40
- const trpc = createTRPCReact<AppRouter>();
41
- export const useTrpc = () => trpc;
41
+ // @ts-expect-error type errors due to unknown concrete AppRouter
42
+ return trpc.createClient({
43
+ links: [
44
+ splitLink({
45
+ condition(op) {
46
+ return op.context.skipBatch === true;
47
+ },
48
+ true: httpLink(linkOptions),
49
+ false: httpBatchLink(linkOptions),
50
+ }),
51
+ ],
52
+ });
53
+ }, [apiUrl, sigv4Client]);
54
+
55
+ return (
56
+ // @ts-expect-error type errors due to unknown concrete AppRouter
57
+ <trpc.Provider client={trpcClient} queryClient={queryClient}>
58
+ <QueryClientProvider client={queryClient}>
59
+ {children}
60
+ </QueryClientProvider>
61
+ {/* @ts-expect-error type errors due to unknown concrete AppRouter */}
62
+ </trpc.Provider>
63
+ );
64
+ };
65
+
66
+ return {
67
+ trpc,
68
+ Provider: IsolatedTrpcClientProvider,
69
+ };
70
+ };
42
71
  "
43
72
  `;
44
73
 
45
- exports[`trpc react generator > should handle IAM auth option > TRPCClientProvider-IAM.tsx 1`] = `
46
- "import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
47
- import { httpBatchLink } from '@trpc/react-query';
48
- import { useContext, useState, FC } from 'react';
49
- import { useTrpc } from '../../hooks/useTrpc';
50
- import { RuntimeConfigContext } from '../RuntimeConfig';
51
- import useSigV4Client from '@aws-northstar/ui/components/CognitoAuth/hooks/useSigv4Client';
52
-
53
- const TRPCClientProvider: FC<any> = ({ children }) => {
54
- const trpc = useTrpc();
55
- const runtimeContext = useContext(RuntimeConfigContext);
56
- const [queryClient] = useState(() => new QueryClient());
57
- const sigv4Client = useSigV4Client();
58
-
59
- const [trpcClient] = useState(() =>
60
- trpc.createClient({
61
- links: [
62
- httpBatchLink({
63
- url: runtimeContext?.trpcApis?.['TestApi']!,
64
- fetch: sigv4Client,
65
- }),
66
- ],
67
- })
68
- );
74
+ exports[`trpc react generator > should generate trpc react files > TrpcClients-TrpcApis.tsx 1`] = `
75
+ "import {
76
+ AppRouter as TestApiAppRouter,
77
+ Context as TestApiContext,
78
+ } from 'backend';
79
+ import { createIsolatedTrpcClientProvider } from './IsolatedTrpcProvider';
80
+ export default {
81
+ TestApi: createIsolatedTrpcClientProvider<TestApiAppRouter, TestApiContext>(),
82
+ };
83
+ "
84
+ `;
69
85
 
86
+ exports[`trpc react generator > should generate trpc react files > TrpcClients-TrpcClientProviders.tsx 1`] = `
87
+ "import TrpcApis from './TrpcApis';
88
+ import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
89
+ import { FC, PropsWithChildren } from 'react';
90
+ const TrpcClientProviders: FC<PropsWithChildren> = ({ children }) => {
91
+ const runtimeConfig = useRuntimeConfig();
70
92
  return (
71
- <trpc.Provider client={trpcClient} queryClient={queryClient}>
72
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
73
- </trpc.Provider>
93
+ <TrpcApis.TestApi.Provider apiUrl={runtimeConfig.trpcApis.TestApi}>
94
+ {children}
95
+ </TrpcApis.TestApi.Provider>
74
96
  );
75
97
  };
98
+ export default TrpcClientProviders;
99
+ "
100
+ `;
76
101
 
77
- export default TRPCClientProvider;
102
+ exports[`trpc react generator > should generate trpc react files > TrpcClients-index.tsx 1`] = `
103
+ "import TrpcClientProviders from './TrpcClientProviders';
104
+ import _TrpcApis from './TrpcApis';
105
+
106
+ export const TrpcApis = _TrpcApis;
107
+ export default TrpcClientProviders;
108
+ "
109
+ `;
110
+
111
+ exports[`trpc react generator > should generate trpc react files > useTestApi.tsx 1`] = `
112
+ "import { TrpcApis } from '../components/TrpcClients';
113
+
114
+ export const useTestApi = () => TrpcApis.TestApi.trpc;
78
115
  "
79
116
  `;
80
117
 
118
+ exports[`trpc react generator > should handle IAM auth option > TRPCClientProvider-IAM.tsx 1`] = `null`;
119
+
81
120
  exports[`trpc react generator > should modify main.tsx correctly > main.tsx 1`] = `
82
- "import TRPCClientProvider from './components/TRPCClientProvider';
121
+ "import TrpcClientProviders from './components/TrpcClients';
83
122
  import RuntimeConfigProvider from './components/RuntimeConfig';
84
123
  import { App } from './app';
85
124
  import { BrowserRouter } from 'react-router-dom';
@@ -87,9 +126,9 @@ export function Main() {
87
126
  return (
88
127
  <RuntimeConfigProvider>
89
128
  <BrowserRouter>
90
- <TRPCClientProvider>
129
+ <TrpcClientProviders>
91
130
  <App />
92
- </TRPCClientProvider>
131
+ </TrpcClientProviders>
93
132
  </BrowserRouter>
94
133
  </RuntimeConfigProvider>
95
134
  );
@@ -0,0 +1,75 @@
1
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
2
+ import { createTRPCReact } from '@trpc/react-query';
3
+ import {
4
+ httpBatchLink,
5
+ httpLink,
6
+ HTTPBatchLinkOptions,
7
+ HTTPLinkOptions,
8
+ splitLink,
9
+ } from '@trpc/client';
10
+ import {
11
+ useState,
12
+ FC,
13
+ createContext,
14
+ useMemo,
15
+ PropsWithChildren,
16
+ } from 'react';
17
+ <% if(auth === 'IAM') { %> import { useSigV4 } from '../../hooks/useSigV4'; <% } %>
18
+ import { AnyTRPCRouter } from '@trpc/server';
19
+
20
+ export interface IsolatedTrpcClientProviderProps extends PropsWithChildren {
21
+ readonly apiUrl: string;
22
+ }
23
+
24
+ export const createIsolatedTrpcClientProvider = <
25
+ TAppRouter extends AnyTRPCRouter,
26
+ TContext
27
+ >() => {
28
+ const isolatedTrpcContext = createContext(null as any);
29
+ const trpc = createTRPCReact<TAppRouter, TContext>({
30
+ context: isolatedTrpcContext,
31
+ });
32
+
33
+ const IsolatedTrpcClientProvider: FC<IsolatedTrpcClientProviderProps> = ({
34
+ apiUrl,
35
+ children,
36
+ }) => {
37
+ const [queryClient] = useState(() => new QueryClient());
38
+ <% if(auth === 'IAM') { %> const sigv4Client = useSigV4(); <% } %>
39
+
40
+ const trpcClient = useMemo(() => {
41
+ const linkOptions: HTTPLinkOptions<any> & HTTPBatchLinkOptions<any> = {
42
+ url: apiUrl,
43
+ <% if(auth === 'IAM') { %> fetch: sigv4Client <% } %>
44
+ };
45
+
46
+ // @ts-expect-error type errors due to unknown concrete AppRouter
47
+ return trpc.createClient({
48
+ links: [
49
+ splitLink({
50
+ condition(op) {
51
+ return op.context.skipBatch === true;
52
+ },
53
+ true: httpLink(linkOptions),
54
+ false: httpBatchLink(linkOptions),
55
+ }),
56
+ ],
57
+ });
58
+ }, [apiUrl, sigv4Client]);
59
+
60
+ return (
61
+ // @ts-expect-error type errors due to unknown concrete AppRouter
62
+ <trpc.Provider client={trpcClient} queryClient={queryClient}>
63
+ <QueryClientProvider client={queryClient}>
64
+ {children}
65
+ </QueryClientProvider>
66
+ {/* @ts-expect-error type errors due to unknown concrete AppRouter */}
67
+ </trpc.Provider>
68
+ );
69
+ };
70
+
71
+ return {
72
+ trpc,
73
+ Provider: IsolatedTrpcClientProvider,
74
+ };
75
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ FC,
3
+ PropsWithChildren,
4
+ } from 'react';
5
+
6
+ const TrpcClientProviders: FC<PropsWithChildren> = ({ children }) => {
7
+ return children;
8
+ };
9
+
10
+ export default TrpcClientProviders;
@@ -0,0 +1,5 @@
1
+ import TrpcClientProviders from "./TrpcClientProviders";
2
+ import _TrpcApis from "./TrpcApis";
3
+
4
+ export const TrpcApis = _TrpcApis;
5
+ export default TrpcClientProviders;
@@ -0,0 +1,38 @@
1
+ import { AwsClient } from 'aws4fetch';
2
+ import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';
3
+ import { fromCognitoIdentityPool } from '@aws-sdk/credential-provider-cognito-identity';
4
+ import { useCallback } from 'react';
5
+ import { useAuth } from 'react-oidc-context';
6
+ import { useRuntimeConfig } from './useRuntimeConfig';
7
+
8
+ export const useSigV4 = () => {
9
+ const { cognitoProps } = useRuntimeConfig();
10
+ const { user } = useAuth();
11
+
12
+ return useCallback(
13
+ async (input: RequestInfo | URL, init?: RequestInit | undefined) => {
14
+ if (!cognitoProps) {
15
+ throw new Error('cognitoProps is undefined!');
16
+ }
17
+ if (!user?.id_token) {
18
+ throw new Error('user.id_token is undefined!');
19
+ }
20
+
21
+ const credentialsFromCognitoIdentityPool = fromCognitoIdentityPool({
22
+ client: new CognitoIdentityClient({ region: cognitoProps.region }),
23
+ identityPoolId: cognitoProps.identityPoolId,
24
+ logins: {
25
+ [`cognito-idp.${cognitoProps.region}.amazonaws.com/${cognitoProps.userPoolId}`]:
26
+ user.id_token,
27
+ },
28
+ });
29
+ const cognitoidentity = new CognitoIdentityClient({
30
+ credentials: credentialsFromCognitoIdentityPool,
31
+ });
32
+ const credential = await cognitoidentity.config.credentials();
33
+ const awsClient = new AwsClient(credential);
34
+ return awsClient.fetch(input, init);
35
+ },
36
+ [cognitoProps, user?.id_token]
37
+ );
38
+ };
@@ -0,0 +1,3 @@
1
+ import { TrpcApis } from '../components/TrpcClients';
2
+
3
+ export const use<%= apiNameClassName %> = () => TrpcApis.<%= apiNameClassName %>.trpc;