create-react-starter-kit 1.0.6 → 1.0.7

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 (76) hide show
  1. package/dist/cli-args.d.ts.map +1 -1
  2. package/dist/cli-args.js +2 -1
  3. package/dist/cli-args.js.map +1 -1
  4. package/dist/generator/index.d.ts.map +1 -1
  5. package/dist/generator/index.js +1 -0
  6. package/dist/generator/index.js.map +1 -1
  7. package/dist/prompts/index.d.ts.map +1 -1
  8. package/dist/prompts/index.js +8 -0
  9. package/dist/prompts/index.js.map +1 -1
  10. package/dist/templates/README.md.ejs +1 -1
  11. package/dist/templates/__when_apiLayer_axios__/src/services/api.ts.ejs +23 -0
  12. package/dist/templates/__when_apiLayer_axios__/src/services/http/client.ts.ejs +174 -0
  13. package/dist/templates/__when_apiLayer_axios__/src/services/http/errors.ts.ejs +81 -0
  14. package/dist/templates/__when_apiLayer_axios__/src/services/http/index.ts.ejs +5 -0
  15. package/dist/templates/__when_apiLayer_fetch__/src/services/api.ts.ejs +22 -0
  16. package/dist/templates/__when_apiLayer_fetch__/src/services/http/client.ts.ejs +195 -0
  17. package/dist/templates/__when_apiLayer_fetch__/src/services/http/errors.ts.ejs +81 -0
  18. package/dist/templates/__when_apiLayer_fetch__/src/services/http/index.ts.ejs +5 -0
  19. package/dist/templates/__when_buildTool_webpack__/webpack.config.js.ejs +1 -1
  20. package/dist/templates/__when_e2eTesting_cypress__/cypress.config.ts.ejs +2 -1
  21. package/dist/templates/__when_e2eTesting_playwright__/playwright.config.ts.ejs +4 -3
  22. package/dist/templates/__when_serverState_rtk-query__/src/store/postsApi.ts.ejs +28 -5
  23. package/dist/templates/__when_unitTesting_vitest__/tests/feedback.test.tsx.ejs +16 -0
  24. package/dist/templates/__when_unitTesting_vitest__/tests/posts.test.tsx.ejs +1 -3
  25. package/dist/templates/docs/architecture.md.ejs +44 -25
  26. package/dist/templates/docs/best-practices.md.ejs +39 -3
  27. package/dist/templates/docs/examples/README.md.ejs +10 -10
  28. package/dist/templates/docs/examples/api.md.ejs +165 -8
  29. package/dist/templates/docs/examples/data-fetching.md.ejs +107 -6
  30. package/dist/templates/docs/examples/forms.md.ejs +66 -6
  31. package/dist/templates/docs/examples/state.md.ejs +50 -6
  32. package/dist/templates/docs/examples/styling.md.ejs +56 -8
  33. package/dist/templates/docs/examples/testing.md.ejs +63 -9
  34. package/dist/templates/docs/getting-started.md.ejs +63 -15
  35. package/dist/templates/docs/selected-stack.md.ejs +110 -8
  36. package/dist/templates/src/features/feedback/FeedbackForm.tsx.ejs +10 -0
  37. package/dist/templates/src/features/posts/PostsPanel.tsx.ejs +1 -1
  38. package/dist/templates/src/routes/PostsPage.tsx.ejs +7 -2
  39. package/dist/templates/src/types/index.ts.ejs +1 -1
  40. package/dist/templates/src/types/models.ts.ejs +18 -0
  41. package/dist/types.d.ts +1 -1
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/templates/README.md.ejs +1 -1
  45. package/templates/__when_apiLayer_axios__/src/services/api.ts.ejs +23 -0
  46. package/templates/__when_apiLayer_axios__/src/services/http/client.ts.ejs +174 -0
  47. package/templates/__when_apiLayer_axios__/src/services/http/errors.ts.ejs +81 -0
  48. package/templates/__when_apiLayer_axios__/src/services/http/index.ts.ejs +5 -0
  49. package/templates/__when_apiLayer_fetch__/src/services/api.ts.ejs +22 -0
  50. package/templates/__when_apiLayer_fetch__/src/services/http/client.ts.ejs +195 -0
  51. package/templates/__when_apiLayer_fetch__/src/services/http/errors.ts.ejs +81 -0
  52. package/templates/__when_apiLayer_fetch__/src/services/http/index.ts.ejs +5 -0
  53. package/templates/__when_buildTool_webpack__/webpack.config.js.ejs +1 -1
  54. package/templates/__when_e2eTesting_cypress__/cypress.config.ts.ejs +2 -1
  55. package/templates/__when_e2eTesting_playwright__/playwright.config.ts.ejs +4 -3
  56. package/templates/__when_serverState_rtk-query__/src/store/postsApi.ts.ejs +28 -5
  57. package/templates/__when_unitTesting_vitest__/tests/feedback.test.tsx.ejs +16 -0
  58. package/templates/__when_unitTesting_vitest__/tests/posts.test.tsx.ejs +1 -3
  59. package/templates/docs/architecture.md.ejs +44 -25
  60. package/templates/docs/best-practices.md.ejs +39 -3
  61. package/templates/docs/examples/README.md.ejs +10 -10
  62. package/templates/docs/examples/api.md.ejs +165 -8
  63. package/templates/docs/examples/data-fetching.md.ejs +107 -6
  64. package/templates/docs/examples/forms.md.ejs +66 -6
  65. package/templates/docs/examples/state.md.ejs +50 -6
  66. package/templates/docs/examples/styling.md.ejs +56 -8
  67. package/templates/docs/examples/testing.md.ejs +63 -9
  68. package/templates/docs/getting-started.md.ejs +63 -15
  69. package/templates/docs/selected-stack.md.ejs +110 -8
  70. package/templates/src/features/feedback/FeedbackForm.tsx.ejs +10 -0
  71. package/templates/src/features/posts/PostsPanel.tsx.ejs +1 -1
  72. package/templates/src/routes/PostsPage.tsx.ejs +7 -2
  73. package/templates/src/types/index.ts.ejs +1 -1
  74. package/templates/src/types/models.ts.ejs +18 -0
  75. package/dist/templates/src/services/api.ts.ejs +0 -84
  76. package/templates/src/services/api.ts.ejs +0 -84
