@stacksjs/defaults 0.70.354 → 0.70.356

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 (214) hide show
  1. package/ai/skills/stacks-browse/SKILL.md +17 -2
  2. package/ai/skills/stacks-browse/scripts/browse.ts +207 -6
  3. package/ai/skills/stacks-email/SKILL.md +73 -16
  4. package/app/Actions/ContactAction.ts +2 -2
  5. package/app/Actions/Dashboard/Analytics/EventAnalyticsAction.ts +2 -3
  6. package/app/Actions/Dashboard/Analytics/MarketingAnalyticsAction.ts +2 -3
  7. package/app/Actions/Dashboard/Analytics/SalesAnalyticsAction.ts +2 -3
  8. package/app/Actions/Dashboard/Analytics/WebAnalyticsAction.ts +9 -3
  9. package/app/Actions/Dashboard/Auth/MeAction.ts +12 -14
  10. package/app/Actions/Dashboard/Buddy/BuddyChatAction.ts +2 -3
  11. package/app/Actions/Dashboard/Ci/RepoRunJobsAction.ts +10 -15
  12. package/app/Actions/Dashboard/Ci/RepoRunsAction.ts +12 -14
  13. package/app/Actions/Dashboard/Ci/RunnerHistoryAction.ts +11 -10
  14. package/app/Actions/Dashboard/Ci/StatusAction.ts +2 -11
  15. package/app/Actions/Dashboard/Cloud/CloudIndexAction.ts +8 -1
  16. package/app/Actions/Dashboard/Cloud/ServerlessIndexAction.ts +15 -8
  17. package/app/Actions/Dashboard/Commerce/CommerceCategoriesAction.ts +2 -4
  18. package/app/Actions/Dashboard/Commerce/CommerceCouponsAction.ts +2 -4
  19. package/app/Actions/Dashboard/Commerce/CommerceCustomersAction.ts +2 -4
  20. package/app/Actions/Dashboard/Commerce/CommerceDashboardAction.ts +2 -4
  21. package/app/Actions/Dashboard/Commerce/CommerceDeliveryAction.ts +2 -4
  22. package/app/Actions/Dashboard/Commerce/CommerceGiftCardsAction.ts +2 -4
  23. package/app/Actions/Dashboard/Commerce/CommerceOrdersAction.ts +2 -4
  24. package/app/Actions/Dashboard/Commerce/CommercePaymentsAction.ts +2 -4
  25. package/app/Actions/Dashboard/Commerce/CommercePosAction.ts +2 -4
  26. package/app/Actions/Dashboard/Commerce/CommercePosCheckoutAction.ts +76 -61
  27. package/app/Actions/Dashboard/Commerce/CommercePrintDevicesAction.ts +2 -4
  28. package/app/Actions/Dashboard/Commerce/CommercePrintLogsAction.ts +4 -7
  29. package/app/Actions/Dashboard/Commerce/CommerceProductDetailAction.ts +4 -4
  30. package/app/Actions/Dashboard/Commerce/CommerceProductsAction.ts +2 -4
  31. package/app/Actions/Dashboard/Commerce/CommerceTaxesAction.ts +2 -4
  32. package/app/Actions/Dashboard/Commerce/DeliveryRouteIndexAction.ts +2 -4
  33. package/app/Actions/Dashboard/Commerce/DigitalDeliveryIndexAction.ts +2 -4
  34. package/app/Actions/Dashboard/Commerce/DriverIndexAction.ts +2 -4
  35. package/app/Actions/Dashboard/Commerce/LicenseKeyIndexAction.ts +2 -4
  36. package/app/Actions/Dashboard/Commerce/LicenseKeyOptionsAction.ts +2 -4
  37. package/app/Actions/Dashboard/Commerce/ManufacturerIndexAction.ts +2 -4
  38. package/app/Actions/Dashboard/Commerce/PaymentRefundAction.ts +1 -0
  39. package/app/Actions/Dashboard/Commerce/ProductUnitDefaultAction.ts +1 -0
  40. package/app/Actions/Dashboard/Commerce/ProductUnitIndexAction.ts +2 -4
  41. package/app/Actions/Dashboard/Commerce/ProductVariantIndexAction.ts +2 -4
  42. package/app/Actions/Dashboard/Commerce/ProductWaitlistIndexAction.ts +2 -4
  43. package/app/Actions/Dashboard/Commerce/RestaurantWaitlistIndexAction.ts +2 -4
  44. package/app/Actions/Dashboard/Commerce/ReviewIndexAction.ts +2 -4
  45. package/app/Actions/Dashboard/Commerce/ShippingMethodIndexAction.ts +2 -4
  46. package/app/Actions/Dashboard/Commerce/ShippingRateIndexAction.ts +2 -4
  47. package/app/Actions/Dashboard/Commerce/ShippingZoneIndexAction.ts +2 -4
  48. package/app/Actions/Dashboard/Commerce/TaxRateDefaultAction.ts +1 -0
  49. package/app/Actions/Dashboard/DashboardActivityAction.ts +2 -5
  50. package/app/Actions/Dashboard/Data/ActivityIndexAction.ts +2 -5
  51. package/app/Actions/Dashboard/Data/SubscriberIndexAction.ts +2 -5
  52. package/app/Actions/Dashboard/Data/TeamIndexAction.ts +2 -5
  53. package/app/Actions/Dashboard/Data/UserIndexAction.ts +2 -5
  54. package/app/Actions/Dashboard/Deployments/CreateDeployment.ts +26 -21
  55. package/app/Actions/Dashboard/Deployments/GetAverageDeploymentTime.ts +8 -2
  56. package/app/Actions/Dashboard/Deployments/GetDeployScript.ts +3 -6
  57. package/app/Actions/Dashboard/Deployments/GetDeployment.ts +5 -5
  58. package/app/Actions/Dashboard/Deployments/GetDeploymentCount.ts +7 -1
  59. package/app/Actions/Dashboard/Deployments/GetDeploymentLiveTerminalOutput.ts +10 -9
  60. package/app/Actions/Dashboard/Deployments/GetDeployments.ts +2 -4
  61. package/app/Actions/Dashboard/Deployments/GetRecentDeployments.ts +8 -2
  62. package/app/Actions/Dashboard/Deployments/UpdateDeployScript.ts +21 -7
  63. package/app/Actions/Dashboard/Email/CapturedMailIndexAction.ts +2 -4
  64. package/app/Actions/Dashboard/Email/CapturedMailShowAction.ts +3 -4
  65. package/app/Actions/Dashboard/Email/InboxActivityAction.ts +28 -16
  66. package/app/Actions/Dashboard/Email/InboxAttachmentDownloadAction.ts +45 -0
  67. package/app/Actions/Dashboard/Email/InboxDeleteAction.ts +11 -6
  68. package/app/Actions/Dashboard/Email/InboxIndexAction.ts +5 -7
  69. package/app/Actions/Dashboard/Email/InboxMarkReadAction.ts +11 -6
  70. package/app/Actions/Dashboard/Email/InboxMarkUnreadAction.ts +11 -6
  71. package/app/Actions/Dashboard/Email/InboxPreferenceShowAction.ts +10 -4
  72. package/app/Actions/Dashboard/Email/InboxPreferenceUpdateAction.ts +8 -9
  73. package/app/Actions/Dashboard/Email/InboxShowAction.ts +7 -7
  74. package/app/Actions/Dashboard/Email/InboxStatsAction.ts +5 -7
  75. package/app/Actions/Dashboard/Email/inbox-request.ts +33 -0
  76. package/app/Actions/Dashboard/Infrastructure/InsightsAction.ts +15 -14
  77. package/app/Actions/Dashboard/Infrastructure/LogIndexAction.ts +4 -11
  78. package/app/Actions/Dashboard/Infrastructure/ServerShowAction.ts +3 -6
  79. package/app/Actions/Dashboard/Jobs/JobIndexAction.ts +9 -18
  80. package/app/Actions/Dashboard/Jobs/JobRetryAction.ts +4 -3
  81. package/app/Actions/Dashboard/Jobs/JobShowAction.ts +16 -11
  82. package/app/Actions/Dashboard/Jobs/JobStatsAction.ts +2 -4
  83. package/app/Actions/Dashboard/Kanban/BoardDestroyAction.ts +7 -8
  84. package/app/Actions/Dashboard/Kanban/BoardShowAction.ts +11 -19
  85. package/app/Actions/Dashboard/Kanban/BoardStoreAction.ts +6 -6
  86. package/app/Actions/Dashboard/Kanban/BoardUpdateAction.ts +7 -8
  87. package/app/Actions/Dashboard/Kanban/BoardsIndexAction.ts +3 -5
  88. package/app/Actions/Dashboard/Kanban/BoardsReorderAction.ts +6 -6
  89. package/app/Actions/Dashboard/Kanban/CardAssigneesSyncAction.ts +13 -12
  90. package/app/Actions/Dashboard/Kanban/CardCommentDestroyAction.ts +12 -15
  91. package/app/Actions/Dashboard/Kanban/CardCommentStoreAction.ts +21 -46
  92. package/app/Actions/Dashboard/Kanban/CardCommentUpdateAction.ts +43 -0
  93. package/app/Actions/Dashboard/Kanban/CardDestroyAction.ts +7 -8
  94. package/app/Actions/Dashboard/Kanban/CardLabelsSyncAction.ts +8 -9
  95. package/app/Actions/Dashboard/Kanban/CardShowAction.ts +6 -7
  96. package/app/Actions/Dashboard/Kanban/CardStoreAction.ts +9 -9
  97. package/app/Actions/Dashboard/Kanban/CardUpdateAction.ts +7 -8
  98. package/app/Actions/Dashboard/Kanban/CardsReorderAction.ts +6 -6
  99. package/app/Actions/Dashboard/Kanban/ColumnDestroyAction.ts +7 -8
  100. package/app/Actions/Dashboard/Kanban/ColumnStoreAction.ts +6 -6
  101. package/app/Actions/Dashboard/Kanban/ColumnUpdateAction.ts +7 -8
  102. package/app/Actions/Dashboard/Kanban/ColumnsReorderAction.ts +6 -6
  103. package/app/Actions/Dashboard/Kanban/LabelDestroyAction.ts +6 -7
  104. package/app/Actions/Dashboard/Kanban/LabelStoreAction.ts +6 -6
  105. package/app/Actions/Dashboard/Kanban/LabelUpdateAction.ts +7 -8
  106. package/app/Actions/Dashboard/Kanban/UsersListAction.ts +3 -4
  107. package/app/Actions/Dashboard/Kanban/kanban-comment.ts +14 -0
  108. package/app/Actions/Dashboard/Kanban/kanban-model.test.ts +36 -0
  109. package/app/Actions/Dashboard/Kanban/kanban-model.ts +14 -7
  110. package/app/Actions/Dashboard/Kanban/kanban-response.ts +5 -0
  111. package/app/Actions/Dashboard/Library/CreateComponent.ts +15 -6
  112. package/app/Actions/Dashboard/Library/CreateFunction.ts +15 -6
  113. package/app/Actions/Dashboard/Library/DependencyIndexAction.ts +88 -77
  114. package/app/Actions/Dashboard/Library/GetAverageReleaseTime.ts +21 -15
  115. package/app/Actions/Dashboard/Library/GetComponents.ts +14 -7
  116. package/app/Actions/Dashboard/Library/GetDownloadCount.ts +14 -5
  117. package/app/Actions/Dashboard/Library/GetFunctions.ts +12 -5
  118. package/app/Actions/Dashboard/Library/GetReleaseCount.ts +14 -5
  119. package/app/Actions/Dashboard/Library/GetReleases.ts +17 -10
  120. package/app/Actions/Dashboard/Library/PackageIndexAction.ts +14 -7
  121. package/app/Actions/Dashboard/Models/ModelDestroyAction.ts +11 -8
  122. package/app/Actions/Dashboard/Models/ModelShowAction.ts +97 -192
  123. package/app/Actions/Dashboard/Models/ModelStoreAction.ts +14 -12
  124. package/app/Actions/Dashboard/Models/ModelUpdateAction.ts +18 -16
  125. package/app/Actions/Dashboard/Models/ModelsIndexAction.ts +50 -19
  126. package/app/Actions/Dashboard/Models/model-api.ts +27 -0
  127. package/app/Actions/Dashboard/Models/model-write.ts +22 -15
  128. package/app/Actions/Dashboard/Notifications/NotificationDeliveryHistoryAction.ts +49 -40
  129. package/app/Actions/Dashboard/Notifications/NotificationDeliveryIndexAction.ts +20 -10
  130. package/app/Actions/Dashboard/Notifications/NotificationDeliveryOverviewAction.ts +96 -84
  131. package/app/Actions/Dashboard/Notifications/NotificationDeliveryRetryAction.ts +34 -21
  132. package/app/Actions/Dashboard/Queries/QueryDashboardAction.ts +2 -4
  133. package/app/Actions/Dashboard/Queries/QueryShowAction.ts +3 -3
  134. package/app/Actions/Dashboard/Queue/QueueStatsAction.ts +2 -4
  135. package/app/Actions/Dashboard/Queue/QueueWorkersAction.ts +2 -4
  136. package/app/Actions/Dashboard/Rbac/PermissionDestroyAction.ts +6 -6
  137. package/app/Actions/Dashboard/Rbac/PermissionStoreAction.ts +5 -4
  138. package/app/Actions/Dashboard/Rbac/PermissionsIndexAction.ts +2 -3
  139. package/app/Actions/Dashboard/Rbac/RoleDestroyAction.ts +6 -6
  140. package/app/Actions/Dashboard/Rbac/RolePermissionsShowAction.ts +6 -6
  141. package/app/Actions/Dashboard/Rbac/RolePermissionsSyncAction.ts +6 -9
  142. package/app/Actions/Dashboard/Rbac/RoleStoreAction.ts +5 -4
  143. package/app/Actions/Dashboard/Rbac/RolesIndexAction.ts +4 -6
  144. package/app/Actions/Dashboard/Rbac/UserRolesShowAction.ts +6 -7
  145. package/app/Actions/Dashboard/Rbac/UserRolesSyncAction.ts +6 -13
  146. package/app/Actions/Dashboard/Rbac/UsersListAction.ts +2 -3
  147. package/app/Actions/Dashboard/Rbac/rbac-response.ts +10 -0
  148. package/app/Actions/Dashboard/Realtime/RealtimeStatsAction.ts +2 -4
  149. package/app/Actions/Dashboard/Search/GlobalSearchAction.ts +69 -55
  150. package/app/Actions/Dashboard/Teams/TeamInvitationDestroyAction.ts +34 -16
  151. package/app/Actions/Dashboard/Teams/TeamInvitationResendAction.ts +52 -29
  152. package/app/Actions/Dashboard/Teams/TeamInviteAction.ts +104 -73
  153. package/app/Actions/Dashboard/Teams/TeamMemberDestroyAction.ts +36 -17
  154. package/app/Actions/Dashboard/Teams/TeamMemberUpdateAction.ts +41 -28
  155. package/app/Actions/Dashboard/Teams/TeamPeopleIndexAction.ts +71 -58
  156. package/app/Actions/Dashboard/Teams/team-invitation-delivery.ts +29 -7
  157. package/app/Actions/Dashboard/Teams/team-member-count.ts +4 -2
  158. package/app/Actions/Dashboard/Teams/team-records.test.ts +2 -0
  159. package/app/Actions/Dashboard/Teams/team-records.ts +2 -0
  160. package/app/Actions/Dashboard/dashboard-request.ts +13 -0
  161. package/app/Actions/Dashboard/dashboard-response.ts +16 -0
  162. package/app/Actions/SendWelcomeEmail.ts +1 -1
  163. package/app/Actions/Teams/AcceptInvitationAction.ts +74 -51
  164. package/app/Actions/Teams/ShowInvitationAction.ts +21 -14
  165. package/app/Actions/Teams/team-response.ts +23 -0
  166. package/app/Mail/OrderConfirmation.ts +1 -1
  167. package/app/Mail/SubscriptionConfirmation.ts +1 -1
  168. package/app/Mail/TeamInvitation.ts +1 -1
  169. package/app/Models/CardComment.ts +3 -4
  170. package/app/Models/EmailIdempotency.ts +64 -0
  171. package/app/Models/EmailSuppression.ts +52 -0
  172. package/app/Models/EmailWebhookEvent.ts +51 -0
  173. package/app/Models/TeamInvitation.ts +13 -0
  174. package/functions/dashboard-api.ts +51 -10
  175. package/functions/data.ts +0 -1
  176. package/functions/inbox.test.ts +2 -0
  177. package/functions/inbox.ts +27 -2
  178. package/functions/jobs.ts +0 -1
  179. package/functions/public-application-url.test.ts +13 -0
  180. package/functions/public-application-url.ts +27 -0
  181. package/ide/vscode/package.json +1 -1
  182. package/package.json +1 -1
  183. package/resources/components/Dashboard/Auth/AccessTokens.stx +15 -0
  184. package/resources/components/Dashboard/Ci/CiDashboard.stx +24 -6
  185. package/resources/components/Dashboard/Commerce/CommerceTaxDialog.stx +1 -1
  186. package/resources/components/Dashboard/Commerce/ProductWaitlistDashboard.stx +8 -7
  187. package/resources/components/Dashboard/Commerce/RestaurantWaitlistDashboard.stx +8 -7
  188. package/resources/components/Dashboard/Content/BlogDashboard.stx +14 -2
  189. package/resources/components/Dashboard/Content/PostsDashboard.stx +7 -1
  190. package/resources/components/Dashboard/Data/DataRecords.stx +0 -4
  191. package/resources/components/Dashboard/Deployments/DeploymentDetail.stx +16 -2
  192. package/resources/components/Dashboard/Email/EmailNavigation.stx +5 -5
  193. package/resources/components/Dashboard/Email/EmailSidebar.stx +1 -1
  194. package/resources/components/Dashboard/Email/InboxAttachmentList.stx +53 -0
  195. package/resources/components/Dashboard/Email/InboxDashboard.stx +5 -4
  196. package/resources/components/Dashboard/Email/InboxMessageDetail.stx +6 -4
  197. package/resources/components/Dashboard/Jobs/JobDetail.stx +3 -2
  198. package/resources/components/Dashboard/Kanban/KanbanBoardDashboard.stx +63 -6
  199. package/resources/components/Dashboard/Kanban/KanbanBoardsDashboard.stx +3 -6
  200. package/resources/components/Dashboard/Management/PermissionsDashboard.stx +4 -4
  201. package/resources/components/Dashboard/Models/ModelRecordsDashboard.stx +7 -13
  202. package/resources/components/Dashboard/Models/ModelsOverview.stx +1 -1
  203. package/resources/components/Dashboard/NotFoundDashboard.stx +2 -5
  204. package/resources/components/Dashboard/Queries/QueryDashboard.stx +6 -2
  205. package/resources/components/Dashboard/Settings/AppearanceSettingsDashboard.stx +4 -4
  206. package/resources/components/Dashboard/UI/EmptyState.stx +2 -2
  207. package/resources/components/Dashboard/UI/PageLayout.stx +3 -3
  208. package/resources/functions/dashboard/sidebar.ts +4 -4
  209. package/routes/dashboard-api.ts +8 -20
  210. package/views/dashboard/.discovered-models.json +54 -0
  211. package/views/dashboard/layouts/default.stx +19 -16
  212. package/views/dashboard/stores/auth.ts +15 -14
  213. package/views/dashboard/stores/ci.ts +13 -7
  214. package/views/dashboard/stores/kanban.ts +48 -11
