@happyrobot-ai/sdk 0.1.18 → 0.1.19

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/core/http.js CHANGED
@@ -14,6 +14,19 @@ const DEFAULT_BASE_URL = exports.CLUSTER_URLS.us;
14
14
  const DEFAULT_TIMEOUT = 30_000;
15
15
  const DEFAULT_MAX_RETRIES = 2;
16
16
  const INITIAL_BACKOFF_MS = 500;
17
+ function buildRequestBody(config) {
18
+ if (config.rawBody !== undefined) {
19
+ // Don't set Content-Type — let the runtime set it (with multipart boundary)
20
+ return { body: config.rawBody };
21
+ }
22
+ if (config.body !== undefined) {
23
+ return {
24
+ body: JSON.stringify(config.body),
25
+ contentType: "application/json",
26
+ };
27
+ }
28
+ return { body: undefined };
29
+ }
17
30
  class HttpClient {
18
31
  apiKey;
19
32
  baseUrl;
@@ -67,8 +80,9 @@ class HttpClient {
67
80
  Accept: "application/json",
68
81
  ...config.headers,
69
82
  };
70
- if (config.body !== undefined) {
71
- headers["Content-Type"] = "application/json";
83
+ const { body: requestBody, contentType } = buildRequestBody(config);
84
+ if (contentType) {
85
+ headers["Content-Type"] = contentType;
72
86
  }
73
87
  let lastError;
74
88
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
@@ -76,9 +90,7 @@ class HttpClient {
76
90
  const response = await this.fetchWithTimeout(url, {
77
91
  method: config.method,
78
92
  headers,
79
- body: config.body !== undefined
80
- ? JSON.stringify(config.body)
81
- : undefined,
93
+ body: requestBody,
82
94
  }, timeout);
83
95
  if (response.ok) {
84
96
  if (response.status === 204) {
package/core/types.d.ts CHANGED
@@ -22,6 +22,8 @@ export interface RequestConfig {
22
22
  query?: Record<string, string | number | boolean | undefined>;
23
23
  /** JSON request body. */
24
24
  body?: unknown;
25
+ /** Raw body (e.g. FormData for multipart). Skips JSON serialization and Content-Type. */
26
+ rawBody?: FormData | Blob | ReadableStream;
25
27
  /** Additional headers. */
26
28
  headers?: Record<string, string>;
27
29
  /** Override timeout for this request. */
@@ -3,6 +3,8 @@ import type { RunNodeOutput } from "../types/runs.types";
3
3
  export interface TriggerAndWaitForNodeOutputOptions {
4
4
  workflowId: string;
5
5
  payload?: Record<string, unknown>;
6
+ /** File to upload (sends as multipart/form-data instead of JSON). */
7
+ file?: Blob | File;
6
8
  environment?: "production" | "staging" | "development";
7
9
  nodePersistentId: string;
8
10
  timeoutMs?: number;
@@ -17,8 +17,9 @@ const NODE_READY_STATUSES = new Set([
17
17
  "skipped",
18
18
  ]);
19
19
  async function triggerAndWaitForNodeOutput(client, options) {
20
- const { workflowId, payload, environment = "production", nodePersistentId, timeoutMs = 300_000, pollIntervalMs = 2_000, } = options;
20
+ const { workflowId, payload, file, environment = "production", nodePersistentId, timeoutMs = 300_000, pollIntervalMs = 2_000, } = options;
21
21
  const triggerResponse = await client.workflows.triggerRun(workflowId, {
22
+ file,
22
23
  payload,
23
24
  environment,
24
25
  });
@@ -9,6 +9,8 @@ export interface TriggerAndWaitOptions {
9
9
  workflowId: string;
10
10
  /** Trigger payload. */
11
11
  payload?: Record<string, unknown>;
12
+ /** File to upload (sends as multipart/form-data instead of JSON). */
13
+ file?: Blob | File;
12
14
  /** Target environment. */
13
15
  environment?: "production" | "staging" | "development";
14
16
  /** Maximum time to wait in milliseconds. Defaults to 300_000 (5 min). */
@@ -25,9 +25,10 @@ const TERMINAL_STATUSES = new Set([
25
25
  * ```
26
26
  */
27
27
  async function triggerAndWait(client, options) {
28
- const { workflowId, payload, environment = "production", timeoutMs = 300_000, pollIntervalMs = 2_000, fetchSessions = true, } = options;
28
+ const { workflowId, payload, file, environment = "production", timeoutMs = 300_000, pollIntervalMs = 2_000, fetchSessions = true, } = options;
29
29
  // 1. Trigger the run
30
30
  const { run_id } = await client.workflows.triggerRun(workflowId, {
31
+ file,
31
32
  payload,
32
33
  environment,
33
34
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyrobot-ai/sdk",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "TypeScript SDK for the HappyRobot Public API",
5
5
  "main": "./index.js",
6
6
  "module": "./index.mjs",
@@ -17,7 +17,7 @@
17
17
  * POST /workflows/:workflow_id/runs
18
18
  */
19
19
  import type { HttpClient } from "../core/http";
20
- import type { WorkflowRunsQuery, PaginatedWorkflowRunsResponse, TriggerRunBody, TriggerRunResponse } from "../types/runs.types";
20
+ import type { WorkflowRunsQuery, PaginatedWorkflowRunsResponse, TriggerRunBody, TriggerRunResponse, TriggerRunWithFileBody } from "../types/runs.types";
21
21
  import type { ListWorkflowsQuery, WorkflowListItem, PaginatedWorkflowsResponse, CreateWorkflowBody, CreateWorkflowResponse, WorkflowDetailResponse, UpdateWorkflowBody, UpdateWorkflowResponse, DuplicateWorkflowBody, DuplicateWorkflowResponse, ListTemplatesQuery, PaginatedTemplatesResponse, WorkflowPublishResponse, WorkflowUnpublishResponse, CancelRunsResponse, ListWorkflowVersionsQuery, PaginatedWorkflowVersionsResponse } from "../types/workflows.types";
22
22
  export declare class WorkflowsResource {
23
23
  private readonly http;
@@ -50,6 +50,7 @@ export declare class WorkflowsResource {
50
50
  listVersions(workflowId: string, query?: ListWorkflowVersionsQuery): Promise<PaginatedWorkflowVersionsResponse>;
51
51
  /** List runs for a workflow. */
52
52
  listRuns(workflowId: string, query?: WorkflowRunsQuery): Promise<PaginatedWorkflowRunsResponse>;
53
- /** Trigger a run for a workflow. */
54
- triggerRun(workflowId: string, body?: TriggerRunBody): Promise<TriggerRunResponse>;
53
+ /** Trigger a run for a workflow (JSON payload or file upload). */
54
+ triggerRun(workflowId: string, body?: TriggerRunBody | TriggerRunWithFileBody): Promise<TriggerRunResponse>;
55
+ private triggerRunWithFile;
55
56
  }
@@ -121,14 +121,35 @@ class WorkflowsResource {
121
121
  query: query,
122
122
  });
123
123
  }
124
- /** Trigger a run for a workflow. */
124
+ /** Trigger a run for a workflow (JSON payload or file upload). */
125
125
  async triggerRun(workflowId, body) {
126
+ const path = `/workflows/${encodeURIComponent(workflowId)}/runs`;
127
+ if (body && "file" in body && body.file) {
128
+ return this.triggerRunWithFile(path, body);
129
+ }
126
130
  return this.http.request({
127
131
  method: "POST",
128
- path: `/workflows/${encodeURIComponent(workflowId)}/runs`,
132
+ path,
129
133
  body: body ?? {},
130
134
  });
131
135
  }
136
+ async triggerRunWithFile(path, body) {
137
+ const formData = new FormData();
138
+ formData.append("file", body.file);
139
+ if (body.payload) {
140
+ for (const [key, value] of Object.entries(body.payload)) {
141
+ if (value !== undefined && value !== null) {
142
+ formData.append(key, typeof value === "string" ? value : JSON.stringify(value));
143
+ }
144
+ }
145
+ }
146
+ return this.http.request({
147
+ method: "POST",
148
+ path,
149
+ rawBody: formData,
150
+ query: { environment: body.environment ?? "production" },
151
+ });
152
+ }
132
153
  }
133
154
  exports.WorkflowsResource = WorkflowsResource;
134
155
  //# sourceMappingURL=workflows.js.map
@@ -3,10 +3,11 @@
3
3
  */
4
4
  import type { z } from "zod";
5
5
  import type { RunDetailSchema, MarkRunBodySchema, MarkRunResponseSchema, ListFlagsQuerySchema, PaginatedFlagsResponseSchema, FlagItemSchema, GetRunOutputResponseSchema, ListRunNodesQuerySchema, ListRunNodesResponseSchema, RunNodeOutputSchema } from "../../routes/runs/schemas";
6
- import type { WorkflowRunsQuerySchema, PaginatedWorkflowRunsResponseSchema, TriggerRunBodySchema, TriggerRunResponseSchema } from "../../routes/workflows/:workflow_id/runs/schemas";
6
+ import type { WorkflowRunsQuerySchema, PaginatedWorkflowRunsResponseSchema, TriggerRunBodySchema, TriggerRunWithFileBodySchema, TriggerRunResponseSchema } from "../../routes/workflows/:workflow_id/runs/schemas";
7
7
  export type WorkflowRunsQuery = z.input<typeof WorkflowRunsQuerySchema>;
8
8
  export type PaginatedWorkflowRunsResponse = z.infer<typeof PaginatedWorkflowRunsResponseSchema>;
9
9
  export type TriggerRunBody = z.input<typeof TriggerRunBodySchema>;
10
+ export type TriggerRunWithFileBody = z.input<typeof TriggerRunWithFileBodySchema>;
10
11
  export type TriggerRunResponse = z.infer<typeof TriggerRunResponseSchema>;
11
12
  export type RunDetail = z.infer<typeof RunDetailSchema>;
12
13
  export type MarkRunBody = z.input<typeof MarkRunBodySchema>;