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.
- package/dist/api/files/index.js +2 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +64 -148
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +371 -573
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +605 -1012
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.d.ts +78 -17
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +90 -23
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/payments/index.d.ts +2 -1
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js +4 -2
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/users/index.d.ts +34 -31
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +13 -7
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.js +2 -1
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +8 -34
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +43 -232
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +36 -11
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +93 -27
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/command/index.d.ts +1 -1
- package/dist/core/index.browser.js +6 -0
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +6 -0
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +6 -0
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/react/form/index.d.ts +60 -1
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +86 -1
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/head/index.browser.js +16 -1
- package/dist/react/head/index.browser.js.map +1 -1
- package/dist/react/head/index.d.ts +6 -0
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/head/index.js +16 -1
- package/dist/react/head/index.js.map +1 -1
- package/dist/react/router/index.browser.js +0 -10
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +35 -12
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +0 -10
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +124 -0
- package/dist/react/ui/index.d.ts.map +1 -0
- package/dist/react/ui/index.js +206 -0
- package/dist/react/ui/index.js.map +1 -0
- package/dist/router/index.d.ts +13 -13
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +45 -32
- package/dist/router/index.js.map +1 -1
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +1 -0
- package/dist/system/index.js.map +1 -1
- package/dist/topic/core/index.js +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/package.json +6 -23
- package/src/api/files/jobs/FileJobs.ts +2 -1
- package/src/api/jobs/__tests__/$job.spec.ts +316 -2867
- package/src/api/jobs/controllers/AdminJobController.ts +29 -138
- package/src/api/jobs/entities/jobExecutionEntity.ts +27 -19
- package/src/api/jobs/index.browser.ts +5 -7
- package/src/api/jobs/index.ts +23 -51
- package/src/api/jobs/primitives/$job.ts +66 -58
- package/src/api/jobs/providers/JobProvider.ts +561 -566
- package/src/api/jobs/providers/JobQueueProvider.ts +18 -19
- package/src/api/jobs/schemas/jobConfigAtom.ts +20 -23
- package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +3 -27
- package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +5 -7
- package/src/api/jobs/schemas/jobRegistrationSchema.ts +7 -4
- package/src/api/jobs/schemas/triggerJobSchema.ts +0 -1
- package/src/api/jobs/services/JobService.ts +90 -483
- package/src/api/notifications/controllers/AdminNotificationController.ts +19 -12
- package/src/api/notifications/index.ts +7 -4
- package/src/api/notifications/jobs/NotificationJobs.ts +83 -12
- package/src/api/payments/services/PaymentService.ts +4 -2
- package/src/api/users/__tests__/UserJobs.spec.ts +10 -49
- package/src/api/users/audits/UserAudits.ts +3 -1
- package/src/api/users/buckets/UserBuckets.ts +2 -1
- package/src/api/users/index.ts +1 -4
- package/src/api/users/jobs/UserJobs.ts +5 -4
- package/src/api/verifications/jobs/VerificationJobs.ts +2 -1
- package/src/cli/core/__tests__/init.spec.ts +1 -1
- package/src/cli/core/commands/init.ts +0 -12
- package/src/cli/core/services/PackageManagerUtils.ts +2 -9
- package/src/cli/core/services/ProjectScaffolder.ts +17 -65
- package/src/cli/core/templates/agentMd.ts +2 -8
- package/src/cli/core/templates/apiIndexTs.ts +4 -18
- package/src/cli/core/templates/mainCss.ts +1 -36
- package/src/cli/core/templates/vitestConfigTs.ts +17 -0
- package/src/cli/core/templates/webAppRouterTs.ts +2 -85
- package/src/cli/platform/__tests__/CloudflareAdapter.spec.ts +22 -71
- package/src/cli/platform/adapters/CloudflareAdapter.ts +12 -11
- package/src/cli/platform/atoms/platformOptions.ts +9 -0
- package/src/cli/platform/schemas/cloudflare.ts +3 -2
- package/src/cli/platform/services/CloudflareApi.ts +164 -25
- package/src/cli/platform/services/WranglerApi.ts +0 -17
- package/src/core/Alepha.ts +9 -0
- package/src/react/form/index.ts +2 -0
- package/src/react/form/services/parseField.ts +163 -0
- package/src/react/form/services/prettyName.ts +19 -0
- package/src/react/head/providers/BrowserHeadProvider.ts +31 -10
- package/src/react/router/primitives/$page.ts +35 -12
- package/src/react/ui/atoms/uiAtom.ts +28 -0
- package/src/react/ui/components/ColorScheme.tsx +36 -0
- package/src/react/ui/hooks/useColorMode.ts +49 -0
- package/src/react/ui/hooks/useSidebarState.ts +26 -0
- package/src/react/ui/hooks/useTheme.ts +22 -0
- package/src/react/ui/index.ts +35 -0
- package/src/react/ui/services/UiPersistence.ts +41 -0
- package/src/router/TemplatedPathParser.ts +50 -51
- package/src/router/__tests__/RouterProvider.spec.ts +62 -0
- package/src/router/__tests__/TemplatedPathParser.spec.ts +18 -0
- package/src/router/providers/RouterProvider.ts +10 -5
- package/src/system/providers/NodeShellProvider.ts +1 -0
- package/src/topic/core/providers/TopicProvider.ts +1 -1
- package/dist/api/invitations/index.d.ts +0 -790
- package/dist/api/invitations/index.d.ts.map +0 -1
- package/dist/api/invitations/index.js +0 -662
- package/dist/api/invitations/index.js.map +0 -1
- package/dist/api/issues/index.d.ts +0 -810
- package/dist/api/issues/index.d.ts.map +0 -1
- package/dist/api/issues/index.js +0 -444
- package/dist/api/issues/index.js.map +0 -1
- package/dist/api/subscriptions/index.d.ts +0 -1692
- package/dist/api/subscriptions/index.d.ts.map +0 -1
- package/dist/api/subscriptions/index.js +0 -1867
- package/dist/api/subscriptions/index.js.map +0 -1
- package/dist/api/workflows/index.browser.js +0 -246
- package/dist/api/workflows/index.browser.js.map +0 -1
- package/dist/api/workflows/index.d.ts +0 -1618
- package/dist/api/workflows/index.d.ts.map +0 -1
- package/dist/api/workflows/index.js +0 -1495
- package/dist/api/workflows/index.js.map +0 -1
- package/src/api/invitations/__tests__/InvitationService.spec.ts +0 -439
- package/src/api/invitations/controllers/AdminInvitationController.ts +0 -86
- package/src/api/invitations/controllers/InvitationController.ts +0 -84
- package/src/api/invitations/entities/invitations.ts +0 -33
- package/src/api/invitations/index.ts +0 -58
- package/src/api/invitations/jobs/InvitationJobs.ts +0 -37
- package/src/api/invitations/providers/InvitationProvider.ts +0 -45
- package/src/api/invitations/schemas/createInvitationSchema.ts +0 -12
- package/src/api/invitations/schemas/invitationConfigAtom.ts +0 -20
- package/src/api/invitations/schemas/invitationQuerySchema.ts +0 -15
- package/src/api/invitations/schemas/invitationResourceSchema.ts +0 -6
- package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +0 -22
- package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +0 -10
- package/src/api/invitations/services/InvitationService.ts +0 -556
- package/src/api/issues/__tests__/IssueService.spec.ts +0 -263
- package/src/api/issues/controllers/AdminIssueController.ts +0 -149
- package/src/api/issues/controllers/IssueController.ts +0 -44
- package/src/api/issues/entities/issues.ts +0 -49
- package/src/api/issues/index.ts +0 -50
- package/src/api/issues/schemas/createIssueSchema.ts +0 -13
- package/src/api/issues/schemas/issueConfigAtom.ts +0 -13
- package/src/api/issues/schemas/issueQuerySchema.ts +0 -18
- package/src/api/issues/schemas/issueResourceSchema.ts +0 -6
- package/src/api/issues/schemas/myIssueQuerySchema.ts +0 -10
- package/src/api/issues/schemas/updateIssueSchema.ts +0 -13
- package/src/api/issues/services/IssueService.ts +0 -264
- package/src/api/jobs/__tests__/$job-middleware.spec.ts +0 -126
- package/src/api/jobs/__tests__/JobService.spec.ts +0 -31
- package/src/api/jobs/entities/jobExecutionLogEntity.ts +0 -13
- package/src/api/jobs/schemas/jobActivitySchema.ts +0 -15
- package/src/api/jobs/schemas/jobCronInfoSchema.ts +0 -22
- package/src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts +0 -20
- package/src/api/jobs/schemas/jobFailureSchema.ts +0 -9
- package/src/api/jobs/schemas/jobQueueDepthSchema.ts +0 -14
- package/src/api/jobs/schemas/jobStatsSchema.ts +0 -14
- package/src/api/jobs/services/JobService-tests.ts +0 -157
- package/src/api/subscriptions/__tests__/BillingService.spec.ts +0 -218
- package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +0 -278
- package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +0 -212
- package/src/api/subscriptions/controllers/SubscriptionController.ts +0 -189
- package/src/api/subscriptions/entities/subscriptionEvents.ts +0 -54
- package/src/api/subscriptions/entities/subscriptions.ts +0 -68
- package/src/api/subscriptions/index.ts +0 -133
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +0 -382
- package/src/api/subscriptions/middleware/$requireLimit.ts +0 -50
- package/src/api/subscriptions/middleware/$requirePlan.ts +0 -49
- package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +0 -110
- package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +0 -8
- package/src/api/subscriptions/schemas/changePlanSchema.ts +0 -9
- package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +0 -11
- package/src/api/subscriptions/schemas/entitlementsSchema.ts +0 -21
- package/src/api/subscriptions/schemas/mrrSchema.ts +0 -13
- package/src/api/subscriptions/schemas/planDefinitionSchema.ts +0 -71
- package/src/api/subscriptions/schemas/planResourceSchema.ts +0 -25
- package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +0 -8
- package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +0 -19
- package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +0 -6
- package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +0 -32
- package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +0 -23
- package/src/api/subscriptions/services/BillingService.ts +0 -437
- package/src/api/subscriptions/services/SubscriptionConfig.ts +0 -56
- package/src/api/subscriptions/services/SubscriptionService.ts +0 -867
- package/src/api/subscriptions/services/UsageService.ts +0 -118
- package/src/api/workflows/__tests__/$workflow.spec.ts +0 -616
- package/src/api/workflows/controllers/AdminWorkflowController.ts +0 -191
- package/src/api/workflows/entities/workflowExecutions.ts +0 -74
- package/src/api/workflows/entities/workflowStepExecutions.ts +0 -74
- package/src/api/workflows/entities/workflowStepLogs.ts +0 -13
- package/src/api/workflows/index.browser.ts +0 -22
- package/src/api/workflows/index.ts +0 -115
- package/src/api/workflows/jobs/WorkflowJobs.ts +0 -77
- package/src/api/workflows/primitives/$workflow.ts +0 -202
- package/src/api/workflows/providers/WorkflowProvider.ts +0 -1284
- package/src/api/workflows/schemas/workflowActivitySchema.ts +0 -15
- package/src/api/workflows/schemas/workflowConfigAtom.ts +0 -51
- package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +0 -18
- package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +0 -26
- package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +0 -30
- package/src/api/workflows/schemas/workflowRegistrationSchema.ts +0 -26
- package/src/api/workflows/schemas/workflowStatsSchema.ts +0 -16
- package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +0 -15
- package/src/api/workflows/services/WorkflowService.ts +0 -382
- package/src/cli/core/templates/apiAppSecurityTs.ts +0 -43
- 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
|
-
};
|