@@ -2,10 +2,13 @@
2
2
 
3
3
  Welcome to **<%= projectName %>**, a React starter generated by `create-react-starter-kit`.
4
4
 
5
+ This guide walks you from first install to extending the app with confidence.
6
+
5
7
  ## Prerequisites
6
8
 
7
- - Node.js 18+
8
- - <%= stackLabels.packageManager %>
9
+ - **Node.js 18+** (20 LTS recommended)
10
+ - **<%= stackLabels.packageManager %>** installed globally or via Corepack
11
+ - A modern browser for the demo UI
9
12
 
10
13
  ## Install & run
11
14
 
@@ -22,26 +25,68 @@ npm run dev
22
25
  <% } -%>
23
26
  ```
24
27
 
28
+ Dev server URL (default): **http://localhost:<%= buildTool === 'webpack' ? 3000 : 5173 %>**
29
+
30
+ Useful scripts:
31
+
32
+ | Script | Purpose |
33
+ |--------|---------|
34
+ | `dev` | Local development server |
35
+ | `build` | Production bundle |
36
+ | `preview` | Serve the production build locally |
37
+ <% if (unitTesting !== 'none') { -%>
38
+ | `test` / `test:watch` | Unit tests |
39
+ <% } -%>
40
+ <% if (e2eTesting !== 'none') { -%>
41
+ | `test:e2e` | End-to-end tests |
42
+ <% } -%>
43
+ <% if (visualTesting === 'storybook') { -%>
44
+ | `storybook` | Component explorer |
45
+ <% } -%>
46
+ | `lint` / `format` | Code quality |
47
+
25
48
  ## Environment variables
26
49
 
27
- Copy `.env.example` → `.env` and fill values. Restart the dev server after changes.
50
+ 1. Copy `.env.example` → `.env`
51
+ 2. Fill values for your environment
52
+ 3. Restart `dev` after changes
28
53
 
29
- Only variables prefixed for your bundler (e.g. `VITE_`) are exposed to the browser. Keep secrets on the server.
54
+ Only client-safe variables (typically `VITE_*`) are exposed to the browser. Never put private API keys in front-end env vars.
55
+
56
+ | Variable | Purpose |
57
+ |----------|---------|
58
+ | `VITE_API_BASE_URL` | REST API base URL (defaults to JSONPlaceholder for demos) |
59
+ <% if (errorTracking === 'sentry') { -%>
60
+ | `VITE_SENTRY_DSN` | Sentry DSN |
61
+ <% } else if (errorTracking === 'bugsnag') { -%>
62
+ | `VITE_BUGSNAG_API_KEY` | Bugsnag API key |
63
+ <% } else if (errorTracking === 'logrocket') { -%>
64
+ | `VITE_LOGROCKET_APP_ID` | LogRocket app id |
65
+ <% } else if (errorTracking === 'datadog') { -%>
66
+ | `VITE_DATADOG_APPLICATION_ID` / `VITE_DATADOG_CLIENT_TOKEN` | Datadog RUM |
67
+ <% } -%>
30
68
 
31
69
  ## What to explore first
32
70
 
33
- 1. Open `/` demo panels for state, data fetching, and forms.
34
- 2. Open `/about` orientation for the folder layout.
35
- 3. Read `docs/selected-stack.md` why each library is present.
36
- 4. Skim `docs/examples/` focused usage notes per concern.
71
+ 1. **`/`**stack badges and orientation
72
+ 2. **`/counter`**client state (<%= stackLabels.stateManagement %>)
73
+ 3. **`/posts`**server state (<%= stackLabels.serverState %>)
74
+ 4. **`/feedback`**forms + validation (<%= stackLabels.forms %> / <%= stackLabels.validation %>)
75
+ 5. **`docs/selected-stack.md`** — why each library was chosen
76
+ 6. **`docs/examples/`** — deep usage guides with copy-paste patterns
37
77
 
38
- ## Extending the app
78
+ ## Extending the app (recommended flow)
39
79
 
40
- - Add a domain under `src/features/<name>/`.
41
- - Register routes in `src/App.<%= jsxExt %>`.
42
- - Put shared UI in `src/components/`.
43
- - Put HTTP clients in `src/services/`.
44
- - Import with `@/` (maps to `src/`), e.g. `import { env } from '@/config/env'`.
80
+ 1. Create a feature folder: `src/features/<domain>/`
81
+ 2. Add UI, hooks, and domain types next to that feature
82
+ 3. Register a route in `src/App.<%= jsxExt %>`
83
+ 4. Put shared primitives in `src/components/`
84
+ <% if (apiLayer === 'none') { -%>
85
+ 5. Add RTK Query endpoints in `src/store/` (or a feature-local `*Api` slice)
86
+ <% } else { -%>
87
+ 5. Add HTTP helpers in `src/services/api.<%= ext %>` (and keep transport details in `src/services/http/`)
88
+ <% } -%>
89
+ 6. Import with `@/` — e.g. `import { env } from '@/config/env'`
45
90
 
46
91
  ## Testing
47
92
 
@@ -51,5 +96,8 @@ Only variables prefixed for your bundler (e.g. `VITE_`) are exposed to the brows
51
96
  <% if (e2eTesting !== 'none') { -%>
52
97
  - E2E: `<%= packageManager === 'npm' ? 'npm run' : packageManager %> test:e2e`
53
98
  <% } -%>
99
+ <% if (visualTesting === 'storybook') { -%>
100
+ - Storybook: `<%= packageManager === 'npm' ? 'npm run' : packageManager %> storybook`
101
+ <% } -%>
54
102
 
55
- See `docs/best-practices.md` for CI and production notes.
103
+ See `docs/best-practices.md` and `docs/examples/testing.md` for strategy and CI notes.
@@ -1,44 +1,146 @@
1
1
  # Selected stack
2
2
 
3
- This document explains each choice made when generating **<%= projectName %>**.
3
+ This document explains each choice made when generating **<%= projectName %>**, how to use it day-to-day, and the practices that keep the codebase maintainable.
4
4
 
5
5
  ## Build — <%= stackLabels.buildTool %>
6
6
 
7
- Fast local feedback and a production bundle. Prefer keeping config minimal; add plugins only when needed.
7
+ <% if (buildTool === 'vite') { -%>
8
+ Vite gives fast HMR and a Rollup-based production build. Config lives in `vite.config.<%= ext %>`.
8
9
 
9
- **Best practice:** lock Node and package manager versions in CI for reproducible builds.
10
+ **Day-to-day:** `<%= packageManager === 'npm' ? 'npm run' : packageManager %> dev` → http://localhost:5173
11
+ <% } else if (buildTool === 'webpack') { -%>
12
+ Webpack is configured in `webpack.config.js` with Babel (or TS pipeline), HtmlWebpackPlugin, and a dev server.
13
+
14
+ **Day-to-day:** `<%= packageManager === 'npm' ? 'npm run' : packageManager %> dev` → http://localhost:3000
15
+ <% } else { -%>
16
+ Your bundler is wired with scripts in `package.json`. Prefer keeping config minimal; add plugins only when needed.
17
+ <% } -%>
18
+
19
+ **Best practices**
20
+
21
+ - Lock Node and package manager versions in CI.
22
+ - Treat `build` as the source of truth for production issues (not only `dev`).
23
+ - Keep path aliases (`@/`) in sync between TS config and the bundler.
10
24
 
11
25
  ## Language — <%= stackLabels.language %>
12
26
 
13
27
  <% if (isTypeScript) { -%>
14
- TypeScript catches contract mistakes early. Keep `strict` on; avoid `any` except at true boundaries.
28
+ TypeScript catches contract mistakes early. Keep `strict` on; avoid `any` except at true boundaries (third-party quirks, gradual migrations).
29
+
30
+ **Pattern:** model API payloads in `src/types/models.<%= ext %>`, not inline in components.
15
31
  <% } else { -%>
16
- JavaScript keeps the barrier low. Consider migrating hot modules to TypeScript as the app grows.
32
+ JavaScript keeps the barrier low. Prefer JSDoc for public helpers, and consider migrating hot modules to TypeScript as the app grows.
17
33
  <% } -%>
18
34
 
19
35
  ## Routing — <%= stackLabels.router %>
20
36
 
21
37
  Client-side navigation with nested layouts. Keep route modules thin; push data loading into features.
22
38
 
39
+ **Best practices**
40
+
41
+ - Colocate route-level UI under `src/routes/`.
42
+ - Avoid fetching in layout components unless every child needs the data.
43
+ - Use loading/error UI at the feature boundary.
44
+
23
45
  ## Client state — <%= stackLabels.stateManagement %>
24
46
 
25
47
  Use for UI state (modals, wizards, ephemeral counters). Do **not** mirror server entities here if you have a server-state library.
26
48
 
49
+ **Live demo:** `/counter` → `src/features/counter/`
50
+
51
+ **Best practices**
52
+
53
+ - Feature-local state first; promote to global only when multiple distant trees need it.
54
+ - Keep stores/slices focused on one domain.
55
+ - Prefer selectors/hooks over reading the whole store in components.
56
+
27
57
  ## Server state — <%= stackLabels.serverState %>
28
58
 
29
- Caches remote data, handles loading/error, and deduplicates requests. Example: posts panel on the home page.
59
+ Caches remote data, handles loading/error, and deduplicates requests.
60
+
61
+ **Live demo:** `/posts` → `src/features/posts/PostsPanel.<%= jsxExt %>`
62
+
63
+ <% if (serverState === 'rtk-query') { -%>
64
+ **How to use**
65
+
66
+ 1. Define endpoints in `src/store/postsApi.<%= ext %>` (or a new `*Api` slice).
67
+ 2. Export hooks (`useGetPostsQuery`, `useCreateFeedbackMutation`).
68
+ 3. Call hooks from features — no manual `useEffect` fetching.
69
+
70
+ **Best practices**
71
+
72
+ - Use `tagTypes` + `providesTags` / `invalidatesTags` for cache coherence.
73
+ - Put auth headers in `prepareHeaders`, not in every endpoint.
74
+ - Prefer mutations for writes; invalidate related query tags after success.
75
+ <% } else if (serverState === 'tanstack-query') { -%>
76
+ **How to use**
77
+
78
+ ```tsx
79
+ const { data, isLoading, error, refetch } = useQuery({
80
+ queryKey: ['posts'],
81
+ queryFn: ({ signal }) => fetchPosts(signal),
82
+ });
83
+ ```
84
+
85
+ **Best practices**
86
+
87
+ - Stable, hierarchical query keys: `['posts']`, `['posts', id]`.
88
+ - Pass `signal` into your HTTP helpers so navigations cancel in-flight work.
89
+ - Keep `queryFn` thin — call domain API helpers, not raw HTTP.
90
+ <% } else if (serverState === 'swr') { -%>
91
+ **How to use**
92
+
93
+ SWR is configured in `providers.<%= jsxExt %>` with a shared `fetcher`. Components call `useSWR(key)`.
94
+
95
+ **Best practices**
96
+
97
+ - Keys should be URLs or stable resource identifiers.
98
+ - Use `mutate` for local revalidation after writes.
99
+ <% } else { -%>
100
+ No dedicated server-state library was selected. Prefer adding one before the app grows past a few screens.
101
+ <% } -%>
30
102
 
31
103
  ## Forms — <%= stackLabels.forms %> / Validation — <%= stackLabels.validation %>
32
104
 
33
105
  Schemas define the contract; the form library binds inputs. Share schemas with API payloads when possible.
34
106
 
107
+ **Live demo:** `/feedback` → `src/features/feedback/FeedbackForm.<%= jsxExt %>`
108
+ **Schemas:** `src/lib/validation.<%= ext %>`
109
+
110
+ **Best practices**
111
+
112
+ - Validate on submit (and optionally on blur) — avoid blocking every keystroke unless UX requires it.
113
+ - Keep error messages user-facing; log technical details separately.
114
+ - Reuse the same schema on the server if you own both sides.
115
+
35
116
  ## Styling — <%= stackLabels.styling %> / UI — <%= stackLabels.uiLibrary %>
36
117
 
37
118
  Tokens and primitives establish visual consistency. Prefer composition over one-off CSS.
38
119
 
120
+ **Best practices**
121
+
122
+ - Wrap third-party primitives in thin adapters (`UiButton`) so swapping kits later is cheaper.
123
+ - Keep global tokens in `src/styles/`; keep feature-specific styles close to the feature.
124
+
39
125
  ## API — <%= stackLabels.apiLayer %>
40
126
 
41
- Centralize base URL, headers, and error logging in `src/services/api.<%= ext %>`.
127
+ <% if (apiLayer === 'none') { -%>
128
+ HTTP is owned by **RTK Query** (`fetchBaseQuery`). There is intentionally **no** separate Axios/Fetch client in this project.
129
+
130
+ See `docs/examples/data-fetching.md` and `src/store/postsApi.<%= ext %>`.
131
+ <% } else if (apiLayer === 'axios') { -%>
132
+ Axios is configured under `src/services/http/` with:
133
+
134
+ - request interceptors (auth token, request IDs)
135
+ - response interceptors (normalized `ApiError`, 401 event)
136
+ - domain helpers in `src/services/api.<%= ext %>`
137
+
138
+ See `docs/examples/api.md` for patterns and examples.
139
+ <% } else { -%>
140
+ A shared Fetch wrapper lives under `src/services/http/` with timeout, auth headers, request IDs, and normalized `ApiError`s. Domain helpers sit in `src/services/api.<%= ext %>`.
141
+
142
+ See `docs/examples/api.md` for patterns and examples.
143
+ <% } -%>
42
144
 
43
145
  ## Quality gates
44
146
 
@@ -52,4 +154,4 @@ Centralize base URL, headers, and error logging in `src/services/api.<%= ext %>`
52
154
  | Git hooks | Husky + lint-staged + commitlint |
53
155
  | Structure | Feature-based + `@/` aliases |
54
156
 
55
- See `docs/examples/` for focused usage notes.
157
+ See `docs/examples/` for focused usage notes with deeper examples.
@@ -32,7 +32,11 @@ import { validateFeedback<% if (isTypeScript) { %>, type FeedbackValues<% } %> }
32
32
  import { feedbackSchema<% if (isTypeScript) { %>, type FeedbackValues<% } %> } from '@/lib/validation';
33
33
  <% } -%>
34
34
  <% } -%>
35
+ <% if (serverState === 'rtk-query') { -%>
36
+ import { useCreateFeedbackMutation } from '@/store/postsApi';
37
+ <% } else { -%>
35
38
  import { createFeedback } from '@/services/api';
39
+ <% } -%>
36
40
  import { UiButton } from '@/components/ui/UiButton';
37
41
 
38
42
  const defaults<% if (isTypeScript) { %>: FeedbackValues<% } %> = {
@@ -43,6 +47,12 @@ const defaults<% if (isTypeScript) { %>: FeedbackValues<% } %> = {
43
47
 
44
48
  export function FeedbackForm() {
45
49
  const [status, setStatus] = useState<% if (isTypeScript) { %><string | null><% } %>(null);
50
+ <% if (serverState === 'rtk-query') { -%>
51
+ const [createFeedbackMutation] = useCreateFeedbackMutation();
52
+ const createFeedback = async (values<% if (isTypeScript) { %>: FeedbackValues<% } %>) => {
53
+ await createFeedbackMutation(values).unwrap();
54
+ };
55
+ <% } -%>
46
56
 
47
57
  <% if (forms === 'react-hook-form') { -%>
48
58
  const {
@@ -14,7 +14,7 @@ export function PostsPanel() {
14
14
  <% if (serverState === 'tanstack-query') { -%>
15
15
  const { data, isLoading, error, refetch, isFetching } = useQuery({
16
16
  queryKey: ['posts'],
17
- queryFn: fetchPosts,
17
+ queryFn: ({ signal }) => fetchPosts(signal),
18
18
  });
19
19
  <% } else if (serverState === 'swr') { -%>
20
20
  const { data, error, isLoading, isValidating, mutate } = useSWR('/posts?_limit=5');
@@ -7,8 +7,13 @@ export function PostsPage() {
7
7
  <p className="eyebrow">Server state</p>
8
8
  <h1>Posts</h1>
9
9
  <p className="lede">
10
- Fetches sample posts via <strong><%= stackLabels.serverState === 'None' ? stackLabels.apiLayer : stackLabels.serverState %></strong>{' '}
11
- and <strong><%= stackLabels.apiLayer %></strong>.
10
+ Fetches sample posts via <strong><%= stackLabels.serverState === 'None' ? stackLabels.apiLayer : stackLabels.serverState %></strong>
11
+ <% if (apiLayer !== 'none' && serverState !== 'rtk-query') { -%>
12
+ {' '}and <strong><%= stackLabels.apiLayer %></strong>
13
+ <% } else if (serverState === 'rtk-query') { -%>
14
+ {' '}(HTTP via <code>fetchBaseQuery</code>)
15
+ <% } -%>
16
+ .
12
17
  </p>
13
18
  </header>
14
19
  <PostsPanel />
@@ -1,6 +1,6 @@
1
1
  <% if (isTypeScript) { -%>
2
2
  /** Shared domain types used across features. */
3
- export type { Post } from '@/services/api';
3
+ export type { Post, FeedbackPayload } from './models';
4
4
  <% } else { -%>
5
5
  // Shared types live here when you migrate hot paths to TypeScript.
6
6
  export {};
@@ -0,0 +1,18 @@
1
+ <% if (isTypeScript) { -%>
2
+ /** Shared domain models used by features and the HTTP / RTK layers. */
3
+ export interface Post {
4
+ userId: number;
5
+ id: number;
6
+ title: string;
7
+ body: string;
8
+ }
9
+
10
+ export interface FeedbackPayload {
11
+ name: string;
12
+ email: string;
13
+ message: string;
14
+ }
15
+ <% } else { -%>
16
+ // Shared domain models live here when you migrate hot paths to TypeScript.
17
+ export {};
18
+ <% } -%>
@@ -1,84 +0,0 @@
1
- <% if (apiLayer === 'axios') { -%>
2
- import axios from 'axios';
3
- import { env } from '@/config/env';
4
-
5
- const baseURL = env.apiBaseUrl;
6
-
7
- export const apiClient = axios.create({
8
- baseURL,
9
- headers: { 'Content-Type': 'application/json' },
10
- timeout: 10_000,
11
- });
12
-
13
- apiClient.interceptors.response.use(
14
- (response) => response,
15
- (error) => {
16
- console.error('[api]', error);
17
- return Promise.reject(error);
18
- },
19
- );
20
-
21
- export async function apiGet<% if (isTypeScript) { %><T = unknown><% } %>(path<% if (isTypeScript) { %>: string<% } %>)<% if (isTypeScript) { %>: Promise<T><% } %> {
22
- const { data } = await apiClient.get<% if (isTypeScript) { %><T><% } %>(path);
23
- return data;
24
- }
25
-
26
- export async function apiPost<% if (isTypeScript) { %><T = unknown, B = unknown><% } %>(
27
- path<% if (isTypeScript) { %>: string<% } %>,
28
- body<% if (isTypeScript) { %>: B<% } %>,
29
- )<% if (isTypeScript) { %>: Promise<T><% } %> {
30
- const { data } = await apiClient.post<% if (isTypeScript) { %><T><% } %>(path, body);
31
- return data;
32
- }
33
- <% } else { -%>
34
- import { env } from '@/config/env';
35
-
36
- const baseURL = env.apiBaseUrl;
37
-
38
- async function request<% if (isTypeScript) { %><T = unknown><% } %>(
39
- path<% if (isTypeScript) { %>: string<% } %>,
40
- init<% if (isTypeScript) { %>?: RequestInit<% } %>,
41
- )<% if (isTypeScript) { %>: Promise<T><% } %> {
42
- const response = await fetch(`${baseURL}${path}`, {
43
- headers: { 'Content-Type': 'application/json', ...(init?.headers ?? {}) },
44
- ...init,
45
- });
46
-
47
- if (!response.ok) {
48
- throw new Error(`Request failed: ${response.status}`);
49
- }
50
-
51
- return response.json();
52
- }
53
-
54
- export async function apiGet<% if (isTypeScript) { %><T = unknown><% } %>(path<% if (isTypeScript) { %>: string<% } %>)<% if (isTypeScript) { %>: Promise<T><% } %> {
55
- return request<% if (isTypeScript) { %><T><% } %>(path);
56
- }
57
-
58
- export async function apiPost<% if (isTypeScript) { %><T = unknown, B = unknown><% } %>(
59
- path<% if (isTypeScript) { %>: string<% } %>,
60
- body<% if (isTypeScript) { %>: B<% } %>,
61
- )<% if (isTypeScript) { %>: Promise<T><% } %> {
62
- return request<% if (isTypeScript) { %><T><% } %>(path, {
63
- method: 'POST',
64
- body: JSON.stringify(body),
65
- });
66
- }
67
- <% } -%>
68
-
69
- <% if (isTypeScript) { -%>
70
- export interface Post {
71
- userId: number;
72
- id: number;
73
- title: string;
74
- body: string;
75
- }
76
- <% } -%>
77
-
78
- export async function fetchPosts() {
79
- return apiGet<% if (isTypeScript) { %><Post[]><% } %>('/posts?_limit=5');
80
- }
81
-
82
- export async function createFeedback(payload<% if (isTypeScript) { %>: { name: string; email: string; message: string }<% } %>) {
83
- return apiPost('/posts', payload);
84
- }
@@ -1,84 +0,0 @@
1
- <% if (apiLayer === 'axios') { -%>
2
- import axios from 'axios';
3
- import { env } from '@/config/env';
4
-
5
- const baseURL = env.apiBaseUrl;
6
-
7
- export const apiClient = axios.create({
8
- baseURL,
9
- headers: { 'Content-Type': 'application/json' },
10
- timeout: 10_000,
11
- });
12
-
13
- apiClient.interceptors.response.use(
14
- (response) => response,
15
- (error) => {
16
- console.error('[api]', error);
17
- return Promise.reject(error);
18
- },
19
- );
20
-
21
- export async function apiGet<% if (isTypeScript) { %><T = unknown><% } %>(path<% if (isTypeScript) { %>: string<% } %>)<% if (isTypeScript) { %>: Promise<T><% } %> {
22
- const { data } = await apiClient.get<% if (isTypeScript) { %><T><% } %>(path);
23
- return data;
24
- }
25
-
26
- export async function apiPost<% if (isTypeScript) { %><T = unknown, B = unknown><% } %>(
27
- path<% if (isTypeScript) { %>: string<% } %>,
28
- body<% if (isTypeScript) { %>: B<% } %>,
29
- )<% if (isTypeScript) { %>: Promise<T><% } %> {
30
- const { data } = await apiClient.post<% if (isTypeScript) { %><T><% } %>(path, body);
31
- return data;
32
- }
33
- <% } else { -%>
34
- import { env } from '@/config/env';
35
-
36
- const baseURL = env.apiBaseUrl;
37
-
38
- async function request<% if (isTypeScript) { %><T = unknown><% } %>(
39
- path<% if (isTypeScript) { %>: string<% } %>,
40
- init<% if (isTypeScript) { %>?: RequestInit<% } %>,
41
- )<% if (isTypeScript) { %>: Promise<T><% } %> {
42
- const response = await fetch(`${baseURL}${path}`, {
43
- headers: { 'Content-Type': 'application/json', ...(init?.headers ?? {}) },
44
- ...init,
45
- });
46
-
47
- if (!response.ok) {
48
- throw new Error(`Request failed: ${response.status}`);
49
- }
50
-
51
- return response.json();
52
- }
53
-
54
- export async function apiGet<% if (isTypeScript) { %><T = unknown><% } %>(path<% if (isTypeScript) { %>: string<% } %>)<% if (isTypeScript) { %>: Promise<T><% } %> {
55
- return request<% if (isTypeScript) { %><T><% } %>(path);
56
- }
57
-
58
- export async function apiPost<% if (isTypeScript) { %><T = unknown, B = unknown><% } %>(
59
- path<% if (isTypeScript) { %>: string<% } %>,
60
- body<% if (isTypeScript) { %>: B<% } %>,
61
- )<% if (isTypeScript) { %>: Promise<T><% } %> {
62
- return request<% if (isTypeScript) { %><T><% } %>(path, {
63
- method: 'POST',
64
- body: JSON.stringify(body),
65
- });
66
- }
67
- <% } -%>
68
-
69
- <% if (isTypeScript) { -%>
70
- export interface Post {
71
- userId: number;
72
- id: number;
73
- title: string;
74
- body: string;
75
- }
76
- <% } -%>
77
-
78
- export async function fetchPosts() {
79
- return apiGet<% if (isTypeScript) { %><Post[]><% } %>('/posts?_limit=5');
80
- }
81
-
82
- export async function createFeedback(payload<% if (isTypeScript) { %>: { name: string; email: string; message: string }<% } %>) {
83
- return apiPost('/posts', payload);
84
- }