@opensaas/stack-auth 0.1.5 → 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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/dist/config/index.d.ts +0 -42
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +0 -83
- package/dist/config/index.js.map +1 -1
- package/dist/config/plugin.d.ts +25 -0
- package/dist/config/plugin.d.ts.map +1 -0
- package/dist/config/plugin.js +80 -0
- package/dist/config/plugin.js.map +1 -0
- package/dist/index.d.ts +14 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/dist/mcp/better-auth.d.ts +1 -1
- package/dist/mcp/better-auth.js +1 -1
- package/dist/server/index.d.ts +3 -5
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +73 -37
- package/dist/server/index.js.map +1 -1
- package/package.json +3 -3
- package/src/config/index.ts +0 -95
- package/src/config/plugin.ts +86 -0
- package/src/index.ts +14 -13
- package/src/mcp/better-auth.ts +1 -1
- package/src/server/index.ts +86 -45
- package/tests/config.test.ts +223 -64
- package/tsconfig.tsbuildinfo +1 -1
package/tests/config.test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { normalizeAuthConfig
|
|
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 {
|
|
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('
|
|
152
|
-
it('should
|
|
153
|
-
const
|
|
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
|
|
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
|
|
212
|
-
const
|
|
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
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
)
|
|
223
|
-
|
|
224
|
-
expect(
|
|
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
|
|
231
|
-
const
|
|
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
|
|
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
|
|
245
|
-
const
|
|
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
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
256
|
-
|
|
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
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
})
|