alepha 0.20.1 → 0.20.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 (232) hide show
  1. package/dist/api/files/index.js +2 -1
  2. package/dist/api/files/index.js.map +1 -1
  3. package/dist/api/jobs/index.browser.js +64 -148
  4. package/dist/api/jobs/index.browser.js.map +1 -1
  5. package/dist/api/jobs/index.d.ts +371 -573
  6. package/dist/api/jobs/index.d.ts.map +1 -1
  7. package/dist/api/jobs/index.js +605 -1012
  8. package/dist/api/jobs/index.js.map +1 -1
  9. package/dist/api/notifications/index.d.ts +78 -17
  10. package/dist/api/notifications/index.d.ts.map +1 -1
  11. package/dist/api/notifications/index.js +90 -23
  12. package/dist/api/notifications/index.js.map +1 -1
  13. package/dist/api/payments/index.d.ts +2 -1
  14. package/dist/api/payments/index.d.ts.map +1 -1
  15. package/dist/api/payments/index.js +4 -2
  16. package/dist/api/payments/index.js.map +1 -1
  17. package/dist/api/users/index.d.ts +34 -31
  18. package/dist/api/users/index.d.ts.map +1 -1
  19. package/dist/api/users/index.js +13 -7
  20. package/dist/api/users/index.js.map +1 -1
  21. package/dist/api/verifications/index.js +2 -1
  22. package/dist/api/verifications/index.js.map +1 -1
  23. package/dist/cli/core/index.d.ts +8 -34
  24. package/dist/cli/core/index.d.ts.map +1 -1
  25. package/dist/cli/core/index.js +43 -232
  26. package/dist/cli/core/index.js.map +1 -1
  27. package/dist/cli/platform/index.d.ts +36 -11
  28. package/dist/cli/platform/index.d.ts.map +1 -1
  29. package/dist/cli/platform/index.js +93 -27
  30. package/dist/cli/platform/index.js.map +1 -1
  31. package/dist/command/index.d.ts +1 -1
  32. package/dist/core/index.browser.js +6 -0
  33. package/dist/core/index.browser.js.map +1 -1
  34. package/dist/core/index.d.ts +6 -0
  35. package/dist/core/index.d.ts.map +1 -1
  36. package/dist/core/index.js +6 -0
  37. package/dist/core/index.js.map +1 -1
  38. package/dist/core/index.native.js +6 -0
  39. package/dist/core/index.native.js.map +1 -1
  40. package/dist/core/index.workerd.js +6 -0
  41. package/dist/core/index.workerd.js.map +1 -1
  42. package/dist/react/form/index.d.ts +60 -1
  43. package/dist/react/form/index.d.ts.map +1 -1
  44. package/dist/react/form/index.js +86 -1
  45. package/dist/react/form/index.js.map +1 -1
  46. package/dist/react/head/index.browser.js +16 -1
  47. package/dist/react/head/index.browser.js.map +1 -1
  48. package/dist/react/head/index.d.ts +6 -0
  49. package/dist/react/head/index.d.ts.map +1 -1
  50. package/dist/react/head/index.js +16 -1
  51. package/dist/react/head/index.js.map +1 -1
  52. package/dist/react/router/index.browser.js +0 -10
  53. package/dist/react/router/index.browser.js.map +1 -1
  54. package/dist/react/router/index.d.ts +35 -12
  55. package/dist/react/router/index.d.ts.map +1 -1
  56. package/dist/react/router/index.js +0 -10
  57. package/dist/react/router/index.js.map +1 -1
  58. package/dist/react/ui/index.d.ts +124 -0
  59. package/dist/react/ui/index.d.ts.map +1 -0
  60. package/dist/react/ui/index.js +206 -0
  61. package/dist/react/ui/index.js.map +1 -0
  62. package/dist/router/index.d.ts +13 -13
  63. package/dist/router/index.d.ts.map +1 -1
  64. package/dist/router/index.js +45 -32
  65. package/dist/router/index.js.map +1 -1
  66. package/dist/system/index.d.ts.map +1 -1
  67. package/dist/system/index.js +1 -0
  68. package/dist/system/index.js.map +1 -1
  69. package/dist/topic/core/index.js +1 -1
  70. package/dist/topic/core/index.js.map +1 -1
  71. package/package.json +6 -23
  72. package/src/api/files/jobs/FileJobs.ts +2 -1
  73. package/src/api/jobs/__tests__/$job.spec.ts +316 -2867
  74. package/src/api/jobs/controllers/AdminJobController.ts +29 -138
  75. package/src/api/jobs/entities/jobExecutionEntity.ts +27 -19
  76. package/src/api/jobs/index.browser.ts +5 -7
  77. package/src/api/jobs/index.ts +23 -51
  78. package/src/api/jobs/primitives/$job.ts +66 -58
  79. package/src/api/jobs/providers/JobProvider.ts +561 -566
  80. package/src/api/jobs/providers/JobQueueProvider.ts +18 -19
  81. package/src/api/jobs/schemas/jobConfigAtom.ts +20 -23
  82. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +3 -27
  83. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +5 -7
  84. package/src/api/jobs/schemas/jobRegistrationSchema.ts +7 -4
  85. package/src/api/jobs/schemas/triggerJobSchema.ts +0 -1
  86. package/src/api/jobs/services/JobService.ts +90 -483
  87. package/src/api/notifications/controllers/AdminNotificationController.ts +19 -12
  88. package/src/api/notifications/index.ts +7 -4
  89. package/src/api/notifications/jobs/NotificationJobs.ts +83 -12
  90. package/src/api/payments/services/PaymentService.ts +4 -2
  91. package/src/api/users/__tests__/UserJobs.spec.ts +10 -49
  92. package/src/api/users/audits/UserAudits.ts +3 -1
  93. package/src/api/users/buckets/UserBuckets.ts +2 -1
  94. package/src/api/users/index.ts +1 -4
  95. package/src/api/users/jobs/UserJobs.ts +5 -4
  96. package/src/api/verifications/jobs/VerificationJobs.ts +2 -1
  97. package/src/cli/core/__tests__/init.spec.ts +1 -1
  98. package/src/cli/core/commands/init.ts +0 -12
  99. package/src/cli/core/services/PackageManagerUtils.ts +2 -9
  100. package/src/cli/core/services/ProjectScaffolder.ts +17 -65
  101. package/src/cli/core/templates/agentMd.ts +2 -8
  102. package/src/cli/core/templates/apiIndexTs.ts +4 -18
  103. package/src/cli/core/templates/mainCss.ts +1 -36
  104. package/src/cli/core/templates/vitestConfigTs.ts +17 -0
  105. package/src/cli/core/templates/webAppRouterTs.ts +2 -85
  106. package/src/cli/platform/__tests__/CloudflareAdapter.spec.ts +22 -71
  107. package/src/cli/platform/adapters/CloudflareAdapter.ts +12 -11
  108. package/src/cli/platform/atoms/platformOptions.ts +9 -0
  109. package/src/cli/platform/schemas/cloudflare.ts +3 -2
  110. package/src/cli/platform/services/CloudflareApi.ts +164 -25
  111. package/src/cli/platform/services/WranglerApi.ts +0 -17
  112. package/src/core/Alepha.ts +9 -0
  113. package/src/react/form/index.ts +2 -0
  114. package/src/react/form/services/parseField.ts +163 -0
  115. package/src/react/form/services/prettyName.ts +19 -0
  116. package/src/react/head/providers/BrowserHeadProvider.ts +31 -10
  117. package/src/react/router/primitives/$page.ts +35 -12
  118. package/src/react/ui/atoms/uiAtom.ts +28 -0
  119. package/src/react/ui/components/ColorScheme.tsx +36 -0
  120. package/src/react/ui/hooks/useColorMode.ts +49 -0
  121. package/src/react/ui/hooks/useSidebarState.ts +26 -0
  122. package/src/react/ui/hooks/useTheme.ts +22 -0
  123. package/src/react/ui/index.ts +35 -0
  124. package/src/react/ui/services/UiPersistence.ts +41 -0
  125. package/src/router/TemplatedPathParser.ts +50 -51
  126. package/src/router/__tests__/RouterProvider.spec.ts +62 -0
  127. package/src/router/__tests__/TemplatedPathParser.spec.ts +18 -0
  128. package/src/router/providers/RouterProvider.ts +10 -5
  129. package/src/system/providers/NodeShellProvider.ts +1 -0
  130. package/src/topic/core/providers/TopicProvider.ts +1 -1
  131. package/dist/api/invitations/index.d.ts +0 -790
  132. package/dist/api/invitations/index.d.ts.map +0 -1
  133. package/dist/api/invitations/index.js +0 -662
  134. package/dist/api/invitations/index.js.map +0 -1
  135. package/dist/api/issues/index.d.ts +0 -810
  136. package/dist/api/issues/index.d.ts.map +0 -1
  137. package/dist/api/issues/index.js +0 -444
  138. package/dist/api/issues/index.js.map +0 -1
  139. package/dist/api/subscriptions/index.d.ts +0 -1692
  140. package/dist/api/subscriptions/index.d.ts.map +0 -1
  141. package/dist/api/subscriptions/index.js +0 -1867
  142. package/dist/api/subscriptions/index.js.map +0 -1
  143. package/dist/api/workflows/index.browser.js +0 -246
  144. package/dist/api/workflows/index.browser.js.map +0 -1
  145. package/dist/api/workflows/index.d.ts +0 -1618
  146. package/dist/api/workflows/index.d.ts.map +0 -1
  147. package/dist/api/workflows/index.js +0 -1495
  148. package/dist/api/workflows/index.js.map +0 -1
  149. package/src/api/invitations/__tests__/InvitationService.spec.ts +0 -439
  150. package/src/api/invitations/controllers/AdminInvitationController.ts +0 -86
  151. package/src/api/invitations/controllers/InvitationController.ts +0 -84
  152. package/src/api/invitations/entities/invitations.ts +0 -33
  153. package/src/api/invitations/index.ts +0 -58
  154. package/src/api/invitations/jobs/InvitationJobs.ts +0 -37
  155. package/src/api/invitations/providers/InvitationProvider.ts +0 -45
  156. package/src/api/invitations/schemas/createInvitationSchema.ts +0 -12
  157. package/src/api/invitations/schemas/invitationConfigAtom.ts +0 -20
  158. package/src/api/invitations/schemas/invitationQuerySchema.ts +0 -15
  159. package/src/api/invitations/schemas/invitationResourceSchema.ts +0 -6
  160. package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +0 -22
  161. package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +0 -10
  162. package/src/api/invitations/services/InvitationService.ts +0 -556
  163. package/src/api/issues/__tests__/IssueService.spec.ts +0 -263
  164. package/src/api/issues/controllers/AdminIssueController.ts +0 -149
  165. package/src/api/issues/controllers/IssueController.ts +0 -44
  166. package/src/api/issues/entities/issues.ts +0 -49
  167. package/src/api/issues/index.ts +0 -50
  168. package/src/api/issues/schemas/createIssueSchema.ts +0 -13
  169. package/src/api/issues/schemas/issueConfigAtom.ts +0 -13
  170. package/src/api/issues/schemas/issueQuerySchema.ts +0 -18
  171. package/src/api/issues/schemas/issueResourceSchema.ts +0 -6
  172. package/src/api/issues/schemas/myIssueQuerySchema.ts +0 -10
  173. package/src/api/issues/schemas/updateIssueSchema.ts +0 -13
  174. package/src/api/issues/services/IssueService.ts +0 -264
  175. package/src/api/jobs/__tests__/$job-middleware.spec.ts +0 -126
  176. package/src/api/jobs/__tests__/JobService.spec.ts +0 -31
  177. package/src/api/jobs/entities/jobExecutionLogEntity.ts +0 -13
  178. package/src/api/jobs/schemas/jobActivitySchema.ts +0 -15
  179. package/src/api/jobs/schemas/jobCronInfoSchema.ts +0 -22
  180. package/src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts +0 -20
  181. package/src/api/jobs/schemas/jobFailureSchema.ts +0 -9
  182. package/src/api/jobs/schemas/jobQueueDepthSchema.ts +0 -14
  183. package/src/api/jobs/schemas/jobStatsSchema.ts +0 -14
  184. package/src/api/jobs/services/JobService-tests.ts +0 -157
  185. package/src/api/subscriptions/__tests__/BillingService.spec.ts +0 -218
  186. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +0 -278
  187. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +0 -212
  188. package/src/api/subscriptions/controllers/SubscriptionController.ts +0 -189
  189. package/src/api/subscriptions/entities/subscriptionEvents.ts +0 -54
  190. package/src/api/subscriptions/entities/subscriptions.ts +0 -68
  191. package/src/api/subscriptions/index.ts +0 -133
  192. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +0 -382
  193. package/src/api/subscriptions/middleware/$requireLimit.ts +0 -50
  194. package/src/api/subscriptions/middleware/$requirePlan.ts +0 -49
  195. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +0 -110
  196. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +0 -8
  197. package/src/api/subscriptions/schemas/changePlanSchema.ts +0 -9
  198. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +0 -11
  199. package/src/api/subscriptions/schemas/entitlementsSchema.ts +0 -21
  200. package/src/api/subscriptions/schemas/mrrSchema.ts +0 -13
  201. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +0 -71
  202. package/src/api/subscriptions/schemas/planResourceSchema.ts +0 -25
  203. package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +0 -8
  204. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +0 -19
  205. package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +0 -6
  206. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +0 -32
  207. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +0 -23
  208. package/src/api/subscriptions/services/BillingService.ts +0 -437
  209. package/src/api/subscriptions/services/SubscriptionConfig.ts +0 -56
  210. package/src/api/subscriptions/services/SubscriptionService.ts +0 -867
  211. package/src/api/subscriptions/services/UsageService.ts +0 -118
  212. package/src/api/workflows/__tests__/$workflow.spec.ts +0 -616
  213. package/src/api/workflows/controllers/AdminWorkflowController.ts +0 -191
  214. package/src/api/workflows/entities/workflowExecutions.ts +0 -74
  215. package/src/api/workflows/entities/workflowStepExecutions.ts +0 -74
  216. package/src/api/workflows/entities/workflowStepLogs.ts +0 -13
  217. package/src/api/workflows/index.browser.ts +0 -22
  218. package/src/api/workflows/index.ts +0 -115
  219. package/src/api/workflows/jobs/WorkflowJobs.ts +0 -77
  220. package/src/api/workflows/primitives/$workflow.ts +0 -202
  221. package/src/api/workflows/providers/WorkflowProvider.ts +0 -1284
  222. package/src/api/workflows/schemas/workflowActivitySchema.ts +0 -15
  223. package/src/api/workflows/schemas/workflowConfigAtom.ts +0 -51
  224. package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +0 -18
  225. package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +0 -26
  226. package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +0 -30
  227. package/src/api/workflows/schemas/workflowRegistrationSchema.ts +0 -26
  228. package/src/api/workflows/schemas/workflowStatsSchema.ts +0 -16
  229. package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +0 -15
  230. package/src/api/workflows/services/WorkflowService.ts +0 -382
  231. package/src/cli/core/templates/apiAppSecurityTs.ts +0 -43
  232. package/src/cli/core/templates/webAdminDashboardTsx.ts +0 -17
