@better-auth/infra 0.2.0 → 0.2.1

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/dist/index.d.mts CHANGED
@@ -723,7 +723,7 @@ interface DashIdRow {
723
723
  id: string;
724
724
  }
725
725
  //#endregion
726
- //#region ../../node_modules/.bun/@better-auth+scim@1.6.1+7c6411af93091c12/node_modules/@better-auth/scim/dist/index.d.mts
726
+ //#region ../../node_modules/.bun/@better-auth+scim@1.6.1+27eabf8bb9704597/node_modules/@better-auth/scim/dist/index.d.mts
727
727
  //#region src/types.d.ts
728
728
  interface SCIMProvider {
729
729
  id: string;
@@ -4507,34 +4507,29 @@ interface DashUserOrganizationsResponse {
4507
4507
  }
4508
4508
  type DashCreateUserResponse = DashUser;
4509
4509
  type DashUpdateUserResponse = DashUser;
4510
+ /** One period of sign-up stats; null when the underlying query failed. */
4511
+ interface DashUserStatsSignUpPeriod {
4512
+ signUps: number | null;
4513
+ /** Omitted when current or previous-period query failed (avoids misleading deltas). */
4514
+ percentage: number | null;
4515
+ }
4516
+ /** One period of active-user stats; null when the underlying query failed. */
4517
+ interface DashUserStatsActivePeriod {
4518
+ active: number | null;
4519
+ percentage: number | null;
4520
+ }
4510
4521
  interface DashUserStatsResponse {
4511
- daily: {
4512
- signUps: number;
4513
- percentage: number;
4514
- };
4515
- weekly: {
4516
- signUps: number;
4517
- percentage: number;
4518
- };
4519
- monthly: {
4520
- signUps: number;
4521
- percentage: number;
4522
- };
4523
- total: number;
4522
+ daily: DashUserStatsSignUpPeriod;
4523
+ weekly: DashUserStatsSignUpPeriod;
4524
+ monthly: DashUserStatsSignUpPeriod;
4525
+ total: number | null;
4524
4526
  activeUsers: {
4525
- daily: {
4526
- active: number;
4527
- percentage: number;
4528
- };
4529
- weekly: {
4530
- active: number;
4531
- percentage: number;
4532
- };
4533
- monthly: {
4534
- active: number;
4535
- percentage: number;
4536
- };
4527
+ daily: DashUserStatsActivePeriod;
4528
+ weekly: DashUserStatsActivePeriod;
4529
+ monthly: DashUserStatsActivePeriod;
4537
4530
  };
4531
+ /** Set when any stat query failed; some fields may be null. */
4532
+ degraded?: boolean;
4538
4533
  }
4539
4534
  interface DashUserGraphPoint {
4540
4535
  date: string | Date;
@@ -5874,4 +5869,4 @@ declare const dash: <O extends DashOptions>(options?: O) => {
5874
5869
  } : {};
5875
5870
  };
5876
5871
  //#endregion
5877
- export { type APIError, CHALLENGE_TTL, type CompromisedPasswordResult, type CredentialStuffingResult, DBField, DEFAULT_DIFFICULTY, DashAddTeamMemberResponse, DashBanManyResponse, DashCheckUserByEmailResponse, DashCheckUserExistsResponse, DashCompleteInvitationResponse, DashConfigResponse, DashCreateOrganizationBody, DashCreateOrganizationResponse, DashCreateTeamResponse, DashCreateUserResponse, DashDeleteManyUsersResponse, DashDirectoryCreateResponse, DashDirectoryDeleteResponse, DashDirectoryItem, DashDirectoryRegenerateTokenResponse, DashExecuteAdapterCountResponse, DashExecuteAdapterFindManyResponse, DashExecuteAdapterFindOneResponse, DashExecuteAdapterMutationResponse, DashExecuteAdapterResponse, DashExportOrganizationsResponse, DashIdRow, DashInviteMemberResponse, DashMaybeSuccessResponse, type DashOptions, DashOptionsInternal, DashOrganizationAddMemberResponse, DashOrganizationDeleteManyResponse, DashOrganizationDetailResponse, DashOrganizationInvitationItem, DashOrganizationInvitationListResponse, DashOrganizationInvitationStatusItem, DashOrganizationListResponse, DashOrganizationMember, DashOrganizationMemberListItem, DashOrganizationMemberListResponse, DashOrganizationMemberUser, DashOrganizationOptionsResponse, DashOrganizationTeamItem, DashOrganizationTeamListResponse, DashOrganizationUpdateMemberRoleResponse, DashOrganizationUpdateResponse, DashSendManyVerificationEmailsResponse, DashSessionRevokeManyResponse, DashSsoCreateProviderResponse, DashSsoDeleteResponse, DashSsoMarkDomainVerifiedResponse, DashSsoProviderItem, DashSsoProviderSummary, DashSsoUpdateProviderResponse, DashSsoVerificationTokenResponse, DashSsoVerifyDomainResponse, DashSuccessResponse, DashTeam, DashTeamMember, DashTeamMemberListResponse, DashTwoFactorBackupCodesResponse, DashTwoFactorEnableResponse, DashTwoFactorTotpViewResponse, DashUpdateTeamResponse, DashUpdateUserResponse, DashUserDetailsResponse, DashUserGraphDataResponse, DashUserListResponse, DashUserOrganizationsResponse, DashUserRetentionDataResponse, DashUserStatsResponse, DashValidateResponse, DirectorySyncConnection, EMAIL_TEMPLATES, type EmailConfig, type EmailTemplateId, type EmailTemplateVariables, type Endpoint, type EndpointOptions, type EventLocation, type EventTypesResponse, type ImpossibleTravelResult, InfraEndpointContext, InfraPluginConnectionOptions, InfraPluginConnectionOptionsInternal, LocationData, LocationDataContext, type PoWChallenge, type PoWSolution, SCIMPlugin, type SMSConfig, type SMSTemplateId, type SMSTemplateVariables, SMS_TEMPLATES, type SecurityEvent, type SecurityEventType, type SecurityOptions, type SecurityVerdict, type SendBulkEmailsOptions, type SendBulkEmailsResult, type SendEmailOptions, type SendEmailResult, type SendSMSOptions, type SendSMSResult, type SentinelOptions, SentinelOptionsInternal, type StaleUserResult, type ThresholdConfig, USER_EVENT_TYPES, type UserEvent, type UserEventType, type UserEventsResponse, createEmailSender, createSMSSender, dash, decodePoWChallenge, encodePoWSolution, normalizeEmail, sendBulkEmails, sendEmail, sendSMS, sentinel, solvePoWChallenge, verifyPoWSolution };
5872
+ export { type APIError, CHALLENGE_TTL, type CompromisedPasswordResult, type CredentialStuffingResult, DBField, DEFAULT_DIFFICULTY, DashAddTeamMemberResponse, DashBanManyResponse, DashCheckUserByEmailResponse, DashCheckUserExistsResponse, DashCompleteInvitationResponse, DashConfigResponse, DashCreateOrganizationBody, DashCreateOrganizationResponse, DashCreateTeamResponse, DashCreateUserResponse, DashDeleteManyUsersResponse, DashDirectoryCreateResponse, DashDirectoryDeleteResponse, DashDirectoryItem, DashDirectoryRegenerateTokenResponse, DashExecuteAdapterCountResponse, DashExecuteAdapterFindManyResponse, DashExecuteAdapterFindOneResponse, DashExecuteAdapterMutationResponse, DashExecuteAdapterResponse, DashExportOrganizationsResponse, DashIdRow, DashInviteMemberResponse, DashMaybeSuccessResponse, type DashOptions, DashOptionsInternal, DashOrganizationAddMemberResponse, DashOrganizationDeleteManyResponse, DashOrganizationDetailResponse, DashOrganizationInvitationItem, DashOrganizationInvitationListResponse, DashOrganizationInvitationStatusItem, DashOrganizationListResponse, DashOrganizationMember, DashOrganizationMemberListItem, DashOrganizationMemberListResponse, DashOrganizationMemberUser, DashOrganizationOptionsResponse, DashOrganizationTeamItem, DashOrganizationTeamListResponse, DashOrganizationUpdateMemberRoleResponse, DashOrganizationUpdateResponse, DashSendManyVerificationEmailsResponse, DashSessionRevokeManyResponse, DashSsoCreateProviderResponse, DashSsoDeleteResponse, DashSsoMarkDomainVerifiedResponse, DashSsoProviderItem, DashSsoProviderSummary, DashSsoUpdateProviderResponse, DashSsoVerificationTokenResponse, DashSsoVerifyDomainResponse, DashSuccessResponse, DashTeam, DashTeamMember, DashTeamMemberListResponse, DashTwoFactorBackupCodesResponse, DashTwoFactorEnableResponse, DashTwoFactorTotpViewResponse, DashUpdateTeamResponse, DashUpdateUserResponse, DashUserDetailsResponse, DashUserGraphDataResponse, DashUserListResponse, DashUserOrganizationsResponse, DashUserRetentionDataResponse, DashUserStatsActivePeriod, DashUserStatsResponse, DashUserStatsSignUpPeriod, DashValidateResponse, DirectorySyncConnection, EMAIL_TEMPLATES, type EmailConfig, type EmailTemplateId, type EmailTemplateVariables, type Endpoint, type EndpointOptions, type EventLocation, type EventTypesResponse, type ImpossibleTravelResult, InfraEndpointContext, InfraPluginConnectionOptions, InfraPluginConnectionOptionsInternal, LocationData, LocationDataContext, type PoWChallenge, type PoWSolution, SCIMPlugin, type SMSConfig, type SMSTemplateId, type SMSTemplateVariables, SMS_TEMPLATES, type SecurityEvent, type SecurityEventType, type SecurityOptions, type SecurityVerdict, type SendBulkEmailsOptions, type SendBulkEmailsResult, type SendEmailOptions, type SendEmailResult, type SendSMSOptions, type SendSMSResult, type SentinelOptions, SentinelOptionsInternal, type StaleUserResult, type ThresholdConfig, USER_EVENT_TYPES, type UserEvent, type UserEventType, type UserEventsResponse, createEmailSender, createSMSSender, dash, decodePoWChallenge, encodePoWSolution, normalizeEmail, sendBulkEmails, sendEmail, sendSMS, sentinel, solvePoWChallenge, verifyPoWSolution };
package/dist/index.mjs CHANGED
@@ -2746,7 +2746,7 @@ const jwtValidateMiddleware = (options) => createAuthMiddleware(async (ctx) => {
2746
2746
  });
2747
2747
  //#endregion
2748
2748
  //#region src/version.ts
2749
- const PLUGIN_VERSION = "0.2.0";
2749
+ const PLUGIN_VERSION = "0.2.1";
2750
2750
  //#endregion
2751
2751
  //#region src/routes/auth/config.ts
2752
2752
  const PLUGIN_OPTIONS_EXCLUDE_KEYS = { stripe: new Set(["stripeClient"]) };
@@ -6625,7 +6625,7 @@ async function countUniqueActiveUsers(ctx, range, options) {
6625
6625
  break;
6626
6626
  }
6627
6627
  }
6628
- }, { concurrency: 50 });
6628
+ }, { concurrency: 10 });
6629
6629
  return activeUserIds.size;
6630
6630
  }
6631
6631
  const sessions = await ctx.context.adapter.findMany({
@@ -6635,6 +6635,34 @@ async function countUniqueActiveUsers(ctx, range, options) {
6635
6635
  });
6636
6636
  return new Set(sessions.map((s) => s.userId)).size;
6637
6637
  }
6638
+ function optionalQuery(ctx, label, getCount) {
6639
+ return async function runQuery() {
6640
+ try {
6641
+ return {
6642
+ ok: true,
6643
+ value: await getCount()
6644
+ };
6645
+ } catch (error) {
6646
+ ctx.context.logger.warn(`[Dash] User stats query "${label}" failed`, error);
6647
+ return {
6648
+ ok: false,
6649
+ value: null
6650
+ };
6651
+ }
6652
+ };
6653
+ }
6654
+ function signUpPeriod(current, previous, calculatePercentage) {
6655
+ return {
6656
+ signUps: current.ok ? current.value : null,
6657
+ percentage: current.ok && previous.ok ? calculatePercentage(current.value, previous.value) : null
6658
+ };
6659
+ }
6660
+ function activePeriod(current, previous, calculatePercentage) {
6661
+ return {
6662
+ active: current.ok ? current.value : null,
6663
+ percentage: current.ok && previous.ok ? calculatePercentage(current.value, previous.value) : null
6664
+ };
6665
+ }
6638
6666
  const getUserStats = (options) => createAuthEndpoint("/dash/user-stats", {
6639
6667
  method: "GET",
6640
6668
  use: [jwtMiddleware(options)]
@@ -6648,16 +6676,16 @@ const getUserStats = (options) => createAuthEndpoint("/dash/user-stats", {
6648
6676
  const twoMonthsAgo = /* @__PURE__ */ new Date(now.getTime() - 1440 * 60 * 60 * 1e3);
6649
6677
  const activityTrackingEnabled = !!options.activityTracking?.enabled;
6650
6678
  const storeInSecondaryStorageOnly = isSessionInSecondaryStorageOnly(ctx.context);
6651
- const [dailyCount, previousDailyCount, weeklyCount, previousWeeklyCount, monthlyCount, previousMonthlyCount, totalCount, dailyActiveCount, previousDailyActiveCount, weeklyActiveCount, previousWeeklyActiveCount, monthlyActiveCount, previousMonthlyActiveCount] = await Promise.all([
6652
- ctx.context.adapter.count({
6679
+ const [rDailySignups, rPrevDaySignups, rWeeklySignups, rPrevWeekSignups, rMonthlySignups, rPrevMonthSignups, rTotalUsers, rActiveDaily, rActivePrevDay, rActiveWeekly, rActivePrevWeek, rActiveMonthly, rActivePrevMonth] = await withConcurrency([
6680
+ optionalQuery(ctx, "daily signups", () => ctx.context.adapter.count({
6653
6681
  model: "user",
6654
6682
  where: [{
6655
6683
  field: "createdAt",
6656
6684
  operator: "gte",
6657
6685
  value: oneDayAgo
6658
6686
  }]
6659
- }),
6660
- ctx.context.adapter.count({
6687
+ })),
6688
+ optionalQuery(ctx, "previous day signups", () => ctx.context.adapter.count({
6661
6689
  model: "user",
6662
6690
  where: [{
6663
6691
  field: "createdAt",
@@ -6668,16 +6696,16 @@ const getUserStats = (options) => createAuthEndpoint("/dash/user-stats", {
6668
6696
  operator: "lt",
6669
6697
  value: oneDayAgo
6670
6698
  }]
6671
- }),
6672
- ctx.context.adapter.count({
6699
+ })),
6700
+ optionalQuery(ctx, "weekly signups", () => ctx.context.adapter.count({
6673
6701
  model: "user",
6674
6702
  where: [{
6675
6703
  field: "createdAt",
6676
6704
  operator: "gte",
6677
6705
  value: oneWeekAgo
6678
6706
  }]
6679
- }),
6680
- ctx.context.adapter.count({
6707
+ })),
6708
+ optionalQuery(ctx, "previous week signups", () => ctx.context.adapter.count({
6681
6709
  model: "user",
6682
6710
  where: [{
6683
6711
  field: "createdAt",
@@ -6688,16 +6716,16 @@ const getUserStats = (options) => createAuthEndpoint("/dash/user-stats", {
6688
6716
  operator: "lt",
6689
6717
  value: oneWeekAgo
6690
6718
  }]
6691
- }),
6692
- ctx.context.adapter.count({
6719
+ })),
6720
+ optionalQuery(ctx, "monthly signups", () => ctx.context.adapter.count({
6693
6721
  model: "user",
6694
6722
  where: [{
6695
6723
  field: "createdAt",
6696
6724
  operator: "gte",
6697
6725
  value: oneMonthAgo
6698
6726
  }]
6699
- }),
6700
- ctx.context.adapter.count({
6727
+ })),
6728
+ optionalQuery(ctx, "previous month signups", () => ctx.context.adapter.count({
6701
6729
  model: "user",
6702
6730
  where: [{
6703
6731
  field: "createdAt",
@@ -6708,75 +6736,74 @@ const getUserStats = (options) => createAuthEndpoint("/dash/user-stats", {
6708
6736
  operator: "lt",
6709
6737
  value: oneMonthAgo
6710
6738
  }]
6711
- }),
6712
- ctx.context.adapter.count({ model: "user" }),
6713
- countUniqueActiveUsers(ctx, { from: oneDayAgo }, {
6739
+ })),
6740
+ optionalQuery(ctx, "total users", () => ctx.context.adapter.count({ model: "user" })),
6741
+ optionalQuery(ctx, "active users (daily window)", () => countUniqueActiveUsers(ctx, { from: oneDayAgo }, {
6714
6742
  storeInSecondaryStorageOnly,
6715
6743
  activityTrackingEnabled
6716
- }),
6717
- countUniqueActiveUsers(ctx, {
6744
+ })),
6745
+ optionalQuery(ctx, "active users (previous day window)", () => countUniqueActiveUsers(ctx, {
6718
6746
  from: twoDaysAgo,
6719
6747
  to: oneDayAgo
6720
6748
  }, {
6721
6749
  storeInSecondaryStorageOnly,
6722
6750
  activityTrackingEnabled
6723
- }),
6724
- countUniqueActiveUsers(ctx, { from: oneWeekAgo }, {
6751
+ })),
6752
+ optionalQuery(ctx, "active users (weekly window)", () => countUniqueActiveUsers(ctx, { from: oneWeekAgo }, {
6725
6753
  storeInSecondaryStorageOnly,
6726
6754
  activityTrackingEnabled
6727
- }),
6728
- countUniqueActiveUsers(ctx, {
6755
+ })),
6756
+ optionalQuery(ctx, "active users (previous week window)", () => countUniqueActiveUsers(ctx, {
6729
6757
  from: twoWeeksAgo,
6730
6758
  to: oneWeekAgo
6731
6759
  }, {
6732
6760
  storeInSecondaryStorageOnly,
6733
6761
  activityTrackingEnabled
6734
- }),
6735
- countUniqueActiveUsers(ctx, { from: oneMonthAgo }, {
6762
+ })),
6763
+ optionalQuery(ctx, "active users (monthly window)", () => countUniqueActiveUsers(ctx, { from: oneMonthAgo }, {
6736
6764
  storeInSecondaryStorageOnly,
6737
6765
  activityTrackingEnabled
6738
- }),
6739
- countUniqueActiveUsers(ctx, {
6766
+ })),
6767
+ optionalQuery(ctx, "active users (previous month window)", () => countUniqueActiveUsers(ctx, {
6740
6768
  from: twoMonthsAgo,
6741
6769
  to: oneMonthAgo
6742
6770
  }, {
6743
6771
  storeInSecondaryStorageOnly,
6744
6772
  activityTrackingEnabled
6745
- })
6746
- ]);
6773
+ }))
6774
+ ], (fn) => fn(), { concurrency: 5 });
6747
6775
  const calculatePercentage = (current, previous) => {
6748
6776
  if (previous === 0) return current > 0 ? 100 : 0;
6749
6777
  return (current - previous) / previous * 100;
6750
6778
  };
6751
- return {
6752
- daily: {
6753
- signUps: dailyCount,
6754
- percentage: calculatePercentage(dailyCount, previousDailyCount)
6755
- },
6756
- weekly: {
6757
- signUps: weeklyCount,
6758
- percentage: calculatePercentage(weeklyCount, previousWeeklyCount)
6759
- },
6760
- monthly: {
6761
- signUps: monthlyCount,
6762
- percentage: calculatePercentage(monthlyCount, previousMonthlyCount)
6763
- },
6764
- total: totalCount,
6779
+ const degraded = [
6780
+ rDailySignups,
6781
+ rPrevDaySignups,
6782
+ rWeeklySignups,
6783
+ rPrevWeekSignups,
6784
+ rMonthlySignups,
6785
+ rPrevMonthSignups,
6786
+ rTotalUsers,
6787
+ rActiveDaily,
6788
+ rActivePrevDay,
6789
+ rActiveWeekly,
6790
+ rActivePrevWeek,
6791
+ rActiveMonthly,
6792
+ rActivePrevMonth
6793
+ ].some((r) => !r.ok);
6794
+ const body = {
6795
+ daily: signUpPeriod(rDailySignups, rPrevDaySignups, calculatePercentage),
6796
+ weekly: signUpPeriod(rWeeklySignups, rPrevWeekSignups, calculatePercentage),
6797
+ monthly: signUpPeriod(rMonthlySignups, rPrevMonthSignups, calculatePercentage),
6798
+ total: rTotalUsers.ok ? rTotalUsers.value : null,
6765
6799
  activeUsers: {
6766
- daily: {
6767
- active: dailyActiveCount,
6768
- percentage: calculatePercentage(dailyActiveCount, previousDailyActiveCount)
6769
- },
6770
- weekly: {
6771
- active: weeklyActiveCount,
6772
- percentage: calculatePercentage(weeklyActiveCount, previousWeeklyActiveCount)
6773
- },
6774
- monthly: {
6775
- active: monthlyActiveCount,
6776
- percentage: calculatePercentage(monthlyActiveCount, previousMonthlyActiveCount)
6777
- }
6800
+ daily: activePeriod(rActiveDaily, rActivePrevDay, calculatePercentage),
6801
+ weekly: activePeriod(rActiveWeekly, rActivePrevWeek, calculatePercentage),
6802
+ monthly: activePeriod(rActiveMonthly, rActivePrevMonth, calculatePercentage)
6778
6803
  }
6779
6804
  };
6805
+ if (degraded) body.degraded = true;
6806
+ return body;
6780
6807
  });
6781
6808
  const getUserGraphData = (options) => createAuthEndpoint("/dash/user-graph-data", {
6782
6809
  method: "GET",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/infra",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Dashboard and analytics plugin for Better Auth",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",