@opensaas/stack-auth 0.1.4 → 0.1.6

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.
@@ -1,8 +1,9 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { normalizeAuthConfig, authConfig, withAuth } from '../src/config/index.js'
2
+ import { normalizeAuthConfig } from '../src/config/index.js'
3
+ import { authPlugin } from '../src/config/plugin.js'
3
4
  import { config, list } from '@opensaas/stack-core'
4
- import { text } from '@opensaas/stack-core/fields'
5
- import type { AuthConfig } from '../src/config/types.js'
5
+ import { text, select } from '@opensaas/stack-core/fields'
6
+ import type { NormalizedAuthConfig } from '../src/config/types.js'
6
7
 
7
8
  describe('normalizeAuthConfig', () => {
8
9
  it('should apply default values for disabled features', () => {
@@ -148,32 +149,14 @@ describe('normalizeAuthConfig', () => {
148
149
  })
149
150
  })
150
151
 
151
- describe('authConfig', () => {
152
- it('should return the input config unchanged', () => {
153
- const input: AuthConfig = {
154
- emailAndPassword: { enabled: true },
155
- sessionFields: ['userId', 'email'],
156
- }
157
-
158
- const result = authConfig(input)
159
-
160
- expect(result).toEqual(input)
161
- })
162
-
163
- it('should work with empty config', () => {
164
- const result = authConfig({})
165
-
166
- expect(result).toEqual({})
167
- })
168
- })
169
-
170
- describe('withAuth', () => {
171
- it('should merge auth lists into opensaas config', () => {
172
- const baseConfig = config({
152
+ describe('authPlugin', () => {
153
+ it('should inject all auth lists into config', async () => {
154
+ const result = await config({
173
155
  db: {
174
156
  provider: 'sqlite',
175
157
  url: 'file:./test.db',
176
158
  },
159
+ plugins: [authPlugin({})],
177
160
  lists: {
178
161
  Post: list({
179
162
  fields: {
@@ -183,8 +166,6 @@ describe('withAuth', () => {
183
166
  },
184
167
  })
185
168
 
186
- const result = withAuth(baseConfig, authConfig({}))
187
-
188
169
  // Should have both user lists and auth lists
189
170
  expect(result.lists).toHaveProperty('Post')
190
171
  expect(result.lists).toHaveProperty('User')
@@ -193,47 +174,139 @@ describe('withAuth', () => {
193
174
  expect(result.lists).toHaveProperty('Verification')
194
175
  })
195
176
 
196
- it('should preserve database config', () => {
197
- const baseConfig = config({
177
+ it('should preserve database config', async () => {
178
+ const result = await config({
198
179
  db: {
199
180
  provider: 'postgresql',
200
181
  url: 'postgresql://test',
201
182
  },
183
+ plugins: [authPlugin({})],
202
184
  lists: {},
203
185
  })
204
186
 
205
- const result = withAuth(baseConfig, authConfig({}))
206
-
207
187
  expect(result.db.provider).toBe('postgresql')
208
188
  expect(result.db.url).toBe('postgresql://test')
209
189
  })
210
190
 
211
- it('should attach normalized auth config internally', () => {
212
- const baseConfig = config({
191
+ it('should store normalized auth config in _pluginData', async () => {
192
+ const result = await config({
193
+ db: { provider: 'sqlite', url: 'file:./test.db' },
194
+ plugins: [
195
+ authPlugin({
196
+ emailAndPassword: { enabled: true, minPasswordLength: 12 },
197
+ sessionFields: ['userId', 'email', 'name', 'role'],
198
+ }),
199
+ ],
200
+ lists: {},
201
+ })
202
+
203
+ expect(result._pluginData).toHaveProperty('auth')
204
+ const authConfig = result._pluginData.auth as NormalizedAuthConfig
205
+ expect(authConfig.emailAndPassword.enabled).toBe(true)
206
+ expect(authConfig.emailAndPassword.minPasswordLength).toBe(12)
207
+ expect(authConfig.sessionFields).toEqual(['userId', 'email', 'name', 'role'])
208
+ })
209
+
210
+ it('should extend User list with custom fields', async () => {
211
+ const result = await config({
212
+ db: { provider: 'sqlite', url: 'file:./test.db' },
213
+ plugins: [
214
+ authPlugin({
215
+ extendUserList: {
216
+ fields: {
217
+ role: select({
218
+ options: [
219
+ { label: 'Admin', value: 'admin' },
220
+ { label: 'User', value: 'user' },
221
+ ],
222
+ }),
223
+ company: text(),
224
+ },
225
+ },
226
+ }),
227
+ ],
228
+ lists: {},
229
+ })
230
+
231
+ const userList = result.lists.User
232
+ expect(userList).toBeDefined()
233
+ expect(userList.fields).toHaveProperty('role')
234
+ expect(userList.fields).toHaveProperty('company')
235
+ // Should also have base auth fields
236
+ expect(userList.fields).toHaveProperty('email')
237
+ expect(userList.fields).toHaveProperty('name')
238
+ })
239
+
240
+ it('should generate User list with correct fields', async () => {
241
+ const result = await config({
213
242
  db: { provider: 'sqlite', url: 'file:./test.db' },
243
+ plugins: [authPlugin({})],
214
244
  lists: {},
215
245
  })
216
246
 
217
- const result = withAuth(
218
- baseConfig,
219
- authConfig({
220
- emailAndPassword: { enabled: true },
221
- }),
222
- ) as typeof baseConfig & { __authConfig?: unknown }
223
-
224
- expect(result.__authConfig).toBeDefined()
225
- expect(
226
- (result.__authConfig as { emailAndPassword: { enabled: boolean } }).emailAndPassword.enabled,
227
- ).toBe(true)
247
+ const userList = result.lists.User
248
+ expect(userList).toBeDefined()
249
+ expect(userList.fields).toHaveProperty('name')
250
+ expect(userList.fields).toHaveProperty('email')
251
+ expect(userList.fields).toHaveProperty('emailVerified')
252
+ expect(userList.fields).toHaveProperty('image')
253
+ expect(userList.fields).toHaveProperty('sessions')
254
+ expect(userList.fields).toHaveProperty('accounts')
228
255
  })
229
256
 
230
- it('should handle empty lists in base config', () => {
231
- const baseConfig = config({
257
+ it('should generate Session list with correct fields', async () => {
258
+ const result = await config({
232
259
  db: { provider: 'sqlite', url: 'file:./test.db' },
260
+ plugins: [authPlugin({})],
233
261
  lists: {},
234
262
  })
235
263
 
236
- const result = withAuth(baseConfig, authConfig({}))
264
+ const sessionList = result.lists.Session
265
+ expect(sessionList).toBeDefined()
266
+ expect(sessionList.fields).toHaveProperty('token')
267
+ expect(sessionList.fields).toHaveProperty('expiresAt')
268
+ expect(sessionList.fields).toHaveProperty('ipAddress')
269
+ expect(sessionList.fields).toHaveProperty('userAgent')
270
+ expect(sessionList.fields).toHaveProperty('user')
271
+ })
272
+
273
+ it('should generate Account list with correct fields', async () => {
274
+ const result = await config({
275
+ db: { provider: 'sqlite', url: 'file:./test.db' },
276
+ plugins: [authPlugin({})],
277
+ lists: {},
278
+ })
279
+
280
+ const accountList = result.lists.Account
281
+ expect(accountList).toBeDefined()
282
+ expect(accountList.fields).toHaveProperty('accountId')
283
+ expect(accountList.fields).toHaveProperty('providerId')
284
+ expect(accountList.fields).toHaveProperty('accessToken')
285
+ expect(accountList.fields).toHaveProperty('refreshToken')
286
+ expect(accountList.fields).toHaveProperty('password')
287
+ expect(accountList.fields).toHaveProperty('user')
288
+ })
289
+
290
+ it('should generate Verification list with correct fields', async () => {
291
+ const result = await config({
292
+ db: { provider: 'sqlite', url: 'file:./test.db' },
293
+ plugins: [authPlugin({})],
294
+ lists: {},
295
+ })
296
+
297
+ const verificationList = result.lists.Verification
298
+ expect(verificationList).toBeDefined()
299
+ expect(verificationList.fields).toHaveProperty('identifier')
300
+ expect(verificationList.fields).toHaveProperty('value')
301
+ expect(verificationList.fields).toHaveProperty('expiresAt')
302
+ })
303
+
304
+ it('should work with empty auth config', async () => {
305
+ const result = await config({
306
+ db: { provider: 'sqlite', url: 'file:./test.db' },
307
+ plugins: [authPlugin({})],
308
+ lists: {},
309
+ })
237
310
 
238
311
  expect(result.lists).toHaveProperty('User')
239
312
  expect(result.lists).toHaveProperty('Session')
@@ -241,30 +314,116 @@ describe('withAuth', () => {
241
314
  expect(result.lists).toHaveProperty('Verification')
242
315
  })
243
316
 
244
- it('should extend User list with custom fields', () => {
245
- const baseConfig = config({
317
+ it('should merge with other user-defined lists', async () => {
318
+ const result = await config({
319
+ db: { provider: 'sqlite', url: 'file:./test.db' },
320
+ plugins: [authPlugin({})],
321
+ lists: {
322
+ Post: list({
323
+ fields: {
324
+ title: text(),
325
+ content: text(),
326
+ },
327
+ }),
328
+ Comment: list({
329
+ fields: {
330
+ text: text(),
331
+ },
332
+ }),
333
+ },
334
+ })
335
+
336
+ // Should have both auth lists and user lists
337
+ expect(result.lists).toHaveProperty('User')
338
+ expect(result.lists).toHaveProperty('Session')
339
+ expect(result.lists).toHaveProperty('Account')
340
+ expect(result.lists).toHaveProperty('Verification')
341
+ expect(result.lists).toHaveProperty('Post')
342
+ expect(result.lists).toHaveProperty('Comment')
343
+ })
344
+
345
+ it('should pass through config options to normalized config', async () => {
346
+ const result = await config({
246
347
  db: { provider: 'sqlite', url: 'file:./test.db' },
348
+ plugins: [
349
+ authPlugin({
350
+ emailAndPassword: {
351
+ enabled: true,
352
+ minPasswordLength: 10,
353
+ requireConfirmation: false,
354
+ },
355
+ emailVerification: {
356
+ enabled: true,
357
+ sendOnSignUp: false,
358
+ tokenExpiration: 3600,
359
+ },
360
+ passwordReset: {
361
+ enabled: true,
362
+ tokenExpiration: 7200,
363
+ },
364
+ session: {
365
+ expiresIn: 86400,
366
+ updateAge: false,
367
+ },
368
+ sessionFields: ['userId', 'email', 'role'],
369
+ socialProviders: {
370
+ github: {
371
+ clientId: 'test-id',
372
+ clientSecret: 'test-secret',
373
+ },
374
+ },
375
+ }),
376
+ ],
247
377
  lists: {},
248
378
  })
249
379
 
250
- const result = withAuth(
251
- baseConfig,
252
- authConfig({
253
- extendUserList: {
380
+ const authConfig = result._pluginData.auth as NormalizedAuthConfig
381
+ expect(authConfig.emailAndPassword.enabled).toBe(true)
382
+ expect(authConfig.emailAndPassword.minPasswordLength).toBe(10)
383
+ expect(authConfig.emailAndPassword.requireConfirmation).toBe(false)
384
+ expect(authConfig.emailVerification.enabled).toBe(true)
385
+ expect(authConfig.emailVerification.sendOnSignUp).toBe(false)
386
+ expect(authConfig.passwordReset.enabled).toBe(true)
387
+ expect(authConfig.session.expiresIn).toBe(86400)
388
+ expect(authConfig.sessionFields).toEqual(['userId', 'email', 'role'])
389
+ expect(authConfig.socialProviders).toHaveProperty('github')
390
+ })
391
+
392
+ it('should process Better Auth plugins with schemas', async () => {
393
+ // Mock Better Auth plugin with schema (using snake_case like Better Auth does)
394
+ const mockPlugin = {
395
+ id: 'test-plugin',
396
+ schema: {
397
+ test_table: {
254
398
  fields: {
255
- role: text(),
256
- company: text(),
399
+ id: { type: 'string', required: true },
400
+ name: { type: 'string' },
401
+ isActive: { type: 'boolean' },
402
+ count: { type: 'number' },
403
+ createdAt: { type: 'date' },
257
404
  },
258
405
  },
259
- }),
260
- )
406
+ },
407
+ }
261
408
 
262
- const userList = result.lists.User
263
- expect(userList).toBeDefined()
264
- expect(userList.fields).toHaveProperty('role')
265
- expect(userList.fields).toHaveProperty('company')
266
- // Should also have base auth fields
267
- expect(userList.fields).toHaveProperty('email')
268
- expect(userList.fields).toHaveProperty('name')
409
+ const result = await config({
410
+ db: { provider: 'sqlite', url: 'file:./test.db' },
411
+ plugins: [
412
+ authPlugin({
413
+ betterAuthPlugins: [mockPlugin],
414
+ }),
415
+ ],
416
+ lists: {},
417
+ })
418
+
419
+ // Should have auth lists plus the plugin's list (converted to PascalCase)
420
+ expect(result.lists).toHaveProperty('User')
421
+ expect(result.lists).toHaveProperty('TestTable')
422
+
423
+ // Verify the converted list has correct fields
424
+ const testTableList = result.lists.TestTable
425
+ expect(testTableList.fields).toHaveProperty('name')
426
+ expect(testTableList.fields).toHaveProperty('isActive')
427
+ expect(testTableList.fields).toHaveProperty('count')
269
428
  })
270
429
  })