@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 +231 -3
- package/dist/index.js +335 -294
- package/dist/lib/demo-scaffold-backend/api.d.ts +857 -119
- package/dist/lib/demo-scaffold-backend/api.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,7 +1,235 @@
|
|
|
1
1
|
# @open-kingdom/shared-frontend-data-access-api-client
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
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
|
+
```
|