@@ -4,6 +4,7 @@ import { Action } from '@stacksjs/actions'
4
4
  import { buddyState, createAIClient } from '@stacksjs/ai'
5
5
  import { config } from '@stacksjs/config'
6
6
  import { response } from '@stacksjs/router'
7
+ import { dashboardOperationalError } from '../dashboard-response'
7
8
  import { buddySystemPrompt, isBuddyProviderConfigured, publicBuddyHistory, resolveBuddyProvider } from './buddy-chat'
8
9
 
9
10
  export default new Action({
@@ -49,9 +50,7 @@ export default new Action({
49
50
  }
50
51
  }
51
52
  catch (error) {
52
- return response.json({
53
- message: error instanceof Error ? error.message : 'Buddy could not answer the question.',
54
- }, 502)
53
+ return dashboardOperationalError(error, 'Buddy could not answer the question.', 'BuddyChatAction', 502)
55
54
  }
56
55
  },
57
56
  })
@@ -1,6 +1,8 @@
1
+ import type { RequestInstance } from '@stacksjs/types'
1
2
  import { Action } from '@stacksjs/actions'
2
3
  import { dashboard as dashboardConfig } from '@stacksjs/config'
3
4
  import { fetchRunJobs } from '@stacksjs/github'
5
+ import { response } from '@stacksjs/router'
4
6
 
