@hanzo/iam 0.1.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/dist/client.js ADDED
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Core HTTP client for Hanzo IAM (Casdoor) API.
3
+ */
4
+ const DEFAULT_TIMEOUT_MS = 10_000;
5
+ export class IamClient {
6
+ baseUrl;
7
+ clientId;
8
+ clientSecret;
9
+ orgName;
10
+ appName;
11
+ discoveryCache = null;
12
+ constructor(config) {
13
+ this.baseUrl = config.serverUrl.replace(/\/+$/, "");
14
+ this.clientId = config.clientId;
15
+ this.clientSecret = config.clientSecret;
16
+ this.orgName = config.orgName;
17
+ this.appName = config.appName;
18
+ }
19
+ // -----------------------------------------------------------------------
20
+ // Internal HTTP helpers
21
+ // -----------------------------------------------------------------------
22
+ async request(path, opts) {
23
+ const url = new URL(path, this.baseUrl);
24
+ if (opts?.params) {
25
+ for (const [k, v] of Object.entries(opts.params)) {
26
+ url.searchParams.set(k, v);
27
+ }
28
+ }
29
+ const controller = new AbortController();
30
+ const timer = setTimeout(() => controller.abort(), opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS);
31
+ const headers = {
32
+ Accept: "application/json",
33
+ };
34
+ if (opts?.token) {
35
+ headers.Authorization = `Bearer ${opts.token}`;
36
+ }
37
+ if (opts?.body) {
38
+ headers["Content-Type"] = "application/json";
39
+ }
40
+ // Server-side basic auth for confidential client operations
41
+ if (this.clientSecret && !opts?.token) {
42
+ const credentials = `${this.clientId}:${this.clientSecret}`;
43
+ const basic = typeof Buffer !== "undefined"
44
+ ? Buffer.from(credentials).toString("base64")
45
+ : btoa(credentials);
46
+ headers.Authorization = `Basic ${basic}`;
47
+ }
48
+ try {
49
+ const res = await fetch(url.toString(), {
50
+ method: opts?.method ?? "GET",
51
+ headers,
52
+ body: opts?.body ? JSON.stringify(opts.body) : undefined,
53
+ signal: controller.signal,
54
+ });
55
+ if (!res.ok) {
56
+ const text = await res.text().catch(() => "");
57
+ throw new IamApiError(res.status, `${res.statusText}: ${text}`.trim());
58
+ }
59
+ return (await res.json());
60
+ }
61
+ finally {
62
+ clearTimeout(timer);
63
+ }
64
+ }
65
+ // -----------------------------------------------------------------------
66
+ // OIDC Discovery
67
+ // -----------------------------------------------------------------------
68
+ async getDiscovery() {
69
+ const CACHE_TTL_MS = 5 * 60 * 1000;
70
+ if (this.discoveryCache && Date.now() - this.discoveryCache.fetchedAt < CACHE_TTL_MS) {
71
+ return this.discoveryCache.data;
72
+ }
73
+ const data = await this.request("/.well-known/openid-configuration");
74
+ this.discoveryCache = { data, fetchedAt: Date.now() };
75
+ return data;
76
+ }
77
+ /** Get JWKS URI from OIDC discovery (cached). */
78
+ async getJwksUri() {
79
+ const discovery = await this.getDiscovery();
80
+ return discovery.jwks_uri;
81
+ }
82
+ // -----------------------------------------------------------------------
83
+ // OAuth2 / Token
84
+ // -----------------------------------------------------------------------
85
+ /** Build the authorization URL for user login redirect. */
86
+ async getAuthorizationUrl(params) {
87
+ const discovery = await this.getDiscovery();
88
+ const url = new URL(discovery.authorization_endpoint);
89
+ url.searchParams.set("client_id", this.clientId);
90
+ url.searchParams.set("response_type", "code");
91
+ url.searchParams.set("redirect_uri", params.redirectUri);
92
+ url.searchParams.set("state", params.state);
93
+ url.searchParams.set("scope", params.scope ?? "openid profile email");
94
+ if (params.codeChallenge) {
95
+ url.searchParams.set("code_challenge", params.codeChallenge);
96
+ url.searchParams.set("code_challenge_method", params.codeChallengeMethod ?? "S256");
97
+ }
98
+ return url.toString();
99
+ }
100
+ /** Exchange authorization code for tokens. */
101
+ async exchangeCode(params) {
102
+ const discovery = await this.getDiscovery();
103
+ const body = new URLSearchParams({
104
+ grant_type: "authorization_code",
105
+ client_id: this.clientId,
106
+ code: params.code,
107
+ redirect_uri: params.redirectUri,
108
+ });
109
+ if (this.clientSecret) {
110
+ body.set("client_secret", this.clientSecret);
111
+ }
112
+ if (params.codeVerifier) {
113
+ body.set("code_verifier", params.codeVerifier);
114
+ }
115
+ const controller = new AbortController();
116
+ const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
117
+ try {
118
+ const res = await fetch(discovery.token_endpoint, {
119
+ method: "POST",
120
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
121
+ body: body.toString(),
122
+ signal: controller.signal,
123
+ });
124
+ if (!res.ok) {
125
+ const text = await res.text().catch(() => "");
126
+ throw new IamApiError(res.status, `Token exchange failed: ${text}`);
127
+ }
128
+ return (await res.json());
129
+ }
130
+ finally {
131
+ clearTimeout(timer);
132
+ }
133
+ }
134
+ /** Refresh an access token. */
135
+ async refreshToken(refreshToken) {
136
+ const discovery = await this.getDiscovery();
137
+ const body = new URLSearchParams({
138
+ grant_type: "refresh_token",
139
+ client_id: this.clientId,
140
+ refresh_token: refreshToken,
141
+ });
142
+ if (this.clientSecret) {
143
+ body.set("client_secret", this.clientSecret);
144
+ }
145
+ const controller = new AbortController();
146
+ const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
147
+ try {
148
+ const res = await fetch(discovery.token_endpoint, {
149
+ method: "POST",
150
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
151
+ body: body.toString(),
152
+ signal: controller.signal,
153
+ });
154
+ if (!res.ok) {
155
+ const text = await res.text().catch(() => "");
156
+ throw new IamApiError(res.status, `Token refresh failed: ${text}`);
157
+ }
158
+ return (await res.json());
159
+ }
160
+ finally {
161
+ clearTimeout(timer);
162
+ }
163
+ }
164
+ // -----------------------------------------------------------------------
165
+ // User
166
+ // -----------------------------------------------------------------------
167
+ /** Get user info from access token (OIDC userinfo endpoint). */
168
+ async getUserInfo(accessToken) {
169
+ const discovery = await this.getDiscovery();
170
+ const controller = new AbortController();
171
+ const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
172
+ try {
173
+ const res = await fetch(discovery.userinfo_endpoint, {
174
+ headers: { Authorization: `Bearer ${accessToken}` },
175
+ signal: controller.signal,
176
+ });
177
+ if (!res.ok) {
178
+ throw new IamApiError(res.status, "Failed to fetch userinfo");
179
+ }
180
+ return (await res.json());
181
+ }
182
+ finally {
183
+ clearTimeout(timer);
184
+ }
185
+ }
186
+ /** Get a user by ID ("org/username" format). */
187
+ async getUser(userId, token) {
188
+ const resp = await this.request("/api/get-user", {
189
+ params: { id: userId },
190
+ token,
191
+ });
192
+ return resp.data ?? null;
193
+ }
194
+ // -----------------------------------------------------------------------
195
+ // Organization
196
+ // -----------------------------------------------------------------------
197
+ /** List organizations (for the configured owner). */
198
+ async getOrganizations(token) {
199
+ const owner = this.orgName ?? "admin";
200
+ const resp = await this.request("/api/get-organizations", { params: { owner }, token });
201
+ return resp.data ?? [];
202
+ }
203
+ /** Get a specific organization. */
204
+ async getOrganization(id, token) {
205
+ const resp = await this.request("/api/get-organization", { params: { id }, token });
206
+ return resp.data ?? null;
207
+ }
208
+ /** Get organizations a user belongs to. */
209
+ async getUserOrganizations(userId, token) {
210
+ // Casdoor returns orgs the user is a member of via the user's properties.
211
+ // We can also query via get-user and read their signupApplication/org.
212
+ const user = await this.getUser(userId, token);
213
+ if (!user)
214
+ return [];
215
+ // The owner field on a user is their org
216
+ const org = await this.getOrganization(`admin/${user.owner}`, token);
217
+ return org ? [org] : [];
218
+ }
219
+ // -----------------------------------------------------------------------
220
+ // Raw request (for extending)
221
+ // -----------------------------------------------------------------------
222
+ /** Make an arbitrary authenticated request to the IAM API. */
223
+ async apiRequest(path, opts) {
224
+ return this.request(path, opts);
225
+ }
226
+ }
227
+ // ---------------------------------------------------------------------------
228
+ // Error
229
+ // ---------------------------------------------------------------------------
230
+ export class IamApiError extends Error {
231
+ status;
232
+ constructor(status, message) {
233
+ super(message);
234
+ this.name = "IamApiError";
235
+ this.status = status;
236
+ }
237
+ }
238
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @hanzo/iam — TypeScript SDK for Hanzo IAM (Casdoor-based identity & access management).
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { IamClient, IamBillingClient, validateToken } from "@hanzo/iam";
7
+ *
8
+ * const client = new IamClient({
9
+ * serverUrl: "https://iam.hanzo.ai",
10
+ * clientId: "my-app",
11
+ * });
12
+ *
13
+ * // Validate a JWT
14
+ * const result = await validateToken(accessToken, {
15
+ * serverUrl: "https://iam.hanzo.ai",
16
+ * clientId: "my-app",
17
+ * });
18
+ * ```
19
+ */
20
+ export { IamClient, IamApiError } from "./client.js";
21
+ export { validateToken, clearJwksCache } from "./auth.js";
22
+ export { IamBillingClient } from "./billing.js";
23
+ export { BrowserIamSdk, type BrowserIamConfig } from "./browser.js";
24
+ export { generatePkceChallenge, generateState } from "./pkce.js";
25
+ export type { IamConfig, OidcDiscovery, TokenResponse, IamJwtClaims, IamUser, IamOrganization, IamSubscription, IamPlan, IamPricing, IamPayment, IamOrder, IamAuthResult, IamApiResponse, } from "./types.js";
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAMjE,YAAY,EACV,SAAS,EACT,aAAa,EACb,aAAa,EACb,YAAY,EACZ,OAAO,EACP,eAAe,EACf,eAAe,EACf,OAAO,EACP,UAAU,EACV,UAAU,EACV,QAAQ,EACR,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @hanzo/iam — TypeScript SDK for Hanzo IAM (Casdoor-based identity & access management).
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { IamClient, IamBillingClient, validateToken } from "@hanzo/iam";
7
+ *
8
+ * const client = new IamClient({
9
+ * serverUrl: "https://iam.hanzo.ai",
10
+ * clientId: "my-app",
11
+ * });
12
+ *
13
+ * // Validate a JWT
14
+ * const result = await validateToken(accessToken, {
15
+ * serverUrl: "https://iam.hanzo.ai",
16
+ * clientId: "my-app",
17
+ * });
18
+ * ```
19
+ */
20
+ // Core client
21
+ export { IamClient, IamApiError } from "./client.js";
22
+ // JWT validation
23
+ export { validateToken, clearJwksCache } from "./auth.js";
24
+ // Billing client
25
+ export { IamBillingClient } from "./billing.js";
26
+ // Browser PKCE auth (re-exported from separate entry point too)
27
+ export { BrowserIamSdk } from "./browser.js";
28
+ export { generatePkceChallenge, generateState } from "./pkce.js";
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc;AACd,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAErD,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE1D,iBAAiB;AACjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,gEAAgE;AAChE,OAAO,EAAE,aAAa,EAAyB,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
package/dist/pkce.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities for browser-side OAuth2 flows.
3
+ *
4
+ * Adapted from casdoor-js-sdk, modernized for native Web Crypto API.
5
+ */
6
+ /** Generate a PKCE code verifier + challenge pair. */
7
+ export declare function generatePkceChallenge(): Promise<{
8
+ codeVerifier: string;
9
+ codeChallenge: string;
10
+ }>;
11
+ /** Generate a random state parameter for CSRF protection. */
12
+ export declare function generateState(): string;
13
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwBH,sDAAsD;AACtD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAKD;AAED,6DAA6D;AAC7D,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
package/dist/pkce.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities for browser-side OAuth2 flows.
3
+ *
4
+ * Adapted from casdoor-js-sdk, modernized for native Web Crypto API.
5
+ */
6
+ function generateRandomString(length) {
7
+ const array = new Uint8Array(length);
8
+ crypto.getRandomValues(array);
9
+ return Array.from(array, (b) => b.toString(36).padStart(2, "0"))
10
+ .join("")
11
+ .slice(0, length);
12
+ }
13
+ async function sha256(plain) {
14
+ const encoder = new TextEncoder();
15
+ return crypto.subtle.digest("SHA-256", encoder.encode(plain));
16
+ }
17
+ function base64UrlEncode(buffer) {
18
+ const bytes = new Uint8Array(buffer);
19
+ let binary = "";
20
+ for (const byte of bytes) {
21
+ binary += String.fromCharCode(byte);
22
+ }
23
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
24
+ }
25
+ /** Generate a PKCE code verifier + challenge pair. */
26
+ export async function generatePkceChallenge() {
27
+ const codeVerifier = generateRandomString(64);
28
+ const hash = await sha256(codeVerifier);
29
+ const codeChallenge = base64UrlEncode(hash);
30
+ return { codeVerifier, codeChallenge };
31
+ }
32
+ /** Generate a random state parameter for CSRF protection. */
33
+ export function generateState() {
34
+ return generateRandomString(32);
35
+ }
36
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,SAAS,oBAAoB,CAAC,MAAc;IAC1C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC7D,IAAI,CAAC,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,KAAa;IACjC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,eAAe,CAAC,MAAmB;IAC1C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,qBAAqB;IAIzC,MAAM,YAAY,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC5C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AACzC,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,aAAa;IAC3B,OAAO,oBAAoB,CAAC,EAAE,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * React bindings for @hanzo/iam.
3
+ *
4
+ * Provides a context provider, auth hooks, and org/project switching
5
+ * that can be dropped into any React application.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { IamProvider, useIam, useOrganizations } from '@hanzo/iam/react'
10
+ *
11
+ * function App() {
12
+ * return (
13
+ * <IamProvider config={{
14
+ * serverUrl: 'https://iam.hanzo.ai',
15
+ * clientId: 'my-app',
16
+ * redirectUri: `${window.location.origin}/auth/callback`,
17
+ * }}>
18
+ * <MyApp />
19
+ * </IamProvider>
20
+ * )
21
+ * }
22
+ *
23
+ * function MyApp() {
24
+ * const { user, isAuthenticated, login, logout } = useIam()
25
+ * const { organizations, currentOrg, switchOrg } = useOrganizations()
26
+ *
27
+ * if (!isAuthenticated) return <button onClick={() => login()}>Log in</button>
28
+ * return <div>Welcome, {user?.displayName}</div>
29
+ * }
30
+ * ```
31
+ *
32
+ * @packageDocumentation
33
+ */
34
+ import type { ReactNode } from "react";
35
+ import { BrowserIamSdk } from "./browser.js";
36
+ import type { BrowserIamConfig } from "./browser.js";
37
+ import type { IamUser, IamOrganization, TokenResponse } from "./types.js";
38
+ export interface IamProviderProps {
39
+ /** Browser IAM SDK configuration. */
40
+ config: BrowserIamConfig;
41
+ /** Auto-initialize on mount (check stored tokens). Default: true. */
42
+ autoInit?: boolean;
43
+ /** Called when authentication state changes. */
44
+ onAuthChange?: (authenticated: boolean) => void;
45
+ children: ReactNode;
46
+ }
47
+ export interface IamContextValue {
48
+ /** The underlying BrowserIamSdk instance for advanced use. */
49
+ sdk: BrowserIamSdk;
50
+ /** The IAM configuration. */
51
+ config: BrowserIamConfig;
52
+ /** Authenticated user (null if not logged in). */
53
+ user: IamUser | null;
54
+ /** Whether the user is currently authenticated. */
55
+ isAuthenticated: boolean;
56
+ /** Whether initial auth check is in progress. */
57
+ isLoading: boolean;
58
+ /** Current access token (null if not authenticated). */
59
+ accessToken: string | null;
60
+ /** Redirect to IAM login page. */
61
+ login: (params?: {
62
+ additionalParams?: Record<string, string>;
63
+ }) => Promise<void>;
64
+ /** Open IAM login in a popup. */
65
+ loginPopup: (params?: {
66
+ width?: number;
67
+ height?: number;
68
+ }) => Promise<void>;
69
+ /** Handle OAuth callback — call on your /auth/callback route. */
70
+ handleCallback: (callbackUrl?: string) => Promise<TokenResponse>;
71
+ /** Log out and clear all tokens. */
72
+ logout: () => void;
73
+ /** Last auth error, if any. */
74
+ error: Error | null;
75
+ }
76
+ export interface OrgState {
77
+ /** All organizations the user belongs to. */
78
+ organizations: IamOrganization[];
79
+ /** Currently selected organization. */
80
+ currentOrg: IamOrganization | null;
81
+ /** Currently selected org ID. */
82
+ currentOrgId: string | null;
83
+ /** Switch to a different organization. */
84
+ switchOrg: (orgId: string) => void;
85
+ /** Currently selected project ID within the org. */
86
+ currentProjectId: string | null;
87
+ /** Switch to a different project (null to clear). */
88
+ switchProject: (projectId: string | null) => void;
89
+ /** Whether organizations are loading. */
90
+ isLoading: boolean;
91
+ }
92
+ declare const IamContext: import("react").Context<IamContextValue | null>;
93
+ /**
94
+ * Root provider for Hanzo IAM in React applications.
95
+ *
96
+ * Wrap your app (or a subtree) with this provider to enable IAM auth.
97
+ * Manages the BrowserIamSdk instance, token lifecycle, and auth state.
98
+ */
99
+ export declare function IamProvider(props: IamProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<IamContextValue | null>>;
100
+ /**
101
+ * Access Hanzo IAM auth state and methods.
102
+ * Must be used within an `<IamProvider>`.
103
+ */
104
+ export declare function useIam(): IamContextValue;
105
+ /**
106
+ * Manage organization and project switching.
107
+ *
108
+ * Fetches the user's organizations from IAM and provides
109
+ * `switchOrg` / `switchProject` to change the active tenant.
110
+ * Selection is persisted to localStorage.
111
+ */
112
+ export declare function useOrganizations(): OrgState;
113
+ /**
114
+ * Hook that provides a valid access token with auto-refresh capability.
115
+ * Returns null while loading or if not authenticated.
116
+ */
117
+ export declare function useIamToken(): {
118
+ token: string | null;
119
+ isValid: boolean;
120
+ refresh: () => Promise<string | null>;
121
+ };
122
+ export { IamContext };
123
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAYH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAM1E,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,MAAM,EAAE,gBAAgB,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,YAAY,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,GAAG,EAAE,aAAa,CAAC;IACnB,6BAA6B;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,kDAAkD;IAClD,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACrB,mDAAmD;IACnD,eAAe,EAAE,OAAO,CAAC;IACzB,iDAAiD;IACjD,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kCAAkC;IAClC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,iCAAiC;IACjC,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,iEAAiE;IACjE,cAAc,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACjE,oCAAoC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+BAA+B;IAC/B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,6CAA6C;IAC7C,aAAa,EAAE,eAAe,EAAE,CAAC;IACjC,uCAAuC;IACvC,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,iCAAiC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oDAAoD;IACpD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,qDAAqD;IACrD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;CACpB;AAMD,QAAA,MAAM,UAAU,iDAA8C,CAAC;AAY/D;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,mGAiNlD;AAMD;;;GAGG;AACH,wBAAgB,MAAM,IAAI,eAAe,CAMxC;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,CAqI3C;AAMD;;;GAGG;AACH,wBAAgB,WAAW,IAAI;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACvC,CAgBA;AAGD,OAAO,EAAE,UAAU,EAAE,CAAC"}