@agentuity/auth 0.0.109 → 0.0.110

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 (95) hide show
  1. package/AGENTS.md +82 -28
  2. package/README.md +259 -236
  3. package/dist/agentuity/config.d.ts +2386 -0
  4. package/dist/agentuity/config.d.ts.map +1 -0
  5. package/dist/agentuity/config.js +220 -0
  6. package/dist/agentuity/config.js.map +1 -0
  7. package/dist/agentuity/plugins/api-key.d.ts +152 -0
  8. package/dist/agentuity/plugins/api-key.d.ts.map +1 -0
  9. package/dist/agentuity/plugins/api-key.js +21 -0
  10. package/dist/agentuity/plugins/api-key.js.map +1 -0
  11. package/dist/agentuity/plugins/index.d.ts +23 -0
  12. package/dist/agentuity/plugins/index.d.ts.map +1 -0
  13. package/dist/agentuity/plugins/index.js +10 -0
  14. package/dist/agentuity/plugins/index.js.map +1 -0
  15. package/dist/agentuity/plugins/jwt.d.ts +34 -0
  16. package/dist/agentuity/plugins/jwt.d.ts.map +1 -0
  17. package/dist/agentuity/plugins/jwt.js +11 -0
  18. package/dist/agentuity/plugins/jwt.js.map +1 -0
  19. package/dist/agentuity/plugins/organization.d.ts +355 -0
  20. package/dist/agentuity/plugins/organization.d.ts.map +1 -0
  21. package/dist/agentuity/plugins/organization.js +12 -0
  22. package/dist/agentuity/plugins/organization.js.map +1 -0
  23. package/dist/agentuity/react.d.ts +1375 -0
  24. package/dist/agentuity/react.d.ts.map +1 -0
  25. package/dist/agentuity/react.js +206 -0
  26. package/dist/agentuity/react.js.map +1 -0
  27. package/dist/agentuity/server.d.ts +220 -0
  28. package/dist/agentuity/server.d.ts.map +1 -0
  29. package/dist/agentuity/server.js +505 -0
  30. package/dist/agentuity/server.js.map +1 -0
  31. package/dist/agentuity/types.d.ts +172 -0
  32. package/dist/agentuity/types.d.ts.map +1 -0
  33. package/dist/agentuity/types.js +7 -0
  34. package/dist/agentuity/types.js.map +1 -0
  35. package/dist/index.d.ts +31 -8
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +33 -8
  38. package/dist/index.js.map +1 -1
  39. package/dist/schema.d.ts +2922 -0
  40. package/dist/schema.d.ts.map +1 -0
  41. package/dist/schema.js +223 -0
  42. package/dist/schema.js.map +1 -0
  43. package/dist/types.d.ts +14 -18
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/types.js +1 -1
  46. package/package.json +15 -39
  47. package/src/agentuity/config.ts +401 -0
  48. package/src/agentuity/plugins/api-key.ts +158 -0
  49. package/src/agentuity/plugins/index.ts +35 -0
  50. package/src/agentuity/plugins/jwt.ts +30 -0
  51. package/src/agentuity/plugins/organization.ts +345 -0
  52. package/src/agentuity/react.tsx +328 -0
  53. package/src/agentuity/server.ts +734 -0
  54. package/src/agentuity/types.ts +201 -0
  55. package/src/index.ts +76 -8
  56. package/src/schema.ts +270 -0
  57. package/src/types.ts +14 -22
  58. package/test/agentuity/config.test.ts +621 -0
  59. package/test/agentuity/server.test.ts +537 -0
  60. package/test/schema.test.ts +147 -0
  61. package/tsconfig.json +3 -2
  62. package/tsconfig.tsbuildinfo +1 -1
  63. package/dist/auth0/client.d.ts +0 -44
  64. package/dist/auth0/client.d.ts.map +0 -1
  65. package/dist/auth0/client.js +0 -79
  66. package/dist/auth0/client.js.map +0 -1
  67. package/dist/auth0/index.d.ts +0 -35
  68. package/dist/auth0/index.d.ts.map +0 -1
  69. package/dist/auth0/index.js +0 -38
  70. package/dist/auth0/index.js.map +0 -1
  71. package/dist/auth0/server.d.ts +0 -91
  72. package/dist/auth0/server.d.ts.map +0 -1
  73. package/dist/auth0/server.js +0 -237
  74. package/dist/auth0/server.js.map +0 -1
  75. package/dist/clerk/client.d.ts +0 -42
  76. package/dist/clerk/client.d.ts.map +0 -1
  77. package/dist/clerk/client.js +0 -65
  78. package/dist/clerk/client.js.map +0 -1
  79. package/dist/clerk/index.d.ts +0 -37
  80. package/dist/clerk/index.d.ts.map +0 -1
  81. package/dist/clerk/index.js +0 -35
  82. package/dist/clerk/index.js.map +0 -1
  83. package/dist/clerk/server.d.ts +0 -55
  84. package/dist/clerk/server.d.ts.map +0 -1
  85. package/dist/clerk/server.js +0 -111
  86. package/dist/clerk/server.js.map +0 -1
  87. package/docs/adding-providers.md +0 -261
  88. package/src/auth0/client.tsx +0 -109
  89. package/src/auth0/index.ts +0 -40
  90. package/src/auth0/server.ts +0 -378
  91. package/src/clerk/client.tsx +0 -86
  92. package/src/clerk/index.ts +0 -37
  93. package/src/clerk/server.ts +0 -168
  94. package/test/clerk-client.test.tsx +0 -21
  95. package/test/clerk-server.test.ts +0 -51