5
7
  /**
6
8
  * `GET /api/dashboard/ci/repos/:owner/:name/runs/:runId/jobs`
@@ -19,27 +21,26 @@ export default new Action({
19
21
  description: 'Job-level breakdown for a single workflow run (drilldown expand).',
20
22
  method: 'GET',
21
23
  apiResponse: true,
22
- async handle(request) {
24
+ async handle(request: RequestInstance) {
23
25
  const ci = dashboardConfig?.ci
24
26
 
25
27
  if (!ci?.enabled) {
26
28
  return { jobs: [], disabled: true }
27
29
  }
28
30
 
29
- const owner = String((request as any)?.params?.owner ?? (request as any)?.param?.('owner') ?? '').trim()
30
- const repo = String((request as any)?.params?.name ?? (request as any)?.param?.('name') ?? '').trim()
31
- const runIdRaw = (request as any)?.params?.runId ?? (request as any)?.param?.('runId') ?? null
32
- const runId = Number(runIdRaw)
31
+ const owner = request.getParam('owner').trim()
32
+ const repo = request.getParam('name').trim()
33
+ const runId = Number(request.getParam('runId'))
33
34
  if (!owner || !repo) {
34
- return { error: 'Both `owner` and `name` route params are required.', status: 400 }
35
+ return response.json({ message: 'Both owner and name route parameters are required.' }, 400)
35
36
  }
36
37
  if (!Number.isFinite(runId) || runId <= 0) {
37
- return { error: '`runId` must be a positive integer.', status: 400 }
38
+ return response.json({ message: 'The run ID must be a positive integer.' }, 400)
38
39
  }
39
40
 
40
41
  const allowedOrgs = ci.orgs ?? []
41
42
  if (allowedOrgs.length > 0 && !allowedOrgs.includes(owner)) {
42
- return { error: 'Org not in `config.dashboard.ci.orgs`.', status: 403 }
43
+ return response.json({ message: 'This organization is not configured for CI tracking.' }, 403)
43
44
  }
44
45
 
45
46
  try {
@@ -48,13 +49,7 @@ export default new Action({
48
49
  }
49
50
  catch (err) {
50
51
  console.error('[dashboard/ci] RepoRunJobsAction failed:', err)
51
- return {
52
- owner,
53
- repo,
54
- runId,
55
- jobs: [],
56
- error: err instanceof Error ? err.message : 'unknown error',
57
- }
52
+ return response.json({ message: 'Workflow jobs could not be loaded.' }, 502)
58
53
  }
59
54
  },
60
55
  })
@@ -1,6 +1,9 @@
1
+ import type { RequestInstance } from '@stacksjs/types'
1
2
  import { Action } from '@stacksjs/actions'
2
3
  import { dashboard as dashboardConfig } from '@stacksjs/config'
3
4
  import { fetchWorkflowRuns } from '@stacksjs/github'
5
+ import { response } from '@stacksjs/router'
6
+ import { dashboardRequestValue } from '../dashboard-request'
4
7
 
5
8
  /**
6
9
  * `GET /api/dashboard/ci/repos/:owner/:name/runs?limit=N`
@@ -23,32 +26,32 @@ export default new Action({
23
26
  description: 'Latest N workflow runs for a single repo (drilldown).',
24
27
  method: 'GET',
25
28
  apiResponse: true,
26
- async handle(request) {
29
+ async handle(request: RequestInstance) {
27
30
  const ci = dashboardConfig?.ci
28
31
 
29
32
  if (!ci?.enabled) {
30
33
  return { owner: null, repo: null, runs: [], disabled: true }
31
34
  }
32
35
 
33
- const owner = String((request as any)?.params?.owner ?? (request as any)?.param?.('owner') ?? '').trim()
34
- const repo = String((request as any)?.params?.name ?? (request as any)?.param?.('name') ?? '').trim()
36
+ const owner = request.getParam('owner').trim()
37
+ const repo = request.getParam('name').trim()
35
38
  if (!owner || !repo) {
36
- return { error: 'Both `owner` and `name` route params are required.', status: 400 }
39
+ return response.json({ message: 'Both owner and name route parameters are required.' }, 400)
37
40
  }
38
41
 
39
42
  // Scope check: only fetch runs for orgs the user explicitly
40
43
  // configured. Stops the endpoint from being a generic GH proxy.
41
44
  const allowedOrgs = ci.orgs ?? []
42
45
  if (allowedOrgs.length > 0 && !allowedOrgs.includes(owner)) {
43
- return { error: 'Org not in `config.dashboard.ci.orgs`.', status: 403 }
46
+ return response.json({ message: 'This organization is not configured for CI tracking.' }, 403)
44
47
  }
45
48
 
46
- const url = new URL(request.url ?? `http://localhost/`)
47
- const rawLimit = Number(url.searchParams.get('limit') ?? '20')
49
+ const rawLimit = Number(dashboardRequestValue(request, 'limit', '20'))
48
50
  const limit = Number.isFinite(rawLimit) && rawLimit > 0
49
51
  ? Math.min(Math.floor(rawLimit), 100)
50
52
  : 20
51
- const branch = url.searchParams.get('branch') || undefined
53
+ const branchValue = dashboardRequestValue(request, 'branch')
54
+ const branch = branchValue || undefined
52
55
 
53
56
  try {
54
57
  const runs = await fetchWorkflowRuns(owner, repo, { limit, branch })
@@ -56,12 +59,7 @@ export default new Action({
56
59
  }
57
60
  catch (err) {
58
61
  console.error('[dashboard/ci] RepoRunsAction failed:', err)
59
- return {
60
- owner,
61
- repo,
62
- runs: [],
63
- error: err instanceof Error ? err.message : 'unknown error',
64
- }
62
+ return response.json({ message: 'Workflow runs could not be loaded.' }, 502)
65
63
  }
66
64
  },
67
65
  })
@@ -1,5 +1,8 @@
1
+ import type { RequestInstance } from '@stacksjs/types'
1
2
  import { Action } from '@stacksjs/actions'
2
3
  import { dashboard as dashboardConfig } from '@stacksjs/config'
4
+ import { response } from '@stacksjs/router'
5
+ import { dashboardRequestValue } from '../dashboard-request'
3
6
  import { fetchRunnerHistory } from './runner-pressure-monitor'
4
7
 
5
8
  /**
@@ -12,33 +15,31 @@ import { fetchRunnerHistory } from './runner-pressure-monitor'
12
15
  * configured retention window — older samples aren't available
13
16
  * because they've been pruned.
14
17
  *
15
- * Soft-errors to an empty samples array on any failure so the
16
- * sparkline gracefully degrades to "no history yet" instead of
17
- * yelling at the user.
18
+ * Operational failures use a real 503 response so the client can
19
+ * distinguish unavailable history from a valid empty sample set.
18
20
  */
