@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 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
- - **ServiceInstance Compatible**: Works with Console's multi-instance architecture
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
- ## Usage
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
- ## Schemas
406
+ ### Query Keys
407
+
408
+ ```typescript
409
+ import { ssoQueryKeys } from '@famgia/omnify-react-sso';
68
410
 
69
- | Schema | Description |
70
- | -------------- | --------------------------------------- |
71
- | User | User account with authentication fields |
72
- | Role | User roles for RBAC |
73
- | Permission | Individual permissions |
74
- | RolePermission | Role-Permission mapping (pivot) |
75
- | Team | Team/Organization grouping |
76
- | TeamPermission | Team-Permission mapping |
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