@geekapps/auth-nextjs 0.14.0 → 0.15.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.
@@ -0,0 +1,15 @@
1
+ import { ConnectedAccount, User, Organization } from './client.js';
2
+ import 'react';
3
+
4
+ declare function getMe(): Promise<{
5
+ user: User | null;
6
+ }>;
7
+ declare function getAccounts(): Promise<{
8
+ accounts: ConnectedAccount[];
9
+ }>;
10
+ declare function getOrganizations(): Promise<{
11
+ organizations: Organization[];
12
+ currentOrgId?: string | null;
13
+ }>;
14
+
15
+ export { getAccounts, getMe, getOrganizations };
@@ -0,0 +1,610 @@
1
+ import { MouseEvent, ReactNode, ReactElement } from 'react';
2
+
3
+ /**
4
+ * A sessão não vale mais: expirou ou foi revogada. O estado local já foi
5
+ * limpo quando este erro é lançado — o tratamento normal é levar ao login.
6
+ */
7
+ declare class GeekappsSessionExpiredError extends Error {
8
+ readonly code: "session_expired";
9
+ constructor(message?: string);
10
+ }
11
+ type UserStatus = "active" | "inactive" | "suspended";
12
+ type OrganizationStatus = "active" | "inactive" | "suspended";
13
+ type OAuthClientType = "public" | "confidential";
14
+ type AuthResult<T = unknown> = {
15
+ success: true;
16
+ data: T;
17
+ } | {
18
+ success: false;
19
+ error: string;
20
+ status?: number;
21
+ };
22
+ type User = {
23
+ id: string;
24
+ email: string;
25
+ name: string | null;
26
+ phone: string | null;
27
+ imageUrl: string | null;
28
+ status?: UserStatus;
29
+ createdAt?: string | Date;
30
+ updatedAt?: string | Date;
31
+ };
32
+ type ConnectedAccount = {
33
+ id: string;
34
+ sessionId?: string;
35
+ isActive: boolean;
36
+ user: User;
37
+ };
38
+ type Permission = {
39
+ id: string;
40
+ applicationId?: string | null;
41
+ key: string;
42
+ name: string;
43
+ description: string | null;
44
+ category: string | null;
45
+ isSystem: boolean;
46
+ isActive: boolean;
47
+ createdAt?: string | Date;
48
+ updatedAt?: string | Date;
49
+ };
50
+ type RolePermission = {
51
+ permissionDefinition: Permission;
52
+ };
53
+ type Role = {
54
+ id: string;
55
+ applicationId?: string | null;
56
+ /** Present only on custom roles */
57
+ organizationId?: string | null;
58
+ /** "system" | "custom" */
59
+ type?: string;
60
+ key: string;
61
+ name: string;
62
+ description: string | null;
63
+ isSystem?: boolean;
64
+ isDefault?: boolean;
65
+ isActive: boolean;
66
+ permissions: RolePermission[];
67
+ createdAt?: string | Date;
68
+ updatedAt?: string | Date;
69
+ };
70
+ type RoleAssignment = {
71
+ id: string;
72
+ roleDefinitionId?: string | null;
73
+ customRoleId?: string | null;
74
+ roleDefinition?: Role | null;
75
+ customRole?: Role | null;
76
+ };
77
+ type OrganizationMember = {
78
+ id: string;
79
+ organizationId?: string;
80
+ userId?: string;
81
+ createdAt?: string | Date;
82
+ user: User;
83
+ roleAssignments?: RoleAssignment[];
84
+ };
85
+ type OrganizationInvite = {
86
+ id: string;
87
+ organizationId: string;
88
+ email: string;
89
+ /**
90
+ * Role que o convidado assume ao aceitar. Vem aninhada do auth-server (não
91
+ * como roleId solto) — null quando o convite não fixa nenhuma e o membro
92
+ * cai na role default da organização.
93
+ */
94
+ role: {
95
+ id: string;
96
+ key: string;
97
+ name: string;
98
+ } | null;
99
+ /** @deprecated use `role.id` — o auth-server não devolve este campo. */
100
+ roleId?: string | null;
101
+ status: "pending" | "accepted" | "expired" | "revoked";
102
+ expiresAt: string | Date;
103
+ acceptedAt?: string | Date | null;
104
+ createdAt?: string | Date;
105
+ redirectUri?: string | null;
106
+ emailTitle?: string | null;
107
+ emailSubtitle?: string | null;
108
+ emailMessage?: string | null;
109
+ };
110
+ type MemberInviteInput = {
111
+ email: string;
112
+ roleId?: string;
113
+ /**
114
+ * URI pra onde o link do e-mail manda o usuário — precisa estar cadastrada
115
+ * em Application.redirectUris (mesma validação do /authorize). Este app
116
+ * deve expor uma rota nessa URI que trata o `?invite_token=` anexado (ver
117
+ * useJoinRequests/inviteApi.preview|accept|reject abaixo).
118
+ */
119
+ redirectUri: string;
120
+ emailTitle?: string;
121
+ emailSubtitle?: string;
122
+ emailMessage?: string;
123
+ };
124
+ type AddMemberInput = {
125
+ userId: string;
126
+ roleId?: string;
127
+ };
128
+ type UpdateMemberInput = {
129
+ status?: "active" | "inactive" | "suspended";
130
+ roleId?: string | null;
131
+ };
132
+ /** @deprecated use UpdateMemberInput */
133
+ type UpdateMemberRoleInput = {
134
+ roleId: string;
135
+ };
136
+ type PublicOrganization = {
137
+ id: string;
138
+ name: string;
139
+ slug: string;
140
+ description: string | null;
141
+ imageUrl: string | null;
142
+ createdAt: string | Date;
143
+ };
144
+ type OrganizationInvitePreview = {
145
+ alreadyAccepted: true;
146
+ organizationId: string;
147
+ organizationName: string;
148
+ applicationName: string;
149
+ applicationImageUrl: string | null;
150
+ applicationImageFileId: string | null;
151
+ organizationImageUrl: string | null;
152
+ organizationImageFileId: string | null;
153
+ websiteUrl: string | null;
154
+ } | {
155
+ alreadyAccepted?: false;
156
+ email: string;
157
+ organizationId: string;
158
+ organizationName: string;
159
+ applicationName: string;
160
+ applicationId: string;
161
+ applicationImageUrl: string | null;
162
+ applicationImageFileId: string | null;
163
+ organizationImageUrl: string | null;
164
+ organizationImageFileId: string | null;
165
+ websiteUrl: string | null;
166
+ redirectUri: string | null;
167
+ appStoreUrl: string | null;
168
+ playStoreUrl: string | null;
169
+ currentAccount: {
170
+ email: string;
171
+ name: string | null;
172
+ } | null;
173
+ };
174
+ type AcceptInviteResult = {
175
+ success: true;
176
+ organizationId: string;
177
+ organizationName: string;
178
+ websiteUrl: string | null;
179
+ } | {
180
+ success: false;
181
+ wrongAccount: true;
182
+ currentEmail: string;
183
+ invitedEmail: string;
184
+ } | {
185
+ success: false;
186
+ wrongAccount: false;
187
+ loginRequired: true;
188
+ } | {
189
+ success: false;
190
+ wrongAccount: false;
191
+ loginRequired: false;
192
+ error: string;
193
+ };
194
+ type JoinRequestStatus = "pending" | "approved" | "rejected" | "cancelled";
195
+ type OrganizationJoinRequest = {
196
+ id: string;
197
+ organizationId: string;
198
+ userId: string;
199
+ status: JoinRequestStatus;
200
+ message: string | null;
201
+ reviewedByUserId: string | null;
202
+ reviewedAt: string | null;
203
+ createdAt: string | Date;
204
+ updatedAt: string | Date;
205
+ };
206
+ type OrganizationOwnedApplication = {
207
+ id: string;
208
+ name: string;
209
+ description: string | null;
210
+ imageUrl: string | null;
211
+ type?: OAuthClientType;
212
+ organizationId: string;
213
+ isFirstParty: boolean;
214
+ ssoEnabled: boolean;
215
+ status?: "active" | "inactive" | "suspended";
216
+ createdAt?: string | Date;
217
+ updatedAt?: string | Date;
218
+ };
219
+ type Organization = {
220
+ id: string;
221
+ name: string;
222
+ description: string | null;
223
+ slug: string;
224
+ domain: string | null;
225
+ imageUrl: string | null;
226
+ faviconUrl: string | null;
227
+ status: OrganizationStatus;
228
+ /** "private" (padrão) nunca sai em listPublicOrganizations(); "public" sai, e aceita join requests. */
229
+ visibility?: "public" | "private";
230
+ members?: OrganizationMember[];
231
+ ownedApplications?: OrganizationOwnedApplication[];
232
+ applicationLinks?: Array<{
233
+ id: string;
234
+ status: OrganizationStatus;
235
+ createdAt?: string | Date;
236
+ application: OrganizationOwnedApplication;
237
+ }>;
238
+ createdAt: string | Date;
239
+ updatedAt: string | Date;
240
+ };
241
+ type SessionApplication = {
242
+ id: string;
243
+ createdAt: string | Date;
244
+ expiresAt: string | Date;
245
+ application: {
246
+ id: string;
247
+ name: string;
248
+ organizationId: string;
249
+ };
250
+ };
251
+ type UserSession = {
252
+ id: string;
253
+ userId: string;
254
+ organizationId: string | null;
255
+ deviceAgent: string | null;
256
+ deviceId: string | null;
257
+ deviceName: string | null;
258
+ ip: string | null;
259
+ authState?: unknown;
260
+ authTime?: string | Date;
261
+ expiresAt: string | Date;
262
+ createdAt: string | Date;
263
+ updatedAt: string | Date;
264
+ user?: User;
265
+ applicationSessions?: SessionApplication[];
266
+ };
267
+ type UserInput = {
268
+ name?: string | null;
269
+ email?: string;
270
+ phone?: string | null;
271
+ imageUrl?: string | null;
272
+ password?: string;
273
+ organizationId?: string | null;
274
+ status?: UserStatus;
275
+ };
276
+ type OrganizationInput = {
277
+ name: string;
278
+ description?: string | null;
279
+ slug: string;
280
+ domain?: string | null;
281
+ imageUrl?: string | null;
282
+ faviconUrl?: string | null;
283
+ };
284
+ type OrganizationUpdateInput = Partial<OrganizationInput> & {
285
+ status?: OrganizationStatus;
286
+ };
287
+ type RoleInput = {
288
+ /** Opcional: sem ele, usa a organização ativa. */
289
+ organizationId?: string;
290
+ applicationId?: string | null;
291
+ key: string;
292
+ name: string;
293
+ description?: string | null;
294
+ permissionDefinitionIds?: string[];
295
+ };
296
+ type RoleUpdateInput = {
297
+ name?: string;
298
+ description?: string | null;
299
+ isActive?: boolean;
300
+ permissionDefinitionIds?: string[];
301
+ };
302
+ type PermissionInput = {
303
+ applicationId?: string | null;
304
+ key: string;
305
+ name: string;
306
+ description?: string | null;
307
+ category?: string | null;
308
+ };
309
+ type PermissionUpdateInput = {
310
+ name?: string;
311
+ description?: string | null;
312
+ category?: string | null;
313
+ isActive?: boolean;
314
+ };
315
+ /**
316
+ * OIDC `prompt` values understood by the Geekapps Auth Server. These control
317
+ * whether — and how — the IDP shows UI during `signIn()`/`signUp()`/`addAccount()`.
318
+ *
319
+ * - `"login"` — Forces the login screen, even if the user already has an active
320
+ * session. Use this for a fresh login, unrelated to whatever session already
321
+ * exists (equivalent to the old `silentLogin: false`).
322
+ * - `"select_account"` — Shows the account picker so the user can choose among
323
+ * their connected accounts, or add a new one. Use this when you want to let
324
+ * the user switch accounts explicitly.
325
+ * - `"none"` — Never shows any UI. The IDP authenticates silently if there is
326
+ * exactly one active session (and no other interaction — like consent or a
327
+ * security check — is pending); otherwise it fails immediately with an OIDC
328
+ * error (`login_required`, `account_selection_required`, `consent_required`,
329
+ * or `interaction_required`) instead of prompting the user. Use this for
330
+ * silent-auth checks (e.g. "is the user still logged in?") where you don't
331
+ * want to interrupt them with a screen.
332
+ * - `"consent"` — Forces the consent screen even if the user already granted
333
+ * the requested scopes before.
334
+ *
335
+ * Omitting `prompt` entirely runs the IDP's default flow: reuse a single
336
+ * existing session silently, ask the user to pick when there are multiple
337
+ * connected accounts, or show the login screen when there's none.
338
+ */
339
+ type OidcPrompt = "login" | "select_account" | "none" | "consent";
340
+ type SignInOptions = {
341
+ redirectTo?: string;
342
+ authorizationFlowId?: string;
343
+ /**
344
+ * Controls whether the IDP shows UI, and which screen, during sign-in. See
345
+ * {@link OidcPrompt} for what each value does. Omit it to run the default flow.
346
+ */
347
+ prompt?: OidcPrompt;
348
+ /**
349
+ * @deprecated Use `prompt: "login"` instead. Kept for backwards compatibility —
350
+ * `silentLogin: false` is equivalent to `prompt: "login"`.
351
+ */
352
+ silentLogin?: boolean;
353
+ };
354
+ type SignInInput = SignInOptions | MouseEvent<HTMLElement>;
355
+ type CallbackUrlOptions = SignInOptions & {
356
+ callbackUrl?: string;
357
+ };
358
+ type PermissionCheckOptions = {
359
+ permission: string;
360
+ organizationId?: string | null;
361
+ applicationId?: string | null;
362
+ resourceId?: string | null;
363
+ };
364
+ type LoginResponse = {
365
+ user: User;
366
+ redirectTo?: string | null;
367
+ };
368
+ type RegisterResponse = User;
369
+ type GeekappsAuthProviderProps = {
370
+ children: ReactNode;
371
+ basePath?: string;
372
+ initialUser?: User | null;
373
+ initialOrganizations?: Organization[];
374
+ initialCurrentOrgId?: string | null;
375
+ };
376
+ type RequestOptions = {
377
+ body?: unknown;
378
+ method?: "GET" | "POST" | "PATCH" | "DELETE";
379
+ };
380
+ type ClientActionOptions = {
381
+ basePath?: string;
382
+ };
383
+ declare function loginWithPassword(params: {
384
+ identifier?: string;
385
+ email?: string;
386
+ phone?: string;
387
+ password: string;
388
+ authorizationFlowId?: string;
389
+ redirectTo?: string;
390
+ }, options?: ClientActionOptions): Promise<AuthResult<LoginResponse>>;
391
+ declare function registerWithPassword(params: {
392
+ name: string;
393
+ email: string;
394
+ phone?: string;
395
+ imageUrl?: string;
396
+ address?: Record<string, unknown>;
397
+ password: string;
398
+ redirectTo?: string;
399
+ }, options?: ClientActionOptions): Promise<AuthResult<RegisterResponse>>;
400
+ declare function startGoogleLogin(params?: CallbackUrlOptions, options?: ClientActionOptions): void;
401
+ declare function requestPasswordlessLink(params: {
402
+ email: string;
403
+ authorizationFlowId?: string;
404
+ redirectTo?: string;
405
+ callbackUrl?: string;
406
+ }, options?: ClientActionOptions): Promise<AuthResult>;
407
+ type GeekappsAuthContextValue = {
408
+ basePath: string;
409
+ user: User | null;
410
+ isAuthenticated: boolean;
411
+ isLoading: boolean;
412
+ accounts: ConnectedAccount[];
413
+ isLoadingAccounts: boolean;
414
+ organizations: Organization[];
415
+ currentOrg: Organization | null;
416
+ currentOrgId: string | null;
417
+ isLoadingOrganizations: boolean;
418
+ request: <T>(path: string, options?: RequestOptions) => Promise<T>;
419
+ signIn: (options?: SignInInput) => Promise<void>;
420
+ signUp: (options?: SignInInput) => Promise<void>;
421
+ addAccount: (options?: SignInInput) => Promise<void>;
422
+ signOut: () => Promise<void>;
423
+ signOutAll: () => Promise<void>;
424
+ refreshUser: () => Promise<void>;
425
+ refreshAccounts: () => Promise<void>;
426
+ switchAccount: (sessionId: string, options?: SignInOptions) => Promise<void>;
427
+ loginWithPassword: (params: {
428
+ identifier?: string;
429
+ email?: string;
430
+ phone?: string;
431
+ password: string;
432
+ authorizationFlowId?: string;
433
+ redirectTo?: string;
434
+ }) => Promise<AuthResult<LoginResponse>>;
435
+ registerWithPassword: (params: {
436
+ name: string;
437
+ email: string;
438
+ phone?: string;
439
+ imageUrl?: string;
440
+ address?: Record<string, unknown>;
441
+ password: string;
442
+ redirectTo?: string;
443
+ }) => Promise<AuthResult<RegisterResponse>>;
444
+ startGoogleLogin: (params?: CallbackUrlOptions) => void;
445
+ requestPasswordlessLink: (params: {
446
+ email: string;
447
+ authorizationFlowId?: string;
448
+ redirectTo?: string;
449
+ callbackUrl?: string;
450
+ }) => Promise<AuthResult>;
451
+ refreshOrganizations: () => Promise<void>;
452
+ setCurrentOrg: (organizationId: string | null) => Promise<void>;
453
+ createOrganization: (input: OrganizationInput) => Promise<AuthResult<Organization>>;
454
+ updateOrganization: (id: string, input: OrganizationUpdateInput) => Promise<AuthResult<Organization>>;
455
+ deleteOrganization: (id: string) => Promise<AuthResult<null>>;
456
+ hasPermission: (options: PermissionCheckOptions) => Promise<boolean>;
457
+ /** Organizações públicas e ativas deste app — nunca inclui privadas, não exige membership. Separado de `organizations` (só as do próprio usuário). */
458
+ listPublicOrganizations: () => Promise<PublicOrganization[]>;
459
+ requestToJoin: (organizationId: string, input?: {
460
+ message?: string | null;
461
+ }) => Promise<AuthResult<OrganizationJoinRequest>>;
462
+ getMyJoinRequest: (organizationId: string) => Promise<OrganizationJoinRequest | null>;
463
+ cancelJoinRequest: (organizationId: string) => Promise<AuthResult<null>>;
464
+ listJoinRequests: (organizationId: string) => Promise<OrganizationJoinRequest[]>;
465
+ approveJoinRequest: (organizationId: string, requestId: string) => Promise<AuthResult<OrganizationJoinRequest>>;
466
+ rejectJoinRequest: (organizationId: string, requestId: string) => Promise<AuthResult<OrganizationJoinRequest>>;
467
+ /** Preview do convite por token — funciona com ou sem sessão (currentAccount vem null se deslogado). */
468
+ getInvitePreview: (token: string) => Promise<OrganizationInvitePreview>;
469
+ /** Aceita o convite. loginRequired:true significa que signIn() precisa rodar antes. */
470
+ acceptInvite: (token: string) => Promise<AcceptInviteResult>;
471
+ /** Recusa o convite — não exige estar logado. */
472
+ rejectInvite: (token: string) => Promise<{
473
+ success: true;
474
+ } | {
475
+ success: false;
476
+ error: string;
477
+ }>;
478
+ listUsers: (params?: {
479
+ organizationId?: string | null;
480
+ }) => Promise<User[]>;
481
+ getUser: (id: string) => Promise<User>;
482
+ createUser: (input: UserInput) => Promise<AuthResult<User>>;
483
+ updateUser: (id: string, input: UserInput) => Promise<AuthResult<User>>;
484
+ deleteUser: (id: string) => Promise<AuthResult<null>>;
485
+ /**
486
+ * Roles da organização. `organizationId` é opcional: sem ele, usa a
487
+ * organização ativa. `applicationId`/`type` são aceitos por
488
+ * compatibilidade e não filtram nada — a separação system/custom vem no
489
+ * próprio retorno.
490
+ */
491
+ listRoles: (params?: {
492
+ organizationId?: string;
493
+ applicationId?: string;
494
+ type?: "system" | "custom" | "all";
495
+ }) => Promise<{
496
+ systemRoles: Role[];
497
+ customRoles: Role[];
498
+ }>;
499
+ getRole: (id: string, type?: "system" | "custom", organizationId?: string) => Promise<Role>;
500
+ createRole: (input: RoleInput) => Promise<AuthResult<Role>>;
501
+ updateRole: (id: string, input: RoleUpdateInput, organizationId?: string) => Promise<AuthResult<Role>>;
502
+ deleteRole: (id: string, organizationId?: string) => Promise<AuthResult<null>>;
503
+ listPermissions: (params?: {
504
+ applicationId?: string;
505
+ roleId?: string | null;
506
+ }) => Promise<Permission[]>;
507
+ createPermission: (input: PermissionInput) => Promise<AuthResult<Permission>>;
508
+ updatePermission: (id: string, input: PermissionUpdateInput) => Promise<AuthResult<Permission>>;
509
+ deletePermission: (id: string) => Promise<AuthResult<null>>;
510
+ listUserSessions: (params?: {
511
+ userId?: string;
512
+ organizationId?: string | null;
513
+ }) => Promise<UserSession[]>;
514
+ revokeUserSession: (sessionId: string) => Promise<AuthResult<null>>;
515
+ listMembers: (organizationId: string) => Promise<OrganizationMember[]>;
516
+ getMember: (organizationId: string, memberId: string) => Promise<OrganizationMember>;
517
+ addMember: (organizationId: string, input: AddMemberInput) => Promise<AuthResult<OrganizationMember>>;
518
+ updateMember: (organizationId: string, memberId: string, input: UpdateMemberInput) => Promise<AuthResult<OrganizationMember>>;
519
+ /** @deprecated use updateMember */
520
+ updateMemberRole: (organizationId: string, memberId: string, input: UpdateMemberRoleInput) => Promise<AuthResult<OrganizationMember>>;
521
+ removeMember: (organizationId: string, memberId: string) => Promise<AuthResult<null>>;
522
+ inviteMember: (organizationId: string, input: MemberInviteInput) => Promise<AuthResult<OrganizationInvite>>;
523
+ listInvites: (organizationId: string) => Promise<OrganizationInvite[]>;
524
+ revokeInvite: (organizationId: string, inviteId: string) => Promise<AuthResult<null>>;
525
+ };
526
+ type UseOrgResult = Pick<GeekappsAuthContextValue, "organizations" | "currentOrg" | "currentOrgId" | "isLoadingOrganizations" | "refreshOrganizations" | "setCurrentOrg" | "createOrganization" | "updateOrganization" | "deleteOrganization" | "hasPermission">;
527
+ type UseAccountsResult = Pick<GeekappsAuthContextValue, "accounts" | "addAccount" | "isLoadingAccounts" | "refreshAccounts" | "switchAccount">;
528
+ type UseUsersResult = Pick<GeekappsAuthContextValue, "listUsers" | "getUser" | "createUser" | "updateUser" | "deleteUser">;
529
+ type UseRolesResult = Pick<GeekappsAuthContextValue, "listRoles" | "getRole" | "createRole" | "updateRole" | "deleteRole">;
530
+ type UsePermissionsResult = Pick<GeekappsAuthContextValue, "listPermissions" | "createPermission" | "updatePermission" | "deletePermission">;
531
+ type UseSessionsResult = Pick<GeekappsAuthContextValue, "listUserSessions" | "revokeUserSession">;
532
+ type UseMembersResult = Pick<GeekappsAuthContextValue, "listMembers" | "getMember" | "addMember" | "updateMember" | "updateMemberRole" | "removeMember" | "inviteMember" | "listInvites" | "revokeInvite">;
533
+ type UsePublicOrganizationsResult = Pick<GeekappsAuthContextValue, "listPublicOrganizations">;
534
+ type UseJoinRequestsResult = Pick<GeekappsAuthContextValue, "requestToJoin" | "getMyJoinRequest" | "cancelJoinRequest" | "listJoinRequests" | "approveJoinRequest" | "rejectJoinRequest">;
535
+ type UseInvitesResult = Pick<GeekappsAuthContextValue, "getInvitePreview" | "acceptInvite" | "rejectInvite">;
536
+ declare function GeekappsAuthProvider({ children, basePath, initialUser, initialOrganizations, initialCurrentOrgId, }: GeekappsAuthProviderProps): ReactElement;
537
+ declare function useAuth(): GeekappsAuthContextValue;
538
+ declare function useOrg(): UseOrgResult;
539
+ declare function useAccounts(): UseAccountsResult;
540
+ declare function useUsers(): UseUsersResult;
541
+ declare function useRoles(): UseRolesResult;
542
+ declare function usePermissions(): UsePermissionsResult;
543
+ declare function useSessions(): UseSessionsResult;
544
+ declare function useMembers(): UseMembersResult;
545
+ /**
546
+ * Descoberta de organizações PÚBLICAS do app — bem separado de `useOrg()`,
547
+ * que lida com as organizações do próprio usuário (as que ele já é
548
+ * membro/dono). `usePublicOrganizations()` nunca retorna organizações
549
+ * privadas, e não exige que o usuário já pertença a elas.
550
+ */
551
+ declare function usePublicOrganizations(): UsePublicOrganizationsResult;
552
+ /**
553
+ * Solicitações de entrada em organizações públicas: um usuário pede pra
554
+ * entrar (requestToJoin) e um admin da organização aprova/rejeita
555
+ * (approveJoinRequest/rejectJoinRequest, exigem permissão org:members:add).
556
+ */
557
+ declare function useJoinRequests(): UseJoinRequestsResult;
558
+ /**
559
+ * Aceite/recusa de convite por email — chamadas a partir do ?invite_token=
560
+ * que este app recebe na sua própria redirectUri (a que foi passada em
561
+ * useMembers().inviteMember). getInvitePreview funciona sem sessão
562
+ * (currentAccount vem null); rejectInvite não exige login; acceptInvite
563
+ * retorna loginRequired:true se não houver sessão.
564
+ */
565
+ declare function useInvites(): UseInvitesResult;
566
+ type ServiceAccount = {
567
+ id: string;
568
+ membershipId: string;
569
+ organizationId: string;
570
+ applicationId: string | null;
571
+ name: string;
572
+ status: "active" | "inactive" | "suspended";
573
+ serviceId: string | null;
574
+ roleAssignment: {
575
+ role: {
576
+ id: string;
577
+ key: string;
578
+ name: string;
579
+ };
580
+ } | null;
581
+ createdAt: string;
582
+ updatedAt: string;
583
+ };
584
+ type ServiceAccountWithSecret = ServiceAccount & {
585
+ serviceSecret: string;
586
+ };
587
+ type CreateServiceAccountInput = {
588
+ organizationId: string;
589
+ applicationId?: string;
590
+ name: string;
591
+ description?: string;
592
+ roleId?: string;
593
+ };
594
+ type UseServiceAccountResult = {
595
+ listServiceAccounts: (params: {
596
+ organizationId: string;
597
+ applicationId?: string;
598
+ }) => Promise<ServiceAccount[]>;
599
+ createServiceAccount: (input: CreateServiceAccountInput) => Promise<ServiceAccountWithSecret>;
600
+ updateServiceAccountRole: (id: string, roleId: string | null) => Promise<void>;
601
+ revokeServiceAccount: (id: string) => Promise<void>;
602
+ rotateServiceAccountSecret: (id: string) => Promise<{
603
+ serviceId: string;
604
+ serviceSecret: string;
605
+ }>;
606
+ deleteServiceAccount: (id: string) => Promise<void>;
607
+ };
608
+ declare function useServiceAccount(): UseServiceAccountResult;
609
+
610
+ export { type AcceptInviteResult, type AddMemberInput, type AuthResult, type CallbackUrlOptions, type ConnectedAccount, type CreateServiceAccountInput, type GeekappsAuthContextValue, GeekappsAuthProvider, type GeekappsAuthProviderProps, GeekappsSessionExpiredError, type JoinRequestStatus, type LoginResponse, type MemberInviteInput, type OAuthClientType, type OidcPrompt, type Organization, type OrganizationInput, type OrganizationInvite, type OrganizationInvitePreview, type OrganizationJoinRequest, type OrganizationMember, type OrganizationOwnedApplication, type OrganizationStatus, type OrganizationUpdateInput, type Permission, type PermissionCheckOptions, type PermissionInput, type PermissionUpdateInput, type PublicOrganization, type RegisterResponse, type Role, type RoleAssignment, type RoleInput, type RolePermission, type RoleUpdateInput, type ServiceAccount, type ServiceAccountWithSecret, type SessionApplication, type SignInInput, type SignInOptions, type UpdateMemberInput, type UpdateMemberRoleInput, type UseAccountsResult, type UseInvitesResult, type UseJoinRequestsResult, type UseMembersResult, type UseOrgResult, type UsePermissionsResult, type UsePublicOrganizationsResult, type UseRolesResult, type UseServiceAccountResult, type UseSessionsResult, type UseUsersResult, type User, type UserInput, type UserSession, type UserStatus, loginWithPassword, registerWithPassword, requestPasswordlessLink, startGoogleLogin, useAccounts, useAuth, useInvites, useJoinRequests, useMembers, useOrg, usePermissions, usePublicOrganizations, useRoles, useServiceAccount, useSessions, useUsers };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * App Connections — chamar ações de negócio de OUTRA Application.
3
+ *
4
+ * Uma conexão liga um USUÁRIO desta app (X) a uma app alvo (Y). Ele a aprova
5
+ * uma vez no consent, escolhendo as ações liberadas e a organização dentro do
6
+ * Y sob a qual elas rodam. A chamada vai com o access token desse usuário (o
7
+ * da sessão, por padrão): é ele que diz ao proxy qual conexão usar.
8
+ *
9
+ * Nada aqui fala com a API do Y diretamente: tudo passa pelo proxy do
10
+ * auth-server, que valida a conexão e injeta a credencial. Esta app nunca vê
11
+ * essa credencial — é esse o ponto do proxy.
12
+ *
13
+ * O catálogo tipado (`GeekappsConnections`) vem do arquivo gerado por
14
+ * `npx geekapps-connections`.
15
+ */
16
+ /** Opções por chamada. Sem `userToken`, usa o access token do usuário logado na sessão. */
17
+ type ConnectionCallOptions = {
18
+ userToken?: string;
19
+ };
20
+ type AppConnectionsConfig = {
21
+ issuer?: string;
22
+ /** client_id/secret desta app (a consumidora, X). */
23
+ clientId?: string;
24
+ clientSecret?: string;
25
+ };
26
+ /**
27
+ * Preenchida por declaration merging no arquivo gerado
28
+ * (`geekapps-connections.d.ts`). Vazia aqui de propósito: o SDK não sabe
29
+ * quais apps existem — quem sabe é o auth-server, no momento da geração.
30
+ */
31
+ interface GeekappsConnections {
32
+ }
33
+ /** Erro de uma chamada de proxy — carrega o status HTTP para dar pra tratar. */
34
+ declare class AppConnectionError extends Error {
35
+ readonly status: number;
36
+ readonly code: string | undefined;
37
+ readonly body: unknown;
38
+ constructor(message: string, status: number, code: string | undefined, body: unknown);
39
+ }
40
+ /**
41
+ * A chamada crua do proxy, para quando não há catálogo gerado. `targetAppId` é
42
+ * o client_id da app alvo e `actionKey` é a AppAction.key — o mesmo valor que
43
+ * aparece como scope no consent.
44
+ */
45
+ declare function callAppConnection<T = unknown>(params: {
46
+ targetAppId: string;
47
+ actionKey: string;
48
+ payload?: unknown;
49
+ /** Access token do usuário dono da conexão. Padrão: o do usuário logado. */
50
+ userToken?: string;
51
+ config?: AppConnectionsConfig;
52
+ }): Promise<T>;
53
+ type ConnectionRegistryEntry = {
54
+ appId: string;
55
+ actions: Record<string, string>;
56
+ };
57
+ /** Chamado por arquivos gerados no formato antigo. Não é necessário no fluxo automático. */
58
+ declare function registerConnections(entries: Record<string, ConnectionRegistryEntry>): void;
59
+ /**
60
+ * Sem tipos gerados (primeira execução), qualquer `app.ação` é aceita. Assim
61
+ * que o SDK escreve `geekapps-connections.d.ts`, a interface estendida passa a
62
+ * valer e o TypeScript confere payload e retorno.
63
+ */
64
+ type AppConnectionsClient = keyof GeekappsConnections extends never ? Record<string, Record<string, (payload?: unknown, options?: ConnectionCallOptions) => Promise<unknown>>> : GeekappsConnections;
65
+ /** Cliente com config explícita — para quem não usa as env vars padrão. */
66
+ declare function createAppConnections(config?: AppConnectionsConfig): AppConnectionsClient;
67
+ /** Catálogo explícito, como o gerado por `npx geekapps-connections` (`geekappsConnectionsCatalog`). */
68
+ type ConnectionsCatalog = Record<string, {
69
+ readonly appId: string;
70
+ readonly actions: Readonly<Record<string, string>>;
71
+ }>;
72
+ /**
73
+ * Opcional: usa um catálogo fixo em vez de consultar o auth-server. Útil em
74
+ * testes ou quando a app não pode falar com o servidor em runtime.
75
+ *
76
+ * const connections = defineAppConnections<GeekappsConnections>(geekappsConnectionsCatalog);
77
+ */
78
+ declare function defineAppConnections<T>(catalog: ConnectionsCatalog, config?: AppConnectionsConfig): T;
79
+ /** Cliente padrão, lendo GEEKAPPS_AUTH_CLIENT_ID / _SECRET do ambiente. */
80
+ declare const appConnections: AppConnectionsClient;
81
+ type ConnectAppParams = {
82
+ /** client_id da app ALVO (a que expõe as ações). */
83
+ targetAppId: string;
84
+ /** AppAction.key das ações pedidas — as mesmas que aparecem no consent. */
85
+ actions: string[];
86
+ /** URL desta app que recebe o retorno do consent (rota que chama `completeAppConnection`). Precisa estar nos redirect URIs desta app. */
87
+ redirectUri: string;
88
+ /** Para onde `completeAppConnection` manda o usuário depois (padrão "/"). */
89
+ returnTo?: string;
90
+ /** Nome desta app exibido no consent. */
91
+ displayName?: string;
92
+ config?: AppConnectionsConfig;
93
+ };
94
+ /**
95
+ * Inicia a conexão desta app com `targetAppId`: guarda PKCE/state em cookies
96
+ * httpOnly e redireciona para o consent. Chame de um Server Action ou Route
97
+ * Handler — não retorna (o `redirect` do Next interrompe a execução).
98
+ */
99
+ declare function connectApp(params: ConnectAppParams): Promise<never>;
100
+ /**
101
+ * Fecha o fluxo de `connectApp`. Chame no callback com o `code` e o `state`
102
+ * da query; devolve o `returnTo` para você redirecionar. Lança
103
+ * AppConnectionError se o state não bater ou o auth-server recusar.
104
+ */
105
+ declare function completeAppConnection(params: {
106
+ code: string;
107
+ state: string;
108
+ config?: AppConnectionsConfig;
109
+ }): Promise<{
110
+ returnTo: string;
111
+ }>;
112
+
113
+ export { AppConnectionError, type AppConnectionsClient, type AppConnectionsConfig, type ConnectAppParams, type ConnectionCallOptions, type ConnectionsCatalog, type GeekappsConnections, appConnections, callAppConnection, completeAppConnection, connectApp, createAppConnections, defineAppConnections, registerConnections };
@@ -0,0 +1,22 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+
3
+ type AuthMiddlewareConfig = {
4
+ issuer?: string;
5
+ basePath?: string;
6
+ /**
7
+ * @deprecated cookiePrefix is now auto-derived from GEEKAPPS_AUTH_CLIENT_ID.
8
+ * This field is kept for backwards compatibility but is ignored.
9
+ */
10
+ cookiePrefix?: string;
11
+ secureCookies?: boolean;
12
+ /** Base URL of this app (e.g. "https://meuapp.com"). Overrides the GEEKAPPS_APP_URL env var. */
13
+ appUrl?: string;
14
+ /**
15
+ * When true, unauthenticated requests are redirected to sign-in.
16
+ * Defaults to false — the app controls its own auth-gating.
17
+ */
18
+ forceLoginOnUnauthenticated?: boolean;
19
+ };
20
+ declare function createAuthMiddleware(input?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
21
+
22
+ export { type AuthMiddlewareConfig, createAuthMiddleware };
@@ -0,0 +1,138 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { JWTPayload } from 'jose';
3
+
4
+ /**
5
+ * A sessão não vale mais: expirou, foi revogada no painel ou o refresh token
6
+ * foi invalidado. Os cookies já foram limpos quando este erro é lançado, então
7
+ * o tratamento normal é redirecionar para o login.
8
+ */
9
+ declare class GeekappsSessionExpiredError extends Error {
10
+ readonly code: "session_expired";
11
+ constructor(message?: string);
12
+ }
13
+ /**
14
+ * Fixed URL of the Geekapps Auth Server (OIDC issuer + API). This never
15
+ * changes per-environment, so it is hardcoded rather than read from env.
16
+ */
17
+ declare const GEEKAPPS_AUTH_SERVER_URL = "https://accounts-api.geekapps.com.br";
18
+ type GeekappsAuthConfig = {
19
+ /**
20
+ * Auth Server (OIDC) issuer URL. Defaults to GEEKAPPS_AUTH_SERVER_URL and
21
+ * should not need overriding in normal use.
22
+ *
23
+ * Deprecated (still supported as a fallback): GEEKAPPS_AUTH_SERVER_ISSUER,
24
+ * GEEKAPPS_AUTH_ISSUER, GEEKAPPS_AUTH_SERVER_URL env, GEEKAPPS_AUTH_API_URL
25
+ */
26
+ issuer?: string;
27
+ /**
28
+ * OAuth client id. Optional when GEEKAPPS_AUTH_CLIENT_ID is defined.
29
+ */
30
+ clientId?: string;
31
+ /**
32
+ * OAuth client secret for confidential clients. Optional when
33
+ * GEEKAPPS_AUTH_CLIENT_SECRET is defined.
34
+ */
35
+ clientSecret?: string;
36
+ /**
37
+ * Callback URL. Optional when GEEKAPPS_AUTH_REDIRECT_URI is defined.
38
+ * If omitted, it is inferred from the current request origin + basePath/callback.
39
+ */
40
+ redirectUri?: string;
41
+ scopes?: string[];
42
+ basePath?: string;
43
+ /**
44
+ * @deprecated cookiePrefix is now auto-derived from clientId.
45
+ * This field is kept for backwards compatibility but is ignored.
46
+ */
47
+ cookiePrefix?: string;
48
+ secureCookies?: boolean;
49
+ /**
50
+ * Friendly alias used by apps. Same as afterSignInRedirectTo.
51
+ */
52
+ redirectTo?: string;
53
+ afterSignInRedirectTo?: string;
54
+ afterSignOutRedirectTo?: string;
55
+ };
56
+ type SessionTokens = {
57
+ accessToken: string | null;
58
+ refreshToken: string | null;
59
+ idToken: string | null;
60
+ sessionId: string | null;
61
+ };
62
+ type StoredAccount = {
63
+ /** Stable identifier — `sub` from id_token or fallback to sessionId. */
64
+ id: string;
65
+ accessToken: string;
66
+ refreshToken: string | null;
67
+ idToken: string | null;
68
+ sessionId: string | null;
69
+ user: {
70
+ sub: string;
71
+ name?: string | null;
72
+ email?: string | null;
73
+ picture?: string | null;
74
+ phone?: string | null;
75
+ };
76
+ };
77
+ type ServerAuthApiClient = {
78
+ get: <T>(path: string) => Promise<T>;
79
+ post: <T>(path: string, body?: unknown) => Promise<T>;
80
+ patch: <T>(path: string, body?: unknown) => Promise<T>;
81
+ put: <T>(path: string, body?: unknown) => Promise<T>;
82
+ delete: <T>(path: string) => Promise<T>;
83
+ };
84
+ type ServiceAccountConfig = {
85
+ issuer?: string;
86
+ clientId?: string;
87
+ clientSecret?: string;
88
+ };
89
+ /**
90
+ * Returns a service account access token.
91
+ * The issuer is always the Geekapps Auth Server (GEEKAPPS_AUTH_SERVER_URL) —
92
+ * it does not need to be configured. Reads GEEKAPPS_SERVICE_ACCOUNT_CLIENT_ID,
93
+ * GEEKAPPS_SERVICE_ACCOUNT_CLIENT_SECRET by default.
94
+ * Any field can be overridden via the optional config argument.
95
+ * Tokens are cached per client and auto-renewed before expiry (~7 min TTL).
96
+ */
97
+ declare function getServiceAccountToken(override?: ServiceAccountConfig): Promise<string | null>;
98
+ declare function verifyToken(token: string, issuer: string): Promise<JWTPayload | null>;
99
+ declare function configureGeekappsAuth(input?: GeekappsAuthConfig): {
100
+ handlers: {
101
+ GET: (request: NextRequest) => Promise<NextResponse<any>>;
102
+ POST: (request: NextRequest) => Promise<NextResponse<any>>;
103
+ PATCH: (request: NextRequest) => Promise<NextResponse<any>>;
104
+ DELETE: (request: NextRequest) => Promise<NextResponse<any>>;
105
+ };
106
+ GetSession: () => Promise<SessionTokens | null>;
107
+ GetUser: () => Promise<StoredAccount["user"] | null>;
108
+ GetUserById: (userId: string, applicationId?: string) => Promise<unknown | null>;
109
+ GetOrganizations: () => Promise<{
110
+ organizations: unknown[];
111
+ currentOrgId: string | null;
112
+ }>;
113
+ SaveSession: (tokens: SessionTokens) => Promise<void>;
114
+ GetAccessToken: () => Promise<string | null>;
115
+ GetRefreshToken: () => Promise<string | null>;
116
+ IsAuthenticated: () => Promise<boolean>;
117
+ TryRefreshTokens: () => Promise<string | null>;
118
+ RequireUser: (options?: {
119
+ redirectTo?: string;
120
+ }) => Promise<string>;
121
+ CreateAuthApiClient: () => ServerAuthApiClient;
122
+ cookiePrefix: string;
123
+ VerifyToken: (token: string) => Promise<JWTPayload | null>;
124
+ SignInUrl: (redirectTo?: string) => Promise<string>;
125
+ };
126
+ declare function handlers(options?: GeekappsAuthConfig): {
127
+ GET: (request: NextRequest) => Promise<NextResponse<any>>;
128
+ POST: (request: NextRequest) => Promise<NextResponse<any>>;
129
+ PATCH: (request: NextRequest) => Promise<NextResponse<any>>;
130
+ DELETE: (request: NextRequest) => Promise<NextResponse<any>>;
131
+ };
132
+ /**
133
+ * Returns true if the current request has a valid access token in cookies.
134
+ * Safe to call in Server Components, Server Actions, and Route Handlers.
135
+ */
136
+ declare function isAuthenticated(options?: GeekappsAuthConfig): Promise<boolean>;
137
+
138
+ export { GEEKAPPS_AUTH_SERVER_URL, type GeekappsAuthConfig, GeekappsSessionExpiredError, type ServerAuthApiClient, type SessionTokens, type StoredAccount, configureGeekappsAuth, getServiceAccountToken, handlers, isAuthenticated, verifyToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekapps/auth-nextjs",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "types": "/dist",
@@ -31,7 +31,9 @@
31
31
  "README.md"
32
32
  ],
33
33
  "scripts": {
34
- "build": "tsup"
34
+ "prebuild": "npm run build --prefix ../auth-cli",
35
+ "build": "tsup",
36
+ "prepublishOnly": "npm run build && node -e \"const fs=require('fs');const p=require('./package.json');const miss=Object.values(p.exports||{}).map(e=>e.types).filter(t=>t&&!fs.existsSync(t));if(miss.length){console.error('Faltam declaracoes:',miss.join(', '));process.exit(1)}\""
35
37
  },
36
38
  "dependencies": {
37
39
  "jose": "^6.2.3",