19
21
  export default new Action({
20
22
  name: 'Dashboard CI Runner History',
21
23
  description: 'Recent runner-sample history for one org (sparkline data).',
22
24
  method: 'GET',
23
25
  apiResponse: true,
24
- async handle(request) {
26
+ async handle(request: RequestInstance) {
25
27
  const ci = dashboardConfig?.ci
26
28
  if (!ci?.enabled || !ci.alerts?.enabled) {
27
29
  return { org: null, samples: [], disabled: true }
28
30
  }
29
31
 
30
- const url = new URL(request.url ?? 'http://localhost/')
31
- const org = String(url.searchParams.get('org') ?? '').trim()
32
+ const org = dashboardRequestValue(request, 'org')
32
33
  if (!org) {
33
- return { error: '`org` query param is required.', status: 400 }
34
+ return response.json({ message: 'The org query parameter is required.' }, 400)
34
35
  }
35
36
 
36
37
  const allowedOrgs = ci.orgs ?? []
37
38
  if (allowedOrgs.length > 0 && !allowedOrgs.includes(org)) {
38
- return { error: 'Org not in `config.dashboard.ci.orgs`.', status: 403 }
39
+ return response.json({ message: 'This organization is not configured for CI tracking.' }, 403)
39
40
  }
40
41
 
41
- const rawLimit = Number(url.searchParams.get('limit') ?? '60')
42
+ const rawLimit = Number(dashboardRequestValue(request, 'limit', '60'))
42
43
  const limit = Number.isFinite(rawLimit) && rawLimit > 0
43
44
  ? Math.min(Math.floor(rawLimit), 500)
44
45
  : 60
@@ -52,7 +53,7 @@ export default new Action({
52
53
  }
53
54
  catch (err) {
54
55
  console.error('[dashboard/ci] RunnerHistoryAction failed:', err)
55
- return { org, samples: [], error: err instanceof Error ? err.message : 'unknown error' }
56
+ return response.json({ message: 'Runner history could not be loaded.' }, 503)
56
57
  }
57
58
  },
58
59
  })
@@ -1,6 +1,7 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { dashboard as dashboardConfig } from '@stacksjs/config'
3
3
  import { getDashboardData } from '@stacksjs/github'
4
+ import { response } from '@stacksjs/router'
4
5
  import { runCiFailureNotifier } from './failure-notifier'
5
6
  import { runRunnerPressureMonitor } from './runner-pressure-monitor'
6
7
 
@@ -57,17 +58,7 @@ export default new Action({
57
58
  // shape the page can render without leaking the env-var name to
58
59
  // every browser viewing the dashboard.
59
60
  console.error('[dashboard/ci] snapshot failed:', err)
60
- return {
61
- repos: [],
62
- fetchedAt: new Date().toISOString(),
63
- total: 0,
64
- passing: 0,
65
- failing: 0,
66
- pending: 0,
67
- noRuns: 0,
68
- runners: {},
69
- error: err instanceof Error ? err.message : 'unknown error',
70
- }
61
+ return response.json({ message: 'CI status could not be loaded.' }, 502)
71
62
  }
72
63
  },
73
64
  })
