@ogcio/sag-client 0.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.
Files changed (58) hide show
  1. package/README.md +533 -0
  2. package/dist/auth.d.ts +55 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +154 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/client.d.ts +93 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +118 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/fetcher.d.ts +39 -0
  11. package/dist/fetcher.d.ts.map +1 -0
  12. package/dist/fetcher.js +141 -0
  13. package/dist/fetcher.js.map +1 -0
  14. package/dist/index.d.ts +9 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +12 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/onboarding.d.ts +68 -0
  19. package/dist/onboarding.d.ts.map +1 -0
  20. package/dist/onboarding.js +67 -0
  21. package/dist/onboarding.js.map +1 -0
  22. package/dist/react/index.d.ts +15 -0
  23. package/dist/react/index.d.ts.map +1 -0
  24. package/dist/react/index.js +16 -0
  25. package/dist/react/index.js.map +1 -0
  26. package/dist/react/provider.d.ts +22 -0
  27. package/dist/react/provider.d.ts.map +1 -0
  28. package/dist/react/provider.js +31 -0
  29. package/dist/react/provider.js.map +1 -0
  30. package/dist/react/use-auth.d.ts +13 -0
  31. package/dist/react/use-auth.d.ts.map +1 -0
  32. package/dist/react/use-auth.js +84 -0
  33. package/dist/react/use-auth.js.map +1 -0
  34. package/dist/react/use-gateway-fetch.d.ts +29 -0
  35. package/dist/react/use-gateway-fetch.d.ts.map +1 -0
  36. package/dist/react/use-gateway-fetch.js +47 -0
  37. package/dist/react/use-gateway-fetch.js.map +1 -0
  38. package/dist/react/use-gateway-mutation.d.ts +32 -0
  39. package/dist/react/use-gateway-mutation.d.ts.map +1 -0
  40. package/dist/react/use-gateway-mutation.js +58 -0
  41. package/dist/react/use-gateway-mutation.js.map +1 -0
  42. package/dist/react/use-onboarding-guard.d.ts +91 -0
  43. package/dist/react/use-onboarding-guard.d.ts.map +1 -0
  44. package/dist/react/use-onboarding-guard.js +140 -0
  45. package/dist/react/use-onboarding-guard.js.map +1 -0
  46. package/dist/react/use-public-servant-guard.d.ts +70 -0
  47. package/dist/react/use-public-servant-guard.d.ts.map +1 -0
  48. package/dist/react/use-public-servant-guard.js +79 -0
  49. package/dist/react/use-public-servant-guard.js.map +1 -0
  50. package/dist/roles.d.ts +67 -0
  51. package/dist/roles.d.ts.map +1 -0
  52. package/dist/roles.js +93 -0
  53. package/dist/roles.js.map +1 -0
  54. package/dist/types.d.ts +131 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +28 -0
  57. package/dist/types.js.map +1 -0
  58. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,533 @@
