@famgia/omnify-react-sso 2.1.0 β 2.2.0
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 +418 -12
- package/dist/index.cjs +2143 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1204 -1
- package/dist/index.d.ts +1204 -1
- package/dist/index.js +2059 -72
- package/dist/index.js.map +1 -1
- package/dist/schemas/index.cjs +449 -63
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +1 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +393 -72
- package/dist/schemas/index.js.map +1 -1
- package/dist/testing/index.cjs +120 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +97 -0
- package/dist/testing/index.d.ts +97 -0
- package/dist/testing/index.js +87 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/types-BCBSfJJr.d.cts +136 -0
- package/dist/types-BCBSfJJr.d.ts +136 -0
- package/package.json +104 -79
- package/scripts/build-schemas.ts +112 -13
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @famgia/omnify-react-sso
|
|
2
2
|
|
|
3
|
-
SSO (Single Sign-On) schemas, types, and utilities for Omnify Console integration.
|
|
3
|
+
SSO (Single Sign-On) schemas, types, React hooks, components, and utilities for Omnify Console integration.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -12,11 +12,234 @@ pnpm add @famgia/omnify-react-sso
|
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
|
+
- **React Hooks**: `useSso()`, `useAuth()`, `useOrganization()` for SSO state management
|
|
16
|
+
- **React Components**: `SsoProvider`, `SsoCallback`, `OrganizationSwitcher`, `ProtectedRoute`
|
|
17
|
+
- **SSO Service**: `createSsoService()` for API communication
|
|
15
18
|
- **User Management**: User schema with Zod validation and i18n support
|
|
16
19
|
- **Role-Based Access Control (RBAC)**: Role, Permission, and RolePermission schemas
|
|
17
20
|
- **Team Management**: Team and TeamPermission schemas
|
|
18
21
|
- **Multi-locale Support**: Japanese and English labels/messages
|
|
19
|
-
- **
|
|
22
|
+
- **Query Keys**: Pre-defined TanStack Query keys for SSO data
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
// 1. Wrap your app with SsoProvider
|
|
28
|
+
import { SsoProvider } from '@famgia/omnify-react-sso';
|
|
29
|
+
|
|
30
|
+
function App() {
|
|
31
|
+
return (
|
|
32
|
+
<SsoProvider config={{
|
|
33
|
+
apiUrl: process.env.NEXT_PUBLIC_API_URL,
|
|
34
|
+
consoleUrl: process.env.NEXT_PUBLIC_SSO_URL,
|
|
35
|
+
loginPath: '/login',
|
|
36
|
+
callbackPath: '/sso/callback',
|
|
37
|
+
}}>
|
|
38
|
+
<YourApp />
|
|
39
|
+
</SsoProvider>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 2. Use hooks in your components
|
|
44
|
+
import { useSso } from '@famgia/omnify-react-sso';
|
|
45
|
+
|
|
46
|
+
function Dashboard() {
|
|
47
|
+
const { user, isAuthenticated, currentOrg, logout } = useSso();
|
|
48
|
+
|
|
49
|
+
if (!isAuthenticated) return <Login />;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div>
|
|
53
|
+
Welcome, {user.name}!
|
|
54
|
+
Current org: {currentOrg?.name}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## π§ Development & Build Workflow
|
|
63
|
+
|
|
64
|
+
### Prerequisites
|
|
65
|
+
|
|
66
|
+
This package depends on schemas from `omnifyjp/omnify-client-laravel-sso`. The build process will:
|
|
67
|
+
|
|
68
|
+
1. **Try local**: Copy from `../omnify-client-laravel-sso/database/schemas/Sso`
|
|
69
|
+
2. **Fallback to git**: Clone via SSH from GitHub (requires access to omnifyjp org)
|
|
70
|
+
|
|
71
|
+
**SSH Access Required**: Developers must have SSH access to `git@github.com:omnifyjp/omnify-client-laravel-sso.git`
|
|
72
|
+
|
|
73
|
+
### Build Commands
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Full build (schemas + library)
|
|
77
|
+
pnpm build
|
|
78
|
+
|
|
79
|
+
# Build only schemas (fetch + generate types)
|
|
80
|
+
pnpm build:schemas
|
|
81
|
+
|
|
82
|
+
# Build only library (requires schemas to exist)
|
|
83
|
+
pnpm build:lib
|
|
84
|
+
|
|
85
|
+
# Run tests
|
|
86
|
+
pnpm test
|
|
87
|
+
|
|
88
|
+
# Type check
|
|
89
|
+
pnpm typecheck
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Build Process Detail
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
96
|
+
β pnpm build β
|
|
97
|
+
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
|
|
98
|
+
β
|
|
99
|
+
βΌ
|
|
100
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
101
|
+
β Step 1: pnpm build:schemas β
|
|
102
|
+
β β
|
|
103
|
+
β 1. Clean previous builds (schemas/, src/schemas/, src/enum/) β
|
|
104
|
+
β 2. Obtain SSO schemas: β
|
|
105
|
+
β - Try: ../omnify-client-laravel-sso/database/schemas/Sso β
|
|
106
|
+
β - Fallback: git clone from GitHub (sparse checkout) β
|
|
107
|
+
β 3. Run: npx omnify generate --types-only β
|
|
108
|
+
β β Creates @omnify-base in node_modules β
|
|
109
|
+
β β Generates src/schemas/*.ts β
|
|
110
|
+
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
|
|
111
|
+
β
|
|
112
|
+
βΌ
|
|
113
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
114
|
+
β Step 2: pnpm build:lib (tsup) β
|
|
115
|
+
β β
|
|
116
|
+
β - Bundle src/index.ts β dist/index.js β
|
|
117
|
+
β - Bundle src/schemas/index.ts β dist/schemas/index.js β
|
|
118
|
+
β - Generate .d.ts type definitions β
|
|
119
|
+
β - External: zod, @omnify-base/* β
|
|
120
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### First Time Setup
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Option A: Just run build (auto-fetches via SSH)
|
|
127
|
+
pnpm install
|
|
128
|
+
pnpm build # Will clone schemas from git automatically
|
|
129
|
+
|
|
130
|
+
# Option B: Clone laravel-sso as sibling (for frequent schema changes)
|
|
131
|
+
cd packages
|
|
132
|
+
git clone git@github.com:omnifyjp/omnify-client-laravel-sso.git
|
|
133
|
+
cd omnify-client-react-sso
|
|
134
|
+
pnpm install
|
|
135
|
+
pnpm build
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> **Note**: Build script uses SSH (`git@github.com:omnifyjp/...`). Ensure your SSH key is added to GitHub.
|
|
139
|
+
|
|
140
|
+
### When to Rebuild
|
|
141
|
+
|
|
142
|
+
You need to run `pnpm build` when:
|
|
143
|
+
|
|
144
|
+
- β
First time setup
|
|
145
|
+
- β
Schema changes in `omnify-client-laravel-sso`
|
|
146
|
+
- β
After pulling updates from laravel-sso
|
|
147
|
+
- β
Before publishing to npm
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Local Development with Boilerplate
|
|
152
|
+
|
|
153
|
+
### Linking Package to Boilerplate
|
|
154
|
+
|
|
155
|
+
Instead of using npm registry or tarballs, link the package directly:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# In boilerplate/frontend
|
|
159
|
+
pnpm add /path/to/omnify/packages/omnify-client-react-sso
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This creates a symlink in `package.json`:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
"@famgia/omnify-react-sso": "link:/path/to/omnify/packages/omnify-client-react-sso"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Development Workflow
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
172
|
+
β omnify-client-laravel-sso (Laravel Package) β
|
|
173
|
+
β - SSO schema YAML files (source of truth) β
|
|
174
|
+
β - Backend models, migrations, controllers β
|
|
175
|
+
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
|
|
176
|
+
β schemas copied during build
|
|
177
|
+
βΌ
|
|
178
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
179
|
+
β @famgia/omnify-react-sso (This Package) β
|
|
180
|
+
β β
|
|
181
|
+
β pnpm build β
|
|
182
|
+
β βββ 1. Copy schemas from laravel-sso β
|
|
183
|
+
β βββ 2. omnify generate --types-only β
|
|
184
|
+
β βββ 3. tsup bundle β dist/ β
|
|
185
|
+
β β
|
|
186
|
+
β Exports: β
|
|
187
|
+
β - React hooks (useSso, useAuth, useOrganization) β
|
|
188
|
+
β - React components (SsoProvider, ProtectedRoute, etc.) β
|
|
189
|
+
β - Services (createAuthService, createRoleService, etc.) β
|
|
190
|
+
β - SSO Schemas (Role, Permission, Branch, Team, User) β
|
|
191
|
+
β - Query Keys (ssoQueryKeys) β
|
|
192
|
+
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
|
|
193
|
+
β linked via pnpm
|
|
194
|
+
βΌ
|
|
195
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
196
|
+
β Boilerplate / Your App β
|
|
197
|
+
β β
|
|
198
|
+
β package.json: β
|
|
199
|
+
β "@famgia/omnify-react-sso": "link:/path/to/package" β
|
|
200
|
+
β β
|
|
201
|
+
β omnify.config.ts: β
|
|
202
|
+
β typescriptPlugin({ β
|
|
203
|
+
β exclude: ["Branch", "Role", "Permission", ...] // SSO types β
|
|
204
|
+
β }) β
|
|
205
|
+
β β
|
|
206
|
+
β Imports: β
|
|
207
|
+
β - SSO types β from "@famgia/omnify-react-sso" β
|
|
208
|
+
β - App types β from "@/omnify/schemas" (local generate) β
|
|
209
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### After Changing SSO Schemas
|
|
213
|
+
|
|
214
|
+
1. **Update Laravel package** (if schema YAML changed)
|
|
215
|
+
2. **Rebuild this package:**
|
|
216
|
+
```bash
|
|
217
|
+
cd packages/omnify-client-react-sso
|
|
218
|
+
pnpm build
|
|
219
|
+
```
|
|
220
|
+
3. **Boilerplate automatically uses new dist** (linked)
|
|
221
|
+
|
|
222
|
+
### Boilerplate Configuration
|
|
223
|
+
|
|
224
|
+
In the boilerplate's `omnify.config.ts`, exclude SSO schemas:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
typescriptPlugin({
|
|
228
|
+
modelsPath: "./frontend/src/omnify/schemas",
|
|
229
|
+
exclude: [
|
|
230
|
+
"Branch",
|
|
231
|
+
"Permission",
|
|
232
|
+
"Role",
|
|
233
|
+
"RolePermission",
|
|
234
|
+
"Team",
|
|
235
|
+
"TeamPermission",
|
|
236
|
+
],
|
|
237
|
+
})
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
This prevents duplicate schema generation - SSO types come from this package.
|
|
241
|
+
|
|
242
|
+
---
|
|
20
243
|
|
|
21
244
|
## Architecture Note
|
|
22
245
|
|
|
@@ -35,7 +258,123 @@ Console (SSO Provider) Your React App (SSO Client)
|
|
|
35
258
|
|
|
36
259
|
> **Note:** Your app only needs the `service_slug`. Console manages credentials per-organization through ServiceInstance.
|
|
37
260
|
|
|
38
|
-
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## API Reference
|
|
264
|
+
|
|
265
|
+
### Hooks
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { useSso, useAuth, useOrganization } from '@famgia/omnify-react-sso';
|
|
269
|
+
|
|
270
|
+
// Main hook - all SSO functionality
|
|
271
|
+
const {
|
|
272
|
+
user, // Current user
|
|
273
|
+
isAuthenticated, // Auth status
|
|
274
|
+
isLoading, // Loading state
|
|
275
|
+
organizations, // User's organizations
|
|
276
|
+
currentOrg, // Current organization
|
|
277
|
+
hasMultipleOrgs, // Has more than one org?
|
|
278
|
+
login, // Redirect to login
|
|
279
|
+
logout, // Logout current session
|
|
280
|
+
globalLogout, // Logout from all sessions
|
|
281
|
+
switchOrg, // Switch organization
|
|
282
|
+
getHeaders, // Get auth headers
|
|
283
|
+
config, // SSO config
|
|
284
|
+
} = useSso();
|
|
285
|
+
|
|
286
|
+
// Auth-focused hook
|
|
287
|
+
const { user, isAuthenticated, login, logout } = useAuth();
|
|
288
|
+
|
|
289
|
+
// Organization-focused hook
|
|
290
|
+
const { organizations, currentOrg, switchOrg, hasMultipleOrgs } = useOrganization();
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Components
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
import {
|
|
297
|
+
SsoProvider,
|
|
298
|
+
SsoCallback,
|
|
299
|
+
OrganizationSwitcher,
|
|
300
|
+
ProtectedRoute,
|
|
301
|
+
} from '@famgia/omnify-react-sso';
|
|
302
|
+
|
|
303
|
+
// Provider - wrap your app
|
|
304
|
+
<SsoProvider config={ssoConfig}>
|
|
305
|
+
<App />
|
|
306
|
+
</SsoProvider>
|
|
307
|
+
|
|
308
|
+
// Callback page - handle OAuth redirect
|
|
309
|
+
<SsoCallback
|
|
310
|
+
onSuccess={(user) => router.push('/dashboard')}
|
|
311
|
+
onError={(error) => console.error(error)}
|
|
312
|
+
/>
|
|
313
|
+
|
|
314
|
+
// Organization switcher dropdown
|
|
315
|
+
<OrganizationSwitcher />
|
|
316
|
+
|
|
317
|
+
// Protected route wrapper
|
|
318
|
+
<ProtectedRoute fallback={<Login />}>
|
|
319
|
+
<Dashboard />
|
|
320
|
+
</ProtectedRoute>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Services (Recommended)
|
|
324
|
+
|
|
325
|
+
Use individual services for better tree-shaking and type safety:
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import {
|
|
329
|
+
createAuthService,
|
|
330
|
+
createRoleService,
|
|
331
|
+
createPermissionService,
|
|
332
|
+
createBranchService,
|
|
333
|
+
createUserRoleService,
|
|
334
|
+
} from '@famgia/omnify-react-sso';
|
|
335
|
+
|
|
336
|
+
const config = { apiUrl: 'https://api.example.com' };
|
|
337
|
+
|
|
338
|
+
// Auth Service
|
|
339
|
+
const authService = createAuthService(config);
|
|
340
|
+
await authService.callback({ code: 'oauth-code' });
|
|
341
|
+
await authService.getUser();
|
|
342
|
+
await authService.logout();
|
|
343
|
+
|
|
344
|
+
// Role Service
|
|
345
|
+
const roleService = createRoleService(config);
|
|
346
|
+
await roleService.list();
|
|
347
|
+
await roleService.get(roleId);
|
|
348
|
+
await roleService.create({ name: 'Editor', slug: 'editor' });
|
|
349
|
+
await roleService.syncPermissions(roleId, { permissions: ['read', 'write'] });
|
|
350
|
+
|
|
351
|
+
// Permission Service
|
|
352
|
+
const permissionService = createPermissionService(config);
|
|
353
|
+
await permissionService.list();
|
|
354
|
+
await permissionService.getMatrix();
|
|
355
|
+
|
|
356
|
+
// Branch Service
|
|
357
|
+
const branchService = createBranchService(config);
|
|
358
|
+
await branchService.list();
|
|
359
|
+
await branchService.getPrimary();
|
|
360
|
+
|
|
361
|
+
// User Role Service (Scoped Assignments)
|
|
362
|
+
const userRoleService = createUserRoleService(config);
|
|
363
|
+
await userRoleService.listForUser(userId);
|
|
364
|
+
await userRoleService.assign({ user_id, role_id, scope: 'branch', branch_id });
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Legacy Service (Deprecated)
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// @deprecated - Use individual services instead
|
|
371
|
+
import { createSsoService } from '@famgia/omnify-react-sso';
|
|
372
|
+
|
|
373
|
+
const ssoService = createSsoService({ apiUrl: 'https://api.example.com' });
|
|
374
|
+
await ssoService.getRoles(); // Use roleService.list() instead
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Schemas
|
|
39
378
|
|
|
40
379
|
```typescript
|
|
41
380
|
import {
|
|
@@ -64,16 +403,24 @@ import {
|
|
|
64
403
|
} from '@famgia/omnify-react-sso';
|
|
65
404
|
```
|
|
66
405
|
|
|
67
|
-
|
|
406
|
+
### Query Keys
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { ssoQueryKeys } from '@famgia/omnify-react-sso';
|
|
68
410
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
411
|
+
// Use with TanStack Query
|
|
412
|
+
useQuery({
|
|
413
|
+
queryKey: ssoQueryKeys.auth.user(),
|
|
414
|
+
queryFn: () => ssoService.getUser(),
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
useQuery({
|
|
418
|
+
queryKey: ssoQueryKeys.roles.list(),
|
|
419
|
+
queryFn: () => ssoService.getRoles(),
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
---
|
|
77
424
|
|
|
78
425
|
## i18n Support
|
|
79
426
|
|
|
@@ -89,6 +436,65 @@ const label = getUserLabel('ja'); // 'γ¦γΌγΆγΌ'
|
|
|
89
436
|
const emailLabel = getUserFieldLabel('email', 'ja'); // 'γ‘γΌγ«γ’γγ¬γΉ'
|
|
90
437
|
```
|
|
91
438
|
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Testing
|
|
442
|
+
|
|
443
|
+
### Run Tests
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
pnpm test # Run once
|
|
447
|
+
pnpm test:watch # Watch mode
|
|
448
|
+
pnpm typecheck # Type check
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### Test Utilities (for App Tests)
|
|
452
|
+
|
|
453
|
+
The package provides official test mocks:
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
import {
|
|
457
|
+
createMockUser,
|
|
458
|
+
createMockOrganization,
|
|
459
|
+
setMockSsoData,
|
|
460
|
+
resetMockSsoData,
|
|
461
|
+
mockUseSso,
|
|
462
|
+
} from '@famgia/omnify-react-sso/testing';
|
|
463
|
+
|
|
464
|
+
// Create mock data
|
|
465
|
+
const user = createMockUser({ name: 'Custom User' });
|
|
466
|
+
const org = createMockOrganization({ slug: 'my-org' });
|
|
467
|
+
|
|
468
|
+
// Setup mock for tests
|
|
469
|
+
beforeEach(() => {
|
|
470
|
+
setMockSsoData({
|
|
471
|
+
user,
|
|
472
|
+
organizations: [org],
|
|
473
|
+
currentOrg: org,
|
|
474
|
+
isAuthenticated: true,
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
afterEach(() => {
|
|
479
|
+
resetMockSsoData();
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Mock the hooks in vitest
|
|
483
|
+
vi.mock('@famgia/omnify-react-sso', async () => {
|
|
484
|
+
const testing = await import('@famgia/omnify-react-sso/testing');
|
|
485
|
+
return {
|
|
486
|
+
useSso: testing.mockUseSso,
|
|
487
|
+
useAuth: testing.mockUseAuth,
|
|
488
|
+
useOrganization: testing.mockUseOrganization,
|
|
489
|
+
SsoProvider: ({ children }) => children,
|
|
490
|
+
};
|
|
491
|
+
});
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
> **Note**: Subpath exports (`/testing`) require the package to be installed from npm, not linked locally.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
92
498
|
## License
|
|
93
499
|
|
|
94
500
|
MIT
|