@@ -1,12 +1,19 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { tsCloud } from '~/config/cloud'
3
+ import { dashboardOperationalError } from '../dashboard-response'
3
4
  import { getDashboardCloudSnapshot } from './cloud-overview'
4
5
 
5
6
  export default new Action({
6
7
  name: 'CloudIndexAction',
7
8
  description: 'Returns configured cloud infrastructure and persisted deployment state.',
8
9
  method: 'GET',
10
+ apiResponse: true,
9
11
  async handle() {
10
- return getDashboardCloudSnapshot(tsCloud)
12
+ try {
13
+ return await getDashboardCloudSnapshot(tsCloud)
14
+ }
15
+ catch (error) {
16
+ return dashboardOperationalError(error, 'Cloud infrastructure could not be loaded.', 'CloudIndexAction')
17
+ }
11
18
  },
12
19
  })
@@ -1,20 +1,27 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { tsCloud } from '~/config/cloud'
3
+ import { dashboardOperationalError } from '../dashboard-response'
3
4
  import { getDashboardCloudSnapshot } from './cloud-overview'
4
5
 
5
6
  export default new Action({
6
7
  name: 'ServerlessIndexAction',
7
8
  description: 'Returns serverless services derived from environment application manifests.',
8
9
  method: 'GET',
10
+ apiResponse: true,
9
11
  async handle() {
10
- const snapshot = await getDashboardCloudSnapshot(tsCloud)
11
- return {
12
- project: snapshot.project,
13
- environments: snapshot.environments.filter(environment => environment.serverless),
14
- services: snapshot.serverlessServices,
15
- links: snapshot.serverlessLinks,
16
- events: snapshot.events.filter(event => event.service.toLowerCase().includes('serverless')),
17
- generatedAt: snapshot.generatedAt,
12
+ try {
13
+ const snapshot = await getDashboardCloudSnapshot(tsCloud)
14
+ return {
15
+ project: snapshot.project,
16
+ environments: snapshot.environments.filter(environment => environment.serverless),
17
+ services: snapshot.serverlessServices,
18
+ links: snapshot.serverlessLinks,
19
+ events: snapshot.events.filter(event => event.service.toLowerCase().includes('serverless')),
20
+ generatedAt: snapshot.generatedAt,
21
+ }
22
+ }
23
+ catch (error) {
24
+ return dashboardOperationalError(error, 'Serverless infrastructure could not be loaded.', 'ServerlessIndexAction')
18
25
  }
19
26
  },
20
27
  })
@@ -1,6 +1,6 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { Category } from '@stacksjs/orm'
3
- import { response } from '@stacksjs/router'
3
+ import { dashboardOperationalError } from '../dashboard-response'
4
4
  import { normalizeCommerceCategoryRecord, summarizeCommerceCategories } from './commerce-category-records'
5
5
 
6
6
  export default new Action({
@@ -24,9 +24,7 @@ export default new Action({
24
24
  }
25
25
  }
26
26
  catch (error) {
27
- return response.json({
28
- message: error instanceof Error ? error.message : 'Category records could not be read.',
29
- }, 503)
27
+ return dashboardOperationalError(error, 'Category records could not be read.', 'CommerceCategoriesAction')
30
28
  }
31
29
  },
32
30
  })
@@ -1,6 +1,6 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { Coupon, Product } from '@stacksjs/orm'
3
- import { response } from '@stacksjs/router'
3
+ import { dashboardOperationalError } from '../dashboard-response'
4
4
  import { normalizeCouponRecord, summarizeCoupons } from './coupon-records'
5
5
  import { commerceIdentifier, commerceValue } from './commerce-record'
6
6
 
@@ -26,9 +26,7 @@ export default new Action({
26
26
  }
27
27
  }
28
28
  catch (error) {
29
- return response.json({
30
- message: error instanceof Error ? error.message : 'Coupon records could not be read.',
31
- }, 503)
29
+ return dashboardOperationalError(error, 'Coupon records could not be read.', 'CommerceCouponsAction')
32
30
  }
33
31
  },
34
32
  })
@@ -1,7 +1,7 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { config } from '@stacksjs/config'
3
3
  import { Customer } from '@stacksjs/orm'
4
- import { response } from '@stacksjs/router'
4
+ import { dashboardOperationalError } from '../dashboard-response'
5
5
  import {
6
6
  normalizeCommerceCustomerCurrency,
7
7
  normalizeCommerceCustomerRecord,
@@ -25,9 +25,7 @@ export default new Action({
25
25
  }
26
26
  }
27
27
  catch (error) {
28
- return response.json({
29
- message: error instanceof Error ? error.message : 'Customer records could not be read.',
30
- }, 503)
28
+ return dashboardOperationalError(error, 'Customer records could not be read.', 'CommerceCustomersAction')
31
29
  }
32
30
  },
33
31
  })
@@ -1,7 +1,7 @@
1
1
  import type { RequestInstance } from '@stacksjs/types'
2
2
  import { Action } from '@stacksjs/actions'
3
3
  import { Customer, Order, OrderItem, Product } from '@stacksjs/orm'
4
- import { response } from '@stacksjs/router'
4
+ import { dashboardOperationalError } from '../dashboard-response'
5
5
  import {
6
6
  buildCommerceDashboard,
7
7
  commerceDashboardQueryStart,
@@ -56,9 +56,7 @@ export default new Action({
56
56
  )
57
57
  }
58
58
  catch (error) {
59
- return response.json({
60
- message: error instanceof Error ? error.message : 'Commerce overview records could not be read.',
61
- }, 503)
59
+ return dashboardOperationalError(error, 'Commerce overview records could not be read.', 'CommerceDashboardAction')
62
60
  }
63
61
  },
64
62
  })
@@ -1,7 +1,7 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { config } from '@stacksjs/config'
3
3
  import { DeliveryRoute, Driver, ShippingMethod, ShippingZone } from '@stacksjs/orm'
4
- import { response } from '@stacksjs/router'
4
+ import { dashboardOperationalError } from '../dashboard-response'
5
5
  import { buildDeliveryOverview } from './commerce-delivery'
6
6
 
7
7
  export default new Action({
@@ -28,9 +28,7 @@ export default new Action({
28
28
  )
29
29
  }
30
30
  catch (error) {
31
- return response.json({
32
- message: error instanceof Error ? error.message : 'Delivery records could not be read.',
33
- }, 503)
31
+ return dashboardOperationalError(error, 'Delivery records could not be read.', 'CommerceDeliveryAction')
34
32
  }
35
33
  },
36
34
  })
@@ -1,6 +1,6 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { Customer, GiftCard } from '@stacksjs/orm'
3
- import { response } from '@stacksjs/router'
3
+ import { dashboardOperationalError } from '../dashboard-response'
4
4
  import { normalizeGiftCardRecord, summarizeGiftCards } from './gift-card-records'
5
5
  import { commerceIdentifier, commerceValue } from './commerce-record'
6
6
 
@@ -26,9 +26,7 @@ export default new Action({
26
26
  }
27
27
  }
28
28
  catch (error) {
29
- return response.json({
30
- message: error instanceof Error ? error.message : 'Gift card records could not be read.',
31
- }, 503)
29
+ return dashboardOperationalError(error, 'Gift card records could not be read.', 'CommerceGiftCardsAction')
32
30
  }
33
31
  },
34
32
  })
@@ -1,7 +1,7 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { config } from '@stacksjs/config'
3
3
  import { Coupon, Customer, Order, OrderItem } from '@stacksjs/orm'
4
- import { response } from '@stacksjs/router'
4
+ import { dashboardOperationalError } from '../dashboard-response'
5
5
  import {
6
6
  addOrderItemQuantity,
7
7
  normalizeCommerceOrderRecord,
@@ -54,9 +54,7 @@ export default new Action({
54
54
  }
55
55
  }
56
56
  catch (error) {
57
- return response.json({
58
- message: error instanceof Error ? error.message : 'Order records could not be read.',
59
- }, 503)
57
+ return dashboardOperationalError(error, 'Order records could not be read.', 'CommerceOrdersAction')
60
58
  }
61
59
  },
62
60
  })
@@ -1,6 +1,6 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { Customer, Order, Payment } from '@stacksjs/orm'
3
- import { response } from '@stacksjs/router'
3
+ import { dashboardOperationalError } from '../dashboard-response'
4
4
  import { commerceIdentifier, commerceValue } from './commerce-record'
5
5
  import { normalizePaymentRecord, summarizePayments } from './payment-records'
6
6
 
@@ -32,9 +32,7 @@ export default new Action({
32
32
  }
33
33
  }
34
34
  catch (error) {
35
- return response.json({
36
- message: error instanceof Error ? error.message : 'Payment records could not be read.',
37
- }, 503)
35
+ return dashboardOperationalError(error, 'Payment records could not be read.', 'CommercePaymentsAction')
38
36
  }
39
37
  },
40
38
  })
@@ -1,7 +1,7 @@
1
1
  import { Action } from '@stacksjs/actions'
2
2
  import { config } from '@stacksjs/config'
3
3
  import { Category, Customer, Manufacturer, Product, TaxRate } from '@stacksjs/orm'
4
- import { response } from '@stacksjs/router'
4
+ import { dashboardOperationalError } from '../dashboard-response'
5
5
  import {
6
6
  isCommercePosCustomerActive,
7
7
  normalizeCommercePosCustomer,
@@ -63,9 +63,7 @@ export default new Action({
63
63
  }
64
64
  }
65
65
  catch (error) {
66
- return response.json({
67
- message: error instanceof Error ? error.message : 'Point of sale records could not be read.',
68
- }, 503)
66
+ return dashboardOperationalError(error, 'Point of sale records could not be read.', 'CommercePosAction')
69
67
  }
70
68
  },
71
69
  })