cloudcruise 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Shared Event Type Definitions
3
+ * Used by both Webhook and SSE Run event handlers
4
+ */
5
+ export declare enum EventType {
6
+ ExecutionQueued = "execution.queued",
7
+ ExecutionStart = "execution.start",
8
+ ExecutionStep = "execution.step",
9
+ ExecutionPause = "execution.pause",
10
+ ExecutionStopped = "execution.stopped",
11
+ ExecutionFailed = "execution.failed",
12
+ ExecutionSuccess = "execution.success",
13
+ ExecutionRequeued = "execution.requeued",
14
+ FileUploaded = "file.uploaded",
15
+ ScreenshotUploaded = "screenshot.uploaded",
16
+ VideoUploaded = "video.uploaded",
17
+ InteractionWaiting = "interaction.waiting",
18
+ InteractionFinished = "interaction.finished",
19
+ InteractionFailed = "interaction.failed",
20
+ AgentErrorAnalysis = "agent.error_analysis"
21
+ }
22
+ export interface ExecutionQueuedPayload {
23
+ session_id: string;
24
+ workflow_id: string;
25
+ }
26
+ export interface ExecutionStartPayload {
27
+ session_id: string;
28
+ workflow_id: string;
29
+ live_view_url?: string;
30
+ }
31
+ export interface ExecutionStepPayload {
32
+ session_id: string;
33
+ workflow_id: string;
34
+ current_step: string;
35
+ next_step: string;
36
+ }
37
+ export interface InteractionWaitingPayload {
38
+ session_id: string;
39
+ workflow_id: string;
40
+ current_step: string;
41
+ missing_properties: string[];
42
+ expected_json_schema_datamodel: Record<string, any>;
43
+ message: string;
44
+ }
45
+ export type InteractionFinishedPayload = {
46
+ session_id: string;
47
+ workflow_id: string;
48
+ current_step: string;
49
+ missing_properties: [];
50
+ expected_json_schema_datamodel: Record<string, any>;
51
+ message: string;
52
+ } | {
53
+ session_id: string;
54
+ workflow_id: string;
55
+ provided_input: any;
56
+ message?: string;
57
+ expected_json_schema_datamodel: Record<string, any>;
58
+ };
59
+ export interface AgentErrorAnalysisPayload {
60
+ analysis_step_name: string;
61
+ ai_analysis?: string;
62
+ root_cause_analysis?: string;
63
+ error_category?: string;
64
+ }
65
+ export interface ExecutionRequeuedPayload {
66
+ session_id: string;
67
+ workflow_id: string;
68
+ retry_attempt: number;
69
+ max_retries?: number;
70
+ next_execution_time: string;
71
+ delay_ms: number;
72
+ }
73
+ export interface EndRunError {
74
+ message: string;
75
+ error_id: string;
76
+ full_url?: string;
77
+ created_at: string;
78
+ error_code?: string;
79
+ action_type?: string;
80
+ action_display_name?: string;
81
+ llm_error_category?: string;
82
+ }
83
+ export interface EndRunPayload {
84
+ session_id: string;
85
+ workflow_id: string;
86
+ data: any;
87
+ input_variables: Record<string, any>;
88
+ errors: EndRunError[];
89
+ status: EventType.ExecutionSuccess | EventType.ExecutionFailed | EventType.ExecutionStopped;
90
+ encrypted_variables: string[] | null;
91
+ file_urls: any[] | null;
92
+ }
93
+ export interface ExecutionStoppedEarlyPayload {
94
+ message: string;
95
+ error_code: string;
96
+ session_id: string;
97
+ }
98
+ export interface FileUploadedPayload {
99
+ signed_file_url: string;
100
+ file_name: string;
101
+ timestamp: string;
102
+ signed_file_url_expires: string;
103
+ metadata: Record<string, any>;
104
+ session_id: string;
105
+ }
106
+ export interface ScreenshotUploadedPayload {
107
+ screenshot_id: string;
108
+ signed_screenshot_url: string;
109
+ node_display_name: string;
110
+ node_id: string;
111
+ timestamp: string;
112
+ signed_screenshot_url_expires: string;
113
+ error_screenshot: boolean;
114
+ retry_index: number;
115
+ full_length_screenshot: boolean;
116
+ session_id: string;
117
+ }
118
+ export type EventPayloadMap = {
119
+ [EventType.ExecutionQueued]: ExecutionQueuedPayload;
120
+ [EventType.ExecutionStart]: ExecutionStartPayload;
121
+ [EventType.ExecutionStep]: ExecutionStepPayload;
122
+ [EventType.InteractionWaiting]: InteractionWaitingPayload;
123
+ [EventType.InteractionFinished]: InteractionFinishedPayload;
124
+ [EventType.AgentErrorAnalysis]: AgentErrorAnalysisPayload;
125
+ [EventType.ExecutionRequeued]: ExecutionRequeuedPayload;
126
+ [EventType.ExecutionSuccess]: EndRunPayload;
127
+ [EventType.ExecutionFailed]: EndRunPayload;
128
+ [EventType.ExecutionStopped]: EndRunPayload | ExecutionStoppedEarlyPayload;
129
+ [EventType.FileUploaded]: FileUploadedPayload;
130
+ [EventType.ScreenshotUploaded]: ScreenshotUploadedPayload;
131
+ [EventType.VideoUploaded]: never;
132
+ [EventType.ExecutionPause]: never;
133
+ [EventType.InteractionFailed]: never;
134
+ };
135
+ export type WebhookMessage<E extends EventType = EventType> = {
136
+ event: E;
137
+ timestamp: number;
138
+ expires_at: number;
139
+ payload: EventPayloadMap[E];
140
+ metadata?: Record<string, any>;
141
+ };
142
+ export type RunEventMessage<E extends EventType = EventType> = {
143
+ event: "run.event";
144
+ data: {
145
+ event: E;
146
+ payload: EventPayloadMap[E];
147
+ timestamp: number;
148
+ expires_at: number;
149
+ };
150
+ timestamp: string;
151
+ expires_at: string;
152
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared Event Type Definitions
3
+ * Used by both Webhook and SSE Run event handlers
4
+ */
5
+ export var EventType;
6
+ (function (EventType) {
7
+ EventType["ExecutionQueued"] = "execution.queued";
8
+ EventType["ExecutionStart"] = "execution.start";
9
+ EventType["ExecutionStep"] = "execution.step";
10
+ EventType["ExecutionPause"] = "execution.pause";
11
+ EventType["ExecutionStopped"] = "execution.stopped";
12
+ EventType["ExecutionFailed"] = "execution.failed";
13
+ EventType["ExecutionSuccess"] = "execution.success";
14
+ EventType["ExecutionRequeued"] = "execution.requeued";
15
+ EventType["FileUploaded"] = "file.uploaded";
16
+ EventType["ScreenshotUploaded"] = "screenshot.uploaded";
17
+ EventType["VideoUploaded"] = "video.uploaded";
18
+ EventType["InteractionWaiting"] = "interaction.waiting";
19
+ EventType["InteractionFinished"] = "interaction.finished";
20
+ EventType["InteractionFailed"] = "interaction.failed";
21
+ EventType["AgentErrorAnalysis"] = "agent.error_analysis";
22
+ })(EventType || (EventType = {}));
package/dist/index.d.ts CHANGED
@@ -10,7 +10,9 @@ export { RunsClient } from './runs/RunsClient.js';
10
10
  export { WebhookClient } from './webhook/WebhookClient.js';
11
11
  export type { VaultEntry, GetVaultEntriesFilters, ProxyConfig, VaultPostPutHeadersInBody } from './vault/types.js';
12
12
  export type { Workflow, WorkflowInputSchema, WorkflowMetadata } from './workflows/types.js';
13
- export type { EventType, DryRun, Metadata, RunSpecificWebhook, PayloadWebhook, StartRunRequest, StartRunResponse, UserInteractionData, VideoUrl, SignedFileUrl, SignedScreenshotUrl, RunError, WorkflowError, RunResult, GetRunResult, WebhookEvent, WebhookReplayResponse, RunHandle, RunStreamOptions, SseEventName, SseMessage, RunEventEnvelope } from './runs/types.js';
14
- export type { WebhookPayload, WebhookVerificationOptions } from './webhook/types.js';
13
+ export type { DryRun, Metadata, RunSpecificWebhook, PayloadWebhook, StartRunRequest, StartRunResponse, UserInteractionData, VideoUrl, SignedFileUrl, SignedScreenshotUrl, RunError, WorkflowError, RunResult, GetRunResult, WebhookEvent, WebhookReplayResponse, RunHandle, RunStreamOptions, SseEventName, SseMessage, RunEventEnvelope, RunHandleEventMap } from './runs/types.js';
14
+ export { EventType } from './events/types.js';
15
+ export type { WebhookMessage, RunEventMessage } from './events/types.js';
16
+ export type { WebhookVerificationOptions } from './webhook/types.js';
15
17
  export { VerificationError } from './webhook/types.js';
16
18
  export { InputValidationError } from './workflows/types.js';
package/dist/index.js CHANGED
@@ -7,5 +7,7 @@ export { VaultClient } from './vault/VaultClient.js';
7
7
  export { WorkflowsClient } from './workflows/WorkflowsClient.js';
8
8
  export { RunsClient } from './runs/RunsClient.js';
9
9
  export { WebhookClient } from './webhook/WebhookClient.js';
10
+ // Export shared event types
11
+ export { EventType } from './events/types.js';
10
12
  export { VerificationError } from './webhook/types.js';
11
13
  export { InputValidationError } from './workflows/types.js';
@@ -1,3 +1,4 @@
1
+ import { EventType } from '../events/types.js';
1
2
  import { AsyncEventQueue } from '../utils/asyncQueue.js';
2
3
  import { SimpleEventEmitter } from '../utils/events.js';
3
4
  export class RunsClient {
@@ -37,7 +38,9 @@ export class RunsClient {
37
38
  enabled: options?.reconnect?.enabled ?? true,
38
39
  delays: options?.reconnect?.delays ?? [1000, 3000, 10000],
39
40
  };
40
- const isTerminalEvent = (status) => status === 'execution.success' || status === 'execution.failed' || status === 'execution.stopped';
41
+ const isTerminalEvent = (status) => status === EventType.ExecutionSuccess ||
42
+ status === EventType.ExecutionFailed ||
43
+ status === EventType.ExecutionStopped;
41
44
  const emit = (event, payload) => {
42
45
  emitter.emit(event, payload);
43
46
  // Mirror only SSE messages to 'message' for catch-all consumers
@@ -69,6 +72,11 @@ export class RunsClient {
69
72
  return;
70
73
  stream.push(sseMsg);
71
74
  emit('run.event', sseMsg);
75
+ // Emit typed per-event key for better DX
76
+ try {
77
+ emitter.emit(sseMsg.data.event, sseMsg);
78
+ }
79
+ catch { }
72
80
  const eventType = sseMsg.data.event;
73
81
  if (typeof eventType === 'string' && isTerminalEvent(eventType)) {
74
82
  endAndCleanup(eventType);
@@ -107,7 +115,7 @@ export class RunsClient {
107
115
  }
108
116
  else {
109
117
  // End without explicit type; still clean up
110
- endAndCleanup('execution.stopped');
118
+ endAndCleanup(EventType.ExecutionStopped);
111
119
  }
112
120
  });
113
121
  };
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * CloudCruise Runs API Type Definitions
3
3
  */
4
- export type EventType = 'execution.queued' | 'execution.start' | 'execution.step' | 'execution.pause' | 'execution.stopped' | 'execution.failed' | 'execution.success' | 'execution.requeued' | 'file.uploaded' | 'screenshot.uploaded' | 'video.uploaded' | 'interaction.waiting' | 'interaction.finished' | 'interaction.failed';
4
+ import type { EventType, RunEventMessage, EventPayloadMap, ExecutionQueuedPayload, ExecutionStartPayload, ExecutionStepPayload, InteractionWaitingPayload, InteractionFinishedPayload, AgentErrorAnalysisPayload, ExecutionRequeuedPayload, EndRunPayload, EndRunError, ExecutionStoppedEarlyPayload, FileUploadedPayload, ScreenshotUploadedPayload } from '../events/types.js';
5
+ export type { EventType };
6
+ export type { ExecutionQueuedPayload, ExecutionStartPayload, ExecutionStepPayload, InteractionWaitingPayload, InteractionFinishedPayload, AgentErrorAnalysisPayload, ExecutionRequeuedPayload, EndRunPayload, EndRunError, ExecutionStoppedEarlyPayload, FileUploadedPayload, ScreenshotUploadedPayload, EventPayloadMap, };
5
7
  export interface DryRun {
6
8
  enabled: boolean;
7
9
  add_to_output?: Record<string, any>;
@@ -109,27 +111,14 @@ export interface WebhookReplayResponse {
109
111
  * Streaming (SSE) types
110
112
  */
111
113
  export type SseEventName = 'run.event' | 'ping';
112
- export interface RunEventEnvelope {
113
- event: 'run.event';
114
- data: {
115
- event: EventType | string;
116
- payload: {
117
- session_id: string;
118
- [key: string]: any;
119
- };
120
- expires_at: number;
121
- timestamp: number;
122
- };
123
- timestamp?: string;
124
- expires_at?: string;
125
- }
114
+ export type RunEventEnvelope<E extends EventType = EventType> = RunEventMessage<E>;
126
115
  export interface PingEnvelope {
127
116
  event: 'ping';
128
117
  data: {
129
118
  ts: number;
130
119
  } | Record<string, any>;
131
120
  }
132
- export type SseMessage = RunEventEnvelope | PingEnvelope;
121
+ export type SseMessage<E extends EventType = EventType> = RunEventEnvelope<E> | PingEnvelope;
133
122
  export interface RunStreamOptions {
134
123
  signal?: AbortSignal;
135
124
  withCredentials?: boolean;
@@ -140,9 +129,26 @@ export interface RunStreamOptions {
140
129
  jitter?: number;
141
130
  };
142
131
  }
132
+ export type RunEventMap = {
133
+ [K in EventType]: RunEventEnvelope<K>;
134
+ };
135
+ export type RunHandleEventMap = {
136
+ 'open': undefined;
137
+ 'close': undefined;
138
+ 'reconnect': {
139
+ attemptDelayMs: number;
140
+ };
141
+ 'error': unknown;
142
+ 'end': {
143
+ type: EventType;
144
+ };
145
+ 'run.event': SseMessage;
146
+ 'ping': PingEnvelope;
147
+ 'message': SseMessage | PingEnvelope;
148
+ } & RunEventMap;
143
149
  export interface RunHandle {
144
150
  sessionId: string;
145
- on(event: 'open' | 'reconnect' | 'error' | 'end' | SseEventName | 'message', handler: (e: unknown) => void): () => void;
151
+ on<K extends keyof RunHandleEventMap>(event: K, handler: (e: RunHandleEventMap[K]) => void): () => void;
146
152
  wait(): Promise<GetRunResult>;
147
153
  close(): void;
148
154
  [Symbol.asyncIterator](): AsyncIterator<SseMessage>;
@@ -1,8 +1,11 @@
1
1
  import { openSSE } from './sse.js';
2
2
  import { SimpleEventEmitter } from './events.js';
3
3
  import { AsyncEventQueue } from './asyncQueue.js';
4
+ import { EventType } from '../events/types.js';
4
5
  function isFinalEvent(eventType) {
5
- return eventType === 'execution.success' || eventType === 'execution.failed' || eventType === 'execution.stopped';
6
+ return (eventType === EventType.ExecutionSuccess ||
7
+ eventType === EventType.ExecutionFailed ||
8
+ eventType === EventType.ExecutionStopped);
6
9
  }
7
10
  export class ConnectionManager {
8
11
  baseUrl;
@@ -144,7 +147,9 @@ export class ConnectionManager {
144
147
  if (!data) {
145
148
  return;
146
149
  }
147
- const sessionId = data.payload?.session_id;
150
+ // Extract session_id - it's always present in payload
151
+ const payload = data.payload;
152
+ const sessionId = payload?.session_id;
148
153
  if (!sessionId) {
149
154
  return;
150
155
  }
@@ -152,7 +157,12 @@ export class ConnectionManager {
152
157
  if (!channel) {
153
158
  return;
154
159
  }
155
- const msg = { event: 'run.event', data };
160
+ const msg = {
161
+ event: 'run.event',
162
+ data: data,
163
+ timestamp: raw.timestamp || new Date().toISOString(),
164
+ expires_at: raw.expires_at || new Date(Date.now() + 3600000).toISOString()
165
+ };
156
166
  // fan-out to all subscribers
157
167
  for (const q of channel.subscribers)
158
168
  q.push(msg);
@@ -1,7 +1,24 @@
1
1
  export type EventHandler<T = unknown> = (event: T) => void;
2
- export declare class SimpleEventEmitter {
2
+ /**
3
+ * Event emitter that supports both typed and untyped usage.
4
+ *
5
+ * - Use without type parameter for untyped events (backward compatible)
6
+ * - Use with EventMap type parameter for type-safe events
7
+ *
8
+ * @example
9
+ * // Untyped usage
10
+ * const emitter = new SimpleEventEmitter();
11
+ * emitter.on('foo', (data) => console.log(data));
12
+ *
13
+ * @example
14
+ * // Typed usage
15
+ * type Events = { foo: string; bar: number };
16
+ * const emitter = new SimpleEventEmitter<Events>();
17
+ * emitter.on('foo', (data) => console.log(data)); // data is string
18
+ */
19
+ export declare class SimpleEventEmitter<EventMap extends Record<string, any> = Record<string, unknown>> {
3
20
  private listeners;
4
- on(event: string, handler: EventHandler<unknown>): () => void;
5
- emit(event: string, payload?: unknown): void;
21
+ on<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): () => void;
22
+ emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void;
6
23
  clear(): void;
7
24
  }
@@ -1,3 +1,20 @@
1
+ /**
2
+ * Event emitter that supports both typed and untyped usage.
3
+ *
4
+ * - Use without type parameter for untyped events (backward compatible)
5
+ * - Use with EventMap type parameter for type-safe events
6
+ *
7
+ * @example
8
+ * // Untyped usage
9
+ * const emitter = new SimpleEventEmitter();
10
+ * emitter.on('foo', (data) => console.log(data));
11
+ *
12
+ * @example
13
+ * // Typed usage
14
+ * type Events = { foo: string; bar: number };
15
+ * const emitter = new SimpleEventEmitter<Events>();
16
+ * emitter.on('foo', (data) => console.log(data)); // data is string
17
+ */
1
18
  export class SimpleEventEmitter {
2
19
  listeners = new Map();
3
20
  on(event, handler) {
@@ -1,5 +1,15 @@
1
- import type { WebhookPayload, WebhookVerificationOptions } from './types.js';
1
+ import type { WebhookVerificationOptions } from './types.js';
2
+ import type { EventType, WebhookMessage } from '../events/types.js';
2
3
  export declare class WebhookClient {
3
4
  constructor();
4
- verifySignature(receivedData: any, receivedSignature: string, secretKey: string, options?: WebhookVerificationOptions): WebhookPayload;
5
+ /**
6
+ * Verifies the signature of an incoming webhook payload.
7
+ *
8
+ * @param receivedData - Raw request body supplied by the webhook sender.
9
+ * @param receivedSignature - Value from the `x-hmac-signature` request header. e.g req.headers["x-hmac-signature"]
10
+ * @param secretKey - Webhook secret configured in the CloudCruise portal.
11
+ * @param options - Optional overrides controlling signature verification behavior.
12
+ * @returns Verified webhook payload when the signature matches.
13
+ */
14
+ verifySignature<E extends EventType = EventType>(receivedData: any, receivedSignature: string, secretKey: string, options?: WebhookVerificationOptions): WebhookMessage<E>;
5
15
  }
@@ -3,11 +3,15 @@ export class WebhookClient {
3
3
  constructor() {
4
4
  // No makeRequest needed for webhook verification
5
5
  }
6
- /*
7
- 1. receivedSignature will be in the request header: "x-hmac-signature"
8
- 2. receivedData will be the request body.
9
- 3. secretKey is the key you set when creating this webhook in the CloudCruise portal.
10
- */
6
+ /**
7
+ * Verifies the signature of an incoming webhook payload.
8
+ *
9
+ * @param receivedData - Raw request body supplied by the webhook sender.
10
+ * @param receivedSignature - Value from the `x-hmac-signature` request header. e.g req.headers["x-hmac-signature"]
11
+ * @param secretKey - Webhook secret configured in the CloudCruise portal.
12
+ * @param options - Optional overrides controlling signature verification behavior.
13
+ * @returns Verified webhook payload when the signature matches.
14
+ */
11
15
  verifySignature(receivedData, receivedSignature, secretKey, options) {
12
16
  return verifyMessage(receivedData, receivedSignature, secretKey, options);
13
17
  }
@@ -1,13 +1,7 @@
1
- import { EventType } from "../runs/types";
2
1
  export declare class VerificationError extends Error {
3
2
  readonly statusCode: number;
4
3
  constructor(message?: string, statusCode?: number);
5
4
  }
6
- export interface WebhookPayload {
7
- event: EventType;
8
- expires_at: number;
9
- [key: string]: any;
10
- }
11
5
  export interface WebhookVerificationOptions {
12
6
  allowExpired?: boolean;
13
7
  }
@@ -1,2 +1,3 @@
1
- import { type WebhookPayload, type WebhookVerificationOptions } from './types.js';
2
- export declare function verifyMessage(receivedData: any, receivedSignature: string, secretKey: string, options?: WebhookVerificationOptions): WebhookPayload;
1
+ import type { EventType, WebhookMessage } from '../events/types.js';
2
+ import { type WebhookVerificationOptions } from './types.js';
3
+ export declare function verifyMessage<E extends EventType = EventType>(receivedData: any, receivedSignature: string, secretKey: string, options?: WebhookVerificationOptions): WebhookMessage<E>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudcruise",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "The official CloudCruise JS/TS client.",
5
5
  "homepage": "https://github.com/CloudCruise/cloudcruise-js#readme",
6
6
  "bugs": {