@axcode/axcloud-sdk 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/index.mjs ADDED
@@ -0,0 +1,1246 @@
1
+ import { createContext, useContext, useMemo, useCallback, useRef } from 'react';
2
+ import { Auth0Provider, useAuth0 } from '@auth0/auth0-react';
3
+ import { QueryClient, QueryClientProvider, useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
4
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
5
+
6
+ // src/core/errors.ts
7
+ var AxCloudError = class _AxCloudError extends Error {
8
+ constructor(message, code, status, details) {
9
+ super(message);
10
+ this.name = "AxCloudError";
11
+ this.code = code;
12
+ this.status = status;
13
+ this.details = details;
14
+ const ErrorWithCapture = Error;
15
+ if (ErrorWithCapture.captureStackTrace) {
16
+ ErrorWithCapture.captureStackTrace(this, _AxCloudError);
17
+ }
18
+ }
19
+ static fromResponse(status, body) {
20
+ const details = typeof body === "object" ? body : void 0;
21
+ const message = details?.message;
22
+ switch (status) {
23
+ case 401:
24
+ return new _AxCloudError(
25
+ message || "Authentication required",
26
+ "UNAUTHORIZED",
27
+ status,
28
+ details
29
+ );
30
+ case 403:
31
+ return new _AxCloudError(
32
+ message || "Access denied",
33
+ "FORBIDDEN",
34
+ status,
35
+ details
36
+ );
37
+ case 404:
38
+ return new _AxCloudError(
39
+ message || "Resource not found",
40
+ "NOT_FOUND",
41
+ status,
42
+ details
43
+ );
44
+ case 422:
45
+ return new _AxCloudError(
46
+ message || "Validation failed",
47
+ "VALIDATION_ERROR",
48
+ status,
49
+ details
50
+ );
51
+ default:
52
+ if (status >= 500) {
53
+ return new _AxCloudError(
54
+ message || "Server error",
55
+ "SERVER_ERROR",
56
+ status,
57
+ details
58
+ );
59
+ }
60
+ return new _AxCloudError(
61
+ message || "An error occurred",
62
+ "UNKNOWN_ERROR",
63
+ status,
64
+ details
65
+ );
66
+ }
67
+ }
68
+ static networkError(originalError) {
69
+ const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
70
+ const message = isDev && originalError?.message ? originalError.message : "Network request failed";
71
+ return new _AxCloudError(
72
+ message,
73
+ "NETWORK_ERROR",
74
+ 0,
75
+ isDev ? { originalError: originalError?.message } : void 0
76
+ );
77
+ }
78
+ static timeoutError(timeoutMs) {
79
+ return new _AxCloudError(
80
+ `Request timed out after ${timeoutMs}ms`,
81
+ "TIMEOUT_ERROR",
82
+ 0,
83
+ { timeout: timeoutMs }
84
+ );
85
+ }
86
+ };
87
+ function isAxCloudError(error) {
88
+ return error instanceof AxCloudError;
89
+ }
90
+
91
+ // src/core/client.ts
92
+ var AxCloudClient = class {
93
+ constructor(config) {
94
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
95
+ this.getAccessToken = config.getAccessToken;
96
+ this.apiKey = config.apiKey;
97
+ this.defaultTimeout = config.timeout ?? 3e4;
98
+ }
99
+ /**
100
+ * Update the access token getter (used when auth state changes)
101
+ */
102
+ setAccessTokenGetter(getter) {
103
+ this.getAccessToken = getter;
104
+ }
105
+ /**
106
+ * Build URL with query parameters
107
+ */
108
+ buildUrl(path, params) {
109
+ const url = new URL(`${this.baseUrl}${path}`);
110
+ if (params) {
111
+ Object.entries(params).forEach(([key, value]) => {
112
+ if (value !== void 0) {
113
+ url.searchParams.append(key, String(value));
114
+ }
115
+ });
116
+ }
117
+ return url.toString();
118
+ }
119
+ /**
120
+ * Make an authenticated request
121
+ */
122
+ async request(path, options = {}) {
123
+ const { body, params, headers: customHeaders, timeout, ...restOptions } = options;
124
+ const headers = {
125
+ "Content-Type": "application/json"
126
+ };
127
+ if (customHeaders) {
128
+ const customHeadersRecord = customHeaders;
129
+ Object.assign(headers, customHeadersRecord);
130
+ }
131
+ if (this.apiKey) {
132
+ headers["x-api-key"] = this.apiKey;
133
+ }
134
+ if (this.getAccessToken) {
135
+ try {
136
+ const token = await this.getAccessToken();
137
+ if (token) {
138
+ headers["Authorization"] = `Bearer ${token}`;
139
+ }
140
+ } catch (error) {
141
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
142
+ console.warn(
143
+ "[AxCloud SDK] Failed to fetch access token:",
144
+ error instanceof Error ? error.message : error
145
+ );
146
+ }
147
+ }
148
+ }
149
+ const url = this.buildUrl(path, params);
150
+ const controller = new AbortController();
151
+ const requestTimeout = timeout ?? this.defaultTimeout;
152
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
153
+ try {
154
+ const response = await fetch(url, {
155
+ ...restOptions,
156
+ headers,
157
+ body: body ? JSON.stringify(body) : void 0,
158
+ signal: controller.signal
159
+ });
160
+ const contentType = response.headers.get("content-type");
161
+ const isJson = contentType?.includes("application/json");
162
+ if (!response.ok) {
163
+ const errorBody = isJson ? await response.json().catch(() => null) : null;
164
+ throw AxCloudError.fromResponse(response.status, errorBody);
165
+ }
166
+ if (response.status === 204) {
167
+ return {};
168
+ }
169
+ return isJson ? await response.json() : {};
170
+ } catch (error) {
171
+ if (error instanceof AxCloudError) {
172
+ throw error;
173
+ }
174
+ if (error instanceof Error && error.name === "AbortError") {
175
+ throw AxCloudError.timeoutError(requestTimeout);
176
+ }
177
+ throw AxCloudError.networkError(error instanceof Error ? error : void 0);
178
+ } finally {
179
+ clearTimeout(timeoutId);
180
+ }
181
+ }
182
+ /**
183
+ * GET request
184
+ */
185
+ get(path, params) {
186
+ return this.request(path, { method: "GET", params });
187
+ }
188
+ /**
189
+ * POST request
190
+ */
191
+ post(path, body) {
192
+ return this.request(path, { method: "POST", body });
193
+ }
194
+ /**
195
+ * PUT request
196
+ */
197
+ put(path, body) {
198
+ return this.request(path, { method: "PUT", body });
199
+ }
200
+ /**
201
+ * PATCH request
202
+ */
203
+ patch(path, body) {
204
+ return this.request(path, { method: "PATCH", body });
205
+ }
206
+ /**
207
+ * DELETE request
208
+ */
209
+ delete(path) {
210
+ return this.request(path, { method: "DELETE" });
211
+ }
212
+ };
213
+ var clientRegistry = /* @__PURE__ */ new WeakMap();
214
+ function createClient(config, key) {
215
+ const client = new AxCloudClient(config);
216
+ if (key) {
217
+ clientRegistry.set(key, client);
218
+ }
219
+ return client;
220
+ }
221
+ function getClient(key) {
222
+ if (key) {
223
+ const client = clientRegistry.get(key);
224
+ if (client) {
225
+ return client;
226
+ }
227
+ }
228
+ throw new Error("AxCloud client not found. Make sure AxCloudProvider is mounted and use useAxCloudContext() to get the client.");
229
+ }
230
+
231
+ // src/core/types.ts
232
+ function userHasPermission(user, permission) {
233
+ if (user.permissions && user.permissions.length > 0) {
234
+ return user.permissions.includes(permission);
235
+ }
236
+ if (user.customRole?.effectivePermissions) {
237
+ return user.customRole.effectivePermissions.includes(permission);
238
+ }
239
+ return false;
240
+ }
241
+ function userHasAnyPermission(user, permissions) {
242
+ return permissions.some((p) => userHasPermission(user, p));
243
+ }
244
+ function userHasAllPermissions(user, permissions) {
245
+ return permissions.every((p) => userHasPermission(user, p));
246
+ }
247
+
248
+ // src/core/forms.ts
249
+ async function submitForm(apiUrl, submission) {
250
+ const url = `${apiUrl.replace(/\/$/, "")}/public/submit`;
251
+ const response = await fetch(url, {
252
+ method: "POST",
253
+ headers: {
254
+ "Content-Type": "application/json"
255
+ },
256
+ body: JSON.stringify({
257
+ api_key: submission.apiKey,
258
+ site: submission.site,
259
+ form_type: submission.formType,
260
+ email: submission.email,
261
+ data: submission.data || {}
262
+ })
263
+ });
264
+ if (!response.ok) {
265
+ const error = await response.json().catch(() => ({ message: "Form submission failed" }));
266
+ throw new Error(error.message || "Form submission failed");
267
+ }
268
+ const result = await response.json();
269
+ return {
270
+ success: result.success,
271
+ message: result.message,
272
+ submissionId: result.submission_id
273
+ };
274
+ }
275
+ function createFormHelper(config) {
276
+ return {
277
+ /**
278
+ * Submit a waitlist form
279
+ */
280
+ submitWaitlist: (email, data) => submitForm(config.apiUrl, {
281
+ apiKey: config.apiKey,
282
+ site: config.site,
283
+ formType: "waitlist",
284
+ email,
285
+ data
286
+ }),
287
+ /**
288
+ * Submit a contact form
289
+ */
290
+ submitContact: (email, data) => submitForm(config.apiUrl, {
291
+ apiKey: config.apiKey,
292
+ site: config.site,
293
+ formType: "contact",
294
+ email,
295
+ data
296
+ }),
297
+ /**
298
+ * Submit a membership application
299
+ */
300
+ submitMembership: (email, data) => submitForm(config.apiUrl, {
301
+ apiKey: config.apiKey,
302
+ site: config.site,
303
+ formType: "membership",
304
+ email,
305
+ data
306
+ }),
307
+ /**
308
+ * Generic submit function
309
+ */
310
+ submit: (formType, email, data) => submitForm(config.apiUrl, {
311
+ apiKey: config.apiKey,
312
+ site: config.site,
313
+ formType,
314
+ email,
315
+ data
316
+ })
317
+ };
318
+ }
319
+ var AxCloudContext = createContext(null);
320
+ function useAxCloudContext() {
321
+ const context = useContext(AxCloudContext);
322
+ if (!context) {
323
+ throw new Error("useAxCloudContext must be used within a AxCloudProvider");
324
+ }
325
+ return context;
326
+ }
327
+ var defaultQueryClient = new QueryClient({
328
+ defaultOptions: {
329
+ queries: {
330
+ staleTime: 1e3 * 60 * 5,
331
+ // 5 minutes
332
+ gcTime: 1e3 * 60 * 30,
333
+ // 30 minutes (garbage collection)
334
+ retry: 2,
335
+ refetchOnWindowFocus: false
336
+ }
337
+ }
338
+ });
339
+ function AxCloudInnerProvider({
340
+ children,
341
+ config,
342
+ timeout
343
+ }) {
344
+ const { getAccessTokenSilently, isAuthenticated } = useAuth0();
345
+ const tokenGetterRef = useRef(async () => void 0);
346
+ tokenGetterRef.current = isAuthenticated ? async () => {
347
+ try {
348
+ return await getAccessTokenSilently();
349
+ } catch {
350
+ return void 0;
351
+ }
352
+ } : async () => void 0;
353
+ const client = useMemo(() => {
354
+ return new AxCloudClient({
355
+ baseUrl: config.apiUrl,
356
+ apiKey: config.apiKey,
357
+ timeout,
358
+ // Use a wrapper function that delegates to the ref
359
+ // This ensures the client always uses the current auth state
360
+ getAccessToken: async () => {
361
+ if (tokenGetterRef.current) {
362
+ return tokenGetterRef.current();
363
+ }
364
+ return void 0;
365
+ }
366
+ });
367
+ }, [config.apiUrl, config.apiKey, timeout]);
368
+ const contextValue = useMemo(
369
+ () => ({
370
+ config,
371
+ client,
372
+ orgId: config.orgId,
373
+ stage: config.stage,
374
+ isPublicMode: Boolean(config.apiKey) && !isAuthenticated
375
+ }),
376
+ [config, client, isAuthenticated]
377
+ );
378
+ return /* @__PURE__ */ jsx(AxCloudContext.Provider, { value: contextValue, children });
379
+ }
380
+ function AxCloudProvider({
381
+ children,
382
+ orgId,
383
+ apiUrl,
384
+ stage = "dev",
385
+ apiKey,
386
+ auth0,
387
+ queryClient = defaultQueryClient,
388
+ timeout
389
+ }) {
390
+ const config = useMemo(
391
+ () => ({
392
+ orgId,
393
+ apiUrl,
394
+ stage,
395
+ apiKey,
396
+ auth0
397
+ }),
398
+ [orgId, apiUrl, stage, apiKey, auth0]
399
+ );
400
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(
401
+ Auth0Provider,
402
+ {
403
+ domain: auth0.domain,
404
+ clientId: auth0.clientId,
405
+ authorizationParams: {
406
+ redirect_uri: auth0.redirectUri,
407
+ audience: auth0.audience
408
+ },
409
+ children: /* @__PURE__ */ jsx(AxCloudInnerProvider, { config, timeout, children })
410
+ }
411
+ ) });
412
+ }
413
+ function useAuth() {
414
+ const { config } = useAxCloudContext();
415
+ const {
416
+ isAuthenticated,
417
+ isLoading,
418
+ user: auth0User,
419
+ error,
420
+ loginWithRedirect,
421
+ logout: auth0Logout,
422
+ getAccessTokenSilently,
423
+ getIdTokenClaims
424
+ } = useAuth0();
425
+ const login = useCallback(
426
+ (options) => {
427
+ return loginWithRedirect({
428
+ appState: {
429
+ returnTo: options?.returnTo || window.location.pathname
430
+ }
431
+ });
432
+ },
433
+ [loginWithRedirect]
434
+ );
435
+ const logout = useCallback(
436
+ (options) => {
437
+ return auth0Logout({
438
+ logoutParams: {
439
+ returnTo: options?.returnTo || window.location.origin
440
+ }
441
+ });
442
+ },
443
+ [auth0Logout]
444
+ );
445
+ const getAccessToken = useCallback(async () => {
446
+ try {
447
+ return await getAccessTokenSilently();
448
+ } catch {
449
+ return void 0;
450
+ }
451
+ }, [getAccessTokenSilently]);
452
+ const getAuth0Client = useCallback(() => {
453
+ return {
454
+ loginWithRedirect,
455
+ logout: auth0Logout,
456
+ getAccessTokenSilently,
457
+ getIdTokenClaims,
458
+ user: auth0User,
459
+ isAuthenticated,
460
+ isLoading,
461
+ error
462
+ };
463
+ }, [
464
+ loginWithRedirect,
465
+ auth0Logout,
466
+ getAccessTokenSilently,
467
+ getIdTokenClaims,
468
+ auth0User,
469
+ isAuthenticated,
470
+ isLoading,
471
+ error
472
+ ]);
473
+ const requestPasswordReset = useCallback(
474
+ async (email) => {
475
+ const targetEmail = email || auth0User?.email;
476
+ if (!targetEmail) {
477
+ return {
478
+ success: false,
479
+ message: "Email address is required"
480
+ };
481
+ }
482
+ try {
483
+ const auth0Domain = config.auth0.domain;
484
+ const clientId = config.auth0.clientId;
485
+ const connection = config.auth0.connection || "Username-Password-Authentication";
486
+ const response = await fetch(`https://${auth0Domain}/dbconnections/change_password`, {
487
+ method: "POST",
488
+ headers: {
489
+ "Content-Type": "application/json"
490
+ },
491
+ body: JSON.stringify({
492
+ client_id: clientId,
493
+ email: targetEmail.toLowerCase(),
494
+ connection
495
+ })
496
+ });
497
+ if (response.ok) {
498
+ return {
499
+ success: true,
500
+ message: "If an account exists with this email, a password reset link has been sent."
501
+ };
502
+ }
503
+ return {
504
+ success: true,
505
+ message: "If an account exists with this email, a password reset link has been sent."
506
+ };
507
+ } catch {
508
+ return {
509
+ success: false,
510
+ message: "Failed to send password reset email. Please try again."
511
+ };
512
+ }
513
+ },
514
+ [auth0User?.email, config.auth0.domain, config.auth0.clientId]
515
+ );
516
+ return {
517
+ // Simple, abstracted API
518
+ isAuthenticated,
519
+ isLoading,
520
+ error,
521
+ user: auth0User ? {
522
+ id: auth0User.sub || "",
523
+ email: auth0User.email || "",
524
+ name: auth0User.name || "",
525
+ avatar: auth0User.picture
526
+ } : null,
527
+ login,
528
+ logout,
529
+ // Escape hatch for advanced use cases
530
+ getAccessToken,
531
+ getAuth0Client,
532
+ // Password management
533
+ requestPasswordReset
534
+ };
535
+ }
536
+ function useUser() {
537
+ const { isAuthenticated, isLoading: isAuthLoading } = useAuth0();
538
+ const { client, stage, orgId } = useAxCloudContext();
539
+ const query = useQuery({
540
+ queryKey: ["axcloud", "user", "me", stage],
541
+ queryFn: async () => {
542
+ return client.get(`/${stage}/api/users/me`);
543
+ },
544
+ enabled: isAuthenticated && !isAuthLoading,
545
+ staleTime: 1e3 * 60 * 5
546
+ // 5 minutes
547
+ });
548
+ const userData = query.data;
549
+ const userOrgIds = userData?.all_org_ids ?? [];
550
+ const isSuperAdmin = userData?.isSuperAdmin === true;
551
+ const hasOrgAccess = isSuperAdmin || userOrgIds.includes(orgId);
552
+ const orgMembership = userData?.organization_memberships?.[orgId];
553
+ const roleInOrg = orgMembership?.role ?? null;
554
+ return {
555
+ user: query.data ?? null,
556
+ isLoading: isAuthLoading || query.isLoading,
557
+ isError: query.isError,
558
+ error: query.error,
559
+ refetch: query.refetch,
560
+ // Organization access
561
+ hasOrgAccess,
562
+ roleInOrg,
563
+ // Convenience properties
564
+ isAuthenticated,
565
+ role: query.data?.role ?? null,
566
+ organizationId: query.data?.organizationId ?? null,
567
+ sectionId: query.data?.sectionId ?? null,
568
+ permissions: query.data?.permissions ?? [],
569
+ isSuperAdmin
570
+ };
571
+ }
572
+ function useOrg() {
573
+ const { client, orgId, stage, config } = useAxCloudContext();
574
+ const usePublicEndpoint = Boolean(config.apiKey);
575
+ const query = useQuery({
576
+ queryKey: ["axcloud", "organization", orgId, stage, usePublicEndpoint],
577
+ queryFn: async () => {
578
+ if (usePublicEndpoint) {
579
+ return client.get(`/content/public/${orgId}/org`);
580
+ } else {
581
+ return client.get(`/${stage}/api/organizations/${orgId}`);
582
+ }
583
+ },
584
+ staleTime: 1e3 * 60 * 10
585
+ // 10 minutes (org data rarely changes)
586
+ });
587
+ const orgData = query.data;
588
+ const normalizedOrg = orgData ? {
589
+ id: orgData.id || orgData.org_id,
590
+ org_id: orgData.org_id || orgData.id,
591
+ name: orgData.name,
592
+ description: orgData.description,
593
+ branding: orgData.branding || orgData.settings?.theme,
594
+ modules: orgData.modules || [],
595
+ contact: orgData.contact,
596
+ social: orgData.social
597
+ } : null;
598
+ const hasModule = useCallback(
599
+ (module) => {
600
+ const mods = normalizedOrg?.modules || [];
601
+ return mods.includes(module);
602
+ },
603
+ [normalizedOrg?.modules]
604
+ );
605
+ const modules = normalizedOrg?.modules ?? [];
606
+ return {
607
+ org: normalizedOrg,
608
+ orgId,
609
+ isLoading: query.isLoading,
610
+ isError: query.isError,
611
+ error: query.error,
612
+ refetch: query.refetch,
613
+ // Module helpers
614
+ hasModule,
615
+ modules
616
+ };
617
+ }
618
+ function useNews(options = {}) {
619
+ const { client, orgId, isPublicMode } = useAxCloudContext();
620
+ const {
621
+ page = 1,
622
+ pageSize = 20,
623
+ status = "published",
624
+ visibility,
625
+ sectionId,
626
+ search,
627
+ sortBy = "publishedAt",
628
+ sortOrder = "desc",
629
+ publicOnly = false
630
+ } = options;
631
+ const usePublicEndpoint = isPublicMode || publicOnly;
632
+ const query = useQuery({
633
+ queryKey: ["axcloud", "news", orgId, usePublicEndpoint, options],
634
+ queryFn: async () => {
635
+ const endpoint = usePublicEndpoint ? `/content/public/${orgId}/news` : `/content/members/${orgId}/news`;
636
+ return client.get(endpoint, {
637
+ page,
638
+ pageSize,
639
+ status,
640
+ visibility,
641
+ sectionId,
642
+ search,
643
+ sortBy,
644
+ sortOrder
645
+ });
646
+ },
647
+ staleTime: 1e3 * 60 * 5
648
+ // 5 minutes
649
+ });
650
+ return {
651
+ data: query.data?.items ?? [],
652
+ total: query.data?.total ?? 0,
653
+ hasMore: query.data?.hasMore ?? false,
654
+ isLoading: query.isLoading,
655
+ isError: query.isError,
656
+ error: query.error,
657
+ refetch: query.refetch
658
+ };
659
+ }
660
+ var MEMBER_ENDPOINT_TYPES = ["news", "pages", "events"];
661
+ function useContent(contentType, options = {}) {
662
+ const { client, orgId, isPublicMode } = useAxCloudContext();
663
+ const {
664
+ page = 1,
665
+ pageSize = 20,
666
+ status = "published",
667
+ visibility,
668
+ sectionId,
669
+ search,
670
+ sortBy = "createdAt",
671
+ sortOrder = "desc"
672
+ } = options;
673
+ const query = useQuery({
674
+ queryKey: ["axcloud", "content", orgId, contentType, isPublicMode, options],
675
+ queryFn: async () => {
676
+ const useMemberEndpoint = !isPublicMode && MEMBER_ENDPOINT_TYPES.includes(contentType);
677
+ const endpoint = useMemberEndpoint ? `/content/members/${orgId}/${contentType}` : `/content/public/${orgId}/${contentType}`;
678
+ return client.get(endpoint, {
679
+ page,
680
+ pageSize,
681
+ status,
682
+ visibility,
683
+ sectionId,
684
+ search,
685
+ sortBy,
686
+ sortOrder
687
+ });
688
+ },
689
+ staleTime: 1e3 * 60 * 5
690
+ // 5 minutes
691
+ });
692
+ return {
693
+ data: query.data?.items ?? [],
694
+ total: query.data?.total ?? 0,
695
+ hasMore: query.data?.hasMore ?? false,
696
+ isLoading: query.isLoading,
697
+ isError: query.isError,
698
+ error: query.error,
699
+ refetch: query.refetch
700
+ };
701
+ }
702
+ function useContentItem(contentType, idOrSlug, options = {}) {
703
+ const { client, orgId, isPublicMode } = useAxCloudContext();
704
+ const { publicOnly = false } = options;
705
+ const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
706
+ const query = useQuery({
707
+ queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint],
708
+ queryFn: async () => {
709
+ const basePath = useMemberEndpoint ? "members" : "public";
710
+ return client.get(`/content/${basePath}/${orgId}/${contentType}/${idOrSlug}`);
711
+ },
712
+ enabled: !!idOrSlug,
713
+ staleTime: 1e3 * 60 * 5
714
+ // 5 minutes
715
+ });
716
+ return {
717
+ data: query.data ?? null,
718
+ isLoading: query.isLoading,
719
+ isError: query.isError,
720
+ error: query.error,
721
+ refetch: query.refetch
722
+ };
723
+ }
724
+ function useMySection(options = {}) {
725
+ const { includeMembers = true } = options;
726
+ const { isAuthenticated } = useAuth0();
727
+ const { client, orgId, stage } = useAxCloudContext();
728
+ const { user, sectionId, isLoading: isUserLoading } = useUser();
729
+ const query = useQuery({
730
+ queryKey: ["axcloud", "mySection", orgId, sectionId, includeMembers, stage],
731
+ queryFn: async () => {
732
+ if (!sectionId) {
733
+ throw new Error("User is not assigned to a section");
734
+ }
735
+ const section = await client.get(
736
+ `/${stage}/api/sections/${sectionId}`,
737
+ { includeMembers: includeMembers ? "true" : void 0 }
738
+ );
739
+ return section;
740
+ },
741
+ enabled: isAuthenticated && !isUserLoading && !!sectionId,
742
+ staleTime: 1e3 * 60 * 5
743
+ // 5 minutes
744
+ });
745
+ return {
746
+ section: query.data ?? null,
747
+ sectionId,
748
+ members: query.data?.members ?? [],
749
+ memberCount: query.data?.memberCount ?? 0,
750
+ isLoading: isUserLoading || query.isLoading,
751
+ isError: query.isError,
752
+ error: query.error,
753
+ refetch: query.refetch,
754
+ // Helper: Does the user have a section?
755
+ hasSection: !!sectionId,
756
+ // The current user in context
757
+ user
758
+ };
759
+ }
760
+ function useSections() {
761
+ const { client, orgId, stage } = useAxCloudContext();
762
+ const query = useQuery({
763
+ queryKey: ["axcloud", "sections", orgId, stage],
764
+ queryFn: async () => {
765
+ return client.get(`/${stage}/api/organizations/${orgId}/sections`);
766
+ },
767
+ staleTime: 1e3 * 60 * 10
768
+ // 10 minutes
769
+ });
770
+ return {
771
+ sections: query.data ?? [],
772
+ isLoading: query.isLoading,
773
+ isError: query.isError,
774
+ error: query.error,
775
+ refetch: query.refetch
776
+ };
777
+ }
778
+ function useForms(options = {}) {
779
+ const { client, stage } = useAxCloudContext();
780
+ const { formType, status, limit = 50, cursor } = options;
781
+ const query = useQuery({
782
+ queryKey: ["axcloud", "forms", "submissions", stage, options],
783
+ queryFn: async () => {
784
+ const params = { limit };
785
+ if (formType) params.form_type = formType;
786
+ if (status) params.status = status;
787
+ if (cursor) params.cursor = cursor;
788
+ return client.get(`/${stage}/api/admin/forms/submissions`, params);
789
+ },
790
+ staleTime: 1e3 * 30
791
+ // 30 seconds
792
+ });
793
+ return {
794
+ data: query.data?.items ?? [],
795
+ total: query.data?.total ?? 0,
796
+ hasMore: query.data?.hasMore ?? false,
797
+ cursor: query.data?.cursor,
798
+ isLoading: query.isLoading,
799
+ isError: query.isError,
800
+ error: query.error,
801
+ refetch: query.refetch
802
+ };
803
+ }
804
+ function useFormStats(options = {}) {
805
+ const { client, stage } = useAxCloudContext();
806
+ const { days = 30 } = options;
807
+ const query = useQuery({
808
+ queryKey: ["axcloud", "forms", "stats", stage, days],
809
+ queryFn: async () => {
810
+ return client.get(`/${stage}/api/admin/forms/stats`, { days });
811
+ },
812
+ staleTime: 1e3 * 60 * 5
813
+ // 5 minutes
814
+ });
815
+ return {
816
+ stats: query.data?.stats,
817
+ summary: query.data?.summary,
818
+ period: query.data?.period,
819
+ isLoading: query.isLoading,
820
+ isError: query.isError,
821
+ error: query.error,
822
+ refetch: query.refetch
823
+ };
824
+ }
825
+ function useUpdateFormSubmission() {
826
+ const { client, stage } = useAxCloudContext();
827
+ const queryClient = useQueryClient();
828
+ return useMutation({
829
+ mutationFn: async ({
830
+ submissionId,
831
+ status,
832
+ notes
833
+ }) => {
834
+ return client.patch(`/${stage}/api/admin/forms/submissions/${submissionId}`, { status, notes });
835
+ },
836
+ onSuccess: () => {
837
+ queryClient.invalidateQueries({ queryKey: ["axcloud", "forms"] });
838
+ }
839
+ });
840
+ }
841
+ var LINKED_ACCOUNTS_QUERY_KEY = ["axcloud", "linked-accounts"];
842
+ function useLinkedAccounts() {
843
+ const { isAuthenticated } = useAuth();
844
+ const queryClient = useQueryClient();
845
+ const query = useQuery({
846
+ queryKey: LINKED_ACCOUNTS_QUERY_KEY,
847
+ queryFn: async () => {
848
+ const client = getClient();
849
+ return client.get("/api/users/me/identities");
850
+ },
851
+ enabled: isAuthenticated,
852
+ staleTime: 1e3 * 60 * 5
853
+ // 5 minutes
854
+ });
855
+ const linkMutation = useMutation({
856
+ mutationFn: async (provider) => {
857
+ const client = getClient();
858
+ const response = await client.post(
859
+ `/api/users/me/identities/${provider}/link`,
860
+ {}
861
+ );
862
+ if (response.authorization_url) {
863
+ window.location.href = response.authorization_url;
864
+ }
865
+ return response;
866
+ },
867
+ onSuccess: () => {
868
+ queryClient.invalidateQueries({ queryKey: LINKED_ACCOUNTS_QUERY_KEY });
869
+ }
870
+ });
871
+ const unlinkMutation = useMutation({
872
+ mutationFn: async (provider) => {
873
+ const client = getClient();
874
+ return client.delete(
875
+ `/api/users/me/identities/${provider}`
876
+ );
877
+ },
878
+ onSuccess: () => {
879
+ queryClient.invalidateQueries({ queryKey: LINKED_ACCOUNTS_QUERY_KEY });
880
+ }
881
+ });
882
+ return {
883
+ identities: query.data?.identities ?? [],
884
+ availableProviders: query.data?.available_providers ?? [],
885
+ canUnlink: query.data?.can_unlink ?? false,
886
+ isLoading: query.isLoading,
887
+ error: query.error,
888
+ linkAccount: linkMutation.mutate,
889
+ unlinkAccount: unlinkMutation.mutate,
890
+ isLinking: linkMutation.isPending,
891
+ isUnlinking: unlinkMutation.isPending,
892
+ refetch: query.refetch
893
+ };
894
+ }
895
+ function useBranding() {
896
+ const { client, orgId } = useAxCloudContext();
897
+ const query = useQuery({
898
+ queryKey: ["axcloud", "media", "branding", orgId],
899
+ queryFn: async () => {
900
+ return client.get(`/media/public/${orgId}/branding`);
901
+ },
902
+ staleTime: 1e3 * 60 * 30,
903
+ // 30 minutes (logo URL valid for 1 hour)
904
+ gcTime: 1e3 * 60 * 55
905
+ // Garbage collect before URL expires
906
+ });
907
+ return {
908
+ branding: query.data?.branding ?? null,
909
+ logoUrl: query.data?.branding?.logoUrl ?? null,
910
+ organizationName: query.data?.name ?? null,
911
+ isLoading: query.isLoading,
912
+ isError: query.isError,
913
+ error: query.error,
914
+ refetch: query.refetch
915
+ };
916
+ }
917
+ function useLogo() {
918
+ const { client, orgId } = useAxCloudContext();
919
+ const query = useQuery({
920
+ queryKey: ["axcloud", "media", "logo", orgId],
921
+ queryFn: async () => {
922
+ return client.get(`/media/public/${orgId}/logo`);
923
+ },
924
+ staleTime: 1e3 * 60 * 30,
925
+ // 30 minutes
926
+ gcTime: 1e3 * 60 * 55
927
+ // Garbage collect before URL expires
928
+ });
929
+ return {
930
+ logoUrl: query.data?.url ?? null,
931
+ expiresIn: query.data?.expiresIn ?? null,
932
+ isLoading: query.isLoading,
933
+ isError: query.isError,
934
+ error: query.error,
935
+ refetch: query.refetch
936
+ };
937
+ }
938
+ function useAvatar(userId) {
939
+ const { client, orgId } = useAxCloudContext();
940
+ const query = useQuery({
941
+ queryKey: ["axcloud", "media", "avatar", orgId, userId],
942
+ queryFn: async () => {
943
+ return client.get(`/media/public/${orgId}/avatar/${userId}`);
944
+ },
945
+ enabled: !!userId,
946
+ staleTime: 1e3 * 60 * 30,
947
+ gcTime: 1e3 * 60 * 55,
948
+ retry: false
949
+ // Don't retry if avatar doesn't exist
950
+ });
951
+ return {
952
+ avatarUrl: query.data?.url ?? null,
953
+ isLoading: query.isLoading,
954
+ isError: query.isError,
955
+ error: query.error,
956
+ refetch: query.refetch
957
+ };
958
+ }
959
+ function useMediaList(type = "media", limit = 50) {
960
+ const { client, orgId } = useAxCloudContext();
961
+ const query = useQuery({
962
+ queryKey: ["axcloud", "media", "list", orgId, type, limit],
963
+ queryFn: async () => {
964
+ return client.get(`/media/public/${orgId}/list`, {
965
+ type,
966
+ limit
967
+ });
968
+ },
969
+ staleTime: 1e3 * 60 * 5
970
+ // 5 minutes
971
+ });
972
+ return {
973
+ items: query.data?.items ?? [],
974
+ count: query.data?.count ?? 0,
975
+ isLoading: query.isLoading,
976
+ isError: query.isError,
977
+ error: query.error,
978
+ refetch: query.refetch
979
+ };
980
+ }
981
+ function useMedia(mediaId) {
982
+ const { client, orgId } = useAxCloudContext();
983
+ const query = useQuery({
984
+ queryKey: ["axcloud", "media", "file", orgId, mediaId],
985
+ queryFn: async () => {
986
+ return client.get(`/media/public/${orgId}/media/${mediaId}`);
987
+ },
988
+ enabled: !!mediaId,
989
+ staleTime: 1e3 * 60 * 30,
990
+ gcTime: 1e3 * 60 * 55
991
+ });
992
+ return {
993
+ mediaUrl: query.data?.url ?? null,
994
+ expiresIn: query.data?.expiresIn ?? null,
995
+ isLoading: query.isLoading,
996
+ isError: query.isError,
997
+ error: query.error,
998
+ refetch: query.refetch
999
+ };
1000
+ }
1001
+ function LoginButton({
1002
+ children = "Log in",
1003
+ returnTo,
1004
+ className,
1005
+ style
1006
+ }) {
1007
+ const { login, isLoading } = useAuth();
1008
+ const handleClick = () => {
1009
+ login({ returnTo });
1010
+ };
1011
+ return /* @__PURE__ */ jsx(
1012
+ "button",
1013
+ {
1014
+ onClick: handleClick,
1015
+ disabled: isLoading,
1016
+ className,
1017
+ style,
1018
+ type: "button",
1019
+ children: isLoading ? "Loading..." : children
1020
+ }
1021
+ );
1022
+ }
1023
+ function LogoutButton({
1024
+ children = "Log out",
1025
+ returnTo,
1026
+ className,
1027
+ style
1028
+ }) {
1029
+ const { logout } = useAuth();
1030
+ const handleClick = () => {
1031
+ logout({ returnTo });
1032
+ };
1033
+ return /* @__PURE__ */ jsx(
1034
+ "button",
1035
+ {
1036
+ onClick: handleClick,
1037
+ className,
1038
+ style,
1039
+ type: "button",
1040
+ children
1041
+ }
1042
+ );
1043
+ }
1044
+ function ProtectedRoute({
1045
+ children,
1046
+ roles,
1047
+ loadingComponent,
1048
+ unauthenticatedComponent,
1049
+ unauthorizedComponent,
1050
+ redirectToLogin = false,
1051
+ returnTo
1052
+ }) {
1053
+ const { isAuthenticated, isLoading: isAuthLoading, login } = useAuth();
1054
+ const { user, role, isLoading: isUserLoading } = useUser();
1055
+ const isLoading = isAuthLoading || isAuthenticated && isUserLoading;
1056
+ if (isLoading) {
1057
+ return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent ?? /* @__PURE__ */ jsx(DefaultLoadingComponent, {}) });
1058
+ }
1059
+ if (!isAuthenticated) {
1060
+ if (redirectToLogin) {
1061
+ login({ returnTo: returnTo || window.location.pathname });
1062
+ return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent ?? /* @__PURE__ */ jsx(DefaultLoadingComponent, {}) });
1063
+ }
1064
+ return /* @__PURE__ */ jsx(Fragment, { children: unauthenticatedComponent ?? /* @__PURE__ */ jsx(DefaultUnauthenticatedComponent, {}) });
1065
+ }
1066
+ if (roles && role) {
1067
+ const requiredRoles = Array.isArray(roles) ? roles : [roles];
1068
+ const hasRequiredRole = requiredRoles.includes(role);
1069
+ if (!hasRequiredRole) {
1070
+ return /* @__PURE__ */ jsx(Fragment, { children: unauthorizedComponent ?? /* @__PURE__ */ jsx(DefaultUnauthorizedComponent, {}) });
1071
+ }
1072
+ }
1073
+ return /* @__PURE__ */ jsx(Fragment, { children });
1074
+ }
1075
+ function DefaultLoadingComponent() {
1076
+ return /* @__PURE__ */ jsx("div", { style: { padding: "20px", textAlign: "center" }, children: "Loading..." });
1077
+ }
1078
+ function DefaultUnauthenticatedComponent() {
1079
+ return /* @__PURE__ */ jsx("div", { style: { padding: "20px", textAlign: "center" }, children: /* @__PURE__ */ jsx("p", { children: "Please log in to view this content." }) });
1080
+ }
1081
+ function DefaultUnauthorizedComponent() {
1082
+ return /* @__PURE__ */ jsx("div", { style: { padding: "20px", textAlign: "center" }, children: /* @__PURE__ */ jsx("p", { children: "You don't have permission to view this content." }) });
1083
+ }
1084
+ function ModuleGate({
1085
+ module,
1086
+ children,
1087
+ fallback = null,
1088
+ requireAll = false
1089
+ }) {
1090
+ const { hasModule, isLoading } = useOrg();
1091
+ if (isLoading) {
1092
+ return null;
1093
+ }
1094
+ const requiredModules = Array.isArray(module) ? module : [module];
1095
+ const hasAccess = requireAll ? requiredModules.every((m) => hasModule(m)) : requiredModules.some((m) => hasModule(m));
1096
+ if (!hasAccess) {
1097
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
1098
+ }
1099
+ return /* @__PURE__ */ jsx(Fragment, { children });
1100
+ }
1101
+ function useModuleAccess() {
1102
+ const { hasModule, modules, isLoading } = useOrg();
1103
+ return {
1104
+ hasModule,
1105
+ modules,
1106
+ isLoading
1107
+ };
1108
+ }
1109
+ var SUPPORTED_OAUTH_PROVIDERS = ["google", "microsoft", "apple"];
1110
+ function isSupportedOAuthProvider(provider) {
1111
+ return SUPPORTED_OAUTH_PROVIDERS.includes(provider);
1112
+ }
1113
+ var ProviderIcons = {
1114
+ google: ({ className }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className, fill: "currentColor", children: [
1115
+ /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }),
1116
+ /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }),
1117
+ /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }),
1118
+ /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
1119
+ ] }),
1120
+ microsoft: ({ className }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className, children: [
1121
+ /* @__PURE__ */ jsx("path", { fill: "#F25022", d: "M1 1h10v10H1z" }),
1122
+ /* @__PURE__ */ jsx("path", { fill: "#00A4EF", d: "M1 13h10v10H1z" }),
1123
+ /* @__PURE__ */ jsx("path", { fill: "#7FBA00", d: "M13 1h10v10H13z" }),
1124
+ /* @__PURE__ */ jsx("path", { fill: "#FFB900", d: "M13 13h10v10H13z" })
1125
+ ] }),
1126
+ apple: ({ className }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className, fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" }) }),
1127
+ email: ({ className }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className, fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1128
+ /* @__PURE__ */ jsx("path", { d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" }),
1129
+ /* @__PURE__ */ jsx("polyline", { points: "22,6 12,13 2,6" })
1130
+ ] })
1131
+ };
1132
+ function LinkedAccountsList({
1133
+ providers,
1134
+ showConnectButtons = true,
1135
+ className,
1136
+ onUnlink,
1137
+ onLinkInitiated,
1138
+ renderIdentity,
1139
+ renderAvailableProvider
1140
+ }) {
1141
+ const {
1142
+ identities,
1143
+ availableProviders,
1144
+ canUnlink,
1145
+ isLoading,
1146
+ error,
1147
+ linkAccount,
1148
+ unlinkAccount
1149
+ } = useLinkedAccounts();
1150
+ const filteredIdentities = providers ? identities.filter(
1151
+ (i) => providers.some(
1152
+ (p) => i.provider.toLowerCase().includes(p) || i.provider_icon === p
1153
+ )
1154
+ ) : identities;
1155
+ const filteredAvailableProviders = providers ? availableProviders.filter(
1156
+ (p) => providers.some(
1157
+ (provider) => p.provider.toLowerCase().includes(provider) || p.icon === provider
1158
+ )
1159
+ ) : availableProviders;
1160
+ const handleUnlink = (provider) => {
1161
+ unlinkAccount(provider);
1162
+ onUnlink?.(provider);
1163
+ };
1164
+ const handleLink = (provider) => {
1165
+ onLinkInitiated?.(provider);
1166
+ linkAccount(provider);
1167
+ };
1168
+ if (isLoading) {
1169
+ return /* @__PURE__ */ jsx("div", { className: `axcloud-linked-accounts__loading ${className || ""}`, children: "Loading linked accounts..." });
1170
+ }
1171
+ if (error) {
1172
+ return /* @__PURE__ */ jsx("div", { className: `axcloud-linked-accounts__error ${className || ""}`, children: "Failed to load linked accounts. Please try again." });
1173
+ }
1174
+ const getIcon = (iconName, muted = false) => {
1175
+ const IconComponent = ProviderIcons[iconName] || ProviderIcons.email;
1176
+ const iconClass = muted ? "axcloud-linked-accounts__icon axcloud-linked-accounts__icon--muted" : "axcloud-linked-accounts__icon";
1177
+ return /* @__PURE__ */ jsx(IconComponent, { className: iconClass });
1178
+ };
1179
+ return /* @__PURE__ */ jsxs("div", { className: `axcloud-linked-accounts ${className || ""}`, children: [
1180
+ filteredIdentities.map((identity) => {
1181
+ if (renderIdentity) {
1182
+ return renderIdentity(identity, () => handleUnlink(identity.provider));
1183
+ }
1184
+ return /* @__PURE__ */ jsxs("div", { className: "axcloud-linked-accounts__item", children: [
1185
+ /* @__PURE__ */ jsxs("div", { className: "axcloud-linked-accounts__info", children: [
1186
+ getIcon(identity.provider_icon),
1187
+ /* @__PURE__ */ jsxs("div", { children: [
1188
+ /* @__PURE__ */ jsxs("div", { className: "axcloud-linked-accounts__name-row", children: [
1189
+ /* @__PURE__ */ jsx("span", { className: "axcloud-linked-accounts__provider-name", children: identity.provider_display_name }),
1190
+ identity.is_primary && /* @__PURE__ */ jsx("span", { className: "axcloud-linked-accounts__badge", children: "Primary" })
1191
+ ] }),
1192
+ identity.profile_data?.email && /* @__PURE__ */ jsx("div", { className: "axcloud-linked-accounts__email", children: identity.profile_data.email })
1193
+ ] })
1194
+ ] }),
1195
+ /* @__PURE__ */ jsxs("div", { className: "axcloud-linked-accounts__actions", children: [
1196
+ /* @__PURE__ */ jsxs("span", { className: "axcloud-linked-accounts__connected", children: [
1197
+ /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }),
1198
+ "Connected"
1199
+ ] }),
1200
+ canUnlink && !identity.is_primary && /* @__PURE__ */ jsx(
1201
+ "button",
1202
+ {
1203
+ onClick: () => handleUnlink(identity.provider),
1204
+ className: "axcloud-linked-accounts__button axcloud-linked-accounts__button--disconnect",
1205
+ children: "Disconnect"
1206
+ }
1207
+ )
1208
+ ] })
1209
+ ] }, `${identity.provider}-${identity.user_id}`);
1210
+ }),
1211
+ showConnectButtons && filteredAvailableProviders.map((provider) => {
1212
+ if (renderAvailableProvider) {
1213
+ return renderAvailableProvider(provider, () => {
1214
+ if (isSupportedOAuthProvider(provider.provider)) {
1215
+ handleLink(provider.provider);
1216
+ }
1217
+ });
1218
+ }
1219
+ return /* @__PURE__ */ jsxs("div", { className: "axcloud-linked-accounts__available", children: [
1220
+ /* @__PURE__ */ jsxs("div", { className: "axcloud-linked-accounts__info", children: [
1221
+ getIcon(provider.icon, true),
1222
+ /* @__PURE__ */ jsxs("div", { children: [
1223
+ /* @__PURE__ */ jsx("span", { className: "axcloud-linked-accounts__provider-name", children: provider.display_name }),
1224
+ /* @__PURE__ */ jsx("div", { className: "axcloud-linked-accounts__email", children: "Not connected" })
1225
+ ] })
1226
+ ] }),
1227
+ /* @__PURE__ */ jsx(
1228
+ "button",
1229
+ {
1230
+ onClick: () => {
1231
+ if (isSupportedOAuthProvider(provider.provider)) {
1232
+ handleLink(provider.provider);
1233
+ }
1234
+ },
1235
+ className: "axcloud-linked-accounts__button axcloud-linked-accounts__button--connect",
1236
+ children: "Connect"
1237
+ }
1238
+ )
1239
+ ] }, provider.provider);
1240
+ })
1241
+ ] });
1242
+ }
1243
+
1244
+ export { AxCloudClient, AxCloudError, AxCloudProvider, LinkedAccountsList, LoginButton, LogoutButton, ModuleGate, ProtectedRoute, createClient, createFormHelper, getClient, isAxCloudError, submitForm, useAuth, useAvatar, useAxCloudContext, useBranding, useContent, useContentItem, useFormStats, useForms, useLinkedAccounts, useLogo, useMedia, useMediaList, useModuleAccess, useMySection, useNews, useOrg, useSections, useUpdateFormSubmission, useUser, userHasAllPermissions, userHasAnyPermission, userHasPermission };
1245
+ //# sourceMappingURL=index.mjs.map
1246
+ //# sourceMappingURL=index.mjs.map