alepha 0.19.3 → 0.19.4

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 (215) hide show
  1. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  2. package/dist/api/audits/index.d.ts +8 -8
  3. package/dist/api/invitations/index.d.ts +790 -0
  4. package/dist/api/invitations/index.d.ts.map +1 -0
  5. package/dist/api/invitations/index.js +665 -0
  6. package/dist/api/invitations/index.js.map +1 -0
  7. package/dist/api/jobs/index.browser.js +8 -9
  8. package/dist/api/jobs/index.browser.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts +99 -43
  10. package/dist/api/jobs/index.d.ts.map +1 -1
  11. package/dist/api/jobs/index.js +257 -40
  12. package/dist/api/jobs/index.js.map +1 -1
  13. package/dist/api/keys/index.d.ts +5 -5
  14. package/dist/api/notifications/index.browser.js +0 -1
  15. package/dist/api/notifications/index.browser.js.map +1 -1
  16. package/dist/api/notifications/index.d.ts +3 -3
  17. package/dist/api/notifications/index.d.ts.map +1 -1
  18. package/dist/api/notifications/index.js +0 -1
  19. package/dist/api/notifications/index.js.map +1 -1
  20. package/dist/api/parameters/index.browser.js +112 -1
  21. package/dist/api/parameters/index.browser.js.map +1 -1
  22. package/dist/api/parameters/index.d.ts +90 -3
  23. package/dist/api/parameters/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.js +79 -12
  25. package/dist/api/parameters/index.js.map +1 -1
  26. package/dist/{billing → api/payments}/index.d.ts +67 -49
  27. package/dist/api/payments/index.d.ts.map +1 -0
  28. package/dist/{billing → api/payments}/index.js +108 -74
  29. package/dist/api/payments/index.js.map +1 -0
  30. package/dist/api/subscriptions/index.d.ts +1692 -0
  31. package/dist/api/subscriptions/index.d.ts.map +1 -0
  32. package/dist/api/subscriptions/index.js +1870 -0
  33. package/dist/api/subscriptions/index.js.map +1 -0
  34. package/dist/api/users/index.d.ts +18 -2
  35. package/dist/api/users/index.d.ts.map +1 -1
  36. package/dist/api/users/index.js +167 -34
  37. package/dist/api/users/index.js.map +1 -1
  38. package/dist/api/verifications/index.d.ts +13 -13
  39. package/dist/api/workflows/index.browser.js +246 -0
  40. package/dist/api/workflows/index.browser.js.map +1 -0
  41. package/dist/api/workflows/index.d.ts +1618 -0
  42. package/dist/api/workflows/index.d.ts.map +1 -0
  43. package/dist/api/workflows/index.js +1504 -0
  44. package/dist/api/workflows/index.js.map +1 -0
  45. package/dist/cli/core/index.d.ts +44 -28
  46. package/dist/cli/core/index.d.ts.map +1 -1
  47. package/dist/cli/core/index.js +16 -61
  48. package/dist/cli/core/index.js.map +1 -1
  49. package/dist/cli/vendor/index.d.ts +31 -8
  50. package/dist/cli/vendor/index.d.ts.map +1 -1
  51. package/dist/cli/vendor/index.js +79 -24
  52. package/dist/cli/vendor/index.js.map +1 -1
  53. package/dist/core/index.browser.js +21 -2
  54. package/dist/core/index.browser.js.map +1 -1
  55. package/dist/core/index.d.ts +33 -2
  56. package/dist/core/index.d.ts.map +1 -1
  57. package/dist/core/index.js +21 -2
  58. package/dist/core/index.js.map +1 -1
  59. package/dist/core/index.native.js +21 -2
  60. package/dist/core/index.native.js.map +1 -1
  61. package/dist/core/index.workerd.js +21 -2
  62. package/dist/core/index.workerd.js.map +1 -1
  63. package/dist/email/smtp/index.js +24 -8
  64. package/dist/email/smtp/index.js.map +1 -1
  65. package/dist/orm/core/index.browser.js +0 -18
  66. package/dist/orm/core/index.browser.js.map +1 -1
  67. package/dist/orm/core/index.bun.js +0 -17
  68. package/dist/orm/core/index.bun.js.map +1 -1
  69. package/dist/orm/core/index.d.ts +1 -13
  70. package/dist/orm/core/index.d.ts.map +1 -1
  71. package/dist/orm/core/index.js +0 -17
  72. package/dist/orm/core/index.js.map +1 -1
  73. package/dist/orm/postgres/index.bun.js +3 -3
  74. package/dist/orm/postgres/index.bun.js.map +1 -1
  75. package/dist/orm/postgres/index.d.ts.map +1 -1
  76. package/dist/orm/postgres/index.js +3 -3
  77. package/dist/orm/postgres/index.js.map +1 -1
  78. package/dist/react/router/index.browser.js +25 -3
  79. package/dist/react/router/index.browser.js.map +1 -1
  80. package/dist/react/router/index.d.ts +16 -1
  81. package/dist/react/router/index.d.ts.map +1 -1
  82. package/dist/react/router/index.js +25 -3
  83. package/dist/react/router/index.js.map +1 -1
  84. package/dist/security/index.d.ts +28 -0
  85. package/dist/security/index.d.ts.map +1 -1
  86. package/dist/security/index.js +28 -0
  87. package/dist/security/index.js.map +1 -1
  88. package/package.json +37 -20
  89. package/src/api/invitations/__tests__/InvitationService.spec.ts +439 -0
  90. package/src/api/invitations/controllers/AdminInvitationController.ts +86 -0
  91. package/src/api/invitations/controllers/InvitationController.ts +84 -0
  92. package/src/api/invitations/entities/invitations.ts +33 -0
  93. package/src/api/invitations/index.ts +65 -0
  94. package/src/api/invitations/jobs/InvitationJobs.ts +37 -0
  95. package/src/api/invitations/providers/InvitationProvider.ts +45 -0
  96. package/src/api/invitations/schemas/createInvitationSchema.ts +12 -0
  97. package/src/api/invitations/schemas/invitationConfigAtom.ts +20 -0
  98. package/src/api/invitations/schemas/invitationQuerySchema.ts +15 -0
  99. package/src/api/invitations/schemas/invitationResourceSchema.ts +6 -0
  100. package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +22 -0
  101. package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +10 -0
  102. package/src/api/invitations/services/InvitationService.ts +556 -0
  103. package/src/api/jobs/__tests__/$job.spec.ts +876 -0
  104. package/src/api/jobs/controllers/AdminJobController.ts +44 -0
  105. package/src/api/jobs/entities/jobExecutionEntity.ts +0 -2
  106. package/src/api/jobs/index.ts +0 -3
  107. package/src/api/jobs/primitives/$job.ts +22 -11
  108. package/src/api/jobs/providers/JobProvider.ts +229 -19
  109. package/src/api/jobs/schemas/jobConfigAtom.ts +4 -0
  110. package/src/api/jobs/schemas/jobCronInfoSchema.ts +1 -0
  111. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +0 -1
  112. package/src/api/jobs/schemas/jobQueueDepthSchema.ts +1 -0
  113. package/src/api/jobs/schemas/jobRegistrationSchema.ts +1 -6
  114. package/src/api/jobs/services/JobService.ts +51 -12
  115. package/src/api/notifications/schemas/notificationQuerySchema.ts +0 -1
  116. package/src/api/parameters/__tests__/$parameter.spec.ts +327 -0
  117. package/src/api/parameters/controllers/AdminParameterController.ts +29 -3
  118. package/src/api/parameters/index.browser.ts +12 -0
  119. package/src/api/parameters/primitives/$parameter.ts +20 -3
  120. package/src/api/parameters/services/ParameterProvider.ts +48 -7
  121. package/src/{billing → api/payments}/__tests__/PaymentMethodService.spec.ts +32 -6
  122. package/src/api/payments/__tests__/PaymentService.spec.ts +279 -0
  123. package/src/{billing/controllers/AdminBillingController.ts → api/payments/controllers/AdminPaymentController.ts} +26 -21
  124. package/src/{billing/controllers/BillingController.ts → api/payments/controllers/PaymentController.ts} +23 -11
  125. package/src/{billing → api/payments}/entities/paymentIntents.ts +1 -0
  126. package/src/{billing/errors/BillingError.ts → api/payments/errors/PaymentError.ts} +1 -1
  127. package/src/{billing → api/payments}/index.ts +31 -25
  128. package/src/{billing/providers/MemoryBillingProvider.ts → api/payments/providers/MemoryPaymentProvider.ts} +4 -4
  129. package/src/{billing/providers/BillingProvider.ts → api/payments/providers/PaymentProvider.ts} +9 -2
  130. package/src/{billing → api/payments}/services/PaymentMethodService.ts +5 -5
  131. package/src/{billing/services/BillingService.ts → api/payments/services/PaymentService.ts} +94 -18
  132. package/src/api/subscriptions/__tests__/BillingService.spec.ts +218 -0
  133. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +278 -0
  134. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +212 -0
  135. package/src/api/subscriptions/controllers/SubscriptionController.ts +189 -0
  136. package/src/api/subscriptions/entities/subscriptionEvents.ts +54 -0
  137. package/src/api/subscriptions/entities/subscriptions.ts +68 -0
  138. package/src/api/subscriptions/index.ts +144 -0
  139. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +382 -0
  140. package/src/api/subscriptions/middleware/$requireLimit.ts +50 -0
  141. package/src/api/subscriptions/middleware/$requirePlan.ts +49 -0
  142. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +110 -0
  143. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +8 -0
  144. package/src/api/subscriptions/schemas/changePlanSchema.ts +9 -0
  145. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +11 -0
  146. package/src/api/subscriptions/schemas/entitlementsSchema.ts +21 -0
  147. package/src/api/subscriptions/schemas/mrrSchema.ts +13 -0
  148. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +71 -0
  149. package/src/api/subscriptions/schemas/planResourceSchema.ts +25 -0
  150. package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +8 -0
  151. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +19 -0
  152. package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +6 -0
  153. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +32 -0
  154. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +23 -0
  155. package/src/api/subscriptions/services/BillingService.ts +437 -0
  156. package/src/api/subscriptions/services/SubscriptionConfig.ts +56 -0
  157. package/src/api/subscriptions/services/SubscriptionService.ts +867 -0
  158. package/src/api/subscriptions/services/UsageService.ts +118 -0
  159. package/src/api/users/__tests__/AdminUserController.spec.ts +80 -1
  160. package/src/api/users/__tests__/CredentialService.spec.ts +177 -0
  161. package/src/api/users/__tests__/EmailVerification.spec.ts +29 -18
  162. package/src/api/users/__tests__/PasswordReset.spec.ts +3 -0
  163. package/src/api/users/__tests__/RegistrationService.spec.ts +148 -1
  164. package/src/api/users/__tests__/SessionService.spec.ts +142 -1
  165. package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -1
  166. package/src/api/users/controllers/UserController.ts +3 -8
  167. package/src/api/users/notifications/UserNotifications.ts +23 -0
  168. package/src/api/users/schemas/loginSchema.ts +1 -1
  169. package/src/api/users/services/CredentialService.ts +51 -4
  170. package/src/api/users/services/RegistrationService.ts +38 -9
  171. package/src/api/users/services/SessionService.ts +62 -9
  172. package/src/api/users/services/UserService.ts +21 -12
  173. package/src/api/workflows/__tests__/$workflow.spec.ts +616 -0
  174. package/src/api/workflows/controllers/AdminWorkflowController.ts +191 -0
  175. package/src/api/workflows/entities/workflowExecutions.ts +74 -0
  176. package/src/api/workflows/entities/workflowStepExecutions.ts +74 -0
  177. package/src/api/workflows/entities/workflowStepLogs.ts +13 -0
  178. package/src/api/workflows/index.browser.ts +22 -0
  179. package/src/api/workflows/index.ts +124 -0
  180. package/src/api/workflows/jobs/WorkflowJobs.ts +77 -0
  181. package/src/api/workflows/primitives/$workflow.ts +202 -0
  182. package/src/api/workflows/providers/WorkflowProvider.ts +1284 -0
  183. package/src/api/workflows/schemas/workflowActivitySchema.ts +15 -0
  184. package/src/api/workflows/schemas/workflowConfigAtom.ts +51 -0
  185. package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +18 -0
  186. package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +26 -0
  187. package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +30 -0
  188. package/src/api/workflows/schemas/workflowRegistrationSchema.ts +26 -0
  189. package/src/api/workflows/schemas/workflowStatsSchema.ts +16 -0
  190. package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +15 -0
  191. package/src/api/workflows/services/WorkflowService.ts +382 -0
  192. package/src/cli/core/templates/webAppRouterTs.ts +5 -58
  193. package/src/cli/vendor/__tests__/VendorService.spec.ts +283 -178
  194. package/src/cli/vendor/services/VendorService.ts +126 -27
  195. package/src/core/__tests__/TypeProvider.spec.ts +4 -2
  196. package/src/core/providers/SchemaValidator.ts +1 -1
  197. package/src/core/providers/TypeProvider.ts +46 -3
  198. package/src/orm/__tests__/enums.spec.ts +22 -29
  199. package/src/orm/__tests__/orm-showcase-tests.ts +430 -0
  200. package/src/orm/__tests__/orm-showcase.spec.ts +167 -0
  201. package/src/orm/core/providers/DatabaseTypeProvider.ts +0 -29
  202. package/src/orm/postgres/services/PostgresModelBuilder.ts +3 -6
  203. package/src/react/router/__tests__/$page.browser.spec.tsx +157 -0
  204. package/src/react/router/providers/ReactBrowserProvider.ts +39 -0
  205. package/src/react/router/providers/ReactBrowserRouterProvider.ts +22 -0
  206. package/src/security/__tests__/$secure-combinations.spec.ts +945 -0
  207. package/src/security/primitives/$secure.ts +28 -0
  208. package/dist/billing/index.d.ts.map +0 -1
  209. package/dist/billing/index.js.map +0 -1
  210. package/src/billing/__tests__/BillingService.spec.ts +0 -136
  211. /package/src/{billing → api/payments}/entities/paymentMethods.ts +0 -0
  212. /package/src/{billing → api/payments}/entities/refunds.ts +0 -0
  213. /package/src/{billing → api/payments}/schemas/intentSchemas.ts +0 -0
  214. /package/src/{billing → api/payments}/schemas/paymentMethodSchemas.ts +0 -0
  215. /package/src/{billing → api/payments}/schemas/refundSchemas.ts +0 -0
