@korajs/auth 0.4.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@korajs/auth",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Offline-first authentication for Kora.js",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -42,7 +42,7 @@
42
42
  "dist"
43
43
  ],
44
44
  "dependencies": {
45
- "@korajs/core": "0.4.0"
45
+ "@korajs/core": "0.5.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/better-sqlite3": "^7.6.13",
@@ -51,9 +51,9 @@
51
51
  "tsup": "^8.0.0",
52
52
  "typescript": "^5.7.0",
53
53
  "vitest": "^3.0.0",
54
- "@korajs/store": "0.4.0",
55
- "@korajs/server": "0.4.0",
56
- "@korajs/sync": "0.4.0"
54
+ "@korajs/store": "0.5.0",
55
+ "@korajs/sync": "0.5.0",
56
+ "@korajs/server": "0.5.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "react": "^18.0.0 || ^19.0.0",
@@ -1,355 +0,0 @@
1
- import { KoraError } from '@korajs/core';
2
-
3
- /**
4
- * Thrown when an authentication operation fails.
5
- * Includes a machine-readable code and optional context for debugging.
6
- */
7
- declare class AuthError extends KoraError {
8
- constructor(message: string, code: string, context?: Record<string, unknown>);
9
- }
10
- /**
11
- * Possible authentication states for the client.
12
- * - 'loading': Initial state while restoring tokens from storage
13
- * - 'authenticated': User is signed in with a valid session
14
- * - 'unauthenticated': No valid session exists
15
- */
16
- type AuthState = 'loading' | 'authenticated' | 'unauthenticated';
17
- /**
18
- * Authenticated user information.
19
- */
20
- interface AuthUser {
21
- /** Unique user identifier */
22
- id: string;
23
- /** User email address */
24
- email: string;
25
- /** Display name (may be absent if user did not provide one) */
26
- name: string | null;
27
- }
28
- /**
29
- * Configuration for the AuthClient.
30
- */
31
- interface AuthClientConfig {
32
- /** Base URL of the auth server (e.g. 'http://localhost:3001') */
33
- serverUrl: string;
34
- /** Storage key prefix for tokens. Defaults to 'kora_auth' */
35
- storageKey?: string;
36
- }
37
- /**
38
- * Client-side authentication manager for Kora.js.
39
- *
40
- * Manages token storage, session restoration, sign-up, sign-in, sign-out,
41
- * token refresh, and auth state change notifications. Framework-agnostic --
42
- * works in any JavaScript environment with `fetch` and optionally `localStorage`.
43
- *
44
- * @example
45
- * ```typescript
46
- * const auth = new AuthClient({ serverUrl: 'http://localhost:3001' })
47
- * await auth.initialize()
48
- *
49
- * if (!auth.isAuthenticated) {
50
- * await auth.signIn({ email: 'user@example.com', password: 'secret' })
51
- * }
52
- *
53
- * const unsub = auth.onAuthChange((state) => {
54
- * console.log('Auth state:', state)
55
- * })
56
- * ```
57
- */
58
- declare class AuthClient {
59
- private readonly serverUrl;
60
- private readonly storage;
61
- private readonly listeners;
62
- private _state;
63
- private _user;
64
- private _refreshPromise;
65
- private _initialized;
66
- /**
67
- * Creates a new AuthClient.
68
- *
69
- * @param config - Auth client configuration
70
- */
71
- constructor(config: AuthClientConfig);
72
- /** Current authentication state. */
73
- get state(): AuthState;
74
- /** Current authenticated user, or null if not signed in. */
75
- get currentUser(): AuthUser | null;
76
- /** Whether the user is currently authenticated. */
77
- get isAuthenticated(): boolean;
78
- /**
79
- * Initialize the auth client by restoring a session from stored tokens.
80
- *
81
- * Loads tokens from storage, validates the access token, and attempts a
82
- * refresh if the access token is expired but a refresh token is available.
83
- * Safe to call multiple times -- subsequent calls are no-ops once initialized.
84
- */
85
- initialize(): Promise<void>;
86
- /**
87
- * Register a new user account.
88
- *
89
- * @param params - Sign-up credentials
90
- * @returns The newly created AuthUser
91
- * @throws {AuthError} If the request fails or the server returns an error
92
- */
93
- signUp(params: {
94
- email: string;
95
- password: string;
96
- name?: string;
97
- }): Promise<AuthUser>;
98
- /**
99
- * Sign in with email and password.
100
- *
101
- * @param params - Sign-in credentials
102
- * @returns The authenticated AuthUser
103
- * @throws {AuthError} If the credentials are invalid or the request fails
104
- */
105
- signIn(params: {
106
- email: string;
107
- password: string;
108
- }): Promise<AuthUser>;
109
- /**
110
- * Sign out the current user.
111
- *
112
- * Clears local tokens and attempts to revoke the refresh token on the server
113
- * (best-effort — succeeds even if the server is unreachable). This ensures that
114
- * stolen refresh tokens cannot be used after the user explicitly signs out.
115
- */
116
- signOut(): Promise<void>;
117
- /**
118
- * Get a valid access token, automatically refreshing if expired.
119
- *
120
- * @returns A valid access token string, or null if the user is not
121
- * authenticated and refresh is not possible
122
- */
123
- getAccessToken(): Promise<string | null>;
124
- /**
125
- * Get a valid token for the sync engine handshake.
126
- * Alias for {@link getAccessToken}.
127
- *
128
- * @returns A valid access token string, or null if unavailable
129
- */
130
- getSyncToken(): Promise<string | null>;
131
- /**
132
- * Subscribe to authentication state changes.
133
- *
134
- * The callback is invoked whenever the auth state transitions (e.g., from
135
- * 'unauthenticated' to 'authenticated' on sign-in).
136
- *
137
- * @param callback - Function called with the new AuthState on each change
138
- * @returns An unsubscribe function that removes the listener
139
- *
140
- * @example
141
- * ```typescript
142
- * const unsub = auth.onAuthChange((state) => {
143
- * console.log('Auth state changed to:', state)
144
- * })
145
- * // Later: unsub()
146
- * ```
147
- */
148
- onAuthChange(callback: (state: AuthState) => void): () => void;
149
- /**
150
- * Update internal state and notify all listeners.
151
- */
152
- private setState;
153
- /**
154
- * Restore a session from a valid access token by fetching the user profile.
155
- * Falls back to extracting the user ID from the token payload if the
156
- * /auth/me request fails (offline scenario).
157
- */
158
- private restoreSession;
159
- /**
160
- * Fetch the current user profile from the server.
161
- */
162
- private fetchUserProfile;
163
- /**
164
- * Refresh the access token using a refresh token.
165
- * De-duplicates concurrent refresh calls so only one network request is made.
166
- */
167
- private refreshAccessToken;
168
- /**
169
- * Execute the token refresh network request.
170
- */
171
- private performRefresh;
172
- /**
173
- * Make an HTTP request to the auth server.
174
- *
175
- * @param path - URL path relative to serverUrl (e.g. '/auth/signin')
176
- * @param options - Request options
177
- * @returns Parsed JSON response body
178
- * @throws {AuthError} On network failure or non-2xx response
179
- */
180
- private request;
181
- }
182
-
183
- /**
184
- * Organization info returned by the server.
185
- */
186
- interface ClientOrganization {
187
- id: string;
188
- name: string;
189
- slug: string;
190
- ownerId: string;
191
- createdAt: number;
192
- updatedAt: number;
193
- metadata: Record<string, unknown>;
194
- }
195
- /**
196
- * Membership info returned by the server.
197
- */
198
- interface ClientMembership {
199
- id: string;
200
- orgId: string;
201
- userId: string;
202
- role: string;
203
- invitedBy: string | null;
204
- joinedAt: number;
205
- }
206
- /**
207
- * Invitation info returned by the server.
208
- */
209
- interface ClientInvitation {
210
- id: string;
211
- orgId: string;
212
- email: string;
213
- role: string;
214
- invitedBy: string;
215
- token: string;
216
- createdAt: number;
217
- expiresAt: number;
218
- status: string;
219
- }
220
- /**
221
- * Configuration for the OrgClient.
222
- */
223
- interface OrgClientConfig {
224
- /** Base URL of the auth/org server */
225
- serverUrl: string;
226
- /** Function that returns a valid access token for authenticated requests */
227
- getAccessToken: () => Promise<string | null>;
228
- }
229
- /**
230
- * Thrown when an org operation fails.
231
- */
232
- declare class OrgClientError extends KoraError {
233
- constructor(message: string, code: string, context?: Record<string, unknown>);
234
- }
235
- /**
236
- * Client-side organization manager.
237
- *
238
- * Handles org CRUD, member management, invitations, and active org switching.
239
- * Framework-agnostic — works in any JavaScript environment with `fetch`.
240
- *
241
- * @example
242
- * ```typescript
243
- * const orgClient = new OrgClient({
244
- * serverUrl: 'http://localhost:3001',
245
- * getAccessToken: () => authClient.getAccessToken(),
246
- * })
247
- *
248
- * const org = await orgClient.createOrg({ name: 'Acme Inc', slug: 'acme' })
249
- * orgClient.switchOrg(org.id)
250
- * ```
251
- */
252
- declare class OrgClient {
253
- private readonly serverUrl;
254
- private readonly getAccessToken;
255
- private readonly listeners;
256
- private _activeOrgId;
257
- private _activeOrg;
258
- private _activeRole;
259
- constructor(config: OrgClientConfig);
260
- /** Currently active organization ID */
261
- get activeOrgId(): string | null;
262
- /** Currently active organization */
263
- get activeOrg(): ClientOrganization | null;
264
- /** Current user's role in the active organization */
265
- get activeRole(): string | null;
266
- /**
267
- * Create a new organization.
268
- */
269
- createOrg(params: {
270
- name: string;
271
- slug?: string;
272
- metadata?: Record<string, unknown>;
273
- }): Promise<ClientOrganization>;
274
- /**
275
- * List all organizations the current user belongs to.
276
- */
277
- listOrgs(): Promise<ClientOrganization[]>;
278
- /**
279
- * Get an organization by ID.
280
- */
281
- getOrg(orgId: string): Promise<ClientOrganization>;
282
- /**
283
- * Update an organization.
284
- */
285
- updateOrg(orgId: string, params: {
286
- name?: string;
287
- slug?: string;
288
- metadata?: Record<string, unknown>;
289
- }): Promise<ClientOrganization>;
290
- /**
291
- * Delete an organization.
292
- */
293
- deleteOrg(orgId: string): Promise<void>;
294
- /**
295
- * Switch the active organization context.
296
- * Fetches the org details and the user's membership/role.
297
- */
298
- switchOrg(orgId: string): Promise<void>;
299
- /**
300
- * Clear the active organization (no org selected).
301
- */
302
- clearActiveOrg(): void;
303
- /**
304
- * List members of an organization.
305
- */
306
- listMembers(orgId: string): Promise<ClientMembership[]>;
307
- /**
308
- * Remove a member from an organization.
309
- */
310
- removeMember(orgId: string, userId: string): Promise<void>;
311
- /**
312
- * Update a member's role.
313
- */
314
- updateMemberRole(orgId: string, userId: string, role: string): Promise<ClientMembership>;
315
- /**
316
- * Transfer ownership to another member.
317
- */
318
- transferOwnership(orgId: string, newOwnerId: string): Promise<void>;
319
- /**
320
- * Leave an organization (remove yourself).
321
- */
322
- leaveOrg(orgId: string): Promise<void>;
323
- /**
324
- * Invite a user to an organization by email.
325
- */
326
- inviteMember(orgId: string, params: {
327
- email: string;
328
- role: string;
329
- }): Promise<ClientInvitation>;
330
- /**
331
- * Accept an invitation by token.
332
- */
333
- acceptInvitation(token: string): Promise<ClientMembership>;
334
- /**
335
- * List pending invitations for an organization.
336
- */
337
- listInvitations(orgId: string): Promise<ClientInvitation[]>;
338
- /**
339
- * Revoke a pending invitation.
340
- */
341
- revokeInvitation(orgId: string, invitationId: string): Promise<void>;
342
- /**
343
- * List pending invitations for the current user's email.
344
- */
345
- listMyInvitations(email: string): Promise<ClientInvitation[]>;
346
- /**
347
- * Subscribe to active org changes.
348
- * @returns Unsubscribe function
349
- */
350
- onOrgChange(callback: (orgId: string | null) => void): () => void;
351
- private notifyListeners;
352
- private request;
353
- }
354
-
355
- export { AuthClient as A, type ClientInvitation as C, OrgClient as O, type AuthClientConfig as a, AuthError as b, type AuthState as c, type AuthUser as d, type ClientMembership as e, type ClientOrganization as f, type OrgClientConfig as g, OrgClientError as h };