@@ -1,15 +0,0 @@
1
- import { type Static, t } from "alepha";
2
-
3
- export const workflowActivityPointSchema = t.object({
4
- date: t.text(),
5
- completed: t.integer(),
6
- failed: t.integer(),
7
- });
8
-
9
- export type WorkflowActivityPoint = Static<typeof workflowActivityPointSchema>;
10
-
11
- export const workflowActivityQuerySchema = t.object({
12
- days: t.optional(t.integer({ minimum: 1, maximum: 90 })),
13
- });
14
-
15
- export type WorkflowActivityQuery = Static<typeof workflowActivityQuerySchema>;
@@ -1,51 +0,0 @@
1
- import { $atom, type Static, t } from "alepha";
2
-
3
- export const workflowConfig = $atom({
4
- name: "alepha.workflows",
5
- description: "Configuration for the workflow engine.",
6
- schema: t.object({
7
- defaultStepTimeout: t.integer({
8
- description:
9
- "Default step timeout (ms). Used when no per-step timeout is set.",
10
- }),
11
- retentionDays: t.integer({
12
- description: "Days to keep completed/failed workflow executions.",
13
- }),
14
- recovery: t.object({
15
- staleThreshold: t.integer({
16
- description: "Running step age (ms) before assumed crashed.",
17
- }),
18
- }),
19
- maxConcurrentWorkflows: t.integer({
20
- description: "Max concurrent running instances per workflow name.",
21
- }),
22
- maxStepsPerWorkflow: t.integer({
23
- description: "Safety limit on step count.",
24
- }),
25
- drainTimeout: t.integer({
26
- description: "Max time (ms) to wait for in-flight steps during shutdown.",
27
- }),
28
- logMaxEntries: t.integer({
29
- description: "Max log entries captured per step execution.",
30
- }),
31
- }),
32
- default: {
33
- defaultStepTimeout: 300_000,
34
- retentionDays: 30,
35
- recovery: {
36
- staleThreshold: 1_800_000,
37
- },
38
- maxConcurrentWorkflows: 50,
39
- maxStepsPerWorkflow: 100,
40
- drainTimeout: 30_000,
41
- logMaxEntries: 100,
42
- },
43
- });
44
-
45
- export type WorkflowConfig = Static<typeof workflowConfig.schema>;
46
-
47
- declare module "alepha" {
48
- interface State {
49
- [workflowConfig.key]: WorkflowConfig;
50
- }
51
- }
@@ -1,18 +0,0 @@
1
- import { type Static, t } from "alepha";
2
- import { workflowExecutionResourceSchema } from "./workflowExecutionResourceSchema.ts";
3
- import { workflowStepExecutionResourceSchema } from "./workflowStepExecutionResourceSchema.ts";
4
-
5
- export const workflowExecutionDetailSchema = t.extend(
6
- workflowExecutionResourceSchema,
7
- {
8
- steps: t.array(workflowStepExecutionResourceSchema),
9
- },
10
- {
11
- title: "WorkflowExecutionDetail",
12
- description: "A workflow execution with step details.",
13
- },
14
- );
15
-
16
- export type WorkflowExecutionDetail = Static<
17
- typeof workflowExecutionDetailSchema
18
- >;
@@ -1,26 +0,0 @@
1
- import { type Static, t } from "alepha";
2
- import { pageQuerySchema } from "alepha/orm";
3
-
4
- export const workflowExecutionQuerySchema = t.extend(pageQuerySchema, {
5
- workflow: t.optional(t.text({ description: "Filter by workflow name" })),
6
- status: t.optional(
7
- t.enum([
8
- "pending",
9
- "running",
10
- "waiting_for_signal",
11
- "completed",
12
- "failed",
13
- "timed_out",
14
- "compensating",
15
- "compensated",
16
- "compensation_failed",
17
- "cancelled",
18
- ]),
19
- ),
20
- from: t.optional(t.datetime({ description: "From date (ISO)" })),
21
- to: t.optional(t.datetime({ description: "To date (ISO)" })),
22
- });
23
-
24
- export type WorkflowExecutionQuery = Static<
25
- typeof workflowExecutionQuerySchema
26
- >;
@@ -1,30 +0,0 @@
1
- import { type Static, t } from "alepha";
2
- import { workflowExecutions } from "../entities/workflowExecutions.ts";
3
-
4
- export const workflowExecutionCanSchema = t.object({
5
- retry: t.boolean(),
6
- cancel: t.boolean(),
7
- compensate: t.boolean(),
8
- restart: t.boolean(),
9
- signal: t.optional(
10
- t.object({
11
- stepName: t.text(),
12
- schema: t.optional(t.any()),
13
- }),
14
- ),
15
- });
16
-
17
- export type WorkflowExecutionCan = Static<typeof workflowExecutionCanSchema>;
18
-
19
- export const workflowExecutionResourceSchema = t.extend(
20
- workflowExecutions.schema,
21
- { can: workflowExecutionCanSchema },
22
- {
23
- title: "WorkflowExecutionResource",
24
- description: "A workflow execution resource.",
25
- },
26
- );
27
-
28
- export type WorkflowExecutionResource = Static<
29
- typeof workflowExecutionResourceSchema
30
- >;
@@ -1,26 +0,0 @@
1
- import { type Static, t } from "alepha";
2
-
3
- export const workflowRegistrationSchema = t.object({
4
- name: t.text(),
5
- stepCount: t.integer(),
6
- steps: t.array(
7
- t.object({
8
- name: t.text(),
9
- type: t.enum(["handler", "signal", "parallel"]),
10
- hasCompensate: t.boolean(),
11
- hasRetry: t.boolean(),
12
- timeout: t.optional(t.text()),
13
- }),
14
- ),
15
- onError: t.enum(["compensate", "fail"]),
16
- timeout: t.optional(t.text()),
17
- priority: t.text(),
18
- tags: t.optional(t.array(t.text())),
19
- paused: t.boolean(),
20
- running: t.integer(),
21
- pending: t.integer(),
22
- waiting: t.integer(),
23
- failed: t.integer(),
24
- });
25
-
26
- export type WorkflowRegistration = Static<typeof workflowRegistrationSchema>;
@@ -1,16 +0,0 @@
1
- import { type Static, t } from "alepha";
2
-
3
- export const workflowStatsSchema = t.object({
4
- registered: t.integer(),
5
- running: t.integer(),
6
- pending: t.integer(),
7
- waiting: t.integer(),
8
- completed: t.integer(),
9
- failed: t.integer(),
10
- compensated: t.integer(),
11
- compensationFailed: t.integer(),
12
- cancelled: t.integer(),
13
- timedOut: t.integer(),
14
- });
15
-
16
- export type WorkflowStats = Static<typeof workflowStatsSchema>;
@@ -1,15 +0,0 @@
1
- import { type Static, t } from "alepha";
2
- import { workflowStepExecutions } from "../entities/workflowStepExecutions.ts";
3
-
4
- export const workflowStepExecutionResourceSchema = t.extend(
5
- workflowStepExecutions.schema,
6
- {},
7
- {
8
- title: "WorkflowStepExecutionResource",
9
- description: "A workflow step execution resource.",
10
- },
11
- );
12
-
13
- export type WorkflowStepExecutionResource = Static<
14
- typeof workflowStepExecutionResourceSchema
15
- >;
@@ -1,382 +0,0 @@
1
- import { $inject, Alepha, t } from "alepha";
2
- import { DateTimeProvider } from "alepha/datetime";
3
- import { $logger } from "alepha/logger";
4
- import { $repository, DatabaseProvider, sql } from "alepha/orm";
5
- import { NotFoundError } from "alepha/server";
6
- import type { WorkflowExecutionEntity } from "../entities/workflowExecutions.ts";
7
- import { workflowExecutions } from "../entities/workflowExecutions.ts";
8
- import { workflowStepExecutions } from "../entities/workflowStepExecutions.ts";
9
- import { WorkflowProvider } from "../providers/WorkflowProvider.ts";
10
- import type { WorkflowActivityPoint } from "../schemas/workflowActivitySchema.ts";
11
- import type { WorkflowExecutionQuery } from "../schemas/workflowExecutionQuerySchema.ts";
12
- import type { WorkflowExecutionCan } from "../schemas/workflowExecutionResourceSchema.ts";
13
- import type { WorkflowRegistration } from "../schemas/workflowRegistrationSchema.ts";
14
- import type { WorkflowStats } from "../schemas/workflowStatsSchema.ts";
15
-
16
- // -----------------------------------------------------------------------------------------------------------------
17
-
18
- export class WorkflowService {
19
- protected readonly alepha = $inject(Alepha);
20
- protected readonly dt = $inject(DateTimeProvider);
21
- protected readonly log = $logger();
22
- protected readonly workflowProvider = $inject(WorkflowProvider);
23
- protected readonly database = $inject(DatabaseProvider);
24
- protected readonly executions = $repository(workflowExecutions);
25
- protected readonly stepExecutions = $repository(workflowStepExecutions);
26
-
27
- /**
28
- * Compute available actions for a workflow execution based on its status.
29
- */
30
- protected computeCan(
31
- status: string,
32
- signalStepName?: string,
33
- ): WorkflowExecutionCan {
34
- return {
35
- retry: status === "failed" || status === "timed_out",
36
- cancel:
37
- status === "pending" ||
38
- status === "running" ||
39
- status === "waiting_for_signal",
40
- compensate: status === "failed" || status === "timed_out",
41
- restart:
42
- status === "failed" ||
43
- status === "compensated" ||
44
- status === "compensation_failed",
45
- signal: signalStepName ? { stepName: signalStepName } : undefined,
46
- };
47
- }
48
-
49
- /**
50
- * Convert an ISO date string to the raw SQL parameter format
51
- * expected by the current database dialect.
52
- *
53
- * - PostgreSQL: ISO string (timestamp comparison)
54
- * - SQLite: epoch milliseconds (integer comparison)
55
- */
56
- protected toRawDate(iso: string): string | number {
57
- return this.database.dialect === "sqlite" ? new Date(iso).getTime() : iso;
58
- }
59
-
60
- /**
61
- * Get aggregate stats for the workflow engine.
62
- */
63
- public async getStats(days?: number): Promise<WorkflowStats> {
64
- const workflows = this.workflowProvider.getRegisteredWorkflows();
65
- const periodAgo = this.toRawDate(
66
- this.dt
67
- .now()
68
- .subtract(days ?? 1, "day")
69
- .toISOString(),
70
- );
71
-
72
- const rows = await this.executions.query(
73
- (e) => sql`
74
- SELECT
75
- COUNT(*) FILTER (WHERE ${e.status} = 'running') AS running,
76
- COUNT(*) FILTER (WHERE ${e.status} = 'pending') AS pending,
77
- COUNT(*) FILTER (WHERE ${e.status} = 'waiting_for_signal') AS waiting,
78
- COUNT(*) FILTER (WHERE ${e.status} = 'completed' AND ${e.completedAt} >= ${periodAgo}) AS completed,
79
- COUNT(*) FILTER (WHERE ${e.status} = 'failed' AND ${e.completedAt} >= ${periodAgo}) AS failed,
80
- COUNT(*) FILTER (WHERE ${e.status} = 'compensated' AND ${e.completedAt} >= ${periodAgo}) AS compensated,
81
- COUNT(*) FILTER (WHERE ${e.status} = 'compensation_failed' AND ${e.completedAt} >= ${periodAgo}) AS compensation_failed,
82
- COUNT(*) FILTER (WHERE ${e.status} = 'cancelled' AND ${e.completedAt} >= ${periodAgo}) AS cancelled,
83
- COUNT(*) FILTER (WHERE ${e.status} = 'timed_out' AND ${e.completedAt} >= ${periodAgo}) AS timed_out
84
- FROM ${e}
85
- `,
86
- t.object({
87
- running: t.string(),
88
- pending: t.string(),
89
- waiting: t.string(),
90
- completed: t.string(),
91
- failed: t.string(),
92
- compensated: t.string(),
93
- compensation_failed: t.string(),
94
- cancelled: t.string(),
95
- timed_out: t.string(),
96
- }),
97
- );
98
-
99
- const row = rows[0];
100
- return {
101
- registered: workflows.size,
102
- running: Number(row.running),
103
- pending: Number(row.pending),
104
- waiting: Number(row.waiting),
105
- completed: Number(row.completed),
106
- failed: Number(row.failed),
107
- compensated: Number(row.compensated),
108
- compensationFailed: Number(row.compensation_failed),
109
- cancelled: Number(row.cancelled),
110
- timedOut: Number(row.timed_out),
111
- };
112
- }
113
-
114
- /**
115
- * Get the full workflow registry with live counts.
116
- */
117
- public async getRegistry(): Promise<WorkflowRegistration[]> {
118
- const workflows = this.workflowProvider.getRegisteredWorkflows();
119
- const names = [...workflows.keys()];
120
-
121
- // Get live counts per workflow name
122
- const countRows =
123
- names.length > 0
124
- ? await this.executions.query(
125
- (e) => sql`
126
- SELECT
127
- ${e.workflowName} AS workflow_name,
128
- COUNT(*) FILTER (WHERE ${e.status} = 'running') AS running,
129
- COUNT(*) FILTER (WHERE ${e.status} = 'pending') AS pending,
130
- COUNT(*) FILTER (WHERE ${e.status} = 'waiting_for_signal') AS waiting,
131
- COUNT(*) FILTER (WHERE ${e.status} = 'failed') AS failed
132
- FROM ${e}
133
- WHERE ${e.workflowName} IN (${sql.join(
134
- names.map((n) => sql`${n}`),
135
- sql`, `,
136
- )})
137
- GROUP BY ${e.workflowName}
138
- `,
139
- t.object({
140
- workflow_name: t.string(),
141
- running: t.string(),
142
- pending: t.string(),
143
- waiting: t.string(),
144
- failed: t.string(),
145
- }),
146
- )
147
- : [];
148
-
149
- const countsByName = new Map(countRows.map((r) => [r.workflow_name, r]));
150
-
151
- const result: WorkflowRegistration[] = [];
152
-
153
- for (const [name, reg] of workflows) {
154
- const opts = reg.options;
155
- const counts = countsByName.get(name);
156
-
157
- result.push({
158
- name,
159
- stepCount: opts.steps.length,
160
- steps: opts.steps.map((step) => ({
161
- name: step.name,
162
- type: step.type ?? "handler",
163
- hasCompensate: Boolean(step.compensate),
164
- hasRetry: Boolean(step.retry),
165
- timeout: step.timeout ? String(step.timeout) : undefined,
166
- })),
167
- onError: opts.onError ?? "compensate",
168
- timeout: opts.timeout ? String(opts.timeout) : undefined,
169
- priority: opts.priority ?? "normal",
170
- tags: opts.tags,
171
- paused: this.workflowProvider.isWorkflowPaused(name),
172
- running: Number(counts?.running ?? 0),
173
- pending: Number(counts?.pending ?? 0),
174
- waiting: Number(counts?.waiting ?? 0),
175
- failed: Number(counts?.failed ?? 0),
176
- });
177
- }
178
-
179
- return result;
180
- }
181
-
182
- /**
183
- * Paginated query for workflow executions.
184
- */
185
- public async findExecutions(query: WorkflowExecutionQuery = {}) {
186
- query.sort ??= "-createdAt";
187
-
188
- const where = this.executions.createQueryWhere();
189
-
190
- if (query.workflow) {
191
- where.workflowName = { eq: query.workflow };
192
- }
193
-
194
- if (query.status) {
195
- where.status = { eq: query.status };
196
- }
197
-
198
- if (query.from) {
199
- where.createdAt = { gte: query.from };
200
- }
201
-
202
- if (query.to) {
203
- where.createdAt = {
204
- ...(where.createdAt as object),
205
- lte: query.to,
206
- };
207
- }
208
-
209
- const page = await this.executions.paginate(
210
- query,
211
- { where },
212
- { count: true },
213
- );
214
- return {
215
- ...page,
216
- content: page.content.map((exec: WorkflowExecutionEntity) => ({
217
- ...exec,
218
- can: this.computeCan(exec.status),
219
- })),
220
- };
221
- }
222
-
223
- /**
224
- * Get a single workflow execution with step details.
225
- */
226
- public async getExecution(id: string) {
227
- const execution = await this.executions.findById(id);
228
- if (!execution) {
229
- throw new NotFoundError(`Workflow execution not found: ${id}`);
230
- }
231
-
232
- const steps = await this.stepExecutions.findMany({
233
- where: { workflowExecutionId: { eq: id } },
234
- orderBy: { column: "stepIndex", direction: "asc" },
235
- });
236
-
237
- // Determine signal step name if workflow is waiting
238
- let signalStepName: string | undefined;
239
- if (execution.status === "waiting_for_signal") {
240
- const waitingStep = steps.find((s) => s.status === "waiting");
241
- if (waitingStep) {
242
- signalStepName = waitingStep.stepName;
243
- }
244
- }
245
-
246
- return {
247
- ...execution,
248
- can: this.computeCan(execution.status, signalStepName),
249
- steps,
250
- };
251
- }
252
-
253
- /**
254
- * Get daily activity (completed/failed) over a date range.
255
- */
256
- public async getActivity(days = 14): Promise<WorkflowActivityPoint[]> {
257
- const rows = await this.executions.query(
258
- (e) => sql`
259
- WITH date_series AS (
260
- SELECT generate_series(
261
- CURRENT_DATE - ${days - 1}::int,
262
- CURRENT_DATE,
263
- '1 day'::interval
264
- )::date AS date
265
- )
266
- SELECT
267
- ds.date::text AS date,
268
- COALESCE(COUNT(*) FILTER (WHERE ${e.status} = 'completed'), 0) AS completed,
269
- COALESCE(COUNT(*) FILTER (WHERE ${e.status} = 'failed'), 0) AS failed
270
- FROM date_series ds
271
- LEFT JOIN ${e} ON DATE(${e.completedAt}) = ds.date
272
- AND ${e.status} IN ('completed', 'failed')
273
- GROUP BY ds.date
274
- ORDER BY ds.date ASC
275
- `,
276
- t.object({
277
- date: t.string(),
278
- completed: t.string(),
279
- failed: t.string(),
280
- }),
281
- );
282
-
283
- return rows.map((row) => ({
284
- date: row.date,
285
- completed: Number(row.completed),
286
- failed: Number(row.failed),
287
- }));
288
- }
289
-
290
- /**
291
- * Start a new workflow execution by name.
292
- */
293
- public async triggerWorkflow(
294
- name: string,
295
- payload?: Record<string, unknown>,
296
- options?: {
297
- key?: string;
298
- tags?: string[];
299
- triggeredBy?: string;
300
- triggeredByName?: string;
301
- },
302
- ): Promise<{ id: string }> {
303
- this.log.info(`Triggering workflow '${name}'`, {
304
- triggeredBy: options?.triggeredByName ?? options?.triggeredBy,
305
- });
306
-
307
- const id = await this.workflowProvider.start(name, payload ?? {}, {
308
- key: options?.key,
309
- tags: options?.tags,
310
- triggeredBy: options?.triggeredBy,
311
- triggeredByName: options?.triggeredByName,
312
- });
313
-
314
- return { id };
315
- }
316
-
317
- /**
318
- * Cancel a running workflow execution.
319
- */
320
- public async cancelExecution(
321
- id: string,
322
- context?: {
323
- compensate?: boolean;
324
- cancelledBy?: string;
325
- cancelledByName?: string;
326
- },
327
- ): Promise<{ ok: boolean }> {
328
- this.log.info(`Cancelling workflow execution ${id}`, {
329
- cancelledBy: context?.cancelledByName ?? context?.cancelledBy,
330
- });
331
-
332
- await this.workflowProvider.cancel(id, {
333
- compensate: context?.compensate,
334
- cancelledBy: context?.cancelledBy,
335
- cancelledByName: context?.cancelledByName,
336
- });
337
- return { ok: true };
338
- }
339
-
340
- /**
341
- * Retry a failed/timed-out workflow from the failed step.
342
- */
343
- public async retryExecution(id: string): Promise<{ ok: boolean }> {
344
- this.log.info(`Retrying workflow execution ${id}`);
345
- await this.workflowProvider.retry(id);
346
- return { ok: true };
347
- }
348
-
349
- /**
350
- * Restart a terminal workflow as a new execution.
351
- */
352
- public async restartExecution(id: string): Promise<{ id: string }> {
353
- this.log.info(`Restarting workflow execution ${id}`);
354
- const newId = await this.workflowProvider.restart(id);
355
- return { id: newId };
356
- }
357
-
358
- /**
359
- * Trigger compensation on a failed/timed-out workflow.
360
- */
361
- public async compensateExecution(id: string): Promise<{ ok: boolean }> {
362
- this.log.info(`Compensating workflow execution ${id}`);
363
- await this.workflowProvider.compensate(id);
364
- return { ok: true };
365
- }
366
-
367
- /**
368
- * Send a signal to a waiting workflow step.
369
- */
370
- public async signalExecution(
371
- id: string,
372
- stepName: string,
373
- payload?: Record<string, unknown>,
374
- signalledBy?: string,
375
- ): Promise<{ ok: boolean }> {
376
- this.log.info(`Signalling workflow execution ${id} step '${stepName}'`, {
377
- signalledBy,
378
- });
379
- await this.workflowProvider.signal(id, stepName, payload);
380
- return { ok: true };
381
- }
382
- }
@@ -1,43 +0,0 @@
1
- export const apiAppSecurityTs = (opts: { adminEmail?: string } = {}) => {
2
- const adminEmailsValue = opts.adminEmail ? `["${opts.adminEmail}"]` : "[]";
3
-
4
- return `
5
- import { $realm } from "alepha/api/users";
6
-
7
- export class AppSecurity {
8
- users = $realm({
9
- settings: {
10
- // Auto-promote these users to admin on login
11
- adminEmails: ${adminEmailsValue},
12
- adminUsernames: [],
13
-
14
- // Registration & login options
15
- registrationAllowed: true,
16
- email: "required",
17
- username: "none",
18
- phoneNumber: "none",
19
-
20
- // Verification (requires notifications feature)
21
- verifyEmailRequired: false,
22
- verifyPhoneRequired: false,
23
- resetPasswordAllowed: false,
24
- },
25
- features: {
26
- // Enable additional features
27
- notifications: false,
28
- audits: false,
29
- apiKeys: false,
30
- sessionPurge: false,
31
- avatars: false,
32
- parameters: false,
33
- },
34
- identities: {
35
- // Enable authentication providers
36
- credentials: true,
37
- // google: true,
38
- // github: true,
39
- },
40
- });
41
- }
42
- `.trim();
43
- };
@@ -1,17 +0,0 @@
1
- export const webAdminDashboardTsx = () => {
2
- return `import { Flex, Text } from "@alepha/ui";
3
-
4
- const AdminDashboard = () => {
5
- return (
6
- <Flex direction="column" align="center" justify="center" mih="60vh" gap="md">
7
- <Text size="xl" fw={600}>
8
- Admin Panel
9
- </Text>
10
- <Text c="dimmed">Welcome to the admin panel.</Text>
11
- </Flex>
12
- );
13
- };
14
-
15
- export default AdminDashboard;
16
- `;
17
- };