@atolis-hq/wake 0.4.56 → 0.4.58

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 (47) hide show
  1. package/README.md +4 -0
  2. package/dist/src/bootstrap/analytics-reports.d.ts +27 -0
  3. package/dist/src/bootstrap/analytics-reports.js +38 -0
  4. package/dist/src/bootstrap/surface-api-applications.js +2 -0
  5. package/dist/src/bootstrap/version.js +1 -1
  6. package/dist/src/execution/application/run-reports.d.ts +29 -0
  7. package/dist/src/execution/application/run-reports.js +116 -0
  8. package/dist/src/execution/contracts/runner.js +1 -1
  9. package/dist/src/execution/domain/run.d.ts +2 -0
  10. package/dist/src/execution/domain/run.js +10 -0
  11. package/dist/src/execution/index.d.ts +1 -0
  12. package/dist/src/execution/index.js +1 -0
  13. package/dist/src/kernel/contracts/reports.d.ts +39 -0
  14. package/dist/src/kernel/contracts/reports.js +53 -0
  15. package/dist/src/kernel/index.d.ts +1 -0
  16. package/dist/src/kernel/index.js +1 -0
  17. package/dist/src/node_modules/@atolis-hq/eventing/dist/index.d.ts +1 -0
  18. package/dist/src/node_modules/@atolis-hq/eventing/dist/index.d.ts.map +1 -1
  19. package/dist/src/node_modules/@atolis-hq/eventing/dist/index.js +1 -0
  20. package/dist/src/node_modules/@atolis-hq/eventing/dist/store/event-journal.d.ts +2 -0
  21. package/dist/src/node_modules/@atolis-hq/eventing/dist/store/event-journal.d.ts.map +1 -1
  22. package/dist/src/node_modules/@atolis-hq/eventing/dist/store/scan-journal.d.ts +5 -0
  23. package/dist/src/node_modules/@atolis-hq/eventing/dist/store/scan-journal.d.ts.map +1 -0
  24. package/dist/src/node_modules/@atolis-hq/eventing/dist/store/scan-journal.js +34 -0
  25. package/dist/src/node_modules/@atolis-hq/eventing-filesystem/dist/file-event-journal.d.ts +4 -0
  26. package/dist/src/node_modules/@atolis-hq/eventing-filesystem/dist/file-event-journal.d.ts.map +1 -1
  27. package/dist/src/node_modules/@atolis-hq/eventing-filesystem/dist/file-event-journal.js +60 -2
  28. package/dist/src/orchestration/application/work-completion-summary.d.ts +6 -0
  29. package/dist/src/orchestration/application/work-completion-summary.js +49 -0
  30. package/dist/src/orchestration/index.d.ts +1 -0
  31. package/dist/src/orchestration/index.js +1 -0
  32. package/dist/src/surfaces/api/contracts/observability.d.ts +15 -0
  33. package/dist/src/surfaces/api/contracts/observability.js +1 -1
  34. package/dist/src/surfaces/api/http-server.d.ts +1 -1
  35. package/dist/src/surfaces/api/http-server.js +23 -1
  36. package/dist/src/surfaces/api/routes/applications.d.ts +7 -0
  37. package/dist/src/surfaces/api/routes/index.js +2 -2
  38. package/dist/src/surfaces/api/routes/observability.d.ts +1 -1
  39. package/dist/src/surfaces/api/routes/observability.js +5 -1
  40. package/dist/src/surfaces/api/routes/read.d.ts +1 -1
  41. package/dist/src/surfaces/api/routes/read.js +28 -1
  42. package/dist/src/surfaces/web-assets/assets/index-DXxSMyln.js +1131 -0
  43. package/dist/src/surfaces/web-assets/assets/index-EVgZ9q9N.css +1 -0
  44. package/dist/src/surfaces/web-assets/index.html +2 -2
  45. package/package.json +1 -1
  46. package/dist/src/surfaces/web-assets/assets/index-B7SgB4eG.css +0 -1
  47. package/dist/src/surfaces/web-assets/assets/index-DPaH6c6e.js +0 -1131
@@ -27,3 +27,4 @@ export * from './domain/compiler.js';
27
27
  export * from './domain/interpreter.js';
28
28
  export * from './domain/workflow-instance.js';
29
29
  export * from './domain/workflow-selector.js';
30
+ export * from './application/work-completion-summary.js';
@@ -27,3 +27,4 @@ export * from './domain/compiler.js';
27
27
  export * from './domain/interpreter.js';
28
28
  export * from './domain/workflow-instance.js';
29
29
  export * from './domain/workflow-selector.js';