1
+ # @ogcio/sag-client
2
+
3
+ Framework-agnostic TypeScript client for the **Secure API Gateway**. Handles authentication, health checks, and authenticated data fetching with built-in error handling for session expiry (401) and service unavailability (503).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @ogcio/sag-client
9
+ # or
10
+ npm install @ogcio/sag-client
11
+ ```
12
+
13
+ For React hooks, also install peer dependencies:
14
+
15
+ ```bash
16
+ pnpm add react swr
17
+ ```
18
+
19
+ ### Publishing
20
+
21
+ The package is published to npm as `@ogcio/sag-client` via [release-please](https://github.com/googleapis/release-please) and Azure DevOps Pipelines.
22
+
23
+ **How it works:**
24
+
25
+ 1. Use [Conventional Commits](https://www.conventionalcommits.org/) when committing changes to `packages/sag-client/`:
26
+ - `feat: ...` — bumps a minor version
27
+ - `fix: ...` — bumps a patch version
28
+ - `feat!: ...` or `BREAKING CHANGE:` — bumps a major version (once past v1)
29
+ 2. When changes are merged to `main`, the pipeline runs release-please, which opens (or updates) a release PR that bumps the version in `package.json`, updates `CHANGELOG.md`, and updates `.release-please-manifest.json`
30
+ 3. When the release PR is merged, release-please creates a GitHub release and tag, and the pipeline publishes the package to npm
31
+
32
+ **Configuration files (repo root):**
33
+ - `release-please-config.json` — release-please package configuration
34
+ - `.release-please-manifest.json` — current version tracking
35
+ - `.azure/pipeline-sag-client.yaml` — Azure DevOps pipeline (CI + release)
36
+
37
+ ## Entry Points
38
+
39
+ | Import path | Description | Dependencies |
40
+ |---|---|---|
41
+ | `@ogcio/sag-client` | Framework-agnostic core (SagClient class, auth functions, fetcher) | None (built-in `fetch`) |
42
+ | `@ogcio/sag-client/react` | React hooks and provider | `react` >= 19, `swr` >= 2 (peer deps) |
43
+
44
+ ## Core API (`@ogcio/sag-client`)
45
+
46
+ ### SagClient class
47
+
48
+ ```typescript
49
+ import { SagClient } from "@ogcio/sag-client"
50
+
51
+ const client = new SagClient({
52
+ gatewayUrl: "http://localhost:3333",
53
+ appName: "cars",
54
+ // Optional: custom handler for session expiry (default: redirect to sign-in)
55
+ onSessionExpired: () => console.log("Session expired"),
56
+ })
57
+
58
+ // Auth
59
+ const status = await client.checkAuth() // { authenticated, user, app, claims }
60
+ const health = await client.checkHealth() // { available: boolean }
61
+ client.signIn() // POST-redirect to sign-in
62
+ client.signIn({ connector: "social:mygovid" }) // Direct sign-in via social connector
63
+ client.signIn({ redirectUrl: "/dashboard" }) // Explicit post-login redirect
64
+ client.signOut() // POST-redirect to sign-out
65
+ await client.invalidateSession() // Clear server session (e.g. after onboarding)
66
+
67
+ // Organizations
68
+ const orgs = await client.fetchOrganizations() // [{ id, name, description?, roles }]
69
+ await client.selectOrganization("org_xxx") // Set current org (signed cookie)
70
+ const orgId = await client.getSelectedOrganization() // Get current org ID or null
71
+ await client.clearSelectedOrganization() // Clear org selection
72
+
73
+ // Fetching
74
+ const { data } = await client.fetch<Car[]>("/cars")
75
+ const { data: orgData } = await client.fetch<Car[]>("/cars", { organizationId: "org_xxx" })
76
+
77
+ // Or create a reusable fetcher (for SWR, TanStack Query, etc.)
78
+ const fetcher = client.createFetcher<Car[]>()
79
+ const result = await fetcher("http://localhost:3333/cars")
80
+ ```
81
+
82
+ ### Standalone functions
83
+
84
+ For one-off calls without creating a client instance:
85
+
86
+ ```typescript
87
+ import {
88
+ checkAuth, checkHealth, signIn, signOut, invalidateSession,
89
+ fetchOrganizations, selectOrganization, getSelectedOrganization, clearSelectedOrganization,
90
+ createGatewayFetcher,
91
+ } from "@ogcio/sag-client"
92
+
93
+ const status = await checkAuth("http://localhost:3333")
94
+ const health = await checkHealth("http://localhost:3333")
95
+ signIn("http://localhost:3333", "cars")
96
+ signIn("http://localhost:3333", "cars", { connector: "social:mygovid" })
97
+ signOut("http://localhost:3333", "cars")
98
+ await invalidateSession("http://localhost:3333")
99
+
100
+ // Organization management
101
+ const orgs = await fetchOrganizations("http://localhost:3333")
102
+ await selectOrganization("http://localhost:3333", "org_xxx")
103
+ const orgId = await getSelectedOrganization("http://localhost:3333")
104
+ await clearSelectedOrganization("http://localhost:3333")
105
+ ```
106
+
107
+ ### Error handling
108
+
109
+ The fetcher throws `SagFetchError` with `status` and `code` properties:
110
+
111
+ ```typescript
112
+ import { SagFetchError } from "@ogcio/sag-client"
113
+
114
+ try {
115
+ await client.fetch("/cars")
116
+ } catch (err) {
117
+ if (err instanceof SagFetchError) {
118
+ console.log(err.status) // 401, 503, etc.
119
+ console.log(err.code) // "SESSION_EXPIRED", "LOGTO_UNAVAILABLE", etc.
120
+ console.log(err.message) // User-friendly message from the gateway
121
+ }
122
+ }
123
+ ```
124
+
125
+ ### M2M (Machine-to-Machine) requests
126
+
127
+ When the gateway service is configured for M2M, you can request that the gateway uses `client_credentials` instead of the user's session token by passing `actorType: "m2m"`:
128
+
129
+ ```typescript
130
+ // Fetch with M2M token via SagClient
131
+ const { data } = await client.fetch<Notification[]>("/notifications", {
132
+ actorType: "m2m",
133
+ })
134
+
135
+ // Or via the standalone fetcher factory
136
+ const fetcher = createGatewayFetcher("http://localhost:3333", "cars", undefined, {
137
+ actorType: "m2m",
138
+ })
139
+ ```
140
+
141
+ This sends the `X-Request-Actor-Type: m2m` header. The user must still be authenticated (M2M is not anonymous). The header name is also available as a constant:
142
+
143
+ ```typescript
144
+ import { ACTOR_TYPE_HEADER } from "@ogcio/sag-client"
145
+ // ACTOR_TYPE_HEADER === "X-Request-Actor-Type"
146
+ ```
147
+
148
+ ### Organization-Scoped Requests
149
+
150
+ When the gateway has a selected organization (via cookie or explicit header), it uses `getOrganizationToken(orgId)` instead of the default `getAccessToken(resource)`. You can pass `organizationId` to any fetch call:
151
+
152
+ ```typescript
153
+ // Via SagClient
154
+ const { data } = await client.fetch<Message[]>("/messaging", {
155
+ organizationId: "org_xxx",
156
+ })
157
+
158
+ // Via standalone fetcher
159
+ const fetcher = createGatewayFetcher("http://localhost:3333", "messaging", undefined, {
160
+ organizationId: "org_xxx",
161
+ })
162
+ ```
163
+
164
+ This sends the `X-Organization-Id: org_xxx` header. The header name is available as a constant:
165
+
166
+ ```typescript
167
+ import { ORGANIZATION_ID_HEADER } from "@ogcio/sag-client"
168
+ // ORGANIZATION_ID_HEADER === "X-Organization-Id"
169
+ ```
170
+
171
+ ### Role Detection Utilities
172
+
173
+ Pure functions for determining citizen / public-servant / onboarding status from Logto ID-token claims:
174
+
175
+ ```typescript
176
+ import {
177
+ isCitizen,
178
+ isPublicServant,
179
+ isInactivePublicServant,
180
+ isCitizenOnboarded,
181
+ CONNECTOR_MYGOVID,
182
+ CONNECTOR_ENTRAID,
183
+ ALLOWED_SIGNIN_METHODS,
184
+ DEFAULT_PUBLIC_SERVANT_ROLES, // ["Organisation Admin", "Organisation Member"]
185
+ ORG_ROLE_ADMIN, // "Organisation Admin"
186
+ ORG_ROLE_MEMBER, // "Organisation Member"
187
+ } from "@ogcio/sag-client"
188
+
189
+ // After checking auth:
190
+ const status = await client.checkAuth()
191
+ if (status.authenticated) {
192
+ const { organization_roles, roles } = status.claims
193
+
194
+ // Use the platform defaults for citizen-facing apps:
195
+ const citizen = isCitizen(organization_roles, DEFAULT_PUBLIC_SERVANT_ROLES)
196
+ const publicServant = isPublicServant(organization_roles, DEFAULT_PUBLIC_SERVANT_ROLES)
197
+
198
+ // Or use custom roles for admin apps:
199
+ const isMessagingPS = isPublicServant(organization_roles, ["Messaging Public Servant"])
200
+
201
+ const inactive = isInactivePublicServant(organization_roles)
202
+ const onboarded = isCitizenOnboarded(roles)
203
+ }
204
+ ```
205
+
206
+ ### Onboarding Helpers
207
+
208
+ Build redirect URLs for the onboarding and wrong-login-method flows:
209
+
210
+ ```typescript
211
+ import { buildOnboardingRedirectUrl, buildWrongLoginMethodRedirect } from "@ogcio/sag-client"
212
+
213
+ // Redirect to onboarding (after invalidating the session)
214
+ const url = buildOnboardingRedirectUrl({
215
+ profileUrl: "https://profile.example.com",
216
+ currentPath: "/messages/123",
217
+ gatewayUrl: "http://localhost:3333",
218
+ appName: "messaging",
219
+ appBaseUrl: "https://messaging.example.com", // where the user lands after auth
220
+ connector: "social:mygovid", // optional
221
+ })
222
+ window.location.href = url
223
+
224
+ // Redirect to wrong-login-method error page
225
+ const errorUrl = buildWrongLoginMethodRedirect({
226
+ profileUrl: "https://profile.example.com",
227
+ currentUrl: "https://messaging.example.com/messages/123",
228
+ })
229
+ ```
230
+
231
+ ### Onboarding Flow (End-to-End)
232
+
233
+ For citizen-facing **React** applications, the recommended approach is the `useOnboardingGuard` hook (see the [React API](#react-api-ogciosag-clientreact) section below). It encapsulates all role checks, session invalidation, redirect URL construction, and infinite-loop prevention in a single call.
234
+
235
+ For **non-React** or server-side consumers, you can implement the same logic manually with the standalone helpers:
236
+
237
+ ```typescript
238
+ import {
239
+ ALLOWED_SIGNIN_METHODS,
240
+ CONNECTOR_MYGOVID,
241
+ buildOnboardingRedirectUrl,
242
+ buildWrongLoginMethodRedirect,
243
+ isCitizen,
244
+ isCitizenOnboarded,
245
+ } from "@ogcio/sag-client"
246
+
247
+ // After checking auth (e.g. in a page guard):
248
+ const status = await client.checkAuth()
249
+ if (!status.authenticated) return
250
+
251
+ const { roles, organization_roles } = status.claims
252
+
253
+ // 1. Wrong sign-in method → redirect to error page
254
+ const signinMethod = status.claims.signinMethod // if available
255
+ if (signinMethod && !ALLOWED_SIGNIN_METHODS.includes(signinMethod)) {
256
+ window.location.href = buildWrongLoginMethodRedirect({
257
+ profileUrl: PROFILE_URL,
258
+ currentUrl: window.location.href,
259
+ })
260
+ return
261
+ }
262
+
263
+ // 2. Not a citizen → skip (or redirect to admin app)
264
+ if (!isCitizen(organization_roles, PUBLIC_SERVANT_ROLES)) {
265
+ return
266
+ }
267
+
268
+ // 3. Citizen but not onboarded → invalidate session and redirect
269
+ if (!isCitizenOnboarded(roles)) {
270
+ await client.invalidateSession()
271
+ window.location.href = buildOnboardingRedirectUrl({
272
+ profileUrl: PROFILE_URL,
273
+ currentPath: window.location.pathname,
274
+ gatewayUrl: GATEWAY_URL,
275
+ appName: APP_NAME,
276
+ appBaseUrl: APP_BASE_URL, // e.g. "http://localhost:3000"
277
+ connector: CONNECTOR_MYGOVID,
278
+ })
279
+ return
280
+ }
281
+
282
+ // 4. Citizen is onboarded → proceed normally
283
+ ```
284
+
285
+ The redirect chain is:
286
+
287
+ ```
288
+ app → profile-service/onboarding?source=<gateway-sign-in-url>
289
+ → (user completes onboarding, gains "Onboarded citizen" role)
290
+ → GET gateway/auth/sign-in?app=<name>&redirectUrl=<app-url>&connector=social:mygovid
291
+ → Logto OIDC flow (fresh claims)
292
+ → gateway/auth/callback
293
+ → app (original page, now with updated roles)
294
+ ```
295
+
296
+ > **Note:** `appBaseUrl` is the consuming application's URL (e.g. `http://localhost:3000`), not the gateway URL. This ensures the user lands back on the correct app page after the post-onboarding sign-in completes.
297
+
298
+ ### Types
299
+
300
+ ```typescript
301
+ import type {
302
+ ActorType, // "user" | "m2m"
303
+ AuthClaims, // { roles, organizations, organization_roles, signinMethod? }
304
+ AuthStatus,
305
+ AuthUser,
306
+ GatewayFetchOptions, // { actorType?, organizationId? }
307
+ OrganizationInfo, // { id, name, description?, roles }
308
+ SagClientConfig,
309
+ SignInOptions, // { connector?, redirectUrl? }
310
+ UseAuthResult,
311
+ UseOnboardingGuardOptions,
312
+ UseOnboardingGuardResult,
313
+ UsePublicServantGuardOptions,
314
+ UsePublicServantGuardResult,
315
+ OnboardingRedirectParams,
316
+ WrongLoginMethodParams,
317
+ } from "@ogcio/sag-client"
318
+ ```
319
+
320
+ ## React API (`@ogcio/sag-client/react`)
321
+
322
+ ### Provider
323
+
324
+ Wrap your app with `SagClientProvider`:
325
+
326
+ ```tsx
327
+ import { SagClientProvider } from "@ogcio/sag-client/react"
328
+
329
+ export function Providers({ children }) {
330
+ return (
331
+ <SagClientProvider gatewayUrl="http://localhost:3333" appName="cars">
332
+ {children}
333
+ </SagClientProvider>
334
+ )
335
+ }
336
+ ```
337
+
338
+ ### Hooks
339
+
340
+ #### `useAuth`
341
+
342
+ ```tsx
343
+ import {
344
+ useAuth,
345
+ useSagClient,
346
+ CONNECTOR_MYGOVID,
347
+ } from "@ogcio/sag-client/react"
348
+
349
+ function MyComponent() {
350
+ const {
351
+ authenticated,
352
+ user,
353
+ claims, // { roles, organizations, organization_roles, signinMethod? }
354
+ loading,
355
+ logtoAvailable,
356
+ signIn, // accepts optional SignInOptions
357
+ signOut,
358
+ invalidateSession,
359
+ refresh,
360
+ } = useAuth()
361
+
362
+ // Sign in with a specific connector
363
+ const handleCitizenSignIn = () => signIn({ connector: CONNECTOR_MYGOVID })
364
+
365
+ // Direct client access (advanced)
366
+ const client = useSagClient()
367
+ }
368
+ ```
369
+
370
+ #### `useGatewayFetch`
371
+
372
+ ```tsx
373
+ import { useGatewayFetch } from "@ogcio/sag-client/react"
374
+
375
+ // SWR-based data fetching
376
+ const { data, error, isLoading, refresh } = useGatewayFetch<Car[]>("/cars")
377
+
378
+ // Conditional fetching
379
+ const { data: detail } = useGatewayFetch<Car>(`/cars/${id}`, { enabled: !!id })
380
+
381
+ // M2M fetching (sends X-Request-Actor-Type: m2m header)
382
+ const { data: notifications } = useGatewayFetch<Notification[]>("/notifications", {
383
+ actorType: "m2m",
384
+ })
385
+ ```
386
+
387
+ #### `useOnboardingGuard`
388
+
389
+ Encapsulates the full citizen onboarding check for React applications. Must be used inside a `SagClientProvider`. Reads `gatewayUrl` and `appName` from the provider context automatically.
390
+
391
+ ```tsx
392
+ import {
393
+ useOnboardingGuard,
394
+ useAuth,
395
+ CONNECTOR_MYGOVID,
396
+ } from "@ogcio/sag-client/react"
397
+
398
+ function ShellContent({ children }) {
399
+ // publicServantRoles defaults to DEFAULT_PUBLIC_SERVANT_ROLES
400
+ // (["Organisation Admin", "Organisation Member"])
401
+ const { resolved } = useOnboardingGuard({
402
+ profileUrl: "http://localhost:3001",
403
+ appBaseUrl: "http://localhost:3000",
404
+ connector: CONNECTOR_MYGOVID, // optional
405
+ // publicServantRoles: ["Custom Role"], // override for admin apps
406
+ // debounceMs: 30_000, // optional, default: 30000
407
+ })
408
+
409
+ const { user, signIn, signOut } = useAuth()
410
+
411
+ if (!resolved) return <Loading />
412
+
413
+ return user ? <App>{children}</App> : <SignInButton />
414
+ }
415
+ ```
416
+
417
+ **Options:**
418
+
419
+ | Option | Type | Required | Default | Description |
420
+ |--------|------|----------|---------|-------------|
421
+ | `profileUrl` | `string` | Yes | - | Profile service base URL |
422
+ | `appBaseUrl` | `string` | Yes | - | Consuming application's base URL (for post-auth redirect) |
423
+ | `publicServantRoles` | `string[]` | No | `DEFAULT_PUBLIC_SERVANT_ROLES` | Organisation roles that identify a public servant |
424
+ | `connector` | `string` | No | `undefined` | Logto `directSignIn` connector (e.g. `"social:mygovid"`) |
425
+ | `debounceMs` | `number` | No | `30000` | Time window (ms) to prevent redirect loops |
426
+
427
+ **Return value:**
428
+
429
+ | Property | Type | Description |
430
+ |----------|------|-------------|
431
+ | `resolved` | `boolean` | `true` when the onboarding check has passed; `false` while loading or redirecting |
432
+
433
+ **Behaviour:**
434
+
435
+ 1. User is onboarded (`isCitizenOnboarded`) → `resolved = true`
436
+ 2. User is not a citizen → `resolved = true` (let them through)
437
+ 3. Recent redirect within `debounceMs` → `resolved = true` (prevent loops)
438
+ 4. Wrong sign-in method → redirect to profile service error page
439
+ 5. Citizen not onboarded → `invalidateSession()` then redirect to profile service onboarding page
440
+
441
+ > **Important:** Do not render data-fetching children (e.g. `useGatewayFetch`) until `resolved` is `true` to prevent API requests from racing with session invalidation.
442
+
443
+ #### `usePublicServantGuard`
444
+
445
+ Access guard hook for **public-servant-facing** (admin) applications. Checks if the authenticated user is an active public servant and optionally redirects unauthorized users.
446
+
447
+ ```tsx
448
+ import { usePublicServantGuard, useAuth } from "@ogcio/sag-client/react"
449
+
450
+ function AdminShell({ children }) {
451
+ const { resolved, authorized, isInactive } = usePublicServantGuard({
452
+ // Redirect citizens to the citizen-facing app (optional)
453
+ unauthorizedRedirectUrl: "https://citizen-app.example.com",
454
+ // Redirect inactive PS to a specific page (optional)
455
+ inactiveRedirectUrl: "https://admin.example.com/inactive",
456
+ // publicServantRoles: ["Custom Admin Role"], // override defaults
457
+ })
458
+
459
+ const { user } = useAuth()
460
+
461
+ if (!resolved) return <Loading />
462
+ if (!authorized) return <AccessDenied />
463
+ return <>{children}</>
464
+ }
465
+ ```
466
+
467
+ **Options:**
468
+
469
+ | Option | Type | Required | Default | Description |
470
+ |--------|------|----------|---------|-------------|
471
+ | `publicServantRoles` | `string[]` | No | `DEFAULT_PUBLIC_SERVANT_ROLES` | Organisation roles that identify an active public servant |
472
+ | `inactiveRedirectUrl` | `string` | No | `undefined` | URL to redirect inactive PS users to. If omitted, they pass through with `isInactive: true`. |
473
+ | `unauthorizedRedirectUrl` | `string` | No | `undefined` | URL to redirect non-PS users to. If omitted, they pass through with `authorized: false`. |
474
+
475
+ **Return value:**
476
+
477
+ | Property | Type | Description |
478
+ |----------|------|-------------|
479
+ | `resolved` | `boolean` | `true` once the guard check has completed |
480
+ | `authorized` | `boolean` | `true` when the user is an active public servant |
481
+ | `isInactive` | `boolean` | `true` when the user is an inactive public servant |
482
+
483
+ #### `useGatewayFetch` with organization scope
484
+
485
+ ```tsx
486
+ import { useGatewayFetch } from "@ogcio/sag-client/react"
487
+
488
+ // Fetch with an organization-scoped token
489
+ const { data } = useGatewayFetch<Message[]>("/messaging", {
490
+ organizationId: "org_xxx",
491
+ })
492
+ ```
493
+
494
+ #### Role detection utilities
495
+
496
+ Role detection functions are also re-exported from the React entry point for convenience:
497
+
498
+ ```tsx
499
+ import {
500
+ isCitizen,
501
+ isCitizenOnboarded,
502
+ isPublicServant,
503
+ CONNECTOR_MYGOVID,
504
+ ALLOWED_SIGNIN_METHODS,
505
+ DEFAULT_PUBLIC_SERVANT_ROLES,
506
+ ORG_ROLE_ADMIN,
507
+ ORG_ROLE_MEMBER,
508
+ ONBOARDING_PATH,
509
+ ONBOARDING_SOURCE_PARAM,
510
+ WRONG_LOGIN_METHOD_PATH,
511
+ WRONG_LOGIN_RETURN_URL_PARAM,
512
+ } from "@ogcio/sag-client/react"
513
+ ```
514
+
515
+ ## Package Structure
516
+
517
+ ```
518
+ src/
519
+ index.ts # Core entry point
520
+ client.ts # SagClient class
521
+ auth.ts # Standalone auth functions (signIn, signOut, invalidateSession, etc.)
522
+ fetcher.ts # Gateway fetcher factory
523
+ roles.ts # Role detection utilities (isCitizen, isPublicServant, etc.)
524
+ onboarding.ts # Onboarding & wrong-login-method URL builders
525
+ types.ts # All type definitions
526
+ react/
527
+ index.ts # React entry point (re-exports roles & onboarding for convenience)
528
+ provider.tsx # SagClientProvider + useSagClient
529
+ use-auth.ts # useAuth hook (with claims, connector-aware signIn, invalidateSession)
530
+ use-gateway-fetch.ts # useGatewayFetch hook
531
+ use-onboarding-guard.ts # useOnboardingGuard hook (citizen onboarding guard)
532
+ use-public-servant-guard.ts # usePublicServantGuard hook (admin app access guard)
533
+ ```
package/dist/auth.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Standalone authentication helpers for the Secure API Gateway.
3
+ *
4
+ * These are pure functions — no React, no framework dependency.
5
+ * They accept `gatewayUrl` (and optionally `appName`) so they
6
+ * can be called without a SagClient instance.
7
+ */
8
+ import type { AuthStatus, OrganizationInfo, SignInOptions } from "./types";
9
+ /**
10
+ * Check if the user is authenticated against the gateway.
11
+ */
12
+ export declare function checkAuth(gatewayUrl: string): Promise<AuthStatus>;
13
+ /**
14
+ * Check if the authentication service (Logto) is reachable.
15
+ */
16
+ export declare function checkHealth(gatewayUrl: string): Promise<{
17
+ available: boolean;
18
+ }>;
19
+ /**
20
+ * Invalidate the current server session so the next sign-in
21
+ * fetches fresh claims. Used after onboarding completes (the user
22
+ * gains new roles that must appear in the next ID token).
23
+ */
24
+ export declare function invalidateSession(gatewayUrl: string): Promise<void>;
25
+ /**
26
+ * Fetch structured organization data for the authenticated user.
27
+ * Requires an active session. Returns an empty array if not authenticated.
28
+ */
29
+ export declare function fetchOrganizations(gatewayUrl: string): Promise<OrganizationInfo[]>;
30
+ /**
31
+ * Set the user's currently selected organization on the gateway.
32
+ * Persists as a signed cookie.
33
+ */
34
+ export declare function selectOrganization(gatewayUrl: string, organizationId: string): Promise<boolean>;
35
+ /**
36
+ * Get the user's currently selected organization from the gateway.
37
+ */
38
+ export declare function getSelectedOrganization(gatewayUrl: string): Promise<string | null>;
39
+ /**
40
+ * Clear the user's organization selection on the gateway.
41
+ */
42
+ export declare function clearSelectedOrganization(gatewayUrl: string): Promise<boolean>;
43
+ /**
44
+ * Redirect the user to the gateway sign-in endpoint.
45
+ *
46
+ * @param gatewayUrl - Secure API Gateway base URL.
47
+ * @param app - Application name registered in the gateway.
48
+ * @param options - Optional sign-in options (connector, redirectUrl).
49
+ */
50
+ export declare function signIn(gatewayUrl: string, app: string, options?: SignInOptions): void;
51
+ /**
52
+ * Redirect the user to the gateway sign-out endpoint.
53
+ */
54
+ export declare function signOut(gatewayUrl: string, app: string): void;
55
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE1E;;GAEG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAUvE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAUjC;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAW7B;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAYlB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWxB;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAiBD;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,aAAa,GACtB,IAAI,CAKN;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAE7D"}