@@ -0,0 +1,49 @@
1
+ import { $context, createMiddleware, type Middleware } from "alepha";
2
+ import { ForbiddenError } from "alepha/server";
3
+ import { SubscriptionService } from "../services/SubscriptionService.ts";
4
+
5
+ /**
6
+ * Middleware that gates access to a handler behind a subscription feature flag.
7
+ *
8
+ * Resolves the organization from `args[0].user.organization` and checks whether
9
+ * the organization's current plan includes the given feature.
10
+ * Throws `ForbiddenError` if no organization is present or the feature is not available.
11
+ *
12
+ * ```typescript
13
+ * class ReportController {
14
+ * generate = $action({
15
+ * use: [$requirePlan("advanced_reports")],
16
+ * handler: async ({ user }) => { ... },
17
+ * });
18
+ * }
19
+ * ```
20
+ *
21
+ * @param feature The feature identifier to check against the plan's feature list.
22
+ */
23
+ export const $requirePlan = (feature: string): Middleware => {
24
+ const { alepha } = $context();
25
+ const subscriptionService = alepha.inject(SubscriptionService);
26
+
27
+ return createMiddleware({
28
+ name: "$requirePlan",
29
+ options: { feature } as Record<string, unknown>,
30
+ handler: ({ next }) => {
31
+ return async (...args: any[]) => {
32
+ const user = args[0]?.user;
33
+ if (!user?.organization) {
34
+ throw new ForbiddenError("Organization required");
35
+ }
36
+ const allowed = await subscriptionService.can(
37
+ user.organization,
38
+ feature,
39
+ );
40
+ if (!allowed) {
41
+ throw new ForbiddenError(
42
+ `Feature '${feature}' not available on your plan`,
43
+ );
44
+ }
45
+ return next(...args);
46
+ };
47
+ },
48
+ });
49
+ };
@@ -0,0 +1,110 @@
1
+ import { t } from "alepha";
2
+ import { $notification } from "alepha/api/notifications";
3
+
4
+ export class SubscriptionNotifications {
5
+ /**
6
+ * Sent when a trial is ending soon.
7
+ */
8
+ protected readonly trialEnding = $notification({
9
+ name: "subscription-trial-ending",
10
+ category: "subscriptions",
11
+ schema: t.object({
12
+ planName: t.text(),
13
+ trialEndDate: t.text(),
14
+ amount: t.text(),
15
+ interval: t.text(),
16
+ }),
17
+ email: {
18
+ subject: "Your trial is ending soon",
19
+ body: (v) =>
20
+ `Your ${v.planName} trial is ending on ${v.trialEndDate}. You'll be charged ${v.amount}/${v.interval}.`,
21
+ },
22
+ });
23
+
24
+ /**
25
+ * Sent when a payment fails. Critical notification.
26
+ */
27
+ protected readonly paymentFailed = $notification({
28
+ name: "subscription-payment-failed",
29
+ category: "subscriptions",
30
+ critical: true,
31
+ schema: t.object({
32
+ planName: t.text(),
33
+ amount: t.text(),
34
+ retryDate: t.optional(t.text()),
35
+ }),
36
+ email: {
37
+ subject: "Payment failed for your subscription",
38
+ body: (v) =>
39
+ `We couldn't charge your card for ${v.planName} (${v.amount}). ${v.retryDate ? `We'll retry on ${v.retryDate}.` : "Please update your payment method."}`,
40
+ },
41
+ });
42
+
43
+ /**
44
+ * Sent when a subscription is suspended due to failed payments. Critical notification.
45
+ */
46
+ protected readonly subscriptionSuspended = $notification({
47
+ name: "subscription-suspended",
48
+ category: "subscriptions",
49
+ critical: true,
50
+ schema: t.object({ planName: t.text() }),
51
+ email: {
52
+ subject: "Your subscription has been suspended",
53
+ body: (v) =>
54
+ `Your ${v.planName} subscription has been suspended due to failed payments. Update your payment method to reactivate.`,
55
+ },
56
+ });
57
+
58
+ /**
59
+ * Sent when a subscription is successfully renewed.
60
+ */
61
+ protected readonly subscriptionRenewed = $notification({
62
+ name: "subscription-renewed",
63
+ category: "subscriptions",
64
+ schema: t.object({
65
+ planName: t.text(),
66
+ amount: t.text(),
67
+ nextBillingDate: t.text(),
68
+ }),
69
+ email: {
70
+ subject: "Payment received — subscription renewed",
71
+ body: (v) =>
72
+ `Your ${v.planName} subscription has been renewed. Amount: ${v.amount}. Next billing: ${v.nextBillingDate}.`,
73
+ },
74
+ });
75
+
76
+ /**
77
+ * Sent when a subscription plan is changed.
78
+ */
79
+ protected readonly planChanged = $notification({
80
+ name: "subscription-plan-changed",
81
+ category: "subscriptions",
82
+ schema: t.object({
83
+ oldPlanName: t.text(),
84
+ newPlanName: t.text(),
85
+ effectiveDate: t.text(),
86
+ }),
87
+ email: {
88
+ subject: "Your subscription plan has been changed",
89
+ body: (v) =>
90
+ `Your plan has been changed from ${v.oldPlanName} to ${v.newPlanName}, effective ${v.effectiveDate}.`,
91
+ },
92
+ });
93
+
94
+ /**
95
+ * Sent when a subscription is cancelled.
96
+ */
97
+ protected readonly cancellationConfirmed = $notification({
98
+ name: "subscription-cancelled",
99
+ category: "subscriptions",
100
+ schema: t.object({
101
+ planName: t.text(),
102
+ accessUntil: t.optional(t.text()),
103
+ }),
104
+ email: {
105
+ subject: "Your subscription has been cancelled",
106
+ body: (v) =>
107
+ `Your ${v.planName} subscription has been cancelled.${v.accessUntil ? ` You'll have access until ${v.accessUntil}.` : ""}`,
108
+ },
109
+ });
110
+ }
@@ -0,0 +1,8 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const cancelSubscriptionSchema = t.object({
4
+ reason: t.optional(t.string()),
5
+ immediate: t.optional(t.boolean()),
6
+ });
7
+
8
+ export type CancelSubscription = Static<typeof cancelSubscriptionSchema>;
@@ -0,0 +1,9 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const changePlanSchema = t.object({
4
+ planId: t.string(),
5
+ interval: t.optional(t.enum(["monthly", "yearly"])),
6
+ immediate: t.optional(t.boolean()),
7
+ });
8
+
9
+ export type ChangePlan = Static<typeof changePlanSchema>;
@@ -0,0 +1,11 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const createSubscriptionSchema = t.object({
4
+ planId: t.string(),
5
+ interval: t.enum(["monthly", "yearly"]),
6
+ paymentMethodId: t.optional(t.uuid()),
7
+ skipTrial: t.optional(t.boolean()),
8
+ metadata: t.optional(t.record(t.text(), t.any())),
9
+ });
10
+
11
+ export type CreateSubscription = Static<typeof createSubscriptionSchema>;
@@ -0,0 +1,21 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const entitlementsSchema = t.object({
4
+ planId: t.string(),
5
+ planName: t.string(),
6
+ status: t.enum([
7
+ "trialing",
8
+ "active",
9
+ "past_due",
10
+ "suspended",
11
+ "cancelled",
12
+ "expired",
13
+ ]),
14
+ features: t.array(t.string()),
15
+ limits: t.record(t.text(), t.integer()),
16
+ trialEndsAt: t.optional(t.datetime()),
17
+ periodEndsAt: t.datetime(),
18
+ cancelledAt: t.optional(t.datetime()),
19
+ });
20
+
21
+ export type Entitlements = Static<typeof entitlementsSchema>;
@@ -0,0 +1,13 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const mrrSchema = t.object({
4
+ total: t.integer(),
5
+ byPlan: t.record(t.text(), t.integer()),
6
+ growth: t.integer(),
7
+ newMrr: t.integer(),
8
+ expansionMrr: t.integer(),
9
+ contractionMrr: t.integer(),
10
+ churnMrr: t.integer(),
11
+ });
12
+
13
+ export type MrrData = Static<typeof mrrSchema>;
@@ -0,0 +1,71 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const planDefinitionSchema = t.object({
4
+ /**
5
+ * Unique plan identifier (e.g., "free", "starter", "pro", "enterprise").
6
+ */
7
+ id: t.string({ minLength: 1, maxLength: 50 }),
8
+
9
+ /**
10
+ * Display name (e.g., "Pro Plan").
11
+ */
12
+ name: t.string(),
13
+
14
+ /**
15
+ * Optional description.
16
+ */
17
+ description: t.optional(t.string()),
18
+
19
+ /**
20
+ * Whether this plan is available for new subscriptions.
21
+ */
22
+ available: t.boolean({ default: true }),
23
+
24
+ /**
25
+ * Pricing per billing interval.
26
+ * Multiple entries for monthly/yearly.
27
+ */
28
+ pricing: t.array(
29
+ t.object({
30
+ interval: t.enum(["monthly", "yearly"]),
31
+ amount: t.integer({ minimum: 0 }),
32
+ currency: t.string({ minLength: 3, maxLength: 3 }),
33
+ }),
34
+ ),
35
+
36
+ /**
37
+ * Trial configuration for this plan.
38
+ * Overrides global settings.trialDays if set.
39
+ */
40
+ trial: t.optional(
41
+ t.object({
42
+ days: t.integer({ minimum: 0, maximum: 365 }),
43
+ requirePaymentMethod: t.boolean({ default: false }),
44
+ }),
45
+ ),
46
+
47
+ /**
48
+ * Feature entitlements. Boolean flags for feature access.
49
+ * Checked via SubscriptionService.can("feature-name").
50
+ */
51
+ features: t.array(t.string()),
52
+
53
+ /**
54
+ * Usage limits. Numeric caps on resources.
55
+ * Checked via SubscriptionService.limit("resource-name").
56
+ * -1 = unlimited.
57
+ */
58
+ limits: t.record(t.text(), t.integer()),
59
+
60
+ /**
61
+ * Sort order for display (lower = first).
62
+ */
63
+ order: t.integer({ default: 0 }),
64
+
65
+ /**
66
+ * Metadata for app-specific plan data.
67
+ */
68
+ metadata: t.optional(t.record(t.text(), t.any())),
69
+ });
70
+
71
+ export type PlanDefinition = Static<typeof planDefinitionSchema>;
@@ -0,0 +1,25 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const planResourceSchema = t.object({
4
+ id: t.string(),
5
+ name: t.string(),
6
+ description: t.optional(t.string()),
7
+ pricing: t.array(
8
+ t.object({
9
+ interval: t.enum(["monthly", "yearly"]),
10
+ amount: t.integer(),
11
+ currency: t.string(),
12
+ }),
13
+ ),
14
+ features: t.array(t.string()),
15
+ limits: t.record(t.text(), t.integer()),
16
+ trial: t.optional(
17
+ t.object({
18
+ days: t.integer(),
19
+ requirePaymentMethod: t.boolean(),
20
+ }),
21
+ ),
22
+ order: t.integer(),
23
+ });
24
+
25
+ export type PlanResource = Static<typeof planResourceSchema>;
@@ -0,0 +1,8 @@
1
+ import type { Static } from "alepha";
2
+ import { subscriptionEvents } from "../entities/subscriptionEvents.ts";
3
+
4
+ export const subscriptionEventResourceSchema = subscriptionEvents.schema;
5
+
6
+ export type SubscriptionEventResource = Static<
7
+ typeof subscriptionEventResourceSchema
8
+ >;
@@ -0,0 +1,19 @@
1
+ import { type Static, t } from "alepha";
2
+ import { pageQuerySchema } from "alepha/orm";
3
+
4
+ export const subscriptionQuerySchema = t.extend(pageQuerySchema, {
5
+ status: t.optional(
6
+ t.enum([
7
+ "trialing",
8
+ "active",
9
+ "past_due",
10
+ "suspended",
11
+ "cancelled",
12
+ "expired",
13
+ ]),
14
+ ),
15
+ planId: t.optional(t.string()),
16
+ organizationId: t.optional(t.uuid()),
17
+ });
18
+
19
+ export type SubscriptionQuery = Static<typeof subscriptionQuerySchema>;
@@ -0,0 +1,6 @@
1
+ import type { Static } from "alepha";
2
+ import { subscriptions } from "../entities/subscriptions.ts";
3
+
4
+ export const subscriptionResourceSchema = subscriptions.schema;
5
+
6
+ export type SubscriptionResource = Static<typeof subscriptionResourceSchema>;
@@ -0,0 +1,32 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const subscriptionSettingsSchema = t.object({
4
+ /**
5
+ * Default trial days (overridden per-plan if plan.trial.days is set).
6
+ */
7
+ trialDays: t.integer({ default: 14, minimum: 0, maximum: 365 }),
8
+
9
+ /**
10
+ * Days after payment failure before suspension.
11
+ * During grace period, subscription remains active but flagged.
12
+ */
13
+ gracePeriodDays: t.integer({ default: 7, minimum: 0, maximum: 30 }),
14
+
15
+ /**
16
+ * Days after first payment failure to retry, relative to the failure date.
17
+ * e.g., [1, 3, 5, 7] means retry on day 1, 3, 5, 7 after failure.
18
+ */
19
+ dunningSchedule: t.array(t.integer({ minimum: 1 })),
20
+
21
+ /**
22
+ * When user cancels, wait until period end (true) or cancel immediately (false).
23
+ */
24
+ cancelAtPeriodEnd: t.boolean({ default: true }),
25
+
26
+ /**
27
+ * Prorate charges when changing plans mid-cycle.
28
+ */
29
+ prorateOnChange: t.boolean({ default: true }),
30
+ });
31
+
32
+ export type SubscriptionSettings = Static<typeof subscriptionSettingsSchema>;
@@ -0,0 +1,23 @@
1
+ import { type Static, t } from "alepha";
2
+
3
+ export const subscriptionStatsSchema = t.object({
4
+ total: t.integer(),
5
+ trialing: t.integer(),
6
+ active: t.integer(),
7
+ pastDue: t.integer(),
8
+ suspended: t.integer(),
9
+ cancelled: t.integer(),
10
+ expired: t.integer(),
11
+ trialConversionRate: t.number(),
12
+ churnRate: t.number(),
13
+ byPlan: t.record(
14
+ t.text(),
15
+ t.object({
16
+ active: t.integer(),
17
+ trialing: t.integer(),
18
+ total: t.integer(),
19
+ }),
20
+ ),
21
+ });
22
+
23
+ export type SubscriptionStats = Static<typeof subscriptionStatsSchema>;