30
+ export * from './application/work-completion-summary.js';
@@ -1,3 +1,4 @@
1
+ import type { ReportWindow } from '../../../kernel/index.js';
1
2
  export interface AnalyticsWindowResponse {
2
3
  readonly days: number;
3
4
  readonly from: string;
@@ -8,3 +9,17 @@ export interface MetricsResponse {
8
9
  readonly window: AnalyticsWindowResponse;
9
10
  readonly values: Readonly<Record<string, number>>;
10
11
  }
12
+ export { ReportWindowId } from '../../../kernel/index.js';
13
+ export type { ReportWindowId as AnalyticsReportWindowId, ReportDescriptor, ReportWindow, TimeSeriesReport, } from '../../../kernel/index.js';
14
+ export interface AnalyticsSummaryResponse {
15
+ readonly window: ReportWindow;
16
+ readonly runs: number;
17
+ readonly completed: number;
18
+ readonly blockedOrAwaitingApproval: number;
19
+ readonly failed: number;
20
+ readonly totalTokens: number;
21
+ readonly totalCostUsd: number;
22
+ readonly medianRunDurationMs: number | null;
23
+ readonly workItemsDone: number;
24
+ readonly medianEndToEndDurationMs: number | null;
25
+ }
@@ -1 +1 @@
1
- export {};
1
+ export { ReportWindowId } from '../../../kernel/index.js';
@@ -14,7 +14,7 @@ export interface ApiHttpResponse {
14
14
  }
15
15
  /** A transport-only dispatcher supplied by Bootstrap composition. */
16
16
  export interface ApiDispatcher {
17
- dispatch(method: string, pathname: string, body: unknown): Promise<ApiHttpResponse | undefined>;
17
+ dispatch(method: string, pathname: string, body: unknown, signal?: AbortSignal): Promise<ApiHttpResponse | undefined>;
18
18
  }
19
19
  export interface SurfaceHttpServerOptions {
20
20
  readonly dispatcher: ApiDispatcher;
@@ -81,7 +81,29 @@ export function createSurfaceHttpServer(options) {
81
81
  return reply.code(401).send({ status: 401, title: 'Unauthorized' });
82
82
  });
83
83
  protectedApi.all('/*', async (request, reply) => {
84
- const result = await options.dispatcher.dispatch(request.method, request.raw.url ?? request.url, request.body);
84
+ const controller = new AbortController();
85
+ const abort = () => controller.abort();
86
+ const close = () => {
87
+ if (!reply.raw.writableFinished)
88
+ abort();
89
+ };
90
+ request.raw.once('aborted', abort);
91
+ reply.raw.once('close', close);
92
+ let result;
93
+ try {
94
+ result = await options.dispatcher.dispatch(request.method, request.raw.url ?? request.url, request.body, controller.signal);
95
+ }
96
+ catch (error) {
97
+ if (controller.signal.aborted)
98
+ return reply;
99
+ throw error;
100
+ }
101
+ finally {
102
+ request.raw.off('aborted', abort);
103
+ reply.raw.off('close', close);
104
+ }
105
+ if (controller.signal.aborted)
106
+ return reply;
85
107
  if (result === undefined)
86
108
  return sendFastifyJson(reply, {
87
109
  status: 404,
@@ -1,5 +1,7 @@
1
1
  import type { RunStatus } from '../../../execution/index.js';
2
+ import type { ReportDescriptor, ReportWindowId, TimeSeriesReport } from '../../../kernel/index.js';
2
3
  import type { ApiCommandResult, AuditEventResponse, BoardCardResponse, BoardResponse, CommandsResponse, ConfigurationResponse, ControlPlaneStatusResponse, ConversationMessageRequest, HealthResponse, MetricsResponse, ResourceItemResponse, ResourceResponse, ResponseMeta, RunnerResponse, RunResponse, RunTranscriptResponse, StatusResponse, WebhookSetupResponse, WorkDetailResponse, WorkflowDiagramsResponse, WorkflowInstanceResponse, WorkItemResponse, WorkItemTranscriptResponse } from '../contracts/index.js';
4
+ import type { AnalyticsSummaryResponse } from '../contracts/observability.js';
3
5
  export interface CollectionQuery {
4
6
  readonly cursor?: {
5
7
  readonly position: number;
@@ -90,6 +92,11 @@ export interface ApiApplications {
90
92
  list(query: CollectionQuery): Promise<ApiCollectionPage<AuditEventResponse>>;
91
93
  };
92
94
  readonly observability: {
95
+ readonly reports?: {
96
+ catalogue(): readonly ReportDescriptor[];
97
+ report(id: string, window: ReportWindowId, signal?: AbortSignal): Promise<ApiResourceResult<TimeSeriesReport>>;
98
+ summary(window: ReportWindowId, signal?: AbortSignal): Promise<ApiResourceResult<AnalyticsSummaryResponse>>;
99
+ };
93
100
  metrics(query?: {
94
101
  readonly days: number;
95
102
  }): Promise<ApiResourceResult<MetricsResponse>>;
@@ -3,11 +3,11 @@ import { dispatchRead } from './read.js';
3
3
  import { problem } from './responses.js';
4
4
  export function createApiDispatcher(applications) {
5
5
  return {
6
- async dispatch(method, target, body) {
6
+ async dispatch(method, target, body, signal) {
7
7
  const url = new URL(target, 'http://wake.local');
8
8
  if (!url.pathname.startsWith('/api/'))
9
9
  return undefined;
10
- const response = await dispatchRead(applications, method, url);
10
+ const response = await dispatchRead(applications, method, url, signal);
11
11
  if (response !== undefined)
12
12
  return response;
13
13
  if (method === 'POST')
@@ -1 +1 @@
1
- export declare const observabilityRoutes: readonly ["/api/v1/observability/metrics"];
1
+ export declare const observabilityRoutes: readonly ["/api/v1/observability/metrics", "/api/v1/observability/reports", "/api/v1/observability/summary"];
@@ -1 +1,5 @@
1
- export const observabilityRoutes = ['/api/v1/observability/metrics'];
1
+ export const observabilityRoutes = [
2
+ '/api/v1/observability/metrics',
3
+ '/api/v1/observability/reports',
4
+ '/api/v1/observability/summary',
5
+ ];
@@ -1,3 +1,3 @@
1
1
  import type { ApiHttpResponse } from '../http-server.js';
2
2
  import type { ApiApplications } from './applications.js';
3
- export declare function dispatchRead(applications: ApiApplications, method: string, url: URL): Promise<ApiHttpResponse | undefined>;
3
+ export declare function dispatchRead(applications: ApiApplications, method: string, url: URL, signal?: AbortSignal): Promise<ApiHttpResponse | undefined>;
@@ -1,3 +1,4 @@
1
+ import { ReportWindowId } from '../../../kernel/index.js';
1
2
  import { collection, parseCollectionQuery } from './pagination.js';
2
3
  import { ApiPathError, decodePathSegment, found, invalidPath, invalidQuery, noQuery, ok, unavailable, } from './responses.js';
3
4
  const collectionRoutes = new Map([
@@ -9,9 +10,12 @@ const collectionRoutes = new Map([
9
10
  ['/api/v1/events', new Set(['cursor', 'limit', 'workItemKey'])],
10
11
  ['/api/v1/board', new Set(['cursor', 'limit'])],
11
12
  ]);
12
- export async function dispatchRead(applications, method, url) {
13
+ export async function dispatchRead(applications, method, url, signal) {
13
14
  if (method !== 'GET' && method !== 'HEAD')
14
15
  return undefined;
16
+ if (url.pathname === '/api/v1/observability/reports' ||
17
+ url.pathname === '/api/v1/observability/summary')
18
+ return readReports(applications, url, signal);
15
19
  const resource = await readSingleton(applications, url);
16
20
  if (resource !== undefined)
17
21
  return resource;
@@ -182,3 +186,26 @@ async function readRun(applications, segment) {
182
186
  ? invalidPath(runId.message)
183
187
  : found(await applications.execution.get?.(runId));
184
188
  }
189
+ async function readReports(applications, url, signal) {
190
+ const reports = applications.observability.reports;
191
+ if (reports === undefined)
192
+ return unavailable('reports');
193
+ const summary = url.pathname.endsWith('/summary');
194
+ const allowed = new Set(summary ? ['window'] : ['window', 'report']);
195
+ for (const key of url.searchParams.keys()) {
196
+ if (!allowed.has(key) || url.searchParams.getAll(key).length !== 1)
197
+ return invalidQuery(`Unknown or repeated query parameter: ${key}`, key);
198
+ }
199
+ if (!summary && url.search === '')
200
+ return ok({ data: reports.catalogue(), meta: { asOf: applications.now() } });
201
+ const raw = url.searchParams.get('window');
202
+ const window = Object.values(ReportWindowId).find((id) => id === raw);
203
+ if (window === undefined)
204
+ return invalidQuery('window must be 1d, 3d, 5d or 7d', 'window');
205
+ if (summary)
206
+ return ok(await reports.summary(window, signal));
207
+ const report = url.searchParams.get('report');
208
+ if (report === null || !reports.catalogue().some(({ id }) => id === report))
209
+ return invalidQuery('Unknown report identifier', 'report');
210
+ return ok(await reports.report(report, window, signal));
211
+ }