@@ -0,0 +1,621 @@
1
+ import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'bun:test';
2
+ import { Database } from 'bun:sqlite';
3
+ import { createAuth } from '../../src/agentuity/config';
4
+
5
+ // Ensure default env vars exist for BetterAuth lazy initialization
6
+ const DEFAULT_BASE_URL = 'https://test.example.com';
7
+ const DEFAULT_SECRET = 'test-secret-minimum-32-characters-long';
8
+
9
+ describe('Agentuity Auth Config', () => {
10
+ let originalEnv: NodeJS.ProcessEnv;
11
+
12
+ beforeAll(() => {
13
+ // Ensure defaults are set before capturing original env
14
+ if (!process.env.AGENTUITY_BASE_URL) {
15
+ process.env.AGENTUITY_BASE_URL = DEFAULT_BASE_URL;
16
+ }
17
+ if (!process.env.AGENTUITY_AUTH_SECRET) {
18
+ process.env.AGENTUITY_AUTH_SECRET = DEFAULT_SECRET;
19
+ }
20
+ originalEnv = { ...process.env };
21
+ });
22
+
23
+ afterAll(() => {
24
+ // Restore env with defaults to prevent BetterAuth lazy init failures
25
+ process.env = { ...originalEnv };
26
+ });
27
+
28
+ beforeEach(() => {
29
+ delete process.env.BETTER_AUTH_URL;
30
+ delete process.env.AGENTUITY_BASE_URL;
31
+ delete process.env.AGENTUITY_CLOUD_DOMAINS;
32
+ delete process.env.AUTH_TRUSTED_DOMAINS;
33
+ delete process.env.AGENTUITY_AUTH_SECRET;
34
+ delete process.env.BETTER_AUTH_SECRET;
35
+ });
36
+
37
+ afterEach(() => {
38
+ process.env = { ...originalEnv };
39
+ });
40
+
41
+ describe('resolveBaseURL', () => {
42
+ it('returns explicit baseURL when provided', () => {
43
+ process.env.BETTER_AUTH_URL = 'https://env-url.com';
44
+ process.env.AGENTUITY_BASE_URL = 'https://agentuity-url.com';
45
+
46
+ const db = new Database(':memory:');
47
+ const auth = createAuth({
48
+ database: db,
49
+ baseURL: 'https://explicit-url.com',
50
+ basePath: '/api/auth',
51
+ secret: 'test-secret-minimum-32-characters-long',
52
+ });
53
+
54
+ expect(auth.options.baseURL).toBe('https://explicit-url.com');
55
+ });
56
+
57
+ it('prefers AGENTUITY_BASE_URL over BETTER_AUTH_URL', () => {
58
+ process.env.BETTER_AUTH_URL = 'https://better-auth-url.com';
59
+ process.env.AGENTUITY_BASE_URL = 'https://agentuity-url.com';
60
+
61
+ const db = new Database(':memory:');
62
+ const auth = createAuth({
63
+ database: db,
64
+ basePath: '/api/auth',
65
+ secret: 'test-secret-minimum-32-characters-long',
66
+ });
67
+
68
+ expect(auth.options.baseURL).toBe('https://agentuity-url.com');
69
+ });
70
+
71
+ it('falls back to BETTER_AUTH_URL when no AGENTUITY_BASE_URL', () => {
72
+ process.env.BETTER_AUTH_URL = 'https://better-auth-url.com';
73
+
74
+ const db = new Database(':memory:');
75
+ const auth = createAuth({
76
+ database: db,
77
+ basePath: '/api/auth',
78
+ secret: 'test-secret-minimum-32-characters-long',
79
+ });
80
+
81
+ expect(auth.options.baseURL).toBe('https://better-auth-url.com');
82
+ });
83
+
84
+ it('falls back to AGENTUITY_BASE_URL when no BETTER_AUTH_URL', () => {
85
+ process.env.AGENTUITY_BASE_URL = 'https://p1234.agentuity.run';
86
+
87
+ const db = new Database(':memory:');
88
+ const auth = createAuth({
89
+ database: db,
90
+ basePath: '/api/auth',
91
+ secret: 'test-secret-minimum-32-characters-long',
92
+ });
93
+
94
+ expect(auth.options.baseURL).toBe('https://p1234.agentuity.run');
95
+ });
96
+
97
+ it('returns undefined when no baseURL is available', () => {
98
+ // Note: We still provide baseURL to prevent BetterAuth lazy init errors,
99
+ // but we test the resolution priority logic in other tests
100
+ const db = new Database(':memory:');
101
+ const auth = createAuth({
102
+ database: db,
103
+ basePath: '/api/auth',
104
+ secret: 'test-secret-minimum-32-characters-long',
105
+ baseURL: 'https://fallback.example.com',
106
+ });
107
+
108
+ // When env vars are cleared, the explicit baseURL should be used
109
+ expect(auth.options.baseURL).toBe('https://fallback.example.com');
110
+ });
111
+ });
112
+
113
+ describe('trustedOrigins', () => {
114
+ it('uses default trustedOrigins function when not provided', () => {
115
+ process.env.AGENTUITY_BASE_URL = 'https://p1234.agentuity.run';
116
+
117
+ const db = new Database(':memory:');
118
+ const auth = createAuth({
119
+ database: db,
120
+ basePath: '/api/auth',
121
+ secret: 'test-secret-minimum-32-characters-long',
122
+ });
123
+
124
+ expect(typeof auth.options.trustedOrigins).toBe('function');
125
+ });
126
+
127
+ it('respects user-provided trustedOrigins array', () => {
128
+ const customOrigins = ['https://custom.example.com'];
129
+ const db = new Database(':memory:');
130
+ const auth = createAuth({
131
+ database: db,
132
+ baseURL: 'https://test.example.com',
133
+ basePath: '/api/auth',
134
+ secret: 'test-secret-minimum-32-characters-long',
135
+ trustedOrigins: customOrigins,
136
+ });
137
+
138
+ expect(auth.options.trustedOrigins).toEqual(customOrigins);
139
+ });
140
+
141
+ it('includes explicit baseURL origin', async () => {
142
+ const db = new Database(':memory:');
143
+ const auth = createAuth({
144
+ database: db,
145
+ baseURL: 'https://myapp.example.com',
146
+ basePath: '/api/auth',
147
+ secret: 'test-secret-minimum-32-characters-long',
148
+ });
149
+
150
+ const trustedOrigins = auth.options.trustedOrigins as (
151
+ request?: Request
152
+ ) => Promise<string[]>;
153
+ const origins = await trustedOrigins();
154
+
155
+ expect(origins).toContain('https://myapp.example.com');
156
+ });
157
+
158
+ it('includes AGENTUITY_BASE_URL origin', async () => {
159
+ process.env.AGENTUITY_BASE_URL = 'https://p5678.agentuity.run';
160
+
161
+ const db = new Database(':memory:');
162
+ const auth = createAuth({
163
+ database: db,
164
+ basePath: '/api/auth',
165
+ secret: 'test-secret-minimum-32-characters-long',
166
+ });
167
+
168
+ const trustedOrigins = auth.options.trustedOrigins as (
169
+ request?: Request
170
+ ) => Promise<string[]>;
171
+ const origins = await trustedOrigins();
172
+
173
+ expect(origins).toContain('https://p5678.agentuity.run');
174
+ });
175
+
176
+ it('includes request origin dynamically', async () => {
177
+ const db = new Database(':memory:');
178
+ const auth = createAuth({
179
+ database: db,
180
+ baseURL: 'https://test.example.com',
181
+ basePath: '/api/auth',
182
+ secret: 'test-secret-minimum-32-characters-long',
183
+ });
184
+
185
+ const trustedOrigins = auth.options.trustedOrigins as (
186
+ request?: Request
187
+ ) => Promise<string[]>;
188
+ const mockRequest = new Request('https://deployed-app.agentuity.run/api/auth/sign-up');
189
+ const origins = await trustedOrigins(mockRequest);
190
+
191
+ expect(origins).toContain('https://deployed-app.agentuity.run');
192
+ expect(origins).toContain('https://test.example.com');
193
+ });
194
+
195
+ describe('AGENTUITY_CLOUD_DOMAINS (platform-set)', () => {
196
+ it('parses comma-separated full URLs', async () => {
197
+ process.env.AGENTUITY_CLOUD_DOMAINS =
198
+ 'https://d1234.agent.run,https://p5678.agent.run,https://pr9999.agent.run';
199
+
200
+ const db = new Database(':memory:');
201
+ const auth = createAuth({
202
+ database: db,
203
+ baseURL: 'https://test.example.com',
204
+ basePath: '/api/auth',
205
+ secret: 'test-secret-minimum-32-characters-long',
206
+ });
207
+
208
+ const trustedOrigins = auth.options.trustedOrigins as (
209
+ request?: Request
210
+ ) => Promise<string[]>;
211
+ const origins = await trustedOrigins();
212
+
213
+ expect(origins).toContain('https://d1234.agent.run');
214
+ expect(origins).toContain('https://p5678.agent.run');
215
+ expect(origins).toContain('https://pr9999.agent.run');
216
+ });
217
+
218
+ it('parses comma-separated bare domains (adds https://)', async () => {
219
+ process.env.AGENTUITY_CLOUD_DOMAINS =
220
+ 'd1234.agent.run,p5678.agent.run,custom.example.com';
221
+
222
+ const db = new Database(':memory:');
223
+ const auth = createAuth({
224
+ database: db,
225
+ baseURL: 'https://test.example.com',
226
+ basePath: '/api/auth',
227
+ secret: 'test-secret-minimum-32-characters-long',
228
+ });
229
+
230
+ const trustedOrigins = auth.options.trustedOrigins as (
231
+ request?: Request
232
+ ) => Promise<string[]>;
233
+ const origins = await trustedOrigins();
234
+
235
+ expect(origins).toContain('https://d1234.agent.run');
236
+ expect(origins).toContain('https://p5678.agent.run');
237
+ expect(origins).toContain('https://custom.example.com');
238
+ });
239
+
240
+ it('handles mixed full URLs and bare domains', async () => {
241
+ process.env.AGENTUITY_CLOUD_DOMAINS =
242
+ 'https://d1234.agent.run,p5678.agent.run,http://localhost:3500';
243
+
244
+ const db = new Database(':memory:');
245
+ const auth = createAuth({
246
+ database: db,
247
+ baseURL: 'https://test.example.com',
248
+ basePath: '/api/auth',
249
+ secret: 'test-secret-minimum-32-characters-long',
250
+ });
251
+
252
+ const trustedOrigins = auth.options.trustedOrigins as (
253
+ request?: Request
254
+ ) => Promise<string[]>;
255
+ const origins = await trustedOrigins();
256
+
257
+ expect(origins).toContain('https://d1234.agent.run');
258
+ expect(origins).toContain('https://p5678.agent.run');
259
+ expect(origins).toContain('http://localhost:3500');
260
+ });
261
+
262
+ it('handles domains with ports', async () => {
263
+ process.env.AGENTUITY_CLOUD_DOMAINS = 'localhost:3500,127.0.0.1:3500';
264
+
265
+ const db = new Database(':memory:');
266
+ const auth = createAuth({
267
+ database: db,
268
+ baseURL: 'https://test.example.com',
269
+ basePath: '/api/auth',
270
+ secret: 'test-secret-minimum-32-characters-long',
271
+ });
272
+
273
+ const trustedOrigins = auth.options.trustedOrigins as (
274
+ request?: Request
275
+ ) => Promise<string[]>;
276
+ const origins = await trustedOrigins();
277
+
278
+ expect(origins).toContain('https://localhost:3500');
279
+ expect(origins).toContain('https://127.0.0.1:3500');
280
+ });
281
+
282
+ it('trims whitespace around domains', async () => {
283
+ process.env.AGENTUITY_CLOUD_DOMAINS =
284
+ ' https://d1234.agent.run , p5678.agent.run , custom.example.com ';
285
+
286
+ const db = new Database(':memory:');
287
+ const auth = createAuth({
288
+ database: db,
289
+ baseURL: 'https://test.example.com',
290
+ basePath: '/api/auth',
291
+ secret: 'test-secret-minimum-32-characters-long',
292
+ });
293
+
294
+ const trustedOrigins = auth.options.trustedOrigins as (
295
+ request?: Request
296
+ ) => Promise<string[]>;
297
+ const origins = await trustedOrigins();
298
+
299
+ expect(origins).toContain('https://d1234.agent.run');
300
+ expect(origins).toContain('https://p5678.agent.run');
301
+ expect(origins).toContain('https://custom.example.com');
302
+ });
303
+
304
+ it('skips empty entries in comma-separated list', async () => {
305
+ process.env.AGENTUITY_CLOUD_DOMAINS =
306
+ 'https://d1234.agent.run,,https://p5678.agent.run,';
307
+
308
+ const db = new Database(':memory:');
309
+ const auth = createAuth({
310
+ database: db,
311
+ baseURL: 'https://test.example.com',
312
+ basePath: '/api/auth',
313
+ secret: 'test-secret-minimum-32-characters-long',
314
+ });
315
+
316
+ const trustedOrigins = auth.options.trustedOrigins as (
317
+ request?: Request
318
+ ) => Promise<string[]>;
319
+ const origins = await trustedOrigins();
320
+
321
+ expect(origins).toContain('https://d1234.agent.run');
322
+ expect(origins).toContain('https://p5678.agent.run');
323
+ expect(origins.length).toBe(3); // baseURL + 2 cloud domains
324
+ });
325
+
326
+ it('deduplicates origins', async () => {
327
+ process.env.AGENTUITY_CLOUD_DOMAINS =
328
+ 'https://d1234.agent.run,d1234.agent.run,https://d1234.agent.run';
329
+
330
+ const db = new Database(':memory:');
331
+ const auth = createAuth({
332
+ database: db,
333
+ baseURL: 'https://d1234.agent.run', // same as cloud domain
334
+ basePath: '/api/auth',
335
+ secret: 'test-secret-minimum-32-characters-long',
336
+ });
337
+
338
+ const trustedOrigins = auth.options.trustedOrigins as (
339
+ request?: Request
340
+ ) => Promise<string[]>;
341
+ const origins = await trustedOrigins();
342
+
343
+ const d1234Count = origins.filter((o) => o === 'https://d1234.agent.run').length;
344
+ expect(d1234Count).toBe(1);
345
+ });
346
+ });
347
+
348
+ describe('AUTH_TRUSTED_DOMAINS (developer-set)', () => {
349
+ it('parses comma-separated domains', async () => {
350
+ process.env.AUTH_TRUSTED_DOMAINS =
351
+ 'https://extra1.example.com,https://extra2.example.com';
352
+
353
+ const db = new Database(':memory:');
354
+ const auth = createAuth({
355
+ database: db,
356
+ baseURL: 'https://test.example.com',
357
+ basePath: '/api/auth',
358
+ secret: 'test-secret-minimum-32-characters-long',
359
+ });
360
+
361
+ const trustedOrigins = auth.options.trustedOrigins as (
362
+ request?: Request
363
+ ) => Promise<string[]>;
364
+ const origins = await trustedOrigins();
365
+
366
+ expect(origins).toContain('https://extra1.example.com');
367
+ expect(origins).toContain('https://extra2.example.com');
368
+ });
369
+
370
+ it('parses bare domains (adds https://)', async () => {
371
+ process.env.AUTH_TRUSTED_DOMAINS = 'my-dev-domain.com,staging.myapp.io';
372
+
373
+ const db = new Database(':memory:');
374
+ const auth = createAuth({
375
+ database: db,
376
+ baseURL: 'https://test.example.com',
377
+ basePath: '/api/auth',
378
+ secret: 'test-secret-minimum-32-characters-long',
379
+ });
380
+
381
+ const trustedOrigins = auth.options.trustedOrigins as (
382
+ request?: Request
383
+ ) => Promise<string[]>;
384
+ const origins = await trustedOrigins();
385
+
386
+ expect(origins).toContain('https://my-dev-domain.com');
387
+ expect(origins).toContain('https://staging.myapp.io');
388
+ });
389
+
390
+ it('combines with AGENTUITY_CLOUD_DOMAINS', async () => {
391
+ process.env.AGENTUITY_CLOUD_DOMAINS = 'https://d1234.agent.run,https://p5678.agent.run';
392
+ process.env.AUTH_TRUSTED_DOMAINS = 'https://dev.myapp.com';
393
+
394
+ const db = new Database(':memory:');
395
+ const auth = createAuth({
396
+ database: db,
397
+ baseURL: 'https://test.example.com',
398
+ basePath: '/api/auth',
399
+ secret: 'test-secret-minimum-32-characters-long',
400
+ });
401
+
402
+ const trustedOrigins = auth.options.trustedOrigins as (
403
+ request?: Request
404
+ ) => Promise<string[]>;
405
+ const origins = await trustedOrigins();
406
+
407
+ expect(origins).toContain('https://test.example.com'); // baseURL
408
+ expect(origins).toContain('https://d1234.agent.run'); // cloud domain
409
+ expect(origins).toContain('https://p5678.agent.run'); // cloud domain
410
+ expect(origins).toContain('https://dev.myapp.com'); // dev trusted domain
411
+ });
412
+ });
413
+
414
+ describe('malformed URL handling', () => {
415
+ it('skips malformed AGENTUITY_BASE_URL gracefully', async () => {
416
+ process.env.AGENTUITY_BASE_URL = 'not-a-valid-url';
417
+
418
+ const db = new Database(':memory:');
419
+ const auth = createAuth({
420
+ database: db,
421
+ baseURL: 'https://valid-base.example.com',
422
+ basePath: '/api/auth',
423
+ secret: 'test-secret-minimum-32-characters-long',
424
+ });
425
+
426
+ const trustedOrigins = auth.options.trustedOrigins as (
427
+ request?: Request
428
+ ) => Promise<string[]>;
429
+ const origins = await trustedOrigins();
430
+
431
+ expect(origins).toContain('https://valid-base.example.com');
432
+ expect(origins).not.toContain('not-a-valid-url');
433
+ });
434
+
435
+ it('skips malformed entries in AGENTUITY_CLOUD_DOMAINS', async () => {
436
+ process.env.AGENTUITY_CLOUD_DOMAINS =
437
+ 'https://valid1.example.com,://invalid,https://valid2.example.com';
438
+
439
+ const db = new Database(':memory:');
440
+ const auth = createAuth({
441
+ database: db,
442
+ baseURL: 'https://test.example.com',
443
+ basePath: '/api/auth',
444
+ secret: 'test-secret-minimum-32-characters-long',
445
+ });
446
+
447
+ const trustedOrigins = auth.options.trustedOrigins as (
448
+ request?: Request
449
+ ) => Promise<string[]>;
450
+ const origins = await trustedOrigins();
451
+
452
+ expect(origins).toContain('https://valid1.example.com');
453
+ expect(origins).toContain('https://valid2.example.com');
454
+ expect(origins).not.toContain('://invalid');
455
+ });
456
+
457
+ it('skips malformed entries in AUTH_TRUSTED_DOMAINS', async () => {
458
+ process.env.AUTH_TRUSTED_DOMAINS = 'https://valid.example.com,://broken';
459
+
460
+ const db = new Database(':memory:');
461
+ const auth = createAuth({
462
+ database: db,
463
+ baseURL: 'https://test.example.com',
464
+ basePath: '/api/auth',
465
+ secret: 'test-secret-minimum-32-characters-long',
466
+ });
467
+
468
+ const trustedOrigins = auth.options.trustedOrigins as (
469
+ request?: Request
470
+ ) => Promise<string[]>;
471
+ const origins = await trustedOrigins();
472
+
473
+ expect(origins).toContain('https://valid.example.com');
474
+ expect(origins).not.toContain('://broken');
475
+ });
476
+ });
477
+ });
478
+
479
+ describe('resolveSecret', () => {
480
+ it('returns explicit secret when provided', () => {
481
+ process.env.AGENTUITY_AUTH_SECRET = 'env-secret-minimum-32-characters-long';
482
+ process.env.BETTER_AUTH_SECRET = 'better-auth-secret-minimum-32-chars';
483
+
484
+ const db = new Database(':memory:');
485
+ const auth = createAuth({
486
+ database: db,
487
+ baseURL: 'https://test.example.com',
488
+ basePath: '/api/auth',
489
+ secret: 'explicit-secret-minimum-32-characters',
490
+ });
491
+
492
+ expect(auth.options.secret).toBe('explicit-secret-minimum-32-characters');
493
+ });
494
+
495
+ it('prefers AGENTUITY_AUTH_SECRET over BETTER_AUTH_SECRET', () => {
496
+ process.env.AGENTUITY_AUTH_SECRET = 'agentuity-secret-minimum-32-chars-';
497
+ process.env.BETTER_AUTH_SECRET = 'better-auth-secret-minimum-32-chars';
498
+
499
+ const db = new Database(':memory:');
500
+ const auth = createAuth({
501
+ database: db,
502
+ baseURL: 'https://test.example.com',
503
+ basePath: '/api/auth',
504
+ });
505
+
506
+ expect(auth.options.secret).toBe('agentuity-secret-minimum-32-chars-');
507
+ });
508
+
509
+ it('falls back to BETTER_AUTH_SECRET when no AGENTUITY_AUTH_SECRET', () => {
510
+ process.env.BETTER_AUTH_SECRET = 'better-auth-secret-minimum-32-chars';
511
+
512
+ const db = new Database(':memory:');
513
+ const auth = createAuth({
514
+ database: db,
515
+ baseURL: 'https://test.example.com',
516
+ basePath: '/api/auth',
517
+ });
518
+
519
+ expect(auth.options.secret).toBe('better-auth-secret-minimum-32-chars');
520
+ });
521
+
522
+ it('returns undefined when no secret is available', () => {
523
+ const db = new Database(':memory:');
524
+ const auth = createAuth({
525
+ database: db,
526
+ baseURL: 'https://test.example.com',
527
+ basePath: '/api/auth',
528
+ });
529
+
530
+ expect(auth.options.secret).toBeUndefined();
531
+ });
532
+ });
533
+
534
+ describe('default options', () => {
535
+ it('defaults basePath to /api/auth', () => {
536
+ const db = new Database(':memory:');
537
+ const auth = createAuth({
538
+ database: db,
539
+ baseURL: 'https://test.example.com',
540
+ secret: 'test-secret-minimum-32-characters-long',
541
+ });
542
+
543
+ expect(auth.options.basePath).toBe('/api/auth');
544
+ });
545
+
546
+ it('allows overriding basePath', () => {
547
+ const db = new Database(':memory:');
548
+ const auth = createAuth({
549
+ database: db,
550
+ baseURL: 'https://test.example.com',
551
+ basePath: '/auth',
552
+ secret: 'test-secret-minimum-32-characters-long',
553
+ });
554
+
555
+ expect(auth.options.basePath).toBe('/auth');
556
+ });
557
+
558
+ it('defaults emailAndPassword to enabled', () => {
559
+ const db = new Database(':memory:');
560
+ const auth = createAuth({
561
+ database: db,
562
+ baseURL: 'https://test.example.com',
563
+ secret: 'test-secret-minimum-32-characters-long',
564
+ });
565
+
566
+ expect(auth.options.emailAndPassword?.enabled).toBe(true);
567
+ });
568
+
569
+ it('defaults experimental.joins to true', () => {
570
+ const db = new Database(':memory:');
571
+ const auth = createAuth({
572
+ database: db,
573
+ baseURL: 'https://test.example.com',
574
+ secret: 'test-secret-minimum-32-characters-long',
575
+ });
576
+
577
+ expect((auth.options as { experimental?: { joins?: boolean } }).experimental?.joins).toBe(
578
+ true
579
+ );
580
+ });
581
+ });
582
+
583
+ describe('default plugins', () => {
584
+ it('includes organization, jwt, bearer, and apiKey plugins by default', () => {
585
+ const db = new Database(':memory:');
586
+ const auth = createAuth({
587
+ database: db,
588
+ baseURL: 'https://test.example.com',
589
+ secret: 'test-secret-minimum-32-characters-long',
590
+ });
591
+
592
+ expect(auth.options.plugins).toBeDefined();
593
+ expect(auth.options.plugins!.length).toBeGreaterThanOrEqual(4);
594
+ });
595
+
596
+ it('skips default plugins when skipDefaultPlugins is true', () => {
597
+ const db = new Database(':memory:');
598
+ const auth = createAuth({
599
+ database: db,
600
+ baseURL: 'https://test.example.com',
601
+ secret: 'test-secret-minimum-32-characters-long',
602
+ skipDefaultPlugins: true,
603
+ });
604
+
605
+ expect(auth.options.plugins?.length ?? 0).toBe(0);
606
+ });
607
+
608
+ it('allows disabling apiKey plugin', () => {
609
+ const db = new Database(':memory:');
610
+ const auth = createAuth({
611
+ database: db,
612
+ baseURL: 'https://test.example.com',
613
+ secret: 'test-secret-minimum-32-characters-long',
614
+ apiKey: false,
615
+ });
616
+
617
+ expect(auth.options.plugins).toBeDefined();
618
+ expect(auth.options.plugins!.length).toBe(3);
619
+ });
620
+ });
621
+ });