@yackey-labs/yauth-client 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.
Files changed (55) hide show
  1. package/dist/index.js +196 -0
  2. package/package.json +30 -0
  3. package/src/bindings/AccountLockoutMessageResponse.ts +3 -0
  4. package/src/bindings/ApiKeyResponse.ts +3 -0
  5. package/src/bindings/AuthConfigResponse.ts +14 -0
  6. package/src/bindings/AuthMethod.ts +3 -0
  7. package/src/bindings/AuthUser.ts +4 -0
  8. package/src/bindings/AuthorizeQuery.ts +3 -0
  9. package/src/bindings/AuthorizeResponse.ts +3 -0
  10. package/src/bindings/BackupCodeCountResponse.ts +3 -0
  11. package/src/bindings/BackupCodesResponse.ts +3 -0
  12. package/src/bindings/BanRequest.ts +3 -0
  13. package/src/bindings/CallbackBody.ts +3 -0
  14. package/src/bindings/ChangePasswordRequest.ts +3 -0
  15. package/src/bindings/ConfirmTotpRequest.ts +3 -0
  16. package/src/bindings/CreateApiKeyRequest.ts +3 -0
  17. package/src/bindings/CreateApiKeyResponse.ts +3 -0
  18. package/src/bindings/CreateWebhookRequest.ts +3 -0
  19. package/src/bindings/ForgotPasswordRequest.ts +3 -0
  20. package/src/bindings/ListSessionsQuery.ts +3 -0
  21. package/src/bindings/ListUsersQuery.ts +3 -0
  22. package/src/bindings/LoginRequest.ts +3 -0
  23. package/src/bindings/MagicLinkMessageResponse.ts +3 -0
  24. package/src/bindings/MagicLinkSendRequest.ts +3 -0
  25. package/src/bindings/MagicLinkVerifyRequest.ts +3 -0
  26. package/src/bindings/MessageResponse.ts +3 -0
  27. package/src/bindings/MfaAuthResponse.ts +3 -0
  28. package/src/bindings/MfaMessageResponse.ts +3 -0
  29. package/src/bindings/OAuthAccountResponse.ts +3 -0
  30. package/src/bindings/OAuthAuthResponse.ts +3 -0
  31. package/src/bindings/PasskeyInfo.ts +3 -0
  32. package/src/bindings/PasskeyLoginBeginRequest.ts +3 -0
  33. package/src/bindings/PasskeyLoginFinishRequest.ts +3 -0
  34. package/src/bindings/RefreshRequest.ts +3 -0
  35. package/src/bindings/RegisterFinishRequest.ts +3 -0
  36. package/src/bindings/RegisterRequest.ts +3 -0
  37. package/src/bindings/RequestUnlockRequest.ts +3 -0
  38. package/src/bindings/ResendVerificationRequest.ts +3 -0
  39. package/src/bindings/ResetPasswordRequest.ts +3 -0
  40. package/src/bindings/RevokeRequest.ts +3 -0
  41. package/src/bindings/SetupTotpResponse.ts +3 -0
  42. package/src/bindings/TokenRequest.ts +7 -0
  43. package/src/bindings/TokenResponse.ts +3 -0
  44. package/src/bindings/UnlockAccountRequest.ts +3 -0
  45. package/src/bindings/UpdateProfileRequest.ts +3 -0
  46. package/src/bindings/UpdateUserRequest.ts +3 -0
  47. package/src/bindings/UpdateWebhookRequest.ts +3 -0
  48. package/src/bindings/VerifyEmailRequest.ts +3 -0
  49. package/src/bindings/VerifyMfaRequest.ts +3 -0
  50. package/src/bindings/WebhookDeliveryResponse.ts +3 -0
  51. package/src/bindings/WebhookDetailResponse.ts +5 -0
  52. package/src/bindings/WebhookResponse.ts +3 -0
  53. package/src/generated.test.ts +337 -0
  54. package/src/generated.ts +385 -0
  55. package/src/index.ts +419 -0
package/src/index.ts ADDED
@@ -0,0 +1,419 @@
1
+ import type { AuthUser } from "@yackey-labs/yauth-shared";
2
+
3
+ export type { AuthSession, AuthUser } from "@yackey-labs/yauth-shared";
4
+
5
+ export interface YAuthClientOptions {
6
+ /** Base URL for auth endpoints (e.g., '/api/auth' or 'https://api.example.com/api/auth') */
7
+ baseUrl: string;
8
+ /** Custom fetch function (default: window.fetch) */
9
+ fetch?: typeof fetch;
10
+ /** Include credentials in requests (default: true for cookies) */
11
+ credentials?: RequestCredentials;
12
+ }
13
+
14
+ type RequestOptions = {
15
+ method?: string;
16
+ body?: unknown;
17
+ headers?: Record<string, string>;
18
+ };
19
+
20
+ function createClient(opts: YAuthClientOptions) {
21
+ const { baseUrl, credentials = "include" } = opts;
22
+ const fetchFn = opts.fetch ?? globalThis.fetch;
23
+
24
+ async function request<T>(
25
+ path: string,
26
+ options: RequestOptions = {},
27
+ ): Promise<T> {
28
+ const { method = "GET", body, headers = {} } = options;
29
+
30
+ const response = await fetchFn(`${baseUrl}${path}`, {
31
+ method,
32
+ credentials,
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ ...headers,
36
+ },
37
+ body: body ? JSON.stringify(body) : undefined,
38
+ });
39
+
40
+ if (!response.ok) {
41
+ const text = await response.text();
42
+ let error: string;
43
+ try {
44
+ const json = JSON.parse(text);
45
+ error = json.error ?? json.message ?? text;
46
+ } catch {
47
+ error = text;
48
+ }
49
+ throw new YAuthError(error, response.status);
50
+ }
51
+
52
+ const text = await response.text();
53
+ return (text ? JSON.parse(text) : undefined) as T;
54
+ }
55
+
56
+ return {
57
+ /** Core auth operations */
58
+ getSession: () => request<{ user: AuthUser }>("/session"),
59
+
60
+ logout: () => request<{ success: boolean }>("/logout", { method: "POST" }),
61
+
62
+ updateProfile: (data: { display_name?: string }) =>
63
+ request<{ user: AuthUser }>("/me", { method: "PATCH", body: data }),
64
+
65
+ /** Email/password operations */
66
+ emailPassword: {
67
+ register: (data: {
68
+ email: string;
69
+ password: string;
70
+ display_name?: string;
71
+ }) =>
72
+ request<{ message: string }>("/register", {
73
+ method: "POST",
74
+ body: data,
75
+ }),
76
+
77
+ login: (data: { email: string; password: string }) =>
78
+ request<
79
+ | {
80
+ user_id: string;
81
+ email: string;
82
+ display_name: string | null;
83
+ email_verified: boolean;
84
+ }
85
+ | { mfa_required: true; pending_session_id: string }
86
+ >("/login", { method: "POST", body: data }),
87
+
88
+ verify: (token: string) =>
89
+ request<{ message: string }>("/verify-email", {
90
+ method: "POST",
91
+ body: { token },
92
+ }),
93
+
94
+ resendVerification: (email: string) =>
95
+ request<{ message: string }>("/resend-verification", {
96
+ method: "POST",
97
+ body: { email },
98
+ }),
99
+
100
+ forgotPassword: (email: string) =>
101
+ request<{ message: string }>("/forgot-password", {
102
+ method: "POST",
103
+ body: { email },
104
+ }),
105
+
106
+ resetPassword: (token: string, password: string) =>
107
+ request<{ message: string }>("/reset-password", {
108
+ method: "POST",
109
+ body: { token, password },
110
+ }),
111
+
112
+ changePassword: (currentPassword: string, newPassword: string) =>
113
+ request<{ message: string }>("/change-password", {
114
+ method: "POST",
115
+ body: {
116
+ current_password: currentPassword,
117
+ new_password: newPassword,
118
+ },
119
+ }),
120
+ },
121
+
122
+ /** Passkey (WebAuthn) operations */
123
+ passkey: {
124
+ loginBegin: (email?: string) =>
125
+ request<{ challenge_id: string; options: unknown }>(
126
+ "/passkey/login/begin",
127
+ {
128
+ method: "POST",
129
+ body: email ? { email } : {},
130
+ },
131
+ ),
132
+
133
+ loginFinish: (challenge_id: string, credential: unknown) =>
134
+ request<{
135
+ user_id: string;
136
+ email: string;
137
+ display_name: string | null;
138
+ email_verified: boolean;
139
+ }>("/passkey/login/finish", {
140
+ method: "POST",
141
+ body: { challenge_id, credential },
142
+ }),
143
+
144
+ registerBegin: () =>
145
+ request<unknown>("/passkeys/register/begin", {
146
+ method: "POST",
147
+ }),
148
+
149
+ registerFinish: (credential: unknown, name: string) =>
150
+ request<void>("/passkeys/register/finish", {
151
+ method: "POST",
152
+ body: { credential, name },
153
+ }),
154
+
155
+ list: () =>
156
+ request<
157
+ Array<{
158
+ id: string;
159
+ name: string;
160
+ created_at: string;
161
+ last_used_at: string | null;
162
+ }>
163
+ >("/passkeys"),
164
+
165
+ delete: (id: string) =>
166
+ request<{ message: string }>(`/passkeys/${id}`, {
167
+ method: "DELETE",
168
+ }),
169
+ },
170
+
171
+ /** MFA (TOTP + backup codes) operations */
172
+ mfa: {
173
+ setup: () =>
174
+ request<{
175
+ otpauth_url: string;
176
+ secret: string;
177
+ backup_codes: string[];
178
+ }>("/mfa/totp/setup", { method: "POST" }),
179
+
180
+ confirm: (code: string) =>
181
+ request<{ message: string }>("/mfa/totp/confirm", {
182
+ method: "POST",
183
+ body: { code },
184
+ }),
185
+
186
+ verify: (pending_session_id: string, code: string) =>
187
+ request<{
188
+ user_id: string;
189
+ email: string;
190
+ display_name: string | null;
191
+ email_verified: boolean;
192
+ }>("/mfa/verify", {
193
+ method: "POST",
194
+ body: { pending_session_id, code },
195
+ }),
196
+
197
+ disable: () =>
198
+ request<{ message: string }>("/mfa/totp", { method: "DELETE" }),
199
+
200
+ getBackupCodeCount: () =>
201
+ request<{ remaining: number }>("/mfa/backup-codes"),
202
+
203
+ regenerateBackupCodes: () =>
204
+ request<{ backup_codes: string[] }>("/mfa/backup-codes/regenerate", {
205
+ method: "POST",
206
+ }),
207
+ },
208
+
209
+ /** OAuth operations */
210
+ oauth: {
211
+ authorize: (provider: string, redirect_url?: string) => {
212
+ const params = redirect_url
213
+ ? `?redirect_url=${encodeURIComponent(redirect_url)}`
214
+ : "";
215
+ window.location.href = `${baseUrl}/oauth/${provider}/authorize${params}`;
216
+ },
217
+
218
+ callback: (provider: string, code: string, state: string) =>
219
+ request<{
220
+ user_id: string;
221
+ email: string;
222
+ display_name: string | null;
223
+ email_verified: boolean;
224
+ }>(`/oauth/${provider}/callback`, {
225
+ method: "POST",
226
+ body: { code, state },
227
+ }),
228
+
229
+ accounts: () =>
230
+ request<
231
+ Array<{
232
+ id: string;
233
+ provider: string;
234
+ provider_user_id: string;
235
+ created_at: string;
236
+ }>
237
+ >("/oauth/accounts"),
238
+
239
+ unlink: (provider: string) =>
240
+ request<{ message: string }>(`/oauth/${provider}`, {
241
+ method: "DELETE",
242
+ }),
243
+
244
+ link: (provider: string) =>
245
+ request<{ authorize_url: string }>(`/oauth/${provider}/link`, {
246
+ method: "POST",
247
+ }),
248
+ },
249
+
250
+ /** Magic link (passwordless email login) */
251
+ magicLink: {
252
+ send: (email: string) =>
253
+ request<{ message: string }>("/magic-link/send", {
254
+ method: "POST",
255
+ body: { email },
256
+ }),
257
+
258
+ verify: (token: string) =>
259
+ request<{
260
+ user_id: string;
261
+ email: string;
262
+ display_name: string | null;
263
+ email_verified: boolean;
264
+ is_new_user: boolean;
265
+ }>("/magic-link/verify", {
266
+ method: "POST",
267
+ body: { token },
268
+ }),
269
+ },
270
+
271
+ /** Bearer token operations (for mobile/CLI/MCP) */
272
+ bearer: {
273
+ getToken: (email: string, password: string) =>
274
+ request<{
275
+ access_token: string;
276
+ refresh_token: string;
277
+ token_type: string;
278
+ expires_in: number;
279
+ }>("/token", { method: "POST", body: { email, password } }),
280
+
281
+ refresh: (refresh_token: string) =>
282
+ request<{
283
+ access_token: string;
284
+ refresh_token: string;
285
+ token_type: string;
286
+ expires_in: number;
287
+ }>("/token/refresh", { method: "POST", body: { refresh_token } }),
288
+
289
+ revoke: (refresh_token: string) =>
290
+ request<{ success: boolean }>("/token/revoke", {
291
+ method: "POST",
292
+ body: { refresh_token },
293
+ }),
294
+ },
295
+
296
+ /** API key operations */
297
+ apiKeys: {
298
+ create: (data: {
299
+ name: string;
300
+ scopes?: string[];
301
+ expires_in_days?: number;
302
+ }) =>
303
+ request<{
304
+ id: string;
305
+ key: string;
306
+ name: string;
307
+ prefix: string;
308
+ scopes: string[] | null;
309
+ expires_at: string | null;
310
+ created_at: string;
311
+ }>("/api-keys", { method: "POST", body: data }),
312
+
313
+ list: () =>
314
+ request<
315
+ Array<{
316
+ id: string;
317
+ name: string;
318
+ prefix: string;
319
+ scopes: string[] | null;
320
+ last_used_at: string | null;
321
+ expires_at: string | null;
322
+ created_at: string;
323
+ }>
324
+ >("/api-keys"),
325
+
326
+ delete: (id: string) =>
327
+ request<void>(`/api-keys/${id}`, { method: "DELETE" }),
328
+ },
329
+
330
+ /** Admin operations (requires admin role) */
331
+ admin: {
332
+ listUsers: (params?: {
333
+ page?: number;
334
+ per_page?: number;
335
+ search?: string;
336
+ }) => {
337
+ const query = new URLSearchParams();
338
+ if (params?.page) query.set("page", String(params.page));
339
+ if (params?.per_page) query.set("per_page", String(params.per_page));
340
+ if (params?.search) query.set("search", params.search);
341
+ const qs = query.toString();
342
+ return request<{
343
+ users: AuthUser[];
344
+ total: number;
345
+ page: number;
346
+ per_page: number;
347
+ }>(`/admin/users${qs ? `?${qs}` : ""}`);
348
+ },
349
+
350
+ getUser: (id: string) => request<AuthUser>(`/admin/users/${id}`),
351
+
352
+ updateUser: (
353
+ id: string,
354
+ data: Partial<{
355
+ role: string;
356
+ display_name: string;
357
+ email_verified: boolean;
358
+ }>,
359
+ ) =>
360
+ request<AuthUser>(`/admin/users/${id}`, { method: "PUT", body: data }),
361
+
362
+ deleteUser: (id: string) =>
363
+ request<void>(`/admin/users/${id}`, {
364
+ method: "DELETE",
365
+ }),
366
+
367
+ banUser: (id: string, data?: { reason?: string; until?: string }) =>
368
+ request<AuthUser>(`/admin/users/${id}/ban`, {
369
+ method: "POST",
370
+ body: data ?? {},
371
+ }),
372
+
373
+ unbanUser: (id: string) =>
374
+ request<AuthUser>(`/admin/users/${id}/unban`, {
375
+ method: "POST",
376
+ }),
377
+
378
+ impersonate: (id: string) =>
379
+ request<{ token: string; session_id: string; expires_at: string }>(
380
+ `/admin/users/${id}/impersonate`,
381
+ { method: "POST" },
382
+ ),
383
+
384
+ listSessions: (params?: { page?: number; per_page?: number }) => {
385
+ const query = new URLSearchParams();
386
+ if (params?.page) query.set("page", String(params.page));
387
+ if (params?.per_page) query.set("per_page", String(params.per_page));
388
+ const qs = query.toString();
389
+ return request<{
390
+ sessions: unknown[];
391
+ total: number;
392
+ page: number;
393
+ per_page: number;
394
+ }>(`/admin/sessions${qs ? `?${qs}` : ""}`);
395
+ },
396
+
397
+ deleteSession: (id: string) =>
398
+ request<void>(`/admin/sessions/${id}`, {
399
+ method: "DELETE",
400
+ }),
401
+ },
402
+ };
403
+ }
404
+
405
+ export class YAuthError extends Error {
406
+ constructor(
407
+ message: string,
408
+ public status: number,
409
+ ) {
410
+ super(message);
411
+ this.name = "YAuthError";
412
+ }
413
+ }
414
+
415
+ export function createYAuthClient(options: YAuthClientOptions) {
416
+ return createClient(options);
417
+ }
418
+
419
+ export type YAuthClient = ReturnType<typeof createYAuthClient>;