@geekapps/auth-nextjs 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,745 @@
1
+ "use client";
2
+
3
+ // src/client.tsx
4
+ import {
5
+ createContext,
6
+ useCallback,
7
+ useContext,
8
+ useEffect,
9
+ useMemo,
10
+ useState
11
+ } from "react";
12
+
13
+ // src/actions.ts
14
+ import { cookies } from "next/headers";
15
+ function env(name) {
16
+ const value = process.env[name];
17
+ return value && value.trim().length > 0 ? value : void 0;
18
+ }
19
+ function normalizeBaseUrl(url) {
20
+ return url.replace(/\/$/, "");
21
+ }
22
+ function resolveIssuer() {
23
+ return normalizeBaseUrl(
24
+ env("GEEKAPPS_AUTH_ISSUER") ?? env("GEEKAPPS_AUTH_API_URL") ?? "http://localhost:3020"
25
+ );
26
+ }
27
+ function getServerClientHeaders() {
28
+ const clientId = env("GEEKAPPS_AUTH_CLIENT_ID");
29
+ const clientSecret = env("GEEKAPPS_AUTH_CLIENT_SECRET");
30
+ return clientId && clientSecret ? {
31
+ "x-geekapps-client-id": clientId,
32
+ "x-geekapps-client-secret": clientSecret
33
+ } : {};
34
+ }
35
+ function hashClientId(clientId) {
36
+ let h = 5381;
37
+ for (let i = 0; i < clientId.length; i++) {
38
+ h = (h << 5) + h ^ clientId.charCodeAt(i) & 255;
39
+ h = h >>> 0;
40
+ }
41
+ return h.toString(16).padStart(8, "0");
42
+ }
43
+ function deriveCookiePrefix() {
44
+ const clientId = env("GEEKAPPS_AUTH_CLIENT_ID") ?? "";
45
+ if (!clientId) return "gk";
46
+ return `gk_${hashClientId(clientId)}`;
47
+ }
48
+ function decodeMeta(value) {
49
+ try {
50
+ const m = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
51
+ return m.id ? m : null;
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+ async function getCookieNames() {
57
+ const prefix = deriveCookiePrefix();
58
+ return {
59
+ active: `${prefix}_active`,
60
+ count: `${prefix}_count`,
61
+ activeOrganizationId: `${prefix}_ao`,
62
+ slotMeta: (n) => `${prefix}_m${n}`,
63
+ slotAt: (n) => `${prefix}_at${n}`,
64
+ slotRt: (n) => `${prefix}_rt${n}`
65
+ };
66
+ }
67
+ async function getActiveAccessToken() {
68
+ const cookieStore = await cookies();
69
+ const cn = await getCookieNames();
70
+ const raw = cookieStore.get(cn.active)?.value;
71
+ const activeIdx = raw ? Number.parseInt(raw, 10) : 0;
72
+ const countRaw = cookieStore.get(cn.count)?.value;
73
+ const count = countRaw ? Number.parseInt(countRaw, 10) : 0;
74
+ if (count === 0) return null;
75
+ const idx = activeIdx >= 1 && activeIdx <= count ? activeIdx : 1;
76
+ return cookieStore.get(cn.slotAt(idx))?.value ?? null;
77
+ }
78
+ async function getActiveRefreshToken() {
79
+ const cookieStore = await cookies();
80
+ const cn = await getCookieNames();
81
+ const raw = cookieStore.get(cn.active)?.value;
82
+ const activeIdx = raw ? Number.parseInt(raw, 10) : 0;
83
+ const countRaw = cookieStore.get(cn.count)?.value;
84
+ const count = countRaw ? Number.parseInt(countRaw, 10) : 0;
85
+ if (count === 0) return null;
86
+ const idx = activeIdx >= 1 && activeIdx <= count ? activeIdx : 1;
87
+ return cookieStore.get(cn.slotRt(idx))?.value ?? null;
88
+ }
89
+ async function refreshAndSaveTokens() {
90
+ const refreshToken = await getActiveRefreshToken();
91
+ const clientId = env("GEEKAPPS_AUTH_CLIENT_ID") ?? "";
92
+ const clientSecret = env("GEEKAPPS_AUTH_CLIENT_SECRET") ?? "";
93
+ if (!refreshToken || !clientId) return null;
94
+ const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
95
+ const response = await fetch(`${resolveIssuer()}/auth/refresh`, {
96
+ method: "POST",
97
+ headers: {
98
+ "content-type": "application/x-www-form-urlencoded",
99
+ authorization: `Basic ${basicAuth}`
100
+ },
101
+ body: new URLSearchParams({ grant_type: "refresh_token", refresh_token: refreshToken }),
102
+ cache: "no-store"
103
+ });
104
+ if (!response.ok) return null;
105
+ const data = await response.json().catch(() => null);
106
+ if (!data) return null;
107
+ const newAccessToken = data.accessToken ?? data.access_token;
108
+ const newRefreshToken = data.refreshToken ?? data.refresh_token;
109
+ if (!newAccessToken) return null;
110
+ const cookieStore = await cookies();
111
+ const cn = await getCookieNames();
112
+ const raw = cookieStore.get(cn.active)?.value;
113
+ const activeIdx = raw ? Number.parseInt(raw, 10) : 1;
114
+ const opts = {
115
+ httpOnly: true,
116
+ secure: process.env.NODE_ENV === "production",
117
+ sameSite: "lax",
118
+ path: "/",
119
+ maxAge: 60 * 60 * 24 * 30
120
+ };
121
+ cookieStore.set(cn.slotAt(activeIdx), newAccessToken, opts);
122
+ if (newRefreshToken) cookieStore.set(cn.slotRt(activeIdx), newRefreshToken, opts);
123
+ cookieStore.set(`${deriveCookiePrefix()}_tp`, newAccessToken, {
124
+ httpOnly: false,
125
+ secure: process.env.NODE_ENV === "production",
126
+ sameSite: "lax",
127
+ path: "/",
128
+ maxAge: 60 * 60 * 24 * 30
129
+ });
130
+ return newAccessToken;
131
+ }
132
+ async function authFetch(path) {
133
+ let accessToken = await getActiveAccessToken();
134
+ if (!accessToken) throw new Error("Not authenticated");
135
+ const issuer = resolveIssuer();
136
+ const doFetch = (token) => fetch(`${issuer}${path}`, {
137
+ headers: {
138
+ authorization: `Bearer ${token}`,
139
+ ...getServerClientHeaders()
140
+ },
141
+ cache: "no-store"
142
+ });
143
+ let response = await doFetch(accessToken);
144
+ if (response.status === 401) {
145
+ const newToken = await refreshAndSaveTokens();
146
+ if (!newToken) throw new Error("Session expired");
147
+ response = await doFetch(newToken);
148
+ }
149
+ if (!response.ok) {
150
+ const err = await response.json().catch(() => null);
151
+ throw new Error(err?.error_description ?? err?.error ?? err?.message ?? `Auth error ${response.status}`);
152
+ }
153
+ if (response.status === 204) return null;
154
+ return response.json();
155
+ }
156
+ async function getMe() {
157
+ try {
158
+ const data = await authFetch("/auth/me");
159
+ if (!data) return { user: null };
160
+ if (typeof data === "object" && "user" in data) return data;
161
+ return { user: data };
162
+ } catch {
163
+ return { user: null };
164
+ }
165
+ }
166
+ async function getAccounts() {
167
+ const cookieStore = await cookies();
168
+ const cn = await getCookieNames();
169
+ const countRaw = cookieStore.get(cn.count)?.value;
170
+ const count = countRaw ? Number.parseInt(countRaw, 10) : 0;
171
+ const activeRaw = cookieStore.get(cn.active)?.value;
172
+ const activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 0;
173
+ const accounts = [];
174
+ for (let i = 1; i <= count; i++) {
175
+ const at = cookieStore.get(cn.slotAt(i))?.value;
176
+ if (!at) continue;
177
+ const meta = decodeMeta(cookieStore.get(cn.slotMeta(i))?.value ?? "");
178
+ if (!meta) continue;
179
+ accounts.push({
180
+ id: meta.id,
181
+ sessionId: meta.sid ?? meta.id,
182
+ isActive: i === activeIdx,
183
+ user: {
184
+ id: meta.id,
185
+ name: meta.n ?? null,
186
+ email: meta.e ?? null,
187
+ imageUrl: meta.p ?? null,
188
+ phone: null
189
+ }
190
+ });
191
+ }
192
+ return { accounts };
193
+ }
194
+ async function getOrganizations() {
195
+ try {
196
+ const cookieStore = await cookies();
197
+ const cn = await getCookieNames();
198
+ const activeOrgId = cookieStore.get(cn.activeOrganizationId)?.value ?? null;
199
+ const data = await authFetch("/organizations");
200
+ const organizations = Array.isArray(data) ? data : data.organizations;
201
+ const resolvedOrgId = activeOrgId ?? organizations[0]?.id ?? null;
202
+ return { organizations, currentOrgId: resolvedOrgId };
203
+ } catch (err) {
204
+ console.error("[getOrganizations] error:", err);
205
+ return { organizations: [] };
206
+ }
207
+ }
208
+
209
+ // src/client.tsx
210
+ import { jsx } from "react/jsx-runtime";
211
+ function normalizeBasePath(basePath) {
212
+ return basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
213
+ }
214
+ function buildUrl(basePath, path) {
215
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
216
+ return `${normalizeBasePath(basePath)}${normalizedPath}`;
217
+ }
218
+ async function parseError(response) {
219
+ const data = await response.json().catch(() => null);
220
+ return data?.error_description ?? data?.error ?? data?.message ?? `Request failed with status ${response.status}`;
221
+ }
222
+ function redirectTo(path) {
223
+ window.location.assign(path);
224
+ }
225
+ function isMouseEvent(value) {
226
+ return Boolean(value && typeof value === "object" && "preventDefault" in value);
227
+ }
228
+ function normalizeSignInOptions(input) {
229
+ if (!input) return void 0;
230
+ if (isMouseEvent(input)) {
231
+ input.preventDefault();
232
+ return void 0;
233
+ }
234
+ return input;
235
+ }
236
+ async function clientRequest(path, options = {}, basePath = "/api/auth") {
237
+ const response = await fetch(buildUrl(basePath, path), {
238
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
239
+ credentials: "include",
240
+ headers: options.body === void 0 ? void 0 : {
241
+ "content-type": "application/json"
242
+ },
243
+ method: options.method ?? "GET"
244
+ });
245
+ if (!response.ok) {
246
+ throw new Error(await parseError(response));
247
+ }
248
+ if (response.status === 204) {
249
+ return null;
250
+ }
251
+ return await response.json();
252
+ }
253
+ async function toStandaloneAuthResult(fn) {
254
+ try {
255
+ return {
256
+ success: true,
257
+ data: await fn()
258
+ };
259
+ } catch (error) {
260
+ return {
261
+ success: false,
262
+ error: error instanceof Error ? error.message : "Auth request failed"
263
+ };
264
+ }
265
+ }
266
+ async function loginWithPassword(params, options) {
267
+ return toStandaloneAuthResult(async () => {
268
+ const data = await clientRequest(
269
+ "/login/password",
270
+ {
271
+ body: params,
272
+ method: "POST"
273
+ },
274
+ options?.basePath
275
+ );
276
+ if (params.redirectTo ?? data.redirectTo) {
277
+ redirectTo(params.redirectTo ?? data.redirectTo);
278
+ }
279
+ return data;
280
+ });
281
+ }
282
+ async function registerWithPassword(params, options) {
283
+ return toStandaloneAuthResult(async () => {
284
+ const data = await clientRequest(
285
+ "/register/password",
286
+ {
287
+ body: params,
288
+ method: "POST"
289
+ },
290
+ options?.basePath
291
+ );
292
+ if (params.redirectTo) {
293
+ redirectTo(params.redirectTo);
294
+ }
295
+ return data;
296
+ });
297
+ }
298
+ function startGoogleLogin(params, options) {
299
+ const basePath = options?.basePath ?? "/api/auth";
300
+ const url = new URL(buildUrl(basePath, "/login/google"), window.location.origin);
301
+ if (params?.callbackUrl) {
302
+ url.searchParams.set("callbackUrl", params.callbackUrl);
303
+ }
304
+ if (params?.redirectTo) {
305
+ url.searchParams.set("redirectTo", params.redirectTo);
306
+ }
307
+ if (params?.authorizationFlowId) {
308
+ url.searchParams.set("flow_id", params.authorizationFlowId);
309
+ }
310
+ redirectTo(url.toString());
311
+ }
312
+ async function requestPasswordlessLink(params, options) {
313
+ return toStandaloneAuthResult(
314
+ () => clientRequest(
315
+ "/passwordless/link",
316
+ {
317
+ body: params,
318
+ method: "POST"
319
+ },
320
+ options?.basePath
321
+ )
322
+ );
323
+ }
324
+ var GeekappsAuthContext = createContext(null);
325
+ function GeekappsAuthProvider({
326
+ children,
327
+ basePath = "/api/auth",
328
+ initialUser = null,
329
+ initialOrganizations = [],
330
+ initialCurrentOrgId = null
331
+ }) {
332
+ const [user, setUser] = useState(initialUser);
333
+ const [isLoading, setIsLoading] = useState(true);
334
+ const [accounts, setAccounts] = useState([]);
335
+ const [isLoadingAccounts, setIsLoadingAccounts] = useState(true);
336
+ const [organizations, setOrganizations] = useState(initialOrganizations);
337
+ const [currentOrgId, setCurrentOrgId] = useState(initialCurrentOrgId);
338
+ const [isLoadingOrganizations, setIsLoadingOrganizations] = useState(true);
339
+ const request = useCallback(
340
+ async (path, options = {}) => {
341
+ const response = await fetch(buildUrl(basePath, path), {
342
+ method: options.method ?? "GET",
343
+ credentials: "include",
344
+ headers: options.body === void 0 ? void 0 : {
345
+ "content-type": "application/json"
346
+ },
347
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
348
+ });
349
+ if (!response.ok) {
350
+ throw new Error(await parseError(response));
351
+ }
352
+ if (response.status === 204) {
353
+ return null;
354
+ }
355
+ return await response.json();
356
+ },
357
+ [basePath]
358
+ );
359
+ const refreshUser = useCallback(async () => {
360
+ setIsLoading(true);
361
+ try {
362
+ const { user: u } = await getMe();
363
+ setUser(u);
364
+ } catch {
365
+ setUser(null);
366
+ } finally {
367
+ setIsLoading(false);
368
+ }
369
+ }, []);
370
+ const refreshAccounts = useCallback(async () => {
371
+ setIsLoadingAccounts(true);
372
+ try {
373
+ const { accounts: a } = await getAccounts();
374
+ setAccounts(a);
375
+ } catch {
376
+ setAccounts([]);
377
+ } finally {
378
+ setIsLoadingAccounts(false);
379
+ }
380
+ }, []);
381
+ const refreshOrganizations = useCallback(async () => {
382
+ setIsLoadingOrganizations(true);
383
+ try {
384
+ const { organizations: orgs, currentOrgId: nextCurrentOrgId } = await getOrganizations();
385
+ setOrganizations(orgs);
386
+ setCurrentOrgId((current) => {
387
+ if (nextCurrentOrgId !== void 0) return nextCurrentOrgId ?? null;
388
+ if (current && orgs.some((org) => org.id === current)) return current;
389
+ return orgs[0]?.id ?? null;
390
+ });
391
+ } catch {
392
+ setOrganizations([]);
393
+ setCurrentOrgId(null);
394
+ } finally {
395
+ setIsLoadingOrganizations(false);
396
+ }
397
+ }, []);
398
+ useEffect(() => {
399
+ void refreshUser();
400
+ void refreshAccounts();
401
+ void refreshOrganizations();
402
+ }, [refreshAccounts, refreshOrganizations, refreshUser]);
403
+ const currentOrg = useMemo(
404
+ () => organizations.find((organization) => organization.id === currentOrgId) ?? null,
405
+ [currentOrgId, organizations]
406
+ );
407
+ const setCurrentOrg = useCallback(
408
+ async (organizationId) => {
409
+ await request("/organizations/active", {
410
+ method: "POST",
411
+ body: { organizationId }
412
+ });
413
+ setCurrentOrgId(organizationId);
414
+ },
415
+ [request]
416
+ );
417
+ const signIn = useCallback(
418
+ async (input) => {
419
+ const options = normalizeSignInOptions(input);
420
+ const url = new URL(buildUrl(basePath, "/sign-in"), window.location.origin);
421
+ if (options?.redirectTo) url.searchParams.set("redirectTo", options.redirectTo);
422
+ if (options?.authorizationFlowId) url.searchParams.set("flow_id", options.authorizationFlowId);
423
+ redirectTo(url.toString());
424
+ },
425
+ [basePath]
426
+ );
427
+ const signUp = useCallback(
428
+ async (input) => {
429
+ const options = normalizeSignInOptions(input);
430
+ const url = new URL(buildUrl(basePath, "/sign-up"), window.location.origin);
431
+ if (options?.redirectTo) url.searchParams.set("redirectTo", options.redirectTo);
432
+ if (options?.authorizationFlowId) url.searchParams.set("flow_id", options.authorizationFlowId);
433
+ redirectTo(url.toString());
434
+ },
435
+ [basePath]
436
+ );
437
+ const addAccount = useCallback(
438
+ async (input) => {
439
+ const options = normalizeSignInOptions(input);
440
+ const url = new URL(buildUrl(basePath, "/add-account"), window.location.origin);
441
+ if (options?.redirectTo) url.searchParams.set("redirectTo", options.redirectTo);
442
+ redirectTo(url.toString());
443
+ },
444
+ [basePath]
445
+ );
446
+ const signOut = useCallback(async () => {
447
+ await request("/sign-out", { method: "POST" });
448
+ setUser(null);
449
+ await refreshAccounts();
450
+ }, [refreshAccounts, request]);
451
+ const signOutAll = useCallback(async () => {
452
+ await request("/sign-out-all", { method: "POST" });
453
+ setUser(null);
454
+ setAccounts([]);
455
+ }, [request]);
456
+ const switchAccount = useCallback(
457
+ async (sessionId, options) => {
458
+ await request("/accounts/switch", {
459
+ method: "POST",
460
+ body: { sessionId }
461
+ });
462
+ await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);
463
+ if (options?.redirectTo) redirectTo(options.redirectTo);
464
+ },
465
+ [refreshAccounts, refreshOrganizations, refreshUser, request]
466
+ );
467
+ async function toAuthResult(fn) {
468
+ try {
469
+ return { success: true, data: await fn() };
470
+ } catch (error) {
471
+ return { success: false, error: error instanceof Error ? error.message : "Unexpected error" };
472
+ }
473
+ }
474
+ const value = useMemo(
475
+ () => ({
476
+ basePath,
477
+ user,
478
+ isLoading,
479
+ accounts,
480
+ isLoadingAccounts,
481
+ organizations,
482
+ currentOrg,
483
+ currentOrgId,
484
+ isLoadingOrganizations,
485
+ request,
486
+ signIn,
487
+ signUp,
488
+ addAccount,
489
+ signOut,
490
+ signOutAll,
491
+ refreshUser,
492
+ refreshAccounts,
493
+ switchAccount,
494
+ loginWithPassword: (params) => toAuthResult(async () => {
495
+ const data = await request("/login/password", { method: "POST", body: params });
496
+ await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);
497
+ if (params.redirectTo ?? data.redirectTo) redirectTo(params.redirectTo ?? data.redirectTo);
498
+ return data;
499
+ }),
500
+ registerWithPassword: (params) => toAuthResult(async () => {
501
+ const data = await request("/register/password", { method: "POST", body: params });
502
+ await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);
503
+ if (params.redirectTo) redirectTo(params.redirectTo);
504
+ return data;
505
+ }),
506
+ startGoogleLogin: (params) => {
507
+ const url = new URL(buildUrl(basePath, "/login/google"), window.location.origin);
508
+ if (params?.callbackUrl) url.searchParams.set("callbackUrl", params.callbackUrl);
509
+ if (params?.redirectTo) url.searchParams.set("redirectTo", params.redirectTo);
510
+ if (params?.authorizationFlowId) url.searchParams.set("flow_id", params.authorizationFlowId);
511
+ redirectTo(url.toString());
512
+ },
513
+ requestPasswordlessLink: (params) => toAuthResult(() => request("/passwordless/link", { method: "POST", body: params })),
514
+ refreshOrganizations,
515
+ setCurrentOrg,
516
+ createOrganization: (input) => toAuthResult(async () => {
517
+ const organization = await request("/organizations", { method: "POST", body: input });
518
+ await refreshOrganizations();
519
+ setCurrentOrgId(organization.id);
520
+ return organization;
521
+ }),
522
+ updateOrganization: (id, input) => toAuthResult(async () => {
523
+ const organization = await request(`/organizations/${id}`, { method: "PATCH", body: input });
524
+ await refreshOrganizations();
525
+ return organization;
526
+ }),
527
+ deleteOrganization: (id) => toAuthResult(async () => {
528
+ await request(`/organizations/${id}`, { method: "DELETE" });
529
+ await refreshOrganizations();
530
+ return null;
531
+ }),
532
+ hasPermission: async (options) => {
533
+ try {
534
+ const data = await request("/permissions/check", {
535
+ method: "POST",
536
+ body: options
537
+ });
538
+ return data.allowed;
539
+ } catch {
540
+ return false;
541
+ }
542
+ },
543
+ listUsers: (params) => {
544
+ const query = new URLSearchParams();
545
+ if (params?.organizationId) query.set("organizationId", params.organizationId);
546
+ return request(`/users${query.size ? `?${query.toString()}` : ""}`);
547
+ },
548
+ getUser: (id) => request(`/users/${id}`),
549
+ createUser: (input) => toAuthResult(() => request("/users", { method: "POST", body: input })),
550
+ updateUser: (id, input) => toAuthResult(() => request(`/users/${id}`, { method: "PATCH", body: input })),
551
+ deleteUser: (id) => toAuthResult(async () => {
552
+ await request(`/users/${id}`, { method: "DELETE" });
553
+ return null;
554
+ }),
555
+ listRoles: (params) => {
556
+ const query = new URLSearchParams();
557
+ if (params?.organizationId) query.set("organizationId", params.organizationId);
558
+ if (params?.applicationId) query.set("applicationId", params.applicationId);
559
+ if (params?.type) query.set("type", params.type);
560
+ return request(`/roles${query.size ? `?${query.toString()}` : ""}`);
561
+ },
562
+ getRole: (id, type) => request(type === "custom" ? `/roles/custom/${id}` : `/roles/definitions/${id}`),
563
+ createRole: (input) => toAuthResult(() => request("/roles", { method: "POST", body: input })),
564
+ updateRole: (id, input) => toAuthResult(() => request(`/roles/custom/${id}`, { method: "PATCH", body: input })),
565
+ deleteRole: (id) => toAuthResult(async () => {
566
+ await request(`/roles/custom/${id}`, { method: "DELETE" });
567
+ return null;
568
+ }),
569
+ listPermissions: (params) => {
570
+ const query = new URLSearchParams();
571
+ if (params?.applicationId) query.set("applicationId", params.applicationId);
572
+ if (params?.roleId) query.set("roleId", params.roleId);
573
+ return request(`/permissions${query.size ? `?${query.toString()}` : ""}`);
574
+ },
575
+ createPermission: (input) => toAuthResult(() => request("/permissions", { method: "POST", body: input })),
576
+ updatePermission: (id, input) => toAuthResult(() => request(`/permissions/${id}`, { method: "PATCH", body: input })),
577
+ deletePermission: (id) => toAuthResult(async () => {
578
+ await request(`/permissions/${id}`, { method: "DELETE" });
579
+ return null;
580
+ }),
581
+ listUserSessions: (params) => {
582
+ const query = new URLSearchParams();
583
+ if (params?.userId) query.set("userId", params.userId);
584
+ if (params?.organizationId) query.set("organizationId", params.organizationId);
585
+ return request(`/sessions${query.size ? `?${query.toString()}` : ""}`);
586
+ },
587
+ revokeUserSession: (sessionId) => toAuthResult(async () => {
588
+ await request(`/sessions/${sessionId}`, { method: "DELETE" });
589
+ return null;
590
+ })
591
+ }),
592
+ [
593
+ accounts,
594
+ addAccount,
595
+ basePath,
596
+ currentOrg,
597
+ currentOrgId,
598
+ isLoading,
599
+ isLoadingAccounts,
600
+ isLoadingOrganizations,
601
+ organizations,
602
+ refreshAccounts,
603
+ refreshOrganizations,
604
+ refreshUser,
605
+ request,
606
+ setCurrentOrg,
607
+ signIn,
608
+ signOut,
609
+ signOutAll,
610
+ signUp,
611
+ switchAccount,
612
+ user
613
+ ]
614
+ );
615
+ return /* @__PURE__ */ jsx(GeekappsAuthContext.Provider, { value, children });
616
+ }
617
+ function useAuth() {
618
+ const context = useContext(GeekappsAuthContext);
619
+ if (!context) throw new Error("useAuth must be used inside GeekappsAuthProvider");
620
+ return context;
621
+ }
622
+ function useOrg() {
623
+ const context = useAuth();
624
+ return {
625
+ organizations: context.organizations,
626
+ currentOrg: context.currentOrg,
627
+ currentOrgId: context.currentOrgId,
628
+ isLoadingOrganizations: context.isLoadingOrganizations,
629
+ refreshOrganizations: context.refreshOrganizations,
630
+ setCurrentOrg: context.setCurrentOrg,
631
+ createOrganization: context.createOrganization,
632
+ updateOrganization: context.updateOrganization,
633
+ deleteOrganization: context.deleteOrganization,
634
+ hasPermission: context.hasPermission
635
+ };
636
+ }
637
+ function useAccounts() {
638
+ const context = useAuth();
639
+ return {
640
+ accounts: context.accounts,
641
+ addAccount: context.addAccount,
642
+ isLoadingAccounts: context.isLoadingAccounts,
643
+ refreshAccounts: context.refreshAccounts,
644
+ switchAccount: context.switchAccount
645
+ };
646
+ }
647
+ function useUsers() {
648
+ const context = useAuth();
649
+ return {
650
+ listUsers: context.listUsers,
651
+ getUser: context.getUser,
652
+ createUser: context.createUser,
653
+ updateUser: context.updateUser,
654
+ deleteUser: context.deleteUser
655
+ };
656
+ }
657
+ function useRoles() {
658
+ const context = useAuth();
659
+ return {
660
+ listRoles: context.listRoles,
661
+ getRole: context.getRole,
662
+ createRole: context.createRole,
663
+ updateRole: context.updateRole,
664
+ deleteRole: context.deleteRole
665
+ };
666
+ }
667
+ function usePermissions() {
668
+ const context = useAuth();
669
+ return {
670
+ listPermissions: context.listPermissions,
671
+ createPermission: context.createPermission,
672
+ updatePermission: context.updatePermission,
673
+ deletePermission: context.deletePermission
674
+ };
675
+ }
676
+ function useSessions() {
677
+ const context = useAuth();
678
+ return {
679
+ listUserSessions: context.listUserSessions,
680
+ revokeUserSession: context.revokeUserSession
681
+ };
682
+ }
683
+ function useServiceAccount() {
684
+ const { request } = useAuth();
685
+ const listServiceAccounts = useCallback(
686
+ (params) => {
687
+ const query = new URLSearchParams({ organizationId: params.organizationId });
688
+ if (params.applicationId) query.set("applicationId", params.applicationId);
689
+ return request(`/service-accounts?${query.toString()}`);
690
+ },
691
+ [request]
692
+ );
693
+ const createServiceAccount = useCallback(
694
+ (input) => request("/service-accounts", { method: "POST", body: input }),
695
+ [request]
696
+ );
697
+ const updateServiceAccountRole = useCallback(
698
+ async (id, roleId) => {
699
+ await request(`/service-accounts/${id}`, { method: "PATCH", body: { roleId } });
700
+ },
701
+ [request]
702
+ );
703
+ const revokeServiceAccount = useCallback(
704
+ async (id) => {
705
+ await request(`/service-accounts/${id}/revoke`, { method: "POST" });
706
+ },
707
+ [request]
708
+ );
709
+ const rotateServiceAccountSecret = useCallback(
710
+ (id) => request(`/service-accounts/${id}/rotate-secret`, {
711
+ method: "POST"
712
+ }),
713
+ [request]
714
+ );
715
+ const deleteServiceAccount = useCallback(
716
+ async (id) => {
717
+ await request(`/service-accounts/${id}`, { method: "DELETE" });
718
+ },
719
+ [request]
720
+ );
721
+ return {
722
+ listServiceAccounts,
723
+ createServiceAccount,
724
+ updateServiceAccountRole,
725
+ revokeServiceAccount,
726
+ rotateServiceAccountSecret,
727
+ deleteServiceAccount
728
+ };
729
+ }
730
+ export {
731
+ GeekappsAuthProvider,
732
+ loginWithPassword,
733
+ registerWithPassword,
734
+ requestPasswordlessLink,
735
+ startGoogleLogin,
736
+ useAccounts,
737
+ useAuth,
738
+ useOrg,
739
+ usePermissions,
740
+ useRoles,
741
+ useServiceAccount,
742
+ useSessions,
743
+ useUsers
744
+ };
745
+ //# sourceMappingURL=client.js.map