better-auth-studio 1.1.1-beta.4 → 1.1.1-beta.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.
Files changed (78) hide show
  1. package/dist/adapters/hono.d.ts.map +1 -1
  2. package/dist/adapters/hono.js +5 -0
  3. package/dist/adapters/hono.js.map +1 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/core/handler.d.ts.map +1 -1
  7. package/dist/core/handler.js +85 -4
  8. package/dist/core/handler.js.map +1 -1
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +3 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/providers/events/helpers.d.ts +22 -0
  14. package/dist/providers/events/helpers.d.ts.map +1 -0
  15. package/dist/providers/events/helpers.js +874 -0
  16. package/dist/providers/events/helpers.js.map +1 -0
  17. package/dist/public/assets/main-RoeYO1I-.css +1 -0
  18. package/dist/public/assets/{main-BDwnIMk3.js → main-wiXkwSx1.js} +82 -82
  19. package/dist/public/index.html +2 -2
  20. package/dist/routes.d.ts.map +1 -1
  21. package/dist/routes.js +181 -0
  22. package/dist/routes.js.map +1 -1
  23. package/dist/studio.d.ts.map +1 -1
  24. package/dist/studio.js +78 -2
  25. package/dist/studio.js.map +1 -1
  26. package/dist/types/events.d.ts +43 -0
  27. package/dist/types/events.d.ts.map +1 -0
  28. package/dist/types/events.js +306 -0
  29. package/dist/types/events.js.map +1 -0
  30. package/dist/types/handler.d.ts +31 -0
  31. package/dist/types/handler.d.ts.map +1 -1
  32. package/dist/types/handler.js.map +1 -1
  33. package/dist/utils/auth-callbacks-injector.d.ts +3 -0
  34. package/dist/utils/auth-callbacks-injector.d.ts.map +1 -0
  35. package/dist/utils/auth-callbacks-injector.js +225 -0
  36. package/dist/utils/auth-callbacks-injector.js.map +1 -0
  37. package/dist/utils/auth-callbacks-wrapper.d.ts +7 -0
  38. package/dist/utils/auth-callbacks-wrapper.d.ts.map +1 -0
  39. package/dist/utils/auth-callbacks-wrapper.js +123 -0
  40. package/dist/utils/auth-callbacks-wrapper.js.map +1 -0
  41. package/dist/utils/database-hook-injector.d.ts +3 -0
  42. package/dist/utils/database-hook-injector.d.ts.map +1 -0
  43. package/dist/utils/database-hook-injector.js +141 -0
  44. package/dist/utils/database-hook-injector.js.map +1 -0
  45. package/dist/utils/email-otp-hooks-injector.d.ts +29 -0
  46. package/dist/utils/email-otp-hooks-injector.d.ts.map +1 -0
  47. package/dist/utils/email-otp-hooks-injector.js +134 -0
  48. package/dist/utils/email-otp-hooks-injector.js.map +1 -0
  49. package/dist/utils/event-ingestion.d.ts +38 -0
  50. package/dist/utils/event-ingestion.d.ts.map +1 -0
  51. package/dist/utils/event-ingestion.js +169 -0
  52. package/dist/utils/event-ingestion.js.map +1 -0
  53. package/dist/utils/hook-injector.d.ts +9 -0
  54. package/dist/utils/hook-injector.d.ts.map +1 -0
  55. package/dist/utils/hook-injector.js +592 -0
  56. package/dist/utils/hook-injector.js.map +1 -0
  57. package/dist/utils/html-injector.d.ts +17 -0
  58. package/dist/utils/html-injector.d.ts.map +1 -1
  59. package/dist/utils/html-injector.js +15 -1
  60. package/dist/utils/html-injector.js.map +1 -1
  61. package/dist/utils/org-hooks-injector.d.ts +74 -0
  62. package/dist/utils/org-hooks-injector.d.ts.map +1 -0
  63. package/dist/utils/org-hooks-injector.js +648 -0
  64. package/dist/utils/org-hooks-injector.js.map +1 -0
  65. package/dist/utils/org-hooks-wrapper.d.ts +74 -0
  66. package/dist/utils/org-hooks-wrapper.d.ts.map +1 -0
  67. package/dist/utils/org-hooks-wrapper.js +687 -0
  68. package/dist/utils/org-hooks-wrapper.js.map +1 -0
  69. package/dist/utils/organization-hooks-wrapper.d.ts +38 -0
  70. package/dist/utils/organization-hooks-wrapper.d.ts.map +1 -0
  71. package/dist/utils/organization-hooks-wrapper.js +297 -0
  72. package/dist/utils/organization-hooks-wrapper.js.map +1 -0
  73. package/package.json +3 -3
  74. package/public/assets/main-RoeYO1I-.css +1 -0
  75. package/public/assets/{main-BDwnIMk3.js → main-wiXkwSx1.js} +82 -82
  76. package/public/index.html +2 -2
  77. package/dist/public/assets/main-s8HrXBxq.css +0 -1
  78. package/public/assets/main-s8HrXBxq.css +0 -1
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/png" href="/logo.png" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Better Auth Studio</title>
8
- <script type="module" crossorigin src="/assets/main-BDwnIMk3.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/main-s8HrXBxq.css">
8
+ <script type="module" crossorigin src="/assets/main-wiXkwSx1.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/main-RoeYO1I-.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAeA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAU9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA0GnE,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,GAAG,EACtB,oBAAoB,CAAC,EAAE,GAAG,EAC1B,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,GAAG,GACjB,MAAM,CA85MR;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC,CA+FD"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAeA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAU9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA0GnE,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,GAAG,EACtB,oBAAoB,CAAC,EAAE,GAAG,EAC1B,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,GAAG,GACjB,MAAM,CAumNR;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC,CA+FD"}
package/dist/routes.js CHANGED
@@ -1091,6 +1091,14 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
1091
1091
  where: [{ field: 'id', value: userId }],
1092
1092
  update: updateData,
1093
1093
  });
1094
+ // Emit event
1095
+ const { emitEvent } = await import('./utils/event-ingestion.js');
1096
+ await emitEvent('user.updated', {
1097
+ status: 'success',
1098
+ userId,
1099
+ metadata: updateData,
1100
+ request: { headers: req.headers, ip: req.ip },
1101
+ }).catch(() => { });
1094
1102
  res.json({ success: true, user });
1095
1103
  }
1096
1104
  catch (_error) {
@@ -1307,6 +1315,18 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
1307
1315
  id: userId,
1308
1316
  data: { banned: true },
1309
1317
  });
1318
+ // Emit event
1319
+ const { emitEvent } = await import('./utils/event-ingestion.js');
1320
+ await emitEvent('user.banned', {
1321
+ status: 'success',
1322
+ userId,
1323
+ metadata: {
1324
+ name: user?.name,
1325
+ email: user?.email,
1326
+ reason: req.body?.reason,
1327
+ },
1328
+ request: { headers: req.headers, ip: req.ip },
1329
+ }).catch(() => { });
1310
1330
  res.json({ success: true, user });
1311
1331
  }
1312
1332
  catch (_error) {
@@ -1486,6 +1506,156 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
1486
1506
  res.status(500).json({ error: 'Failed to fetch organization' });
1487
1507
  }
1488
1508
  });
1509
+ // Events API endpoint with cursor-based pagination
1510
+ router.get('/api/events', async (req, res) => {
1511
+ try {
1512
+ const limit = parseInt(req.query.limit, 10) || 20;
1513
+ const after = req.query.after; // Cursor
1514
+ const sort = req.query.sort || 'desc'; // Default: 'desc' = newest first
1515
+ const type = req.query.type;
1516
+ const userId = req.query.userId;
1517
+ const { getEventIngestionProvider } = await import('./utils/event-ingestion.js');
1518
+ const eventProvider = getEventIngestionProvider();
1519
+ if (eventProvider && eventProvider.query) {
1520
+ try {
1521
+ const result = await eventProvider.query({
1522
+ limit,
1523
+ after,
1524
+ sort: sort,
1525
+ type,
1526
+ userId,
1527
+ });
1528
+ // Import event utilities for template fallback
1529
+ const eventTypes = await import('./types/events.js');
1530
+ const EVENT_TEMPLATES = eventTypes.EVENT_TEMPLATES;
1531
+ const getEventSeverity = eventTypes.getEventSeverity;
1532
+ const transformedEvents = result.events.map((event) => {
1533
+ if (!event.display?.message || event.display.message === event.type) {
1534
+ const tempEvent = {
1535
+ id: event.id,
1536
+ type: event.type,
1537
+ timestamp: event.timestamp,
1538
+ status: event.status || 'success',
1539
+ userId: event.userId,
1540
+ sessionId: event.sessionId,
1541
+ organizationId: event.organizationId,
1542
+ metadata: event.metadata || {},
1543
+ source: event.source,
1544
+ };
1545
+ const templateMessage = EVENT_TEMPLATES[event.type]?.(tempEvent);
1546
+ if (templateMessage) {
1547
+ event.display = {
1548
+ message: templateMessage,
1549
+ severity: event.display?.severity || getEventSeverity(event),
1550
+ };
1551
+ }
1552
+ }
1553
+ return event;
1554
+ });
1555
+ return res.json({
1556
+ events: transformedEvents,
1557
+ hasMore: result.hasMore,
1558
+ nextCursor: result.nextCursor,
1559
+ });
1560
+ }
1561
+ catch (providerError) {
1562
+ console.error('Event provider query failed:', providerError);
1563
+ // If provider query fails, don't fall back to adapter - return error
1564
+ return res.status(500).json({
1565
+ error: 'Failed to query events from provider',
1566
+ details: providerError?.message || String(providerError),
1567
+ provider: 'event-ingestion',
1568
+ });
1569
+ }
1570
+ }
1571
+ // Fallback to adapter (for storage provider or when provider doesn't support query)
1572
+ const adapter = await getAuthAdapterWithConfig();
1573
+ if (!adapter) {
1574
+ return res.status(500).json({ error: 'Event provider or adapter not available' });
1575
+ }
1576
+ const where = [];
1577
+ // Cursor-based pagination
1578
+ if (after) {
1579
+ if (sort === 'desc') {
1580
+ where.push({ field: 'id', operator: '<', value: after });
1581
+ }
1582
+ else {
1583
+ where.push({ field: 'id', operator: '>', value: after });
1584
+ }
1585
+ }
1586
+ if (type) {
1587
+ where.push({ field: 'type', value: type });
1588
+ }
1589
+ if (userId) {
1590
+ where.push({ field: 'userId', value: userId });
1591
+ }
1592
+ let events = [];
1593
+ if (adapter.findMany) {
1594
+ events = await adapter.findMany({
1595
+ model: 'auth_events',
1596
+ where,
1597
+ orderBy: [{ field: 'timestamp', direction: sort === 'desc' ? 'desc' : 'asc' }],
1598
+ limit: limit + 1, // Get one extra to check hasMore
1599
+ });
1600
+ }
1601
+ const hasMore = events.length > limit;
1602
+ const paginatedEvents = events.slice(0, limit);
1603
+ // Import event utilities
1604
+ const eventTypes = await import('./types/events.js');
1605
+ const EVENT_TEMPLATES = eventTypes.EVENT_TEMPLATES;
1606
+ const getEventSeverity = eventTypes.getEventSeverity;
1607
+ const transformedEvents = paginatedEvents.map((event) => {
1608
+ // Parse metadata
1609
+ const metadata = typeof event.metadata === 'string' ? JSON.parse(event.metadata) : event.metadata || {};
1610
+ // Create a temporary event object for template function
1611
+ const tempEvent = {
1612
+ id: event.id,
1613
+ type: event.type,
1614
+ timestamp: new Date(event.timestamp || event.createdAt),
1615
+ status: event.status || 'success',
1616
+ userId: event.userId || event.user_id,
1617
+ sessionId: event.sessionId || event.session_id,
1618
+ organizationId: event.organizationId || event.organization_id,
1619
+ metadata,
1620
+ source: event.source || 'app',
1621
+ };
1622
+ return {
1623
+ id: event.id,
1624
+ type: event.type,
1625
+ timestamp: event.timestamp || event.createdAt,
1626
+ status: event.status || 'success',
1627
+ userId: event.userId || event.user_id,
1628
+ sessionId: event.sessionId || event.session_id,
1629
+ organizationId: event.organizationId || event.organization_id,
1630
+ metadata,
1631
+ ipAddress: event.ipAddress || event.ip_address,
1632
+ userAgent: event.userAgent || event.user_agent,
1633
+ source: event.source || 'app',
1634
+ display: {
1635
+ message: event.displayMessage ||
1636
+ event.display_message ||
1637
+ EVENT_TEMPLATES[event.type]?.(tempEvent) ||
1638
+ event.type,
1639
+ severity: event.displaySeverity ||
1640
+ event.display_severity ||
1641
+ getEventSeverity(tempEvent, event.status || 'success'),
1642
+ },
1643
+ };
1644
+ });
1645
+ res.json({
1646
+ events: transformedEvents,
1647
+ hasMore,
1648
+ nextCursor: hasMore ? transformedEvents[transformedEvents.length - 1].id : null,
1649
+ });
1650
+ }
1651
+ catch (error) {
1652
+ console.error('Failed to fetch events:', error);
1653
+ res.status(500).json({
1654
+ error: 'Failed to fetch events',
1655
+ details: error instanceof Error ? error.message : String(error),
1656
+ });
1657
+ }
1658
+ });
1489
1659
  router.get('/api/users', async (req, res) => {
1490
1660
  try {
1491
1661
  const page = parseInt(req.query.page, 10) || 1;
@@ -2202,6 +2372,17 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
2202
2372
  where: [{ field: 'id', value: req.body.userId }],
2203
2373
  update: { banned: false, banReason: null, banExpires: null },
2204
2374
  });
2375
+ // Emit event
2376
+ const { emitEvent } = await import('./utils/event-ingestion.js');
2377
+ await emitEvent('user.unbanned', {
2378
+ status: 'success',
2379
+ userId: req.body.userId,
2380
+ metadata: {
2381
+ name: unbannedUser?.name,
2382
+ email: unbannedUser?.email,
2383
+ },
2384
+ request: { headers: req.headers, ip: req.ip },
2385
+ }).catch(() => { });
2205
2386
  res.json({ success: true, user: unbannedUser });
2206
2387
  }
2207
2388
  catch (error) {