@agility/management-sdk 0.1.37 → 0.1.39
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/.github/workflows/npm-publish.yml +61 -0
- package/README.md +396 -371
- package/dist/apiMethods/instanceMethods.d.ts +13 -0
- package/dist/apiMethods/instanceMethods.js +48 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/models/exception.d.ts +4 -0
- package/dist/models/exception.js +17 -1
- package/dist/models/fetchApiStatus.d.ts +38 -0
- package/dist/models/fetchApiStatus.js +2 -0
- package/docs/asset-methods.md +381 -381
- package/docs/auth-component.md +360 -360
- package/docs/auth.md +593 -593
- package/docs/batch-methods.md +243 -243
- package/docs/cicd.md +606 -606
- package/docs/container-methods.md +267 -267
- package/docs/content-methods.md +491 -491
- package/docs/instance-methods.md +185 -105
- package/docs/instance-user-methods.md +230 -230
- package/docs/model-methods.md +433 -433
- package/docs/multi-instance-operations.md +191 -191
- package/docs/page-methods.md +737 -737
- package/docs/server-user-methods.md +279 -279
- package/docs/webhook-methods.md +451 -451
- package/license.txt +20 -20
- package/package.json +42 -41
- package/tsconfig.json +14 -14
package/docs/auth-component.md
CHANGED
|
@@ -1,361 +1,361 @@
|
|
|
1
|
-
# Agility CMS Authentication Component
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The Agility CMS Authentication Component provides a complete, reusable authentication system for React applications. It handles OAuth authentication, token management, and provides a rich set of hooks and components for building authentication UIs.
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- **OAuth Authentication**: Secure popup-based authentication flow
|
|
10
|
-
- **Token Management**: Automatic token refresh and secure storage
|
|
11
|
-
- **Type Safety**: Full TypeScript support with comprehensive interfaces
|
|
12
|
-
- **Multiple Display Modes**: Fullscreen, footer bar, and button-only modes
|
|
13
|
-
- **Extensive Customization**: Callbacks, styling, and slot-based customization
|
|
14
|
-
- **Performance Optimized**: Uses React hooks and context for efficient state management
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install @agility/management-sdk-typescript
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Basic Usage
|
|
23
|
-
|
|
24
|
-
### 1. Using the Authentication Hook
|
|
25
|
-
|
|
26
|
-
The simplest way to add authentication to your app:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { useAgilityAuth } from '@agility/management-sdk-typescript';
|
|
30
|
-
|
|
31
|
-
function MyApp() {
|
|
32
|
-
const {
|
|
33
|
-
isAuthenticated,
|
|
34
|
-
isLoading,
|
|
35
|
-
user,
|
|
36
|
-
websiteAccess,
|
|
37
|
-
selectedWebsite,
|
|
38
|
-
selectedLocale,
|
|
39
|
-
locales,
|
|
40
|
-
error,
|
|
41
|
-
authenticate,
|
|
42
|
-
signOut,
|
|
43
|
-
selectWebsite,
|
|
44
|
-
selectLocale,
|
|
45
|
-
clearError,
|
|
46
|
-
hasSelection,
|
|
47
|
-
currentSelection
|
|
48
|
-
} = useAgilityAuth({
|
|
49
|
-
redirectUri: 'https://myapp.com/auth-callback.html',
|
|
50
|
-
scope: 'openid profile email offline_access',
|
|
51
|
-
autoCheckAuth: true // Automatically check auth on mount
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
if (isLoading) return <div>Loading...</div>;
|
|
55
|
-
if (error) return <div>Error: {error}</div>;
|
|
56
|
-
|
|
57
|
-
if (!isAuthenticated) {
|
|
58
|
-
return (
|
|
59
|
-
<button onClick={authenticate}>
|
|
60
|
-
Sign in with Agility CMS
|
|
61
|
-
</button>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<div>
|
|
67
|
-
<h1>Welcome, {user?.userName}!</h1>
|
|
68
|
-
|
|
69
|
-
<select
|
|
70
|
-
value={selectedWebsite}
|
|
71
|
-
onChange={(e) => selectWebsite(e.target.value)}
|
|
72
|
-
>
|
|
73
|
-
<option value="">Choose a website...</option>
|
|
74
|
-
{websiteAccess.map(site => (
|
|
75
|
-
<option key={site.websiteGuid} value={site.websiteGuid}>
|
|
76
|
-
{site.websiteName}
|
|
77
|
-
</option>
|
|
78
|
-
))}
|
|
79
|
-
</select>
|
|
80
|
-
|
|
81
|
-
{selectedWebsite && (
|
|
82
|
-
<select
|
|
83
|
-
value={selectedLocale}
|
|
84
|
-
onChange={(e) => selectLocale(e.target.value)}
|
|
85
|
-
>
|
|
86
|
-
<option value="">Choose a locale...</option>
|
|
87
|
-
{locales.map(locale => (
|
|
88
|
-
<option key={locale.localeCode} value={locale.localeCode}>
|
|
89
|
-
{locale.localeName}
|
|
90
|
-
</option>
|
|
91
|
-
))}
|
|
92
|
-
</select>
|
|
93
|
-
)}
|
|
94
|
-
|
|
95
|
-
{hasSelection && (
|
|
96
|
-
<div>
|
|
97
|
-
<p>Current Selection: {currentSelection?.websiteName} - {currentSelection?.localeName}</p>
|
|
98
|
-
</div>
|
|
99
|
-
)}
|
|
100
|
-
|
|
101
|
-
<button onClick={signOut}>Sign Out</button>
|
|
102
|
-
</div>
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### 2. Using the Context Provider
|
|
108
|
-
|
|
109
|
-
For larger applications, use the context provider to share authentication state:
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
import { AuthProvider, useAuthContext } from '@agility/management-sdk-typescript';
|
|
113
|
-
|
|
114
|
-
// App component
|
|
115
|
-
function App() {
|
|
116
|
-
return (
|
|
117
|
-
<AuthProvider>
|
|
118
|
-
<MyAuthenticatedApp />
|
|
119
|
-
</AuthProvider>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Child component that uses auth context
|
|
124
|
-
function MyAuthenticatedApp() {
|
|
125
|
-
const { state, actions } = useAuthContext();
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
<div>
|
|
129
|
-
{state.isAuthenticated ? (
|
|
130
|
-
<Dashboard user={state.user} />
|
|
131
|
-
) : (
|
|
132
|
-
<LoginForm onLogin={actions.setAuthenticated} />
|
|
133
|
-
)}
|
|
134
|
-
</div>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### 3. Using Granular Context Hooks
|
|
140
|
-
|
|
141
|
-
For more specific use cases, use the granular hooks:
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
import {
|
|
145
|
-
useIsAuthenticated,
|
|
146
|
-
useCurrentUser,
|
|
147
|
-
useSelection,
|
|
148
|
-
useLoadingStates,
|
|
149
|
-
useAuthError
|
|
150
|
-
} from '@agility/management-sdk-typescript';
|
|
151
|
-
|
|
152
|
-
function UserProfile() {
|
|
153
|
-
const isAuthenticated = useIsAuthenticated();
|
|
154
|
-
const user = useCurrentUser();
|
|
155
|
-
const { isLoading } = useLoadingStates();
|
|
156
|
-
|
|
157
|
-
if (!isAuthenticated) return <div>Please log in</div>;
|
|
158
|
-
if (isLoading) return <div>Loading...</div>;
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<div>
|
|
162
|
-
<h2>{user?.userName}</h2>
|
|
163
|
-
<p>{user?.emailAddress}</p>
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function WebsiteSelector() {
|
|
169
|
-
const { selectedWebsite, selectedLocale, hasSelection } = useSelection();
|
|
170
|
-
const { error, clearError } = useAuthError();
|
|
171
|
-
|
|
172
|
-
return (
|
|
173
|
-
<div>
|
|
174
|
-
{error && (
|
|
175
|
-
<div className="error">
|
|
176
|
-
{error}
|
|
177
|
-
<button onClick={clearError}>Clear</button>
|
|
178
|
-
</div>
|
|
179
|
-
)}
|
|
180
|
-
|
|
181
|
-
{hasSelection && (
|
|
182
|
-
<div>Selected: {selectedWebsite} - {selectedLocale}</div>
|
|
183
|
-
)}
|
|
184
|
-
</div>
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
## Advanced Usage
|
|
190
|
-
|
|
191
|
-
### Custom OAuth Configuration
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
const auth = useAgilityAuth({
|
|
195
|
-
redirectUri: 'https://myapp.com/auth-callback.html',
|
|
196
|
-
scope: 'openid profile email offline_access',
|
|
197
|
-
region: 'us-west-2',
|
|
198
|
-
autoCheckAuth: true
|
|
199
|
-
});
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Website Selection with Validation
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
import {
|
|
206
|
-
useWebsiteSelection,
|
|
207
|
-
validateSelection,
|
|
208
|
-
sortWebsitesByName
|
|
209
|
-
} from '@agility/management-sdk-typescript';
|
|
210
|
-
|
|
211
|
-
function WebsiteManager() {
|
|
212
|
-
const auth = useAgilityAuth();
|
|
213
|
-
|
|
214
|
-
const selection = useWebsiteSelection(
|
|
215
|
-
auth.websiteAccess,
|
|
216
|
-
auth.selectedWebsite,
|
|
217
|
-
auth.locales,
|
|
218
|
-
auth.selectedLocale,
|
|
219
|
-
auth.isLoadingLocales,
|
|
220
|
-
auth.selectWebsite,
|
|
221
|
-
auth.selectLocale
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
const sortedWebsites = sortWebsitesByName(selection.websites);
|
|
225
|
-
const validation = validateSelection(
|
|
226
|
-
selection.websites,
|
|
227
|
-
selection.selectedWebsite,
|
|
228
|
-
selection.locales,
|
|
229
|
-
selection.selectedLocale
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
return (
|
|
233
|
-
<div>
|
|
234
|
-
<select onChange={(e) => selection.selectWebsite(e.target.value)}>
|
|
235
|
-
{sortedWebsites.map(site => (
|
|
236
|
-
<option key={site.websiteGuid} value={site.websiteGuid}>
|
|
237
|
-
{site.websiteName}
|
|
238
|
-
</option>
|
|
239
|
-
))}
|
|
240
|
-
</select>
|
|
241
|
-
|
|
242
|
-
{!validation.isValid && (
|
|
243
|
-
<div className="validation-errors">
|
|
244
|
-
{validation.errors.map(error => (
|
|
245
|
-
<div key={error} className="error">{error}</div>
|
|
246
|
-
))}
|
|
247
|
-
</div>
|
|
248
|
-
)}
|
|
249
|
-
</div>
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## Type Definitions
|
|
255
|
-
|
|
256
|
-
### Core Types
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
interface AgilityAuthConfig {
|
|
260
|
-
// Callbacks
|
|
261
|
-
onSignIn?: (user: ServerUser) => void;
|
|
262
|
-
onSignOut?: () => void;
|
|
263
|
-
onWebsiteSelect?: (website: WebsiteAccess) => void;
|
|
264
|
-
onLocaleSelect?: (locale: LocaleInfo) => void;
|
|
265
|
-
|
|
266
|
-
// Display & Behavior
|
|
267
|
-
mode?: 'fullscreen' | 'footer' | 'button-only';
|
|
268
|
-
theme?: 'light' | 'dark' | 'auto';
|
|
269
|
-
showCurrentSelection?: boolean;
|
|
270
|
-
|
|
271
|
-
// OAuth Settings
|
|
272
|
-
redirectUri?: string;
|
|
273
|
-
scope?: string;
|
|
274
|
-
region?: string;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
interface WebsiteAccess {
|
|
278
|
-
websiteGuid: string;
|
|
279
|
-
websiteName: string;
|
|
280
|
-
websiteDescription?: string;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
interface LocaleInfo {
|
|
284
|
-
localeCode: string;
|
|
285
|
-
localeID: number;
|
|
286
|
-
localeName: string;
|
|
287
|
-
isDefault?: boolean;
|
|
288
|
-
isEnabled?: boolean;
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
## Coming Soon
|
|
293
|
-
|
|
294
|
-
The following UI components are currently in development:
|
|
295
|
-
|
|
296
|
-
- **AgilityAuth Component**: Full-featured authentication component
|
|
297
|
-
- **AuthButton**: Standalone authentication button
|
|
298
|
-
- **WebsiteSelector**: Website selection dropdown
|
|
299
|
-
- **LocaleSelector**: Locale selection dropdown
|
|
300
|
-
- **UserInfo**: User information display
|
|
301
|
-
- **Footer Mode**: Collapsible footer bar implementation
|
|
302
|
-
|
|
303
|
-
## Migration from Direct SDK Usage
|
|
304
|
-
|
|
305
|
-
If you're currently using the SDK directly, you can gradually migrate:
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
// Before: Direct SDK usage
|
|
309
|
-
const client = new ApiClient();
|
|
310
|
-
await client.auth();
|
|
311
|
-
const user = await client.serverUserMethods.me();
|
|
312
|
-
|
|
313
|
-
// After: Using the hook
|
|
314
|
-
const { authenticate, user, isAuthenticated } = useAgilityAuth();
|
|
315
|
-
if (!isAuthenticated) {
|
|
316
|
-
await authenticate();
|
|
317
|
-
}
|
|
318
|
-
// user is now available directly from the hook
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
## Performance Considerations
|
|
322
|
-
|
|
323
|
-
- State is managed using React's `useReducer` for optimal performance
|
|
324
|
-
- Context values are memoized to prevent unnecessary re-renders
|
|
325
|
-
- All callback functions are memoized with `useCallback`
|
|
326
|
-
- Automatic cleanup of event listeners and timeouts
|
|
327
|
-
|
|
328
|
-
## Browser Support
|
|
329
|
-
|
|
330
|
-
- Modern browsers with ES2017+ support
|
|
331
|
-
- React 16.8+ (hooks support)
|
|
332
|
-
- TypeScript 4.0+ (optional but recommended)
|
|
333
|
-
|
|
334
|
-
## Error Handling
|
|
335
|
-
|
|
336
|
-
The authentication system provides comprehensive error handling:
|
|
337
|
-
|
|
338
|
-
```typescript
|
|
339
|
-
const { error, clearError } = useAuthError();
|
|
340
|
-
|
|
341
|
-
// Display errors to user
|
|
342
|
-
if (error) {
|
|
343
|
-
return (
|
|
344
|
-
<div className="error">
|
|
345
|
-
{error}
|
|
346
|
-
<button onClick={clearError}>Dismiss</button>
|
|
347
|
-
</div>
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
## Security
|
|
353
|
-
|
|
354
|
-
- Tokens are stored securely using `keytar` (Node.js) or `localStorage` (browser)
|
|
355
|
-
- Automatic token refresh prevents expired token issues
|
|
356
|
-
- OAuth flow uses secure popup window with proper origin validation
|
|
357
|
-
- All sensitive operations are handled server-side
|
|
358
|
-
|
|
359
|
-
## Support
|
|
360
|
-
|
|
1
|
+
# Agility CMS Authentication Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Agility CMS Authentication Component provides a complete, reusable authentication system for React applications. It handles OAuth authentication, token management, and provides a rich set of hooks and components for building authentication UIs.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **OAuth Authentication**: Secure popup-based authentication flow
|
|
10
|
+
- **Token Management**: Automatic token refresh and secure storage
|
|
11
|
+
- **Type Safety**: Full TypeScript support with comprehensive interfaces
|
|
12
|
+
- **Multiple Display Modes**: Fullscreen, footer bar, and button-only modes
|
|
13
|
+
- **Extensive Customization**: Callbacks, styling, and slot-based customization
|
|
14
|
+
- **Performance Optimized**: Uses React hooks and context for efficient state management
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @agility/management-sdk-typescript
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Basic Usage
|
|
23
|
+
|
|
24
|
+
### 1. Using the Authentication Hook
|
|
25
|
+
|
|
26
|
+
The simplest way to add authentication to your app:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { useAgilityAuth } from '@agility/management-sdk-typescript';
|
|
30
|
+
|
|
31
|
+
function MyApp() {
|
|
32
|
+
const {
|
|
33
|
+
isAuthenticated,
|
|
34
|
+
isLoading,
|
|
35
|
+
user,
|
|
36
|
+
websiteAccess,
|
|
37
|
+
selectedWebsite,
|
|
38
|
+
selectedLocale,
|
|
39
|
+
locales,
|
|
40
|
+
error,
|
|
41
|
+
authenticate,
|
|
42
|
+
signOut,
|
|
43
|
+
selectWebsite,
|
|
44
|
+
selectLocale,
|
|
45
|
+
clearError,
|
|
46
|
+
hasSelection,
|
|
47
|
+
currentSelection
|
|
48
|
+
} = useAgilityAuth({
|
|
49
|
+
redirectUri: 'https://myapp.com/auth-callback.html',
|
|
50
|
+
scope: 'openid profile email offline_access',
|
|
51
|
+
autoCheckAuth: true // Automatically check auth on mount
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (isLoading) return <div>Loading...</div>;
|
|
55
|
+
if (error) return <div>Error: {error}</div>;
|
|
56
|
+
|
|
57
|
+
if (!isAuthenticated) {
|
|
58
|
+
return (
|
|
59
|
+
<button onClick={authenticate}>
|
|
60
|
+
Sign in with Agility CMS
|
|
61
|
+
</button>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
<h1>Welcome, {user?.userName}!</h1>
|
|
68
|
+
|
|
69
|
+
<select
|
|
70
|
+
value={selectedWebsite}
|
|
71
|
+
onChange={(e) => selectWebsite(e.target.value)}
|
|
72
|
+
>
|
|
73
|
+
<option value="">Choose a website...</option>
|
|
74
|
+
{websiteAccess.map(site => (
|
|
75
|
+
<option key={site.websiteGuid} value={site.websiteGuid}>
|
|
76
|
+
{site.websiteName}
|
|
77
|
+
</option>
|
|
78
|
+
))}
|
|
79
|
+
</select>
|
|
80
|
+
|
|
81
|
+
{selectedWebsite && (
|
|
82
|
+
<select
|
|
83
|
+
value={selectedLocale}
|
|
84
|
+
onChange={(e) => selectLocale(e.target.value)}
|
|
85
|
+
>
|
|
86
|
+
<option value="">Choose a locale...</option>
|
|
87
|
+
{locales.map(locale => (
|
|
88
|
+
<option key={locale.localeCode} value={locale.localeCode}>
|
|
89
|
+
{locale.localeName}
|
|
90
|
+
</option>
|
|
91
|
+
))}
|
|
92
|
+
</select>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
{hasSelection && (
|
|
96
|
+
<div>
|
|
97
|
+
<p>Current Selection: {currentSelection?.websiteName} - {currentSelection?.localeName}</p>
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
100
|
+
|
|
101
|
+
<button onClick={signOut}>Sign Out</button>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2. Using the Context Provider
|
|
108
|
+
|
|
109
|
+
For larger applications, use the context provider to share authentication state:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { AuthProvider, useAuthContext } from '@agility/management-sdk-typescript';
|
|
113
|
+
|
|
114
|
+
// App component
|
|
115
|
+
function App() {
|
|
116
|
+
return (
|
|
117
|
+
<AuthProvider>
|
|
118
|
+
<MyAuthenticatedApp />
|
|
119
|
+
</AuthProvider>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Child component that uses auth context
|
|
124
|
+
function MyAuthenticatedApp() {
|
|
125
|
+
const { state, actions } = useAuthContext();
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div>
|
|
129
|
+
{state.isAuthenticated ? (
|
|
130
|
+
<Dashboard user={state.user} />
|
|
131
|
+
) : (
|
|
132
|
+
<LoginForm onLogin={actions.setAuthenticated} />
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 3. Using Granular Context Hooks
|
|
140
|
+
|
|
141
|
+
For more specific use cases, use the granular hooks:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import {
|
|
145
|
+
useIsAuthenticated,
|
|
146
|
+
useCurrentUser,
|
|
147
|
+
useSelection,
|
|
148
|
+
useLoadingStates,
|
|
149
|
+
useAuthError
|
|
150
|
+
} from '@agility/management-sdk-typescript';
|
|
151
|
+
|
|
152
|
+
function UserProfile() {
|
|
153
|
+
const isAuthenticated = useIsAuthenticated();
|
|
154
|
+
const user = useCurrentUser();
|
|
155
|
+
const { isLoading } = useLoadingStates();
|
|
156
|
+
|
|
157
|
+
if (!isAuthenticated) return <div>Please log in</div>;
|
|
158
|
+
if (isLoading) return <div>Loading...</div>;
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div>
|
|
162
|
+
<h2>{user?.userName}</h2>
|
|
163
|
+
<p>{user?.emailAddress}</p>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function WebsiteSelector() {
|
|
169
|
+
const { selectedWebsite, selectedLocale, hasSelection } = useSelection();
|
|
170
|
+
const { error, clearError } = useAuthError();
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<div>
|
|
174
|
+
{error && (
|
|
175
|
+
<div className="error">
|
|
176
|
+
{error}
|
|
177
|
+
<button onClick={clearError}>Clear</button>
|
|
178
|
+
</div>
|
|
179
|
+
)}
|
|
180
|
+
|
|
181
|
+
{hasSelection && (
|
|
182
|
+
<div>Selected: {selectedWebsite} - {selectedLocale}</div>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Advanced Usage
|
|
190
|
+
|
|
191
|
+
### Custom OAuth Configuration
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const auth = useAgilityAuth({
|
|
195
|
+
redirectUri: 'https://myapp.com/auth-callback.html',
|
|
196
|
+
scope: 'openid profile email offline_access',
|
|
197
|
+
region: 'us-west-2',
|
|
198
|
+
autoCheckAuth: true
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Website Selection with Validation
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import {
|
|
206
|
+
useWebsiteSelection,
|
|
207
|
+
validateSelection,
|
|
208
|
+
sortWebsitesByName
|
|
209
|
+
} from '@agility/management-sdk-typescript';
|
|
210
|
+
|
|
211
|
+
function WebsiteManager() {
|
|
212
|
+
const auth = useAgilityAuth();
|
|
213
|
+
|
|
214
|
+
const selection = useWebsiteSelection(
|
|
215
|
+
auth.websiteAccess,
|
|
216
|
+
auth.selectedWebsite,
|
|
217
|
+
auth.locales,
|
|
218
|
+
auth.selectedLocale,
|
|
219
|
+
auth.isLoadingLocales,
|
|
220
|
+
auth.selectWebsite,
|
|
221
|
+
auth.selectLocale
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const sortedWebsites = sortWebsitesByName(selection.websites);
|
|
225
|
+
const validation = validateSelection(
|
|
226
|
+
selection.websites,
|
|
227
|
+
selection.selectedWebsite,
|
|
228
|
+
selection.locales,
|
|
229
|
+
selection.selectedLocale
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<div>
|
|
234
|
+
<select onChange={(e) => selection.selectWebsite(e.target.value)}>
|
|
235
|
+
{sortedWebsites.map(site => (
|
|
236
|
+
<option key={site.websiteGuid} value={site.websiteGuid}>
|
|
237
|
+
{site.websiteName}
|
|
238
|
+
</option>
|
|
239
|
+
))}
|
|
240
|
+
</select>
|
|
241
|
+
|
|
242
|
+
{!validation.isValid && (
|
|
243
|
+
<div className="validation-errors">
|
|
244
|
+
{validation.errors.map(error => (
|
|
245
|
+
<div key={error} className="error">{error}</div>
|
|
246
|
+
))}
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Type Definitions
|
|
255
|
+
|
|
256
|
+
### Core Types
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
interface AgilityAuthConfig {
|
|
260
|
+
// Callbacks
|
|
261
|
+
onSignIn?: (user: ServerUser) => void;
|
|
262
|
+
onSignOut?: () => void;
|
|
263
|
+
onWebsiteSelect?: (website: WebsiteAccess) => void;
|
|
264
|
+
onLocaleSelect?: (locale: LocaleInfo) => void;
|
|
265
|
+
|
|
266
|
+
// Display & Behavior
|
|
267
|
+
mode?: 'fullscreen' | 'footer' | 'button-only';
|
|
268
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
269
|
+
showCurrentSelection?: boolean;
|
|
270
|
+
|
|
271
|
+
// OAuth Settings
|
|
272
|
+
redirectUri?: string;
|
|
273
|
+
scope?: string;
|
|
274
|
+
region?: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
interface WebsiteAccess {
|
|
278
|
+
websiteGuid: string;
|
|
279
|
+
websiteName: string;
|
|
280
|
+
websiteDescription?: string;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
interface LocaleInfo {
|
|
284
|
+
localeCode: string;
|
|
285
|
+
localeID: number;
|
|
286
|
+
localeName: string;
|
|
287
|
+
isDefault?: boolean;
|
|
288
|
+
isEnabled?: boolean;
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Coming Soon
|
|
293
|
+
|
|
294
|
+
The following UI components are currently in development:
|
|
295
|
+
|
|
296
|
+
- **AgilityAuth Component**: Full-featured authentication component
|
|
297
|
+
- **AuthButton**: Standalone authentication button
|
|
298
|
+
- **WebsiteSelector**: Website selection dropdown
|
|
299
|
+
- **LocaleSelector**: Locale selection dropdown
|
|
300
|
+
- **UserInfo**: User information display
|
|
301
|
+
- **Footer Mode**: Collapsible footer bar implementation
|
|
302
|
+
|
|
303
|
+
## Migration from Direct SDK Usage
|
|
304
|
+
|
|
305
|
+
If you're currently using the SDK directly, you can gradually migrate:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Before: Direct SDK usage
|
|
309
|
+
const client = new ApiClient();
|
|
310
|
+
await client.auth();
|
|
311
|
+
const user = await client.serverUserMethods.me();
|
|
312
|
+
|
|
313
|
+
// After: Using the hook
|
|
314
|
+
const { authenticate, user, isAuthenticated } = useAgilityAuth();
|
|
315
|
+
if (!isAuthenticated) {
|
|
316
|
+
await authenticate();
|
|
317
|
+
}
|
|
318
|
+
// user is now available directly from the hook
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Performance Considerations
|
|
322
|
+
|
|
323
|
+
- State is managed using React's `useReducer` for optimal performance
|
|
324
|
+
- Context values are memoized to prevent unnecessary re-renders
|
|
325
|
+
- All callback functions are memoized with `useCallback`
|
|
326
|
+
- Automatic cleanup of event listeners and timeouts
|
|
327
|
+
|
|
328
|
+
## Browser Support
|
|
329
|
+
|
|
330
|
+
- Modern browsers with ES2017+ support
|
|
331
|
+
- React 16.8+ (hooks support)
|
|
332
|
+
- TypeScript 4.0+ (optional but recommended)
|
|
333
|
+
|
|
334
|
+
## Error Handling
|
|
335
|
+
|
|
336
|
+
The authentication system provides comprehensive error handling:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
const { error, clearError } = useAuthError();
|
|
340
|
+
|
|
341
|
+
// Display errors to user
|
|
342
|
+
if (error) {
|
|
343
|
+
return (
|
|
344
|
+
<div className="error">
|
|
345
|
+
{error}
|
|
346
|
+
<button onClick={clearError}>Dismiss</button>
|
|
347
|
+
</div>
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Security
|
|
353
|
+
|
|
354
|
+
- Tokens are stored securely using `keytar` (Node.js) or `localStorage` (browser)
|
|
355
|
+
- Automatic token refresh prevents expired token issues
|
|
356
|
+
- OAuth flow uses secure popup window with proper origin validation
|
|
357
|
+
- All sensitive operations are handled server-side
|
|
358
|
+
|
|
359
|
+
## Support
|
|
360
|
+
|
|
361
361
|
For issues and feature requests, please visit the [GitHub repository](https://github.com/agility/agility-cms-management-sdk-typescript).
|