@opensaas/stack-auth 0.1.6 → 0.3.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 (41) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +133 -0
  3. package/CLAUDE.md +61 -0
  4. package/dist/config/index.d.ts.map +1 -1
  5. package/dist/config/index.js +1 -0
  6. package/dist/config/index.js.map +1 -1
  7. package/dist/config/plugin.d.ts.map +1 -1
  8. package/dist/config/plugin.js +33 -1
  9. package/dist/config/plugin.js.map +1 -1
  10. package/dist/config/types.d.ts +38 -1
  11. package/dist/config/types.d.ts.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/runtime/types.d.ts +26 -0
  16. package/dist/runtime/types.d.ts.map +1 -0
  17. package/dist/runtime/types.js +6 -0
  18. package/dist/runtime/types.js.map +1 -0
  19. package/dist/server/index.d.ts.map +1 -1
  20. package/dist/server/index.js +42 -9
  21. package/dist/server/index.js.map +1 -1
  22. package/dist/ui/components/ForgotPasswordForm.js +1 -1
  23. package/dist/ui/components/ForgotPasswordForm.js.map +1 -1
  24. package/dist/ui/components/SignInForm.d.ts.map +1 -1
  25. package/dist/ui/components/SignInForm.js +11 -1
  26. package/dist/ui/components/SignInForm.js.map +1 -1
  27. package/dist/ui/components/SignUpForm.d.ts.map +1 -1
  28. package/dist/ui/components/SignUpForm.js +11 -1
  29. package/dist/ui/components/SignUpForm.js.map +1 -1
  30. package/package.json +5 -5
  31. package/src/config/index.ts +1 -0
  32. package/src/config/plugin.ts +37 -2
  33. package/src/config/types.ts +42 -1
  34. package/src/index.ts +3 -0
  35. package/src/runtime/types.ts +27 -0
  36. package/src/server/index.ts +47 -9
  37. package/src/ui/components/ForgotPasswordForm.tsx +1 -1
  38. package/src/ui/components/SignInForm.tsx +10 -1
  39. package/src/ui/components/SignUpForm.tsx +10 -1
  40. package/tests/config.test.ts +4 -13
  41. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState } from 'react';
4
+ import { useRouter } from 'next/navigation.js';
4
5
  /**
5
6
  * Sign up form component
6
7
  * Provides email/password registration and OAuth provider buttons
@@ -16,6 +17,7 @@ import { useState } from 'react';
16
17
  * ```
17
18
  */
18
19
  export function SignUpForm({ authClient, redirectTo = '/', showSocialProviders = true, socialProviders = ['github', 'google'], requirePasswordConfirmation = true, className = '', onSuccess, onError, }) {
20
+ const router = useRouter();
19
21
  const [name, setName] = useState('');
20
22
  const [email, setEmail] = useState('');
21
23
  const [password, setPassword] = useState('');
@@ -41,7 +43,13 @@ export function SignUpForm({ authClient, redirectTo = '/', showSocialProviders =
41
43
  if (result.error) {
42
44
  throw new Error(result.error.message);
43
45
  }
44
- onSuccess?.();
46
+ // If onSuccess is provided, call it. Otherwise, automatically redirect
47
+ if (onSuccess) {
48
+ onSuccess();
49
+ }
50
+ else {
51
+ router.push(redirectTo);
52
+ }
45
53
  }
46
54
  catch (err) {
47
55
  const message = err instanceof Error ? err.message : 'Sign up failed';
@@ -60,6 +68,8 @@ export function SignUpForm({ authClient, redirectTo = '/', showSocialProviders =
60
68
  provider,
61
69
  callbackURL: redirectTo,
62
70
  });
71
+ // Social sign-in handles its own redirect via OAuth flow
72
+ // Only call onSuccess if provided
63
73
  onSuccess?.();
64
74
  }
65
75
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"SignUpForm.js","sourceRoot":"","sources":["../../../src/ui/components/SignUpForm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SignUpForm.js","sourceRoot":"","sources":["../../../src/ui/components/SignUpForm.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensaas/stack-auth",
3
- "version": "0.1.6",
3
+ "version": "0.3.0",
4
4
  "description": "Better-auth integration for OpenSaas Stack",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,10 +49,10 @@
49
49
  "url": "https://github.com/OpenSaasAU/stack/issues"
50
50
  },
51
51
  "peerDependencies": {
52
+ "@opensaas/stack-core": "^0",
52
53
  "better-auth": "^1.3.29",
53
- "react": "^18.0.0 || ^19.0.0",
54
54
  "next": "^15.0.0 || ^16.0.0",
55
- "@opensaas/stack-core": "0.1.6"
55
+ "react": "^18.0.0 || ^19.0.0"
56
56
  },
57
57
  "dependencies": {},
58
58
  "devDependencies": {
@@ -61,11 +61,11 @@
61
61
  "@vitest/coverage-v8": "^4.0.4",
62
62
  "@vitest/ui": "^4.0.0",
63
63
  "better-auth": "^1.3.29",
64
- "next": "^16.0.0",
64
+ "next": "^16.0.1",
65
65
  "react": "^19.2.0",
66
66
  "typescript": "^5.9.3",
67
67
  "vitest": "^4.0.0",
68
- "@opensaas/stack-core": "0.1.6"
68
+ "@opensaas/stack-core": "0.3.0"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "tsc",
@@ -64,6 +64,7 @@ export function normalizeAuthConfig(config: AuthConfig): NormalizedAuthConfig {
64
64
  console.log(`Body: ${html}`)
65
65
  }),
66
66
  betterAuthPlugins: config.betterAuthPlugins || [],
67
+ rateLimit: config.rateLimit,
67
68
  }
68
69
  }
69
70
 
@@ -32,6 +32,11 @@ export function authPlugin(config: AuthConfig): Plugin {
32
32
  name: 'auth',
33
33
  version: '0.1.0',
34
34
 
35
+ runtimeServiceTypes: {
36
+ import: "import type { AuthRuntimeServices } from '@opensaas/stack-auth'",
37
+ typeName: 'AuthRuntimeServices',
38
+ },
39
+
35
40
  init: async (context) => {
36
41
  // Get auth lists from base Better Auth schema
37
42
  const authLists = getAuthLists(normalized.extendUserList)
@@ -40,8 +45,7 @@ export function authPlugin(config: AuthConfig): Plugin {
40
45
  for (const plugin of normalized.betterAuthPlugins) {
41
46
  if (plugin && typeof plugin === 'object' && 'schema' in plugin) {
42
47
  // Plugin has schema property - convert to OpenSaaS lists
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Plugin schema types are dynamic
44
- const pluginSchema = plugin.schema as any
48
+ const pluginSchema = plugin.schema
45
49
  const pluginLists = convertBetterAuthSchema(pluginSchema)
46
50
 
47
51
  // Add or extend lists from plugin
@@ -82,5 +86,36 @@ export function authPlugin(config: AuthConfig): Plugin {
82
86
  // Access at runtime via: config._pluginData.auth
83
87
  context.setPluginData<NormalizedAuthConfig>('auth', normalized)
84
88
  },
89
+
90
+ runtime: (context) => {
91
+ // Provide auth-related utilities at runtime
92
+ return {
93
+ /**
94
+ * Get user by ID
95
+ * Uses the access-controlled context to fetch user data
96
+ */
97
+ getUser: async (userId: string) => {
98
+ // Use 'authUser' if custom User list name was provided, otherwise 'user'
99
+ const userListKey = 'user' // TODO: Make this configurable based on list name
100
+ return await context.db[userListKey].findUnique({
101
+ where: { id: userId },
102
+ })
103
+ },
104
+
105
+ /**
106
+ * Get current user from session
107
+ * Extracts userId from session and fetches user data
108
+ */
109
+ getCurrentUser: async () => {
110
+ if (!context.session?.userId) {
111
+ return null
112
+ }
113
+ const userListKey = 'user'
114
+ return await context.db[userListKey].findUnique({
115
+ where: { id: context.session.userId },
116
+ })
117
+ },
118
+ }
119
+ },
85
120
  }
86
121
  }
@@ -167,6 +167,39 @@ export type AuthConfig = {
167
167
  */
168
168
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Better Auth plugin types are not exposed, must use any
169
169
  betterAuthPlugins?: any[]
170
+
171
+ /**
172
+ * Rate limiting configuration
173
+ * Controls rate limiting for authentication endpoints
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * // Disable rate limiting for testing
178
+ * rateLimit: {
179
+ * enabled: process.env.DISABLE_RATE_LIMITING !== 'true',
180
+ * }
181
+ *
182
+ * // Custom rate limits
183
+ * rateLimit: {
184
+ * enabled: true,
185
+ * window: 60, // 60 seconds
186
+ * max: 100, // 100 requests per window
187
+ * }
188
+ * ```
189
+ */
190
+ rateLimit?: {
191
+ enabled: boolean
192
+ /**
193
+ * Time window in seconds
194
+ * @default 60
195
+ */
196
+ window?: number
197
+ /**
198
+ * Maximum requests per window
199
+ * @default 100
200
+ */
201
+ max?: number
202
+ }
170
203
  }
171
204
 
172
205
  /**
@@ -174,11 +207,19 @@ export type AuthConfig = {
174
207
  * Used after parsing user config
175
208
  */
176
209
  export type NormalizedAuthConfig = Required<
177
- Omit<AuthConfig, 'emailAndPassword' | 'emailVerification' | 'passwordReset' | 'betterAuthPlugins'>
210
+ Omit<
211
+ AuthConfig,
212
+ 'emailAndPassword' | 'emailVerification' | 'passwordReset' | 'betterAuthPlugins' | 'rateLimit'
213
+ >
178
214
  > & {
179
215
  emailAndPassword: Required<EmailPasswordConfig>
180
216
  emailVerification: Required<EmailVerificationConfig>
181
217
  passwordReset: Required<PasswordResetConfig>
182
218
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Better Auth plugin types are not exposed, must use any
183
219
  betterAuthPlugins: any[]
220
+ rateLimit?: {
221
+ enabled: boolean
222
+ window?: number
223
+ max?: number
224
+ }
184
225
  }
package/src/index.ts CHANGED
@@ -34,6 +34,9 @@ export { authPlugin } from './config/plugin.js'
34
34
  export type { AuthConfig, NormalizedAuthConfig } from './config/index.js'
35
35
  export type * from './config/types.js'
36
36
 
37
+ // Runtime type exports
38
+ export type { AuthRuntimeServices } from './runtime/types.js'
39
+
37
40
  // List generators (for advanced use cases)
38
41
  export {
39
42
  getAuthLists,
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Type definitions for auth plugin runtime services
3
+ * These types are used for type-safe access to context.plugins.auth
4
+ */
5
+
6
+ /**
7
+ * Runtime services provided by the auth plugin
8
+ * Available via context.plugins.auth
9
+ */
10
+ export interface AuthRuntimeServices {
11
+ /**
12
+ * Get user by ID
13
+ * Uses the access-controlled context to fetch user data
14
+ *
15
+ * @param userId - The ID of the user to fetch
16
+ * @returns User object or null if not found or access denied
17
+ */
18
+ getUser: (userId: string) => Promise<unknown>
19
+
20
+ /**
21
+ * Get current user from session
22
+ * Extracts userId from session and fetches user data
23
+ *
24
+ * @returns Current user object or null if not authenticated or not found
25
+ */
26
+ getCurrentUser: () => Promise<unknown>
27
+ }
@@ -98,6 +98,15 @@ export function createAuth(
98
98
  {} as Record<string, { clientId: string; clientSecret: string }>,
99
99
  ),
100
100
 
101
+ // Rate limiting configuration
102
+ rateLimit: authConfig.rateLimit
103
+ ? {
104
+ enabled: authConfig.rateLimit.enabled,
105
+ window: authConfig.rateLimit.window,
106
+ max: authConfig.rateLimit.max,
107
+ }
108
+ : undefined,
109
+
101
110
  // Pass through any additional Better Auth plugins
102
111
  plugins: authConfig.betterAuthPlugins || [],
103
112
  }
@@ -113,16 +122,45 @@ export function createAuth(
113
122
  // Return a proxy that lazily initializes the auth instance
114
123
  return new Proxy({} as ReturnType<typeof betterAuth>, {
115
124
  get(_, prop) {
116
- return (...args: unknown[]) => {
117
- return (async () => {
118
- const instance = await getAuthInstance()
119
- const value = instance[prop as keyof typeof instance]
120
- if (typeof value === 'function') {
121
- return (value as (...args: unknown[]) => unknown).apply(instance, args)
122
- }
123
- return value
124
- })()
125
+ if (prop === 'then') {
126
+ // Support await on the proxy itself
127
+ return undefined
128
+ }
129
+
130
+ // Create a lazy wrapper function
131
+ const lazyWrapper = async (...args: unknown[]) => {
132
+ const instance = await getAuthInstance()
133
+ const value = instance[prop as keyof typeof instance]
134
+ if (typeof value === 'function') {
135
+ return (value as (...args: unknown[]) => unknown).apply(instance, args)
136
+ }
137
+ return value
125
138
  }
139
+
140
+ // Return a proxy that supports both direct calls and nested property access
141
+ return new Proxy(lazyWrapper, {
142
+ get(target, subProp) {
143
+ if (subProp === 'then') {
144
+ // Support await on nested properties
145
+ return undefined
146
+ }
147
+ // Handle nested property access (e.g., auth.api.getSession)
148
+ return async (...args: unknown[]) => {
149
+ const instance = await getAuthInstance()
150
+ const parentValue = instance[prop as keyof typeof instance]
151
+ if (parentValue && typeof parentValue === 'object') {
152
+ const childValue = (parentValue as Record<string, unknown>)[subProp as string]
153
+ if (typeof childValue === 'function') {
154
+ return (childValue as (...args: unknown[]) => unknown).apply(parentValue, args)
155
+ }
156
+ return childValue
157
+ }
158
+ throw new Error(
159
+ `Property ${String(prop)}.${String(subProp)} not found on auth instance`,
160
+ )
161
+ }
162
+ },
163
+ })
126
164
  },
127
165
  })
128
166
  }
@@ -55,7 +55,7 @@ export function ForgotPasswordForm({
55
55
  setLoading(true)
56
56
 
57
57
  try {
58
- const result = await authClient.forgetPassword({
58
+ const result = await authClient.requestPasswordReset({
59
59
  email,
60
60
  redirectTo: '/reset-password',
61
61
  })
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import React, { useState } from 'react'
4
+ import { useRouter } from 'next/navigation.js'
4
5
  import type { createAuthClient } from 'better-auth/react'
5
6
 
6
7
  export type SignInFormProps = {
@@ -62,6 +63,7 @@ export function SignInForm({
62
63
  onSuccess,
63
64
  onError,
64
65
  }: SignInFormProps) {
66
+ const router = useRouter()
65
67
  const [email, setEmail] = useState('')
66
68
  const [password, setPassword] = useState('')
67
69
  const [error, setError] = useState('')
@@ -83,7 +85,12 @@ export function SignInForm({
83
85
  throw new Error(result.error.message)
84
86
  }
85
87
 
86
- onSuccess?.()
88
+ // If onSuccess is provided, call it. Otherwise, automatically redirect
89
+ if (onSuccess) {
90
+ onSuccess()
91
+ } else {
92
+ router.push(redirectTo)
93
+ }
87
94
  } catch (err) {
88
95
  const message = err instanceof Error ? err.message : 'Sign in failed'
89
96
  setError(message)
@@ -102,6 +109,8 @@ export function SignInForm({
102
109
  provider,
103
110
  callbackURL: redirectTo,
104
111
  })
112
+ // Social sign-in handles its own redirect via OAuth flow
113
+ // Only call onSuccess if provided
105
114
  onSuccess?.()
106
115
  } catch (err) {
107
116
  const message = err instanceof Error ? err.message : 'Sign in failed'
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import React, { useState } from 'react'
4
+ import { useRouter } from 'next/navigation.js'
4
5
  import type { createAuthClient } from 'better-auth/react'
5
6
 
6
7
  export type SignUpFormProps = {
@@ -67,6 +68,7 @@ export function SignUpForm({
67
68
  onSuccess,
68
69
  onError,
69
70
  }: SignUpFormProps) {
71
+ const router = useRouter()
70
72
  const [name, setName] = useState('')
71
73
  const [email, setEmail] = useState('')
72
74
  const [password, setPassword] = useState('')
@@ -98,7 +100,12 @@ export function SignUpForm({
98
100
  throw new Error(result.error.message)
99
101
  }
100
102
 
101
- onSuccess?.()
103
+ // If onSuccess is provided, call it. Otherwise, automatically redirect
104
+ if (onSuccess) {
105
+ onSuccess()
106
+ } else {
107
+ router.push(redirectTo)
108
+ }
102
109
  } catch (err) {
103
110
  const message = err instanceof Error ? err.message : 'Sign up failed'
104
111
  setError(message)
@@ -117,6 +124,8 @@ export function SignUpForm({
117
124
  provider,
118
125
  callbackURL: redirectTo,
119
126
  })
127
+ // Social sign-in handles its own redirect via OAuth flow
128
+ // Only call onSuccess if provided
120
129
  onSuccess?.()
121
130
  } catch (err) {
122
131
  const message = err instanceof Error ? err.message : 'Sign up failed'
@@ -154,7 +154,6 @@ describe('authPlugin', () => {
154
154
  const result = await config({
155
155
  db: {
156
156
  provider: 'sqlite',
157
- url: 'file:./test.db',
158
157
  },
159
158
  plugins: [authPlugin({})],
160
159
  lists: {
@@ -175,22 +174,23 @@ describe('authPlugin', () => {
175
174
  })
176
175
 
177
176
  it('should preserve database config', async () => {
177
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
178
+ const mockConstructor = (() => null) as any
178
179
  const result = await config({
179
180
  db: {
180
181
  provider: 'postgresql',
181
- url: 'postgresql://test',
182
+ prismaClientConstructor: mockConstructor,
182
183
  },
183
184
  plugins: [authPlugin({})],
184
185
  lists: {},
185
186
  })
186
187
 
187
188
  expect(result.db.provider).toBe('postgresql')
188
- expect(result.db.url).toBe('postgresql://test')
189
+ expect(result.db.prismaClientConstructor).toBe(mockConstructor)
189
190
  })
190
191
 
191
192
  it('should store normalized auth config in _pluginData', async () => {
192
193
  const result = await config({
193
- db: { provider: 'sqlite', url: 'file:./test.db' },
194
194
  plugins: [
195
195
  authPlugin({
196
196
  emailAndPassword: { enabled: true, minPasswordLength: 12 },
@@ -209,7 +209,6 @@ describe('authPlugin', () => {
209
209
 
210
210
  it('should extend User list with custom fields', async () => {
211
211
  const result = await config({
212
- db: { provider: 'sqlite', url: 'file:./test.db' },
213
212
  plugins: [
214
213
  authPlugin({
215
214
  extendUserList: {
@@ -239,7 +238,6 @@ describe('authPlugin', () => {
239
238
 
240
239
  it('should generate User list with correct fields', async () => {
241
240
  const result = await config({
242
- db: { provider: 'sqlite', url: 'file:./test.db' },
243
241
  plugins: [authPlugin({})],
244
242
  lists: {},
245
243
  })
@@ -256,7 +254,6 @@ describe('authPlugin', () => {
256
254
 
257
255
  it('should generate Session list with correct fields', async () => {
258
256
  const result = await config({
259
- db: { provider: 'sqlite', url: 'file:./test.db' },
260
257
  plugins: [authPlugin({})],
261
258
  lists: {},
262
259
  })
@@ -272,7 +269,6 @@ describe('authPlugin', () => {
272
269
 
273
270
  it('should generate Account list with correct fields', async () => {
274
271
  const result = await config({
275
- db: { provider: 'sqlite', url: 'file:./test.db' },
276
272
  plugins: [authPlugin({})],
277
273
  lists: {},
278
274
  })
@@ -289,7 +285,6 @@ describe('authPlugin', () => {
289
285
 
290
286
  it('should generate Verification list with correct fields', async () => {
291
287
  const result = await config({
292
- db: { provider: 'sqlite', url: 'file:./test.db' },
293
288
  plugins: [authPlugin({})],
294
289
  lists: {},
295
290
  })
@@ -303,7 +298,6 @@ describe('authPlugin', () => {
303
298
 
304
299
  it('should work with empty auth config', async () => {
305
300
  const result = await config({
306
- db: { provider: 'sqlite', url: 'file:./test.db' },
307
301
  plugins: [authPlugin({})],
308
302
  lists: {},
309
303
  })
@@ -316,7 +310,6 @@ describe('authPlugin', () => {
316
310
 
317
311
  it('should merge with other user-defined lists', async () => {
318
312
  const result = await config({
319
- db: { provider: 'sqlite', url: 'file:./test.db' },
320
313
  plugins: [authPlugin({})],
321
314
  lists: {
322
315
  Post: list({
@@ -344,7 +337,6 @@ describe('authPlugin', () => {
344
337
 
345
338
  it('should pass through config options to normalized config', async () => {
346
339
  const result = await config({
347
- db: { provider: 'sqlite', url: 'file:./test.db' },
348
340
  plugins: [
349
341
  authPlugin({
350
342
  emailAndPassword: {
@@ -407,7 +399,6 @@ describe('authPlugin', () => {
407
399
  }
408
400
 
409
401
  const result = await config({
410
- db: { provider: 'sqlite', url: 'file:./test.db' },
411
402
  plugins: [
412
403
  authPlugin({
413
404
  betterAuthPlugins: [mockPlugin],