authmi 1.0.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/react.js ADDED
@@ -0,0 +1,812 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react.tsx
21
+ var react_exports = {};
22
+ __export(react_exports, {
23
+ AuthMiClient: () => AuthMiClient,
24
+ AuthMiError: () => AuthMiError,
25
+ AuthMiProvider: () => AuthMiProvider,
26
+ LocalStorageTokenStorage: () => LocalStorageTokenStorage,
27
+ LoginForm: () => LoginForm,
28
+ MemoryTokenStorage: () => MemoryTokenStorage,
29
+ Protected: () => Protected,
30
+ ScopeError: () => ScopeError,
31
+ useAuthActions: () => useAuthActions,
32
+ useAuthMi: () => useAuthMi,
33
+ useAuthMiClient: () => useAuthMiClient,
34
+ useIsAuthenticated: () => useIsAuthenticated,
35
+ useUser: () => useUser
36
+ });
37
+ module.exports = __toCommonJS(react_exports);
38
+ var import_react = require("react");
39
+
40
+ // src/types.ts
41
+ var AuthMiError = class extends Error {
42
+ constructor(message, code, statusCode) {
43
+ super(message);
44
+ this.code = code;
45
+ this.statusCode = statusCode;
46
+ this.name = "AuthMiError";
47
+ }
48
+ };
49
+ var ScopeError = class extends AuthMiError {
50
+ constructor(message, requiredScopes, providedScopes) {
51
+ super(message, "INSUFFICIENT_SCOPES", 403);
52
+ this.requiredScopes = requiredScopes;
53
+ this.providedScopes = providedScopes;
54
+ this.name = "ScopeError";
55
+ }
56
+ };
57
+ var _LocalStorageTokenStorage = class _LocalStorageTokenStorage {
58
+ getToken() {
59
+ if (typeof window === "undefined") return null;
60
+ return localStorage.getItem(_LocalStorageTokenStorage.KEY);
61
+ }
62
+ setToken(token) {
63
+ if (typeof window === "undefined") return;
64
+ localStorage.setItem(_LocalStorageTokenStorage.KEY, token);
65
+ }
66
+ removeToken() {
67
+ if (typeof window === "undefined") return;
68
+ localStorage.removeItem(_LocalStorageTokenStorage.KEY);
69
+ }
70
+ };
71
+ _LocalStorageTokenStorage.KEY = "authmi_token";
72
+ var LocalStorageTokenStorage = _LocalStorageTokenStorage;
73
+ var MemoryTokenStorage = class {
74
+ constructor() {
75
+ this.token = null;
76
+ }
77
+ getToken() {
78
+ return this.token;
79
+ }
80
+ setToken(token) {
81
+ this.token = token;
82
+ }
83
+ removeToken() {
84
+ this.token = null;
85
+ }
86
+ };
87
+
88
+ // src/client.ts
89
+ var AuthMiClient = class {
90
+ constructor(config, tokenStorage) {
91
+ this.config = {
92
+ apiKey: "",
93
+ serviceId: "",
94
+ clientId: "",
95
+ clientSecret: "",
96
+ defaultTokenExpiry: 24,
97
+ ...config
98
+ };
99
+ this.tokenStorage = tokenStorage || new LocalStorageTokenStorage();
100
+ }
101
+ /** Build Basic auth header from clientId:clientSecret */
102
+ basicAuthHeader() {
103
+ if (this.config.clientId && this.config.clientSecret) {
104
+ const encoded = btoa(`${this.config.clientId}:${this.config.clientSecret}`);
105
+ return `Basic ${encoded}`;
106
+ }
107
+ return null;
108
+ }
109
+ // ============ HTTP Utilities ============
110
+ async request(endpoint, options = {}, requireAuth = false) {
111
+ const url = `${this.config.baseUrl}${endpoint}`;
112
+ const headers = {
113
+ "Content-Type": "application/json",
114
+ ...options.headers || {}
115
+ };
116
+ const basic = this.basicAuthHeader();
117
+ if (basic && !requireAuth && !headers["Authorization"]) {
118
+ headers["Authorization"] = basic;
119
+ } else if (this.config.apiKey && !requireAuth && !headers["Authorization"]) {
120
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
121
+ }
122
+ if (requireAuth) {
123
+ const token = this.getAccessToken();
124
+ if (token && !headers["Authorization"]) {
125
+ headers["Authorization"] = `Bearer ${token}`;
126
+ }
127
+ }
128
+ try {
129
+ const response = await fetch(url, {
130
+ ...options,
131
+ headers
132
+ });
133
+ const data = await response.json();
134
+ if (!response.ok) {
135
+ if (response.status === 403 && data.required && data.provided) {
136
+ throw new ScopeError(
137
+ data.error || "Insufficient scopes",
138
+ data.required,
139
+ data.provided
140
+ );
141
+ }
142
+ throw new AuthMiError(
143
+ data.error || `HTTP ${response.status}`,
144
+ data.code || "UNKNOWN_ERROR",
145
+ response.status
146
+ );
147
+ }
148
+ return data;
149
+ } catch (error) {
150
+ if (error instanceof AuthMiError) {
151
+ throw error;
152
+ }
153
+ throw new AuthMiError(
154
+ error instanceof Error ? error.message : "Network error",
155
+ "NETWORK_ERROR"
156
+ );
157
+ }
158
+ }
159
+ // ============ Configuration ============
160
+ /**
161
+ * Update the client's service configuration
162
+ */
163
+ configure(config) {
164
+ this.config = { ...this.config, ...config };
165
+ }
166
+ /**
167
+ * Get current configuration (without sensitive data)
168
+ */
169
+ getConfig() {
170
+ const { apiKey: _, clientSecret: __, ...rest } = this.config;
171
+ return rest;
172
+ }
173
+ // ============ Token Management ============
174
+ /**
175
+ * Get the stored access token
176
+ */
177
+ getAccessToken() {
178
+ return this.tokenStorage.getToken();
179
+ }
180
+ /**
181
+ * Store an access token
182
+ */
183
+ setAccessToken(token) {
184
+ this.tokenStorage.setToken(token);
185
+ }
186
+ /**
187
+ * Remove the stored access token (logout)
188
+ */
189
+ clearAccessToken() {
190
+ this.tokenStorage.removeToken();
191
+ }
192
+ /**
193
+ * Check if user is logged in
194
+ */
195
+ isLoggedIn() {
196
+ return !!this.getAccessToken();
197
+ }
198
+ // ============ Scope Validation ============
199
+ /**
200
+ * Introspect a token or API key and validate required scopes
201
+ */
202
+ async introspect(request) {
203
+ return this.request("/api/v1/introspect", {
204
+ method: "POST",
205
+ body: JSON.stringify(request)
206
+ });
207
+ }
208
+ /**
209
+ * Validate the current token with optional scope checking
210
+ */
211
+ async validateWithScopes(requiredScopes) {
212
+ const token = this.getAccessToken();
213
+ if (!token) {
214
+ return { valid: false, error: "No token provided" };
215
+ }
216
+ if (!this.config.apiKey && !this.config.clientSecret) {
217
+ return { valid: false, error: "Service credentials not configured" };
218
+ }
219
+ if (!this.config.serviceId) {
220
+ return { valid: false, error: "Service ID not configured in AuthMiConfig" };
221
+ }
222
+ try {
223
+ const result = await this.introspect({
224
+ serviceId: this.config.serviceId,
225
+ token,
226
+ requiredScopes
227
+ });
228
+ return {
229
+ valid: result.valid,
230
+ type: result.type === "bearer" ? "token" : "api_key",
231
+ scopes: result.scopes,
232
+ userId: result.userId,
233
+ email: result.email,
234
+ error: result.error
235
+ };
236
+ } catch (error) {
237
+ if (error instanceof ScopeError) {
238
+ return {
239
+ valid: false,
240
+ error: error.message,
241
+ scopes: error.providedScopes
242
+ };
243
+ }
244
+ if (error instanceof AuthMiError && error.statusCode === 401) {
245
+ return { valid: false, error: "Invalid or expired token" };
246
+ }
247
+ throw error;
248
+ }
249
+ }
250
+ /**
251
+ * Check if the current user has all the required scopes
252
+ * Throws ScopeError if scopes are insufficient
253
+ */
254
+ async requireScopes(...requiredScopes) {
255
+ const result = await this.validateWithScopes(requiredScopes);
256
+ if (!result.valid) {
257
+ throw new AuthMiError(
258
+ result.error || "Authentication required",
259
+ "UNAUTHORIZED",
260
+ 401
261
+ );
262
+ }
263
+ const hasScopes = requiredScopes.every(
264
+ (scope) => result.scopes?.includes(scope)
265
+ );
266
+ if (!hasScopes) {
267
+ throw new ScopeError(
268
+ `Required scopes: ${requiredScopes.join(", ")}`,
269
+ requiredScopes,
270
+ result.scopes || []
271
+ );
272
+ }
273
+ return result;
274
+ }
275
+ /**
276
+ * Execute a function only if the user has the required scopes
277
+ */
278
+ async withScope(scopes, fn) {
279
+ await this.requireScopes(...scopes);
280
+ return fn();
281
+ }
282
+ // ============ OAuth ============
283
+ /**
284
+ * Initiate OAuth login flow and return the authorization URL
285
+ */
286
+ async initiateOAuth(provider, redirectUri) {
287
+ if (!this.config.apiKey && !this.config.clientSecret) {
288
+ throw new AuthMiError(
289
+ "API key or client credentials required for OAuth. Configure the client first.",
290
+ "MISSING_CREDENTIALS"
291
+ );
292
+ }
293
+ if (!this.config.serviceId) {
294
+ throw new AuthMiError(
295
+ "serviceId required for OAuth. Configure the client first.",
296
+ "MISSING_SERVICE_ID"
297
+ );
298
+ }
299
+ const response = await this.request(
300
+ "/api/v1/auth/oauth/initiate",
301
+ {
302
+ method: "POST",
303
+ body: JSON.stringify({ provider, redirectUri, client_id: this.config.serviceId })
304
+ }
305
+ );
306
+ return response.url;
307
+ }
308
+ /**
309
+ * Handle OAuth callback URL and store the access token
310
+ * Returns null if no OAuth params are present in the URL
311
+ */
312
+ handleOAuthCallback(url) {
313
+ const parsedUrl = typeof url === "string" ? new URL(url) : url;
314
+ const token = parsedUrl.searchParams.get("token");
315
+ const userId = parsedUrl.searchParams.get("user_id");
316
+ const email = parsedUrl.searchParams.get("email");
317
+ if (!token || !userId || !email) {
318
+ return null;
319
+ }
320
+ this.setAccessToken(token);
321
+ return { token, userId, email };
322
+ }
323
+ /**
324
+ * Check if the current URL contains OAuth callback params
325
+ */
326
+ isOAuthCallback(url) {
327
+ const parsedUrl = typeof url === "string" ? new URL(url) : url;
328
+ return parsedUrl.searchParams.has("token") && parsedUrl.searchParams.has("user_id") && parsedUrl.searchParams.has("email");
329
+ }
330
+ // ============ Authentication ============
331
+ /**
332
+ * Login a user and store the access token
333
+ */
334
+ async login(credentials) {
335
+ if (!this.config.apiKey && !this.config.clientSecret) {
336
+ throw new AuthMiError(
337
+ "API key or client credentials required for login. Configure the client first.",
338
+ "MISSING_CREDENTIALS"
339
+ );
340
+ }
341
+ const response = await this.request("/api/v1/auth/login", {
342
+ method: "POST",
343
+ body: JSON.stringify({
344
+ email: credentials.email,
345
+ password: credentials.password,
346
+ client_id: this.config.serviceId,
347
+ expires_in_hours: credentials.expiresInHours || this.config.defaultTokenExpiry,
348
+ scopes: credentials.scopes
349
+ })
350
+ });
351
+ const token = {
352
+ accessToken: response.access_token,
353
+ tokenType: response.token_type,
354
+ expiresIn: response.expires_in,
355
+ expiresAt: response.expires_at,
356
+ userId: response.user_id,
357
+ email: response.email,
358
+ scopes: response.scopes
359
+ };
360
+ this.setAccessToken(token.accessToken);
361
+ return token;
362
+ }
363
+ /**
364
+ * Logout the current user
365
+ */
366
+ async logout() {
367
+ const token = this.getAccessToken();
368
+ if (token) {
369
+ try {
370
+ await this.request("/api/v1/auth/logout", {
371
+ method: "POST"
372
+ }, true);
373
+ } catch (error) {
374
+ }
375
+ }
376
+ this.clearAccessToken();
377
+ }
378
+ /**
379
+ * Validate the current token or an API key
380
+ * @deprecated Use validateWithScopes instead
381
+ */
382
+ async validate(_credential) {
383
+ return this.validateWithScopes();
384
+ }
385
+ /**
386
+ * Refresh the current token
387
+ */
388
+ async refreshToken() {
389
+ const response = await this.request("/api/v1/auth/refresh", {
390
+ method: "POST"
391
+ }, true);
392
+ const token = {
393
+ accessToken: response.access_token,
394
+ tokenType: response.token_type,
395
+ expiresIn: response.expires_in,
396
+ expiresAt: response.expires_at,
397
+ userId: "",
398
+ // Refresh doesn't return user info
399
+ email: ""
400
+ };
401
+ this.setAccessToken(token.accessToken);
402
+ return token;
403
+ }
404
+ // ============ User Management ============
405
+ /**
406
+ * Create a new user (requires admin API key)
407
+ */
408
+ async createUser(request) {
409
+ const response = await this.request("/api/v1/users/create", {
410
+ method: "POST",
411
+ body: JSON.stringify(request)
412
+ });
413
+ return {
414
+ userId: response.user_id,
415
+ email: response.email,
416
+ createdAt: response.created_at
417
+ };
418
+ }
419
+ /**
420
+ * List all users for the service
421
+ */
422
+ async listUsers() {
423
+ const response = await this.request("/api/v1/users/list");
424
+ return response.users.map((u) => ({
425
+ userId: u.user_id,
426
+ email: u.email,
427
+ createdAt: u.created_at
428
+ }));
429
+ }
430
+ /**
431
+ * Delete a user
432
+ */
433
+ async deleteUser(userId) {
434
+ await this.request("/api/v1/users/delete", {
435
+ method: "POST",
436
+ body: JSON.stringify({ user_id: userId })
437
+ });
438
+ }
439
+ /**
440
+ * Update user password
441
+ */
442
+ async updatePassword(userId, oldPassword, newPassword) {
443
+ await this.request("/api/v1/users/password", {
444
+ method: "POST",
445
+ body: JSON.stringify({
446
+ user_id: userId,
447
+ old_password: oldPassword,
448
+ new_password: newPassword
449
+ })
450
+ });
451
+ }
452
+ // ============ Scope Management ============
453
+ /**
454
+ * List custom scopes for the service
455
+ */
456
+ async listScopes() {
457
+ const response = await this.request("/api/v1/scopes/list");
458
+ return response.scopes;
459
+ }
460
+ /**
461
+ * Create a custom scope
462
+ */
463
+ async createScope(request) {
464
+ const response = await this.request("/api/v1/scopes/create", {
465
+ method: "POST",
466
+ body: JSON.stringify(request)
467
+ });
468
+ return {
469
+ scopeId: response.scope_id,
470
+ name: response.name,
471
+ key: response.key,
472
+ description: response.description,
473
+ createdAt: response.created_at
474
+ };
475
+ }
476
+ /**
477
+ * Delete a custom scope
478
+ */
479
+ async deleteScope(scopeId) {
480
+ await this.request("/api/v1/scopes/delete", {
481
+ method: "POST",
482
+ body: JSON.stringify({ scope_id: scopeId })
483
+ });
484
+ }
485
+ // ============ API Key Management ============
486
+ /**
487
+ * List all API keys for the service
488
+ */
489
+ async listApiKeys() {
490
+ const response = await this.request("/api/v1/keys/list");
491
+ return response.keys.map((k) => ({
492
+ keyId: k.keyId,
493
+ name: k.name,
494
+ scope: k.scope,
495
+ scopes: [],
496
+ keyType: k.keyType,
497
+ revoked: k.revoked,
498
+ createdAt: k.createdAt,
499
+ tpsLimit: k.tpsLimit
500
+ }));
501
+ }
502
+ /**
503
+ * Create a new API key with optional custom scopes
504
+ */
505
+ async createApiKey(request) {
506
+ const response = await this.request("/api/v1/keys/create", {
507
+ method: "POST",
508
+ body: JSON.stringify({
509
+ user_id: request.userId,
510
+ name: request.name,
511
+ scope: request.scope || "service",
512
+ scopes: request.scopes,
513
+ key_type: request.keyType || "service",
514
+ tps_limit: request.tpsLimit || 100
515
+ })
516
+ });
517
+ return {
518
+ keyId: response.key_id,
519
+ apiKey: response.api_key,
520
+ name: response.name,
521
+ scope: response.scope,
522
+ scopes: response.scopes
523
+ };
524
+ }
525
+ /**
526
+ * Revoke an API key
527
+ */
528
+ async revokeApiKey(keyId) {
529
+ await this.request("/api/v1/keys/revoke", {
530
+ method: "POST",
531
+ body: JSON.stringify({ key_id: keyId })
532
+ });
533
+ }
534
+ // ============ Service Management ============
535
+ /**
536
+ * Onboard a new service (requires master admin key)
537
+ */
538
+ async onboardService(request, masterAdminKey) {
539
+ const response = await this.request("/api/v1/services/onboard", {
540
+ method: "POST",
541
+ headers: {
542
+ "x-onboarding-admin-key": masterAdminKey
543
+ },
544
+ body: JSON.stringify({
545
+ service_name: request.serviceName,
546
+ owner_email: request.ownerEmail
547
+ })
548
+ });
549
+ return {
550
+ serviceId: response.service_id,
551
+ serviceName: response.service_name,
552
+ ownerEmail: response.owner_email,
553
+ adminKeyId: response.admin_key_id,
554
+ serviceAdminApiKey: response.service_admin_api_key,
555
+ createdAt: response.created_at
556
+ };
557
+ }
558
+ /**
559
+ * Delete a service (requires master admin key)
560
+ */
561
+ async deleteService(serviceId, masterAdminKey) {
562
+ await this.request("/api/v1/services/deboard", {
563
+ method: "POST",
564
+ headers: {
565
+ "x-onboarding-admin-key": masterAdminKey
566
+ },
567
+ body: JSON.stringify({ service_id: serviceId })
568
+ });
569
+ }
570
+ // ============ Webhook Management ============
571
+ /**
572
+ * List webhooks
573
+ */
574
+ async listWebhooks() {
575
+ const response = await this.request(
576
+ "/api/v1/webhooks/list"
577
+ );
578
+ return response.webhooks;
579
+ }
580
+ /**
581
+ * Register a webhook
582
+ */
583
+ async registerWebhook(request) {
584
+ const response = await this.request("/api/v1/webhooks/register", {
585
+ method: "POST",
586
+ body: JSON.stringify(request)
587
+ });
588
+ return {
589
+ webhookId: response.webhook_id,
590
+ url: response.url,
591
+ events: response.events,
592
+ active: response.active,
593
+ createdAt: response.created_at
594
+ };
595
+ }
596
+ /**
597
+ * Delete a webhook
598
+ */
599
+ async deleteWebhook(webhookId) {
600
+ await this.request("/api/v1/webhooks/delete", {
601
+ method: "POST",
602
+ body: JSON.stringify({ webhook_id: webhookId })
603
+ });
604
+ }
605
+ };
606
+
607
+ // src/react.tsx
608
+ var import_jsx_runtime = require("react/jsx-runtime");
609
+ var AuthMiContext = (0, import_react.createContext)(null);
610
+ function AuthMiProvider({
611
+ config,
612
+ tokenStorage,
613
+ children,
614
+ validateOnMount = true,
615
+ validationInterval = 5 * 60 * 1e3
616
+ }) {
617
+ const [client] = (0, import_react.useState)(() => new AuthMiClient(config, tokenStorage));
618
+ const [isAuthenticated, setIsAuthenticated] = (0, import_react.useState)(false);
619
+ const [user, setUser] = (0, import_react.useState)(null);
620
+ const [isLoading, setIsLoading] = (0, import_react.useState)(true);
621
+ (0, import_react.useEffect)(() => {
622
+ const checkAuth = async () => {
623
+ const token = client.getAccessToken();
624
+ if (token && validateOnMount) {
625
+ try {
626
+ const result = await client.validate();
627
+ if (result.valid) {
628
+ setIsAuthenticated(true);
629
+ } else {
630
+ client.clearAccessToken();
631
+ }
632
+ } catch (error) {
633
+ client.clearAccessToken();
634
+ }
635
+ }
636
+ setIsLoading(false);
637
+ };
638
+ checkAuth();
639
+ }, [client, validateOnMount]);
640
+ (0, import_react.useEffect)(() => {
641
+ if (!isAuthenticated || !validationInterval) return;
642
+ const interval = setInterval(async () => {
643
+ try {
644
+ const result = await client.validate();
645
+ if (!result.valid) {
646
+ setIsAuthenticated(false);
647
+ setUser(null);
648
+ }
649
+ } catch (error) {
650
+ setIsAuthenticated(false);
651
+ setUser(null);
652
+ }
653
+ }, validationInterval);
654
+ return () => clearInterval(interval);
655
+ }, [client, isAuthenticated, validationInterval]);
656
+ const login = (0, import_react.useCallback)(
657
+ async (email, password) => {
658
+ setIsLoading(true);
659
+ try {
660
+ const token = await client.login({ email, password });
661
+ setIsAuthenticated(true);
662
+ setUser({
663
+ userId: token.userId,
664
+ email: token.email,
665
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
666
+ });
667
+ } finally {
668
+ setIsLoading(false);
669
+ }
670
+ },
671
+ [client]
672
+ );
673
+ const logout = (0, import_react.useCallback)(async () => {
674
+ setIsLoading(true);
675
+ try {
676
+ await client.logout();
677
+ } finally {
678
+ setIsAuthenticated(false);
679
+ setUser(null);
680
+ setIsLoading(false);
681
+ }
682
+ }, [client]);
683
+ const validate = (0, import_react.useCallback)(async () => {
684
+ const result = await client.validate();
685
+ if (!result.valid) {
686
+ setIsAuthenticated(false);
687
+ setUser(null);
688
+ }
689
+ return result;
690
+ }, [client]);
691
+ const value = {
692
+ client,
693
+ isAuthenticated,
694
+ user,
695
+ isLoading,
696
+ login,
697
+ logout,
698
+ validate
699
+ };
700
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthMiContext.Provider, { value, children });
701
+ }
702
+ function useAuthMi() {
703
+ const context = (0, import_react.useContext)(AuthMiContext);
704
+ if (!context) {
705
+ throw new Error("useAuthMi must be used within AuthMiProvider");
706
+ }
707
+ return context;
708
+ }
709
+ function useAuthMiClient() {
710
+ return useAuthMi().client;
711
+ }
712
+ function useIsAuthenticated() {
713
+ return useAuthMi().isAuthenticated;
714
+ }
715
+ function useUser() {
716
+ return useAuthMi().user;
717
+ }
718
+ function useAuthActions() {
719
+ const { login, logout, isLoading } = useAuthMi();
720
+ return { login, logout, isLoading };
721
+ }
722
+ function Protected({ children, fallback = null }) {
723
+ const { isAuthenticated, isLoading } = useAuthMi();
724
+ if (isLoading) {
725
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
726
+ }
727
+ if (!isAuthenticated) {
728
+ return null;
729
+ }
730
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
731
+ }
732
+ function LoginForm({ onSuccess, onError, className }) {
733
+ const { login, isLoading } = useAuthMi();
734
+ const [email, setEmail] = (0, import_react.useState)("");
735
+ const [password, setPassword] = (0, import_react.useState)("");
736
+ const [error, setError] = (0, import_react.useState)(null);
737
+ const handleSubmit = async (e) => {
738
+ e.preventDefault();
739
+ setError(null);
740
+ try {
741
+ await login(email, password);
742
+ onSuccess?.();
743
+ } catch (err) {
744
+ const message = err instanceof Error ? err.message : "Login failed";
745
+ setError(message);
746
+ onError?.(err instanceof Error ? err : new Error(message));
747
+ }
748
+ };
749
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: handleSubmit, className, children: [
750
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { color: "red", marginBottom: "1rem" }, children: error }),
751
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: "1rem" }, children: [
752
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "email", children: "Email" }),
753
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
754
+ "input",
755
+ {
756
+ id: "email",
757
+ type: "email",
758
+ value: email,
759
+ onChange: (e) => setEmail(e.target.value),
760
+ required: true,
761
+ style: { display: "block", width: "100%", padding: "0.5rem" }
762
+ }
763
+ )
764
+ ] }),
765
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: "1rem" }, children: [
766
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "password", children: "Password" }),
767
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
768
+ "input",
769
+ {
770
+ id: "password",
771
+ type: "password",
772
+ value: password,
773
+ onChange: (e) => setPassword(e.target.value),
774
+ required: true,
775
+ style: { display: "block", width: "100%", padding: "0.5rem" }
776
+ }
777
+ )
778
+ ] }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
780
+ "button",
781
+ {
782
+ type: "submit",
783
+ disabled: isLoading,
784
+ style: {
785
+ padding: "0.5rem 1rem",
786
+ background: isLoading ? "#ccc" : "#007bff",
787
+ color: "white",
788
+ border: "none",
789
+ borderRadius: "4px",
790
+ cursor: isLoading ? "not-allowed" : "pointer"
791
+ },
792
+ children: isLoading ? "Logging in..." : "Login"
793
+ }
794
+ )
795
+ ] });
796
+ }
797
+ // Annotate the CommonJS export names for ESM import in node:
798
+ 0 && (module.exports = {
799
+ AuthMiClient,
800
+ AuthMiError,
801
+ AuthMiProvider,
802
+ LocalStorageTokenStorage,
803
+ LoginForm,
804
+ MemoryTokenStorage,
805
+ Protected,
806
+ ScopeError,
807
+ useAuthActions,
808
+ useAuthMi,
809
+ useAuthMiClient,
810
+ useIsAuthenticated,
811
+ useUser
812
+ });