@coursebuilder/adapter-drizzle 1.0.0 → 1.0.2

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 (147) hide show
  1. package/dist/chunk-253RMSB3.js +99 -0
  2. package/dist/{chunk-3WYG5OE7.js → chunk-3GONHHMY.js} +2 -2
  3. package/dist/{chunk-L5ZAWSTN.js → chunk-5QEGBX2O.js} +411 -120
  4. package/dist/{chunk-WFC55BSF.js → chunk-FPAQINSA.js} +2 -2
  5. package/dist/{chunk-RCL6HPBL.js → chunk-HWIQUI7O.js} +2 -2
  6. package/dist/{chunk-QGZ2F5SW.js → chunk-LPJ2P2KJ.js} +1162 -1027
  7. package/dist/{chunk-GAKWXOAY.js → chunk-OBUGOZKM.js} +2 -2
  8. package/dist/chunk-ORRM7KVW.js +25 -0
  9. package/dist/{chunk-A6XPL665.js → chunk-PBTEHA7F.js} +2 -2
  10. package/dist/{chunk-5XTOCFDB.js → chunk-YQNIXCD3.js} +2 -2
  11. package/dist/index.js +11 -10
  12. package/dist/lib/mysql/index.cjs +1513 -1060
  13. package/dist/lib/mysql/index.cjs.map +1 -1
  14. package/dist/lib/mysql/index.d.cts +2994 -2258
  15. package/dist/lib/mysql/index.d.ts +2994 -2258
  16. package/dist/lib/mysql/index.js +11 -10
  17. package/dist/lib/mysql/schemas/auth/accounts.cjs +106 -98
  18. package/dist/lib/mysql/schemas/auth/accounts.cjs.map +1 -1
  19. package/dist/lib/mysql/schemas/auth/accounts.js +2 -2
  20. package/dist/lib/mysql/schemas/auth/device-access-token.cjs +99 -91
  21. package/dist/lib/mysql/schemas/auth/device-access-token.cjs.map +1 -1
  22. package/dist/lib/mysql/schemas/auth/device-access-token.js +3 -3
  23. package/dist/lib/mysql/schemas/auth/device-verification.cjs +100 -92
  24. package/dist/lib/mysql/schemas/auth/device-verification.cjs.map +1 -1
  25. package/dist/lib/mysql/schemas/auth/device-verification.js +3 -3
  26. package/dist/lib/mysql/schemas/auth/profiles.cjs +254 -0
  27. package/dist/lib/mysql/schemas/auth/profiles.cjs.map +1 -0
  28. package/dist/lib/mysql/schemas/auth/profiles.d.cts +112 -0
  29. package/dist/lib/mysql/schemas/auth/profiles.d.ts +112 -0
  30. package/dist/lib/mysql/schemas/auth/profiles.js +20 -0
  31. package/dist/lib/mysql/schemas/auth/profiles.js.map +1 -0
  32. package/dist/lib/mysql/schemas/auth/role-permissions.cjs +55 -46
  33. package/dist/lib/mysql/schemas/auth/role-permissions.cjs.map +1 -1
  34. package/dist/lib/mysql/schemas/auth/role-permissions.js +3 -3
  35. package/dist/lib/mysql/schemas/auth/roles.cjs +57 -48
  36. package/dist/lib/mysql/schemas/auth/roles.cjs.map +1 -1
  37. package/dist/lib/mysql/schemas/auth/roles.js +2 -2
  38. package/dist/lib/mysql/schemas/auth/sessions.cjs +96 -88
  39. package/dist/lib/mysql/schemas/auth/sessions.cjs.map +1 -1
  40. package/dist/lib/mysql/schemas/auth/sessions.js +3 -3
  41. package/dist/lib/mysql/schemas/auth/user-permissions.cjs +99 -91
  42. package/dist/lib/mysql/schemas/auth/user-permissions.cjs.map +1 -1
  43. package/dist/lib/mysql/schemas/auth/user-permissions.js +2 -2
  44. package/dist/lib/mysql/schemas/auth/user-prefs.cjs +104 -96
  45. package/dist/lib/mysql/schemas/auth/user-prefs.cjs.map +1 -1
  46. package/dist/lib/mysql/schemas/auth/user-prefs.js +2 -2
  47. package/dist/lib/mysql/schemas/auth/user-roles.cjs +58 -49
  48. package/dist/lib/mysql/schemas/auth/user-roles.cjs.map +1 -1
  49. package/dist/lib/mysql/schemas/auth/user-roles.js +2 -2
  50. package/dist/lib/mysql/schemas/auth/users.cjs +295 -259
  51. package/dist/lib/mysql/schemas/auth/users.cjs.map +1 -1
  52. package/dist/lib/mysql/schemas/auth/users.d.cts +1 -0
  53. package/dist/lib/mysql/schemas/auth/users.d.ts +1 -0
  54. package/dist/lib/mysql/schemas/auth/users.js +2 -2
  55. package/dist/lib/mysql/schemas/commerce/coupon.cjs +131 -123
  56. package/dist/lib/mysql/schemas/commerce/coupon.cjs.map +1 -1
  57. package/dist/lib/mysql/schemas/commerce/coupon.js +2 -2
  58. package/dist/lib/mysql/schemas/commerce/merchant-charge.cjs +96 -88
  59. package/dist/lib/mysql/schemas/commerce/merchant-charge.cjs.map +1 -1
  60. package/dist/lib/mysql/schemas/commerce/merchant-charge.js +2 -2
  61. package/dist/lib/mysql/schemas/commerce/merchant-subscription.cjs +90 -82
  62. package/dist/lib/mysql/schemas/commerce/merchant-subscription.cjs.map +1 -1
  63. package/dist/lib/mysql/schemas/commerce/merchant-subscription.js +2 -2
  64. package/dist/lib/mysql/schemas/commerce/price.cjs +98 -90
  65. package/dist/lib/mysql/schemas/commerce/price.cjs.map +1 -1
  66. package/dist/lib/mysql/schemas/commerce/price.js +2 -2
  67. package/dist/lib/mysql/schemas/commerce/product.cjs +125 -117
  68. package/dist/lib/mysql/schemas/commerce/product.cjs.map +1 -1
  69. package/dist/lib/mysql/schemas/commerce/product.js +2 -2
  70. package/dist/lib/mysql/schemas/commerce/purchase-user-transfer.cjs +131 -123
  71. package/dist/lib/mysql/schemas/commerce/purchase-user-transfer.cjs.map +1 -1
  72. package/dist/lib/mysql/schemas/commerce/purchase-user-transfer.js +3 -3
  73. package/dist/lib/mysql/schemas/commerce/purchase.cjs +184 -176
  74. package/dist/lib/mysql/schemas/commerce/purchase.cjs.map +1 -1
  75. package/dist/lib/mysql/schemas/commerce/purchase.js +2 -2
  76. package/dist/lib/mysql/schemas/commerce/subscription.cjs +117 -109
  77. package/dist/lib/mysql/schemas/commerce/subscription.cjs.map +1 -1
  78. package/dist/lib/mysql/schemas/commerce/subscription.js +2 -2
  79. package/dist/lib/mysql/schemas/commerce/upgradable-products.cjs +105 -97
  80. package/dist/lib/mysql/schemas/commerce/upgradable-products.cjs.map +1 -1
  81. package/dist/lib/mysql/schemas/commerce/upgradable-products.js +3 -3
  82. package/dist/lib/mysql/schemas/communication/comment.cjs +114 -106
  83. package/dist/lib/mysql/schemas/communication/comment.cjs.map +1 -1
  84. package/dist/lib/mysql/schemas/communication/comment.js +2 -2
  85. package/dist/lib/mysql/schemas/communication/communication-preferences.cjs +136 -128
  86. package/dist/lib/mysql/schemas/communication/communication-preferences.cjs.map +1 -1
  87. package/dist/lib/mysql/schemas/communication/communication-preferences.js +2 -2
  88. package/dist/lib/mysql/schemas/content/content-contributions.cjs +144 -136
  89. package/dist/lib/mysql/schemas/content/content-contributions.cjs.map +1 -1
  90. package/dist/lib/mysql/schemas/content/content-contributions.js +2 -2
  91. package/dist/lib/mysql/schemas/content/content-resource-product.cjs +99 -91
  92. package/dist/lib/mysql/schemas/content/content-resource-product.cjs.map +1 -1
  93. package/dist/lib/mysql/schemas/content/content-resource-product.js +2 -2
  94. package/dist/lib/mysql/schemas/content/content-resource-resource.cjs +108 -100
  95. package/dist/lib/mysql/schemas/content/content-resource-resource.cjs.map +1 -1
  96. package/dist/lib/mysql/schemas/content/content-resource-resource.js +2 -2
  97. package/dist/lib/mysql/schemas/content/content-resource-tag.cjs +118 -110
  98. package/dist/lib/mysql/schemas/content/content-resource-tag.cjs.map +1 -1
  99. package/dist/lib/mysql/schemas/content/content-resource-tag.js +2 -2
  100. package/dist/lib/mysql/schemas/content/content-resource-version.cjs +121 -113
  101. package/dist/lib/mysql/schemas/content/content-resource-version.cjs.map +1 -1
  102. package/dist/lib/mysql/schemas/content/content-resource-version.js +2 -2
  103. package/dist/lib/mysql/schemas/content/content-resource.cjs +198 -190
  104. package/dist/lib/mysql/schemas/content/content-resource.cjs.map +1 -1
  105. package/dist/lib/mysql/schemas/content/content-resource.js +2 -2
  106. package/dist/lib/mysql/schemas/content/tag-tag.cjs +103 -95
  107. package/dist/lib/mysql/schemas/content/tag-tag.cjs.map +1 -1
  108. package/dist/lib/mysql/schemas/content/tag-tag.js +2 -2
  109. package/dist/lib/mysql/schemas/content/tag.cjs +116 -108
  110. package/dist/lib/mysql/schemas/content/tag.cjs.map +1 -1
  111. package/dist/lib/mysql/schemas/content/tag.js +2 -2
  112. package/dist/lib/mysql/schemas/entitlements/entitlement-type.cjs +46 -0
  113. package/dist/lib/mysql/schemas/entitlements/entitlement-type.cjs.map +1 -0
  114. package/dist/lib/mysql/schemas/entitlements/entitlement-type.d.cts +60 -0
  115. package/dist/lib/mysql/schemas/entitlements/entitlement-type.d.ts +60 -0
  116. package/dist/lib/mysql/schemas/entitlements/entitlement-type.js +8 -0
  117. package/dist/lib/mysql/schemas/entitlements/entitlement-type.js.map +1 -0
  118. package/dist/lib/mysql/schemas/entitlements/entitlement.cjs +351 -0
  119. package/dist/lib/mysql/schemas/entitlements/entitlement.cjs.map +1 -0
  120. package/dist/lib/mysql/schemas/entitlements/entitlement.d.cts +210 -0
  121. package/dist/lib/mysql/schemas/entitlements/entitlement.d.ts +210 -0
  122. package/dist/lib/mysql/schemas/entitlements/entitlement.js +21 -0
  123. package/dist/lib/mysql/schemas/entitlements/entitlement.js.map +1 -0
  124. package/dist/lib/mysql/schemas/org/organization-membership-roles.cjs +73 -35
  125. package/dist/lib/mysql/schemas/org/organization-membership-roles.cjs.map +1 -1
  126. package/dist/lib/mysql/schemas/org/organization-membership-roles.d.cts +1 -0
  127. package/dist/lib/mysql/schemas/org/organization-membership-roles.d.ts +1 -0
  128. package/dist/lib/mysql/schemas/org/organization-membership-roles.js +2 -3
  129. package/dist/lib/mysql/schemas/org/organization-memberships.cjs +88 -38
  130. package/dist/lib/mysql/schemas/org/organization-memberships.cjs.map +1 -1
  131. package/dist/lib/mysql/schemas/org/organization-memberships.d.cts +1 -0
  132. package/dist/lib/mysql/schemas/org/organization-memberships.d.ts +1 -0
  133. package/dist/lib/mysql/schemas/org/organization-memberships.js +2 -2
  134. package/dist/lib/mysql/schemas/org/organizations.cjs +131 -121
  135. package/dist/lib/mysql/schemas/org/organizations.cjs.map +1 -1
  136. package/dist/lib/mysql/schemas/org/organizations.js +2 -2
  137. package/package.json +4 -3
  138. package/src/lib/mysql/index.ts +349 -26
  139. package/src/lib/mysql/schemas/auth/profiles.ts +50 -0
  140. package/src/lib/mysql/schemas/auth/roles.ts +6 -1
  141. package/src/lib/mysql/schemas/auth/users.ts +6 -1
  142. package/src/lib/mysql/schemas/commerce/subscription.ts +3 -5
  143. package/src/lib/mysql/schemas/entitlements/entitlement-type.ts +21 -0
  144. package/src/lib/mysql/schemas/entitlements/entitlement.ts +66 -0
  145. package/src/lib/mysql/schemas/org/organization-membership-roles.ts +7 -0
  146. package/src/lib/mysql/schemas/org/organization-memberships.ts +6 -0
  147. package/dist/chunk-RP66NZN3.js +0 -81
@@ -61,7 +61,15 @@ import {
61
61
  } from '@coursebuilder/core/schemas/content-resource-schema'
62
62
  import { merchantAccountSchema } from '@coursebuilder/core/schemas/merchant-account-schema'
63
63
  import { merchantCustomerSchema } from '@coursebuilder/core/schemas/merchant-customer-schema'
64
+ import {
65
+ MerchantSession,
66
+ MerchantSessionSchema,
67
+ } from '@coursebuilder/core/schemas/merchant-session'
68
+ import { MerchantSubscriptionSchema } from '@coursebuilder/core/schemas/merchant-subscription'
69
+ import { OrganizationMemberSchema } from '@coursebuilder/core/schemas/organization-member'
70
+ import { OrganizationSchema } from '@coursebuilder/core/schemas/organization-schema'
64
71
  import { type ModuleProgress } from '@coursebuilder/core/schemas/resource-progress-schema'
72
+ import { SubscriptionSchema } from '@coursebuilder/core/schemas/subscription'
65
73
  import { VideoResourceSchema } from '@coursebuilder/core/schemas/video-resource'
66
74
  import { PaymentsProviderConfig } from '@coursebuilder/core/types'
67
75
  import { logger } from '@coursebuilder/core/utils/logger'
@@ -83,6 +91,10 @@ import {
83
91
  getPermissionsRelationsSchema,
84
92
  getPermissionsSchema,
85
93
  } from './schemas/auth/permissions.js'
94
+ import {
95
+ getProfilesRelationsSchema,
96
+ getProfilesSchema,
97
+ } from './schemas/auth/profiles.js'
86
98
  import {
87
99
  getRolePermissionsRelationsSchema,
88
100
  getRolePermissionsSchema,
@@ -196,6 +208,11 @@ import {
196
208
  getTagTagSchema,
197
209
  } from './schemas/content/tag-tag.js'
198
210
  import { getTagRelationsSchema, getTagSchema } from './schemas/content/tag.js'
211
+ import { getEntitlementTypesSchema } from './schemas/entitlements/entitlement-type.js'
212
+ import {
213
+ getEntitlementRelationsSchema,
214
+ getEntitlementsSchema,
215
+ } from './schemas/entitlements/entitlement.js'
199
216
  import {
200
217
  getOrganizationMembershipRolesRelationsSchema,
201
218
  getOrganizationMembershipRolesSchema,
@@ -305,6 +322,11 @@ export function getCourseBuilderSchema(mysqlTable: MySqlTableFn) {
305
322
  getMerchantSubscriptionRelationsSchema(mysqlTable),
306
323
  subscription: getSubscriptionSchema(mysqlTable),
307
324
  subscriptionRelations: getSubscriptionRelationsSchema(mysqlTable),
325
+ profiles: getProfilesSchema(mysqlTable),
326
+ profilesRelations: getProfilesRelationsSchema(mysqlTable),
327
+ entitlementTypes: getEntitlementTypesSchema(mysqlTable),
328
+ entitlements: getEntitlementsSchema(mysqlTable),
329
+ entitlementsRelations: getEntitlementRelationsSchema(mysqlTable),
308
330
  } as const
309
331
  }
310
332
 
@@ -342,6 +364,12 @@ export function mySqlDrizzleAdapter(
342
364
  upgradableProducts,
343
365
  resourceProgress,
344
366
  comments,
367
+ organization: organizationTable,
368
+ organizationMemberships: organizationMembershipTable,
369
+ organizationMembershipRoles: organizationMembershipRoleTable,
370
+ roles: roleTable,
371
+ merchantSubscription: merchantSubscriptionTable,
372
+ subscription: subscriptionTable,
345
373
  } = createTables(tableFn)
346
374
 
347
375
  const adapter: CourseBuilderAdapter = {
@@ -655,6 +683,23 @@ export function mySqlDrizzleAdapter(
655
683
 
656
684
  return parsedCoupon.data
657
685
  },
686
+ async createMerchantSession(options): Promise<MerchantSession> {
687
+ const id = `ms_${v4()}`
688
+ await client.insert(merchantSession).values({
689
+ id,
690
+ identifier: options.identifier,
691
+ merchantAccountId: options.merchantAccountId,
692
+ ...(options.organizationId
693
+ ? { organizationId: options.organizationId }
694
+ : {}),
695
+ })
696
+
697
+ return MerchantSessionSchema.parse(
698
+ await client.query.merchantSession.findFirst({
699
+ where: eq(merchantSession.id, id),
700
+ }),
701
+ )
702
+ },
658
703
  async createMerchantChargeAndPurchase(options): Promise<Purchase> {
659
704
  const purchaseId = await client.transaction(async (trx) => {
660
705
  try {
@@ -673,6 +718,7 @@ export function mySqlDrizzleAdapter(
673
718
  upgradedFromPurchaseId,
674
719
  country,
675
720
  usedCouponId,
721
+ organizationId,
676
722
  } = options
677
723
 
678
724
  const existingMerchantCharge = merchantChargeSchema.nullable().parse(
@@ -761,6 +807,7 @@ export function mySqlDrizzleAdapter(
761
807
  .update(coupon)
762
808
  .set({
763
809
  maxUses: (existingBulkCoupon?.maxUses || 0) + quantity,
810
+ ...(organizationId ? { organizationId } : {}),
764
811
  })
765
812
  .where(eq(coupon.id, bulkCouponId))
766
813
  } else {
@@ -778,6 +825,7 @@ export function mySqlDrizzleAdapter(
778
825
  restrictedToProductId: productId,
779
826
  maxUses: quantity,
780
827
  status: 1,
828
+ ...(organizationId ? { organizationId } : {}),
781
829
  ...(merchantCouponToUse
782
830
  ? {
783
831
  merchantCouponId: merchantCouponToUse.id,
@@ -787,15 +835,14 @@ export function mySqlDrizzleAdapter(
787
835
  }
788
836
  }
789
837
 
838
+ // create a new merchant session
790
839
  const merchantSessionId = `ms_${v4()}`
791
840
 
792
- const newMerchantSession = await client
793
- .insert(merchantSession)
794
- .values({
795
- id: merchantSessionId,
796
- identifier: checkoutSessionId,
797
- merchantAccountId,
798
- })
841
+ await client.insert(merchantSession).values({
842
+ id: merchantSessionId,
843
+ identifier: checkoutSessionId,
844
+ merchantAccountId,
845
+ })
799
846
 
800
847
  const merchantCouponUsed = stripeCouponId
801
848
  ? await client.query.merchantCoupon.findFirst({
@@ -817,7 +864,7 @@ export function mySqlDrizzleAdapter(
817
864
  ? 'Restricted'
818
865
  : 'Valid'
819
866
 
820
- const newPurchase = await client.insert(purchaseTable).values({
867
+ await client.insert(purchaseTable).values({
821
868
  id: purchaseId,
822
869
  status: newPurchaseStatus,
823
870
  userId,
@@ -829,20 +876,20 @@ export function mySqlDrizzleAdapter(
829
876
  country,
830
877
  upgradedFromId: upgradedFromPurchaseId || null,
831
878
  couponId: usedCouponId || null,
879
+ ...(organizationId ? { organizationId } : {}),
832
880
  })
833
881
 
834
882
  const oneWeekInMilliseconds = 1000 * 60 * 60 * 24 * 7
835
883
 
836
- const newPurchaseUserTransfer = await client
837
- .insert(purchaseUserTransfer)
838
- .values({
839
- id: `put_${v4()}`,
840
- purchaseId: purchaseId as string,
841
- expiresAt: existingPurchase
842
- ? new Date()
843
- : new Date(Date.now() + oneWeekInMilliseconds),
844
- sourceUserId: userId,
845
- })
884
+ await client.insert(purchaseUserTransfer).values({
885
+ id: `put_${v4()}`,
886
+ purchaseId: purchaseId as string,
887
+ expiresAt: existingPurchase
888
+ ? new Date()
889
+ : new Date(Date.now() + oneWeekInMilliseconds),
890
+ sourceUserId: userId,
891
+ ...(organizationId ? { organizationId } : {}),
892
+ })
846
893
 
847
894
  // const result = await Promise.all([
848
895
  // newMerchantCharge,
@@ -1098,7 +1145,7 @@ export function mySqlDrizzleAdapter(
1098
1145
 
1099
1146
  const ResultRowSchema = z.object({
1100
1147
  resource_id: z.string(),
1101
- resource_type: z.enum(['lesson', 'exercise']),
1148
+ resource_type: z.enum(['lesson', 'exercise', 'post']),
1102
1149
  resource_slug: z.string().nullable(),
1103
1150
  completed_at: z
1104
1151
  .string()
@@ -1138,10 +1185,9 @@ export function mySqlDrizzleAdapter(
1138
1185
  LEFT JOIN ${resourceProgress} rp ON rp.resourceId = cr.id
1139
1186
  AND rp.userId = ${user.id}
1140
1187
  WHERE
1141
- cr.type IN ('lesson', 'exercise')
1188
+ cr.type IN ('lesson', 'exercise', 'post')
1142
1189
 
1143
1190
  `)
1144
-
1145
1191
  // Process the results
1146
1192
  const completedLessons: ResourceProgress[] = []
1147
1193
  let nextResource: Partial<ContentResource> | null = null
@@ -1471,6 +1517,7 @@ export function mySqlDrizzleAdapter(
1471
1517
  ...fieldsNoImage,
1472
1518
  ...(image?.url && { image }),
1473
1519
  },
1520
+ type: input.type,
1474
1521
  })
1475
1522
  .where(eq(products.id, currentProduct.id))
1476
1523
 
@@ -2441,11 +2488,39 @@ export function mySqlDrizzleAdapter(
2441
2488
 
2442
2489
  await client.insert(users).values({ ...data, id })
2443
2490
 
2444
- return await client
2445
- .select()
2446
- .from(users)
2447
- .where(eq(users.id, id))
2448
- .then((res) => res[0] as AdapterUser)
2491
+ // creating a personal organization for the user
2492
+ // every user gets an organization of their very own
2493
+ const personalOrganization = await adapter.createOrganization({
2494
+ name: `Personal (${data.email})`,
2495
+ })
2496
+
2497
+ if (!personalOrganization) {
2498
+ throw new Error('Failed to create personal organization')
2499
+ }
2500
+
2501
+ const membership = await adapter.addMemberToOrganization({
2502
+ organizationId: personalOrganization.id,
2503
+ userId: id,
2504
+ invitedById: id,
2505
+ })
2506
+
2507
+ if (!membership) {
2508
+ throw new Error('Failed to add user to personal organization')
2509
+ }
2510
+
2511
+ await adapter.addRoleForMember({
2512
+ organizationId: personalOrganization.id,
2513
+ memberId: membership.id,
2514
+ role: 'owner',
2515
+ })
2516
+
2517
+ const user = await adapter.getUser?.(id)
2518
+
2519
+ if (!user) {
2520
+ throw new Error('Failed to get user')
2521
+ }
2522
+
2523
+ return user
2449
2524
  } catch (error) {
2450
2525
  console.error(error)
2451
2526
  throw error
@@ -2631,6 +2706,254 @@ export function mySqlDrizzleAdapter(
2631
2706
 
2632
2707
  return undefined
2633
2708
  },
2709
+ createOrganization: async (options: { name: string }) => {
2710
+ const organizationId = crypto.randomUUID()
2711
+ await client.insert(organizationTable).values({
2712
+ ...options,
2713
+ id: organizationId,
2714
+ })
2715
+
2716
+ return adapter.getOrganization(organizationId)
2717
+ },
2718
+ getOrganization: async (organizationId: string) => {
2719
+ return OrganizationSchema.parse(
2720
+ await client.query.organization.findFirst({
2721
+ where: eq(organizationTable.id, organizationId),
2722
+ }),
2723
+ )
2724
+ },
2725
+ addMemberToOrganization: async (options: {
2726
+ organizationId: string
2727
+ userId: string
2728
+ invitedById: string
2729
+ }) => {
2730
+ const currentMembership =
2731
+ await client.query.organizationMemberships.findFirst({
2732
+ where: and(
2733
+ eq(
2734
+ organizationMembershipTable.organizationId,
2735
+ options.organizationId,
2736
+ ),
2737
+ eq(organizationMembershipTable.userId, options.userId),
2738
+ ),
2739
+ })
2740
+
2741
+ if (currentMembership) {
2742
+ return OrganizationMemberSchema.parse(currentMembership)
2743
+ } else {
2744
+ const id = crypto.randomUUID()
2745
+ await client.insert(organizationMembershipTable).values({
2746
+ ...options,
2747
+ id,
2748
+ })
2749
+
2750
+ return OrganizationMemberSchema.parse(
2751
+ await client.query.organizationMemberships.findFirst({
2752
+ where: eq(organizationMembershipTable.id, id),
2753
+ with: {
2754
+ organization: true,
2755
+ user: true,
2756
+ },
2757
+ }),
2758
+ )
2759
+ }
2760
+ },
2761
+ removeMemberFromOrganization: async (options: {
2762
+ organizationId: string
2763
+ userId: string
2764
+ }) => {
2765
+ await client
2766
+ .delete(organizationMembershipTable)
2767
+ .where(
2768
+ and(
2769
+ eq(
2770
+ organizationMembershipTable.organizationId,
2771
+ options.organizationId,
2772
+ ),
2773
+ eq(organizationMembershipTable.userId, options.userId),
2774
+ ),
2775
+ )
2776
+ },
2777
+ addRoleForMember: async (options: {
2778
+ organizationId: string
2779
+ memberId: string
2780
+ role: string
2781
+ }) => {
2782
+ const existingRole = z
2783
+ .object({
2784
+ id: z.string(),
2785
+ })
2786
+ .nullish()
2787
+ .parse(
2788
+ await client.query.roles.findFirst({
2789
+ where: and(
2790
+ eq(roleTable.organizationId, options.organizationId),
2791
+ eq(roleTable.name, options.role),
2792
+ ),
2793
+ }),
2794
+ )
2795
+
2796
+ const roleId = existingRole?.id || crypto.randomUUID()
2797
+
2798
+ if (!existingRole) {
2799
+ await client.insert(roleTable).values({
2800
+ name: options.role,
2801
+ organizationId: options.organizationId,
2802
+ id: roleId,
2803
+ })
2804
+ }
2805
+
2806
+ const currentOrgMembershipRole =
2807
+ await client.query.organizationMembershipRoles.findFirst({
2808
+ where: and(
2809
+ eq(
2810
+ organizationMembershipRoleTable.organizationMembershipId,
2811
+ options.memberId,
2812
+ ),
2813
+ eq(organizationMembershipRoleTable.roleId, roleId),
2814
+ ),
2815
+ })
2816
+
2817
+ if (!currentOrgMembershipRole) {
2818
+ await client.insert(organizationMembershipRoleTable).values({
2819
+ organizationId: options.organizationId,
2820
+ organizationMembershipId: options.memberId,
2821
+ roleId,
2822
+ })
2823
+ }
2824
+ },
2825
+ removeRoleForMember: async (options: {
2826
+ organizationId: string
2827
+ memberId: string
2828
+ role: string
2829
+ }) => {
2830
+ const existingRole = z
2831
+ .object({
2832
+ id: z.string(),
2833
+ })
2834
+ .nullable()
2835
+ .parse(
2836
+ await client.query.roles.findFirst({
2837
+ where: and(
2838
+ eq(roleTable.organizationId, options.organizationId),
2839
+ eq(roleTable.name, options.role),
2840
+ ),
2841
+ }),
2842
+ )
2843
+
2844
+ const roleId = existingRole?.id
2845
+
2846
+ if (roleId) {
2847
+ await client
2848
+ .delete(organizationMembershipRoleTable)
2849
+ .where(eq(organizationMembershipRoleTable.roleId, roleId))
2850
+ }
2851
+ },
2852
+ getMembershipsForUser: async (userId: string) => {
2853
+ return OrganizationMemberSchema.array().parse(
2854
+ (await client.query.organizationMemberships.findMany({
2855
+ where: eq(organizationMembershipTable.userId, userId),
2856
+ with: {
2857
+ organization: true,
2858
+ user: true,
2859
+ },
2860
+ })) || [],
2861
+ )
2862
+ },
2863
+ getOrganizationMembers: async (organizationId: string) => {
2864
+ return OrganizationMemberSchema.array().parse(
2865
+ (await client.query.organizationMemberships.findMany({
2866
+ where: eq(organizationMembershipTable.organizationId, organizationId),
2867
+ })) || [],
2868
+ )
2869
+ },
2870
+ createSubscription: async (options: {
2871
+ organizationId: string
2872
+ merchantSubscriptionId: string
2873
+ productId: string
2874
+ }) => {
2875
+ const id = `sub_${crypto.randomUUID()}`
2876
+ await client.insert(subscriptionTable).values({
2877
+ ...options,
2878
+ id,
2879
+ })
2880
+
2881
+ return SubscriptionSchema.parse(
2882
+ await client.query.subscription.findFirst({
2883
+ where: eq(subscriptionTable.id, id),
2884
+ with: {
2885
+ product: true,
2886
+ },
2887
+ }),
2888
+ )
2889
+ },
2890
+ getMerchantSubscription: async (merchantSubscriptionId: string) => {
2891
+ return MerchantSubscriptionSchema.parse(
2892
+ await client.query.merchantSubscription.findFirst({
2893
+ where: eq(merchantSubscriptionTable.id, merchantSubscriptionId),
2894
+ }),
2895
+ )
2896
+ },
2897
+ createMerchantSubscription: async (options: {
2898
+ merchantAccountId: string
2899
+ merchantCustomerId: string
2900
+ merchantProductId: string
2901
+ identifier: string
2902
+ }) => {
2903
+ const id = crypto.randomUUID()
2904
+ await client.insert(merchantSubscriptionTable).values({
2905
+ ...options,
2906
+ id,
2907
+ })
2908
+
2909
+ return MerchantSubscriptionSchema.parse(
2910
+ await client.query.merchantSubscription.findFirst({
2911
+ where: eq(merchantSubscriptionTable.id, id),
2912
+ }),
2913
+ )
2914
+ },
2915
+ updateMerchantSubscription: async (options: {
2916
+ merchantSubscriptionId: string
2917
+ status: string
2918
+ }) => {
2919
+ throw new Error('Not implemented')
2920
+ },
2921
+ deleteMerchantSubscription: async (merchantSubscriptionId: string) => {
2922
+ throw new Error('Not implemented')
2923
+ },
2924
+ getSubscriptionForStripeId: async (stripeSubscriptionId: string) => {
2925
+ const merchantSubscriptionParsed = MerchantSubscriptionSchema.safeParse(
2926
+ await client.query.merchantSubscription.findFirst({
2927
+ where: eq(merchantSubscriptionTable.identifier, stripeSubscriptionId),
2928
+ }),
2929
+ )
2930
+
2931
+ if (!merchantSubscriptionParsed.success) {
2932
+ throw new Error(
2933
+ `No merchant subscription found for stripe id ${stripeSubscriptionId} ${merchantSubscriptionParsed.error}`,
2934
+ )
2935
+ }
2936
+
2937
+ const subscriptionParsed = SubscriptionSchema.safeParse(
2938
+ await client.query.subscription.findFirst({
2939
+ where: eq(
2940
+ subscriptionTable.merchantSubscriptionId,
2941
+ merchantSubscriptionParsed.data.id,
2942
+ ),
2943
+ with: {
2944
+ product: true,
2945
+ },
2946
+ }),
2947
+ )
2948
+
2949
+ if (!subscriptionParsed.success) {
2950
+ throw new Error(
2951
+ `No subscription found for merchant subscription ${merchantSubscriptionParsed.data.id} ${subscriptionParsed.error}`,
2952
+ )
2953
+ }
2954
+
2955
+ return subscriptionParsed.data
2956
+ },
2634
2957
  }
2635
2958
 
2636
2959
  return adapter
@@ -0,0 +1,50 @@
1
+ import { relations, sql } from 'drizzle-orm'
2
+ import {
3
+ index,
4
+ json,
5
+ MySqlTableFn,
6
+ timestamp,
7
+ uniqueIndex,
8
+ varchar,
9
+ } from 'drizzle-orm/mysql-core'
10
+
11
+ import { getUsersSchema } from './users.js'
12
+
13
+ export function getProfilesSchema(mysqlTable: MySqlTableFn) {
14
+ return mysqlTable(
15
+ 'Profile',
16
+ {
17
+ id: varchar('id', { length: 255 }).notNull().primaryKey(),
18
+ userId: varchar('userId', { length: 255 }).notNull(),
19
+ type: varchar('type', { length: 255 }).notNull(),
20
+ fields: json('fields').$type<Record<string, any>>().default({}),
21
+ createdAt: timestamp('createdAt', {
22
+ mode: 'date',
23
+ fsp: 3,
24
+ }).default(sql`CURRENT_TIMESTAMP(3)`),
25
+ updatedAt: timestamp('updatedAt', {
26
+ mode: 'date',
27
+ fsp: 3,
28
+ }).default(sql`CURRENT_TIMESTAMP(3)`),
29
+ },
30
+ (profile) => ({
31
+ userIdIdx: index('userId_idx').on(profile.userId),
32
+ uniqueUserType: uniqueIndex('unique_user_type_idx').on(
33
+ profile.userId,
34
+ profile.type,
35
+ ),
36
+ }),
37
+ )
38
+ }
39
+
40
+ export function getProfilesRelationsSchema(mysqlTable: MySqlTableFn) {
41
+ const profiles = getProfilesSchema(mysqlTable)
42
+ const users = getUsersSchema(mysqlTable)
43
+ return relations(profiles, ({ one }) => ({
44
+ user: one(users, {
45
+ fields: [profiles.userId],
46
+ references: [users.id],
47
+ relationName: 'profiles',
48
+ }),
49
+ }))
50
+ }
@@ -5,6 +5,7 @@ import {
5
5
  MySqlTableFn,
6
6
  text,
7
7
  timestamp,
8
+ uniqueIndex,
8
9
  varchar,
9
10
  } from 'drizzle-orm/mysql-core'
10
11
 
@@ -16,7 +17,7 @@ export function getRolesSchema(mysqlTable: MySqlTableFn) {
16
17
  {
17
18
  id: varchar('id', { length: 255 }).notNull().primaryKey(),
18
19
  organizationId: varchar('organizationId', { length: 191 }),
19
- name: varchar('name', { length: 255 }).notNull().unique(),
20
+ name: varchar('name', { length: 255 }).notNull(),
20
21
  description: text('description'),
21
22
  active: boolean('active').notNull().default(true),
22
23
  createdAt: timestamp('createdAt', {
@@ -35,6 +36,10 @@ export function getRolesSchema(mysqlTable: MySqlTableFn) {
35
36
  (role) => ({
36
37
  nameIdx: index('name_idx').on(role.name),
37
38
  organizationIdIdx: index('organizationId_idx').on(role.organizationId),
39
+ uniqueNamePerOrg: uniqueIndex('unique_name_per_org').on(
40
+ role.organizationId,
41
+ role.name,
42
+ ),
38
43
  }),
39
44
  )
40
45
  }
@@ -15,6 +15,7 @@ import { getContentContributionsSchema } from '../content/content-contributions.
15
15
  import { getContentResourceSchema } from '../content/content-resource.js'
16
16
  import { getOrganizationMembershipsSchema } from '../org/organization-memberships.js'
17
17
  import { getAccountsSchema } from './accounts.js'
18
+ import { getProfilesSchema } from './profiles.js'
18
19
  import { getUserPermissionsSchema } from './user-permissions.js'
19
20
  import { getUserPrefsSchema } from './user-prefs.js'
20
21
  import { getUserRolesSchema } from './user-roles.js'
@@ -48,6 +49,7 @@ export function getUsersSchema(mysqlTable: MySqlTableFn) {
48
49
 
49
50
  export function getUsersRelationsSchema(mysqlTable: MySqlTableFn) {
50
51
  const users = getUsersSchema(mysqlTable)
52
+ const profiles = getProfilesSchema(mysqlTable)
51
53
  const accounts = getAccountsSchema(mysqlTable)
52
54
  const communicationPreferences = getCommunicationPreferencesSchema(mysqlTable)
53
55
  const userRoles = getUserRolesSchema(mysqlTable)
@@ -58,7 +60,10 @@ export function getUsersRelationsSchema(mysqlTable: MySqlTableFn) {
58
60
  const comments = getCommentsSchema(mysqlTable)
59
61
  const userPrefs = getUserPrefsSchema(mysqlTable)
60
62
  const organizationMemberships = getOrganizationMembershipsSchema(mysqlTable)
61
- return relations(users, ({ many }) => ({
63
+ return relations(users, ({ many, one }) => ({
64
+ profiles: many(profiles, {
65
+ relationName: 'profiles',
66
+ }),
62
67
  accounts: many(accounts, {
63
68
  relationName: 'user',
64
69
  }),
@@ -8,14 +8,12 @@ import {
8
8
  varchar,
9
9
  } from 'drizzle-orm/mysql-core'
10
10
 
11
- import { getUsersSchema } from '../auth/users.js'
12
11
  import { getOrganizationsSchema } from '../org/organizations.js'
13
- import { getCouponSchema } from './coupon.js'
14
- import { getMerchantChargeSchema } from './merchant-charge.js'
15
- import { getMerchantSessionSchema } from './merchant-session.js'
16
12
  import { getMerchantSubscriptionSchema } from './merchant-subscription.js'
17
13
  import { getProductSchema } from './product.js'
18
14
 
15
+ // TODO: do we add a renewal date here? probably just add that stuff to fields
16
+ // even status feels out of place at the top level maybe
19
17
  export function getSubscriptionSchema(mysqlTable: MySqlTableFn) {
20
18
  return mysqlTable(
21
19
  'Subscription',
@@ -29,7 +27,7 @@ export function getSubscriptionSchema(mysqlTable: MySqlTableFn) {
29
27
  merchantSubscriptionId: varchar('merchantSubscriptionId', {
30
28
  length: 191,
31
29
  }).notNull(),
32
- status: varchar('status', { length: 191 }).default('Valid').notNull(),
30
+ status: varchar('status', { length: 191 }).default('active').notNull(),
33
31
  fields: json('fields').$type<Record<string, any>>().default({}),
34
32
  },
35
33
  (table) => {
@@ -0,0 +1,21 @@
1
+ import {
2
+ MySqlTableFn,
3
+ text,
4
+ uniqueIndex,
5
+ varchar,
6
+ } from 'drizzle-orm/mysql-core'
7
+
8
+ export function getEntitlementTypesSchema(mysqlTable: MySqlTableFn) {
9
+ return mysqlTable(
10
+ 'EntitlementType',
11
+ {
12
+ id: varchar('id', { length: 191 }).notNull().primaryKey(),
13
+ name: varchar('name', { length: 255 }).notNull(),
14
+ description: text('description'),
15
+ // Add any type-specific config fields here
16
+ },
17
+ (table) => ({
18
+ uniqueName: uniqueIndex('unique_name_idx').on(table.name),
19
+ }),
20
+ )
21
+ }