@open-kingdom/shared-frontend-data-access-api-client 0.0.2-13 → 0.0.2-15

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.
package/README.md CHANGED
@@ -1,7 +1,235 @@
1
1
  # @open-kingdom/shared-frontend-data-access-api-client
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ RTK Query base API instance with JWT auth header injection, auth state management (Redux slice), token persistence via a `StorageProvider`, and an adapter pattern for custom auth header formatting.
4
4
 
5
- ## Running unit tests
5
+ ---
6
6
 
7
- Run `nx test @open-kingdom/shared-frontend-data-access-api-client` to execute the unit tests via [Vitest](https://vitest.dev/).
7
+ ## Exports
8
+
9
+ ### Base API
10
+
11
+ | Export | Type | Description |
12
+ | --------------- | ------------ | ---------------------------------------------------- |
13
+ | `baseApi` | `Api<...>` | RTK Query `createApi` instance, `reducerPath: 'api'` |
14
+ | `ApiKey` | `'api'` | The reducer path string constant |
15
+ | `apiReducer` | `Reducer` | `baseApi.reducer` — add to store under `ApiKey` |
16
+ | `apiMiddleware` | `Middleware` | `baseApi.middleware` — add to store middleware chain |
17
+
18
+ ### Auth Slice
19
+
20
+ | Export | Type | Description |
21
+ | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------- |
22
+ | `authSlice` | `Slice<AuthState>` | Redux slice, `name: 'auth'` |
23
+ | `AuthKey` | `'auth'` | The slice name string constant |
24
+ | `AuthState` | `interface` | `{ token: string \| null }` |
25
+ | `AuthPersistence` | `interface` | `{ getToken(): string \| null; setToken(token: string \| null): void }` |
26
+ | `authReducer` | `Reducer<AuthState>` | `authSlice.reducer` |
27
+ | `setToken` | `ActionCreator<string \| null>` | Sets the JWT token in Redux state |
28
+ | `logout` | `ActionCreator<void>` | Clears token and resets RTK Query API state |
29
+ | `selectToken` | `(state: { auth: AuthState }) => string \| null` | Selector for current token |
30
+ | `selectIsAuthenticated` | `(state: { auth: AuthState }) => boolean` | Selector for auth status |
31
+
32
+ ### Auth Listener Middleware
33
+
34
+ | Export | Type | Description |
35
+ | ----------------------------------- | ------------------ | --------------------------------------------------------------------------------------- |
36
+ | `configureAuth(config: AuthConfig)` | `function` | Configures global persistence and logout callback — call before store creation |
37
+ | `createAuthListenerMiddleware()` | `() => Middleware` | RTK listener that persists token on `setToken`/`logout` and handles logout side effects |
38
+ | `createAuthHydrationMiddleware()` | `() => Middleware` | Middleware that hydrates token from persistence on the first dispatched action |
39
+ | `AuthConfig` | `interface` | `{ persistence?: AuthPersistence; onLogout?: () => void }` |
40
+
41
+ ### Auth Adapter
42
+
43
+ | Export | Type | Description |
44
+ | ----------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- |
45
+ | `AuthAdapter` | `interface` | `{ prepareHeaders(headers: Headers, token: string): void }` |
46
+ | `setAuthAdapter(adapter)` | `(adapter: AuthAdapter \| null) => void` | Registers a module-level custom adapter; replaces default `Authorization: Bearer` injection |
47
+ | `getAuthAdapter()` | `() => AuthAdapter \| null` | Returns the currently registered adapter |
48
+ | `createCustomHeaderAdapter(config)` | `(config: CustomHeaderAdapterConfig) => AuthAdapter` | Factory for adapters that set a named header |
49
+ | `CustomHeaderAdapterConfig` | `interface` | `{ headerName: string; formatValue?: (token: string) => string }` |
50
+
51
+ ### Token Persistence
52
+
53
+ | Export | Type | Description |
54
+ | ----------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
55
+ | `storagePersistence(storage, key?)` | `(storage: StorageLike, key?: string) => AuthPersistence` | Creates `AuthPersistence` backed by any `localStorage`-compatible storage; `key` defaults to `'token'` |
56
+
57
+ ---
58
+
59
+ ## Type Definitions
60
+
61
+ ### `AuthState`
62
+
63
+ | Property | Type | Required | Default | Description |
64
+ | -------- | ---------------- | -------- | ------- | ----------------------------------------------------- |
65
+ | `token` | `string \| null` | Yes | — | The current JWT token, or `null` when unauthenticated |
66
+
67
+ ### `AuthPersistence`
68
+
69
+ | Method | Parameters | Returns | Description |
70
+ | ---------- | ----------------------- | ---------------- | ----------------------------- |
71
+ | `getToken` | — | `string \| null` | Retrieves the persisted token |
72
+ | `setToken` | `token: string \| null` | `void` | Persists or clears the token |
73
+
74
+ ### `AuthConfig`
75
+
76
+ | Property | Type | Required | Default | Description |
77
+ | ------------- | ----------------- | -------- | ------- | ------------------------------------------------- |
78
+ | `persistence` | `AuthPersistence` | No | — | Storage backend for token persistence |
79
+ | `onLogout` | `() => void` | No | — | Callback fired when `logout` action is dispatched |
80
+
81
+ ### `AuthAdapter`
82
+
83
+ | Method | Parameters | Returns | Description |
84
+ | ---------------- | --------------------------------- | ------- | ---------------------------------------------------------- |
85
+ | `prepareHeaders` | `headers: Headers, token: string` | `void` | Injects auth credentials into the outgoing request headers |
86
+
87
+ ### `CustomHeaderAdapterConfig`
88
+
89
+ | Property | Type | Required | Default | Description |
90
+ | ------------- | --------------------------- | -------- | ----------------- | ------------------------------------------------ |
91
+ | `headerName` | `string` | Yes | — | The HTTP header name to set (e.g. `'X-Api-Key'`) |
92
+ | `formatValue` | `(token: string) => string` | No | Identity function | Transforms the raw token into the header value |
93
+
94
+ ### `StorageLike`
95
+
96
+ Any `localStorage`-compatible object that implements `getItem(key)`, `setItem(key, value)`, and `removeItem(key)`.
97
+
98
+ ---
99
+
100
+ ## Base API Behavior
101
+
102
+ - `baseUrl` reads `process.env.VITE_API_BASE_URL` (empty string `''` if unset)
103
+ - On every outgoing request, reads `state['auth'].token` from Redux state
104
+ - If a token is present:
105
+ - If a custom `AuthAdapter` is registered via `setAuthAdapter()`, calls `adapter.prepareHeaders(headers, token)`
106
+ - Otherwise, sets `Authorization: Bearer <token>` by default
107
+ - `endpoints` is empty (`endpoints: () => ({})`) — extended via `baseApi.injectEndpoints()` in generated code
108
+ - Generated endpoint hooks are auto-injected at import time via `import './lib/demo-scaffold-backend/api'` in `src/index.ts`
109
+
110
+ ---
111
+
112
+ ## Setup
113
+
114
+ ### Store Registration
115
+
116
+ ```typescript
117
+ import { configureStore } from '@reduxjs/toolkit';
118
+ import { ApiKey, apiReducer, apiMiddleware, AuthKey, authReducer, configureAuth, createAuthListenerMiddleware, createAuthHydrationMiddleware, storagePersistence } from '@open-kingdom/shared-frontend-data-access-api-client';
119
+
120
+ // Configure persistence BEFORE creating the store
121
+ configureAuth({
122
+ persistence: storagePersistence(localStorage, 'auth_token'),
123
+ onLogout: () => {
124
+ window.location.href = '/login';
125
+ },
126
+ });
127
+
128
+ export const store = configureStore({
129
+ reducer: {
130
+ [ApiKey]: apiReducer, // reducerPath: 'api'
131
+ [AuthKey]: authReducer, // name: 'auth'
132
+ },
133
+ middleware: (getDefault) => getDefault().concat(apiMiddleware).concat(createAuthListenerMiddleware()).concat(createAuthHydrationMiddleware()),
134
+ });
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Usage Examples
140
+
141
+ ### Dispatch login / set token
142
+
143
+ ```typescript
144
+ import { setToken } from '@open-kingdom/shared-frontend-data-access-api-client';
145
+ import { useDispatch } from 'react-redux';
146
+
147
+ function LoginHandler() {
148
+ const dispatch = useDispatch();
149
+
150
+ async function handleLogin(email: string, password: string) {
151
+ const response = await authApi.login({ email, password });
152
+ dispatch(setToken(response.access_token));
153
+ }
154
+ }
155
+ ```
156
+
157
+ ### Dispatch logout
158
+
159
+ ```typescript
160
+ import { logout } from '@open-kingdom/shared-frontend-data-access-api-client';
161
+
162
+ // Clears token from Redux, resets all RTK Query cache, fires onLogout callback
163
+ dispatch(logout());
164
+ ```
165
+
166
+ ### Read auth state in components
167
+
168
+ ```typescript
169
+ import { selectToken, selectIsAuthenticated } from '@open-kingdom/shared-frontend-data-access-api-client';
170
+ import { useSelector } from 'react-redux';
171
+
172
+ function AuthStatus() {
173
+ const isAuthenticated = useSelector(selectIsAuthenticated);
174
+ const token = useSelector(selectToken);
175
+ return <span>{isAuthenticated ? 'Logged in' : 'Logged out'}</span>;
176
+ }
177
+ ```
178
+
179
+ ### Custom auth header adapter
180
+
181
+ ```typescript
182
+ import { createCustomHeaderAdapter, setAuthAdapter } from '@open-kingdom/shared-frontend-data-access-api-client';
183
+
184
+ // Set a custom header instead of the default Authorization: Bearer
185
+ setAuthAdapter(
186
+ createCustomHeaderAdapter({
187
+ headerName: 'X-Api-Key',
188
+ formatValue: (token) => token, // raw value, no "Bearer" prefix
189
+ })
190
+ );
191
+ ```
192
+
193
+ ### Custom AuthAdapter implementation
194
+
195
+ ```typescript
196
+ import type { AuthAdapter } from '@open-kingdom/shared-frontend-data-access-api-client';
197
+ import { setAuthAdapter } from '@open-kingdom/shared-frontend-data-access-api-client';
198
+
199
+ const myAdapter: AuthAdapter = {
200
+ prepareHeaders(headers, token) {
201
+ headers.set('Authorization', `Token ${token}`);
202
+ headers.set('X-Client-Version', '2.0.0');
203
+ },
204
+ };
205
+
206
+ setAuthAdapter(myAdapter);
207
+ ```
208
+
209
+ ### Injecting endpoints (generated pattern)
210
+
211
+ ```typescript
212
+ import { baseApi } from '@open-kingdom/shared-frontend-data-access-api-client';
213
+
214
+ // This pattern is used by the OpenAPI code generator plugin:
215
+ const extendedApi = baseApi.injectEndpoints({
216
+ endpoints: (builder) => ({
217
+ getUsers: builder.query<User[], void>({
218
+ query: () => '/users',
219
+ }),
220
+ createUser: builder.mutation<User, CreateUserDto>({
221
+ query: (body) => ({ url: '/users', method: 'POST', body }),
222
+ }),
223
+ }),
224
+ });
225
+
226
+ export const { useGetUsersQuery, useCreateUserMutation } = extendedApi;
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Testing
232
+
233
+ ```bash
234
+ nx test shared-frontend-data-access-api-client
235
+ ```