robotrock 0.3.0 → 0.4.0

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/README.md CHANGED
@@ -134,6 +134,30 @@ if (result.mode === "created") {
134
134
  }
135
135
  ```
136
136
 
137
+ ## Thread updates
138
+
139
+ Send short status updates (1-2 sentences) to a thread. The newest update shows in a status bar at the top of the inbox task detail, with an icon and color from an optional `status`; every update is logged in an expandable history. Updates are scoped to a `threadId`.
140
+
141
+ ```typescript
142
+ // Standalone update against an existing thread
143
+ const update = await robotrock.sendUpdate({
144
+ threadId, // from response.task.threadId
145
+ message: "Deployment started, running smoke tests.",
146
+ status: "running", // optional, defaults to "info"
147
+ });
148
+
149
+ // Or log an initial update when creating the task
150
+ await robotrock.sendToHuman({
151
+ type: "deploy-approval",
152
+ name: "Approve production rollout",
153
+ threadId: `deploy_${deploymentId}`,
154
+ update: { message: "Build finished, awaiting approval.", status: "waiting" },
155
+ actions: [{ id: "approve", title: "Approve" }],
156
+ });
157
+ ```
158
+
159
+ `status` is optional and one of: `info` | `queued` | `running` | `waiting` | `succeeded` | `failed` | `cancelled`. The `update` field is top-level (like `threadId` and `assignTo`), not inside `context`.
160
+
137
161
  ## Other client methods
138
162
 
139
163
  ```typescript
@@ -1,6 +1,6 @@
1
- import { R as RobotRockToolCallInfo, F as FormatToolApprovalTaskOptions, H as HumanToolResult } from '../workflow-BYeIZgD0.js';
2
- export { A as APPROVE_BY_HUMAN_ACTIONS, d as ApproveByHumanToolDurableOptions, c as ApproveByHumanToolOptions, r as CreateRobotRockAiToolsOptions, f as CreateSendToHumanToolDurableOptions, C as CreateSendToHumanToolOptions, B as ResolveToolApprovalsOptions, i as RobotRockAiContext, j as RobotRockAiMode, k as RobotRockAiPollingContext, l as RobotRockAiTriggerContext, m as RobotRockAiWorkflowContext, D as RobotRockToolApprovalConfig, z as RobotRockToolApprovalDecision, E as RunWithRobotRockApprovalsOptions, T as ToolApprovalRequestPart, t as applyRobotRockToolApprovalToTools, g as approveByHumanForAi, b as approveByHumanInputSchema, a as approveByHumanTool, u as collectApprovalRequests, o as createRobotRockAiTools, p as createRobotRockAiTriggerContext, q as createRobotRockAiWorkflowContext, v as createRobotRockNeedsApproval, w as createRobotRockToolApproval, e as createSendToHumanTool, n as normalizeRobotRockAiContext, x as resolveToolApprovalsViaRobotRock, y as runWithRobotRockApprovals, h as sendToHumanForAi, s as sendToHumanToolInputSchema } from '../workflow-BYeIZgD0.js';
3
- import { a as SendToHumanInput } from '../client-Dhk9qxhL.js';
1
+ import { R as RobotRockToolCallInfo, F as FormatToolApprovalTaskOptions, H as HumanToolResult } from '../workflow-iDk0Hlyg.js';
2
+ export { A as APPROVE_BY_HUMAN_ACTIONS, d as ApproveByHumanToolDurableOptions, c as ApproveByHumanToolOptions, r as CreateRobotRockAiToolsOptions, f as CreateSendToHumanToolDurableOptions, C as CreateSendToHumanToolOptions, B as ResolveToolApprovalsOptions, i as RobotRockAiContext, j as RobotRockAiMode, k as RobotRockAiPollingContext, l as RobotRockAiTriggerContext, m as RobotRockAiWorkflowContext, D as RobotRockToolApprovalConfig, z as RobotRockToolApprovalDecision, E as RunWithRobotRockApprovalsOptions, T as ToolApprovalRequestPart, t as applyRobotRockToolApprovalToTools, g as approveByHumanForAi, b as approveByHumanInputSchema, a as approveByHumanTool, u as collectApprovalRequests, o as createRobotRockAiTools, p as createRobotRockAiTriggerContext, q as createRobotRockAiWorkflowContext, v as createRobotRockNeedsApproval, w as createRobotRockToolApproval, e as createSendToHumanTool, n as normalizeRobotRockAiContext, x as resolveToolApprovalsViaRobotRock, y as runWithRobotRockApprovals, h as sendToHumanForAi, s as sendToHumanToolInputSchema } from '../workflow-iDk0Hlyg.js';
3
+ import { a as SendToHumanInput } from '../client-BOm2Ce2f.js';
4
4
  import { DiscriminatedApprovalResult } from '../schemas/index.js';
5
5
  import 'ai';
6
6
  import 'zod';
package/dist/ai/index.js CHANGED
@@ -19,8 +19,8 @@ import {
19
19
  sendToHumanForAi,
20
20
  sendToHumanToolInputSchema,
21
21
  toHumanToolResult
22
- } from "../chunk-DSZ3GMT4.js";
23
- import "../chunk-LXM7VS4Q.js";
22
+ } from "../chunk-RW2CQQZU.js";
23
+ import "../chunk-2KFY7ZJV.js";
24
24
  export {
25
25
  APPROVE_BY_HUMAN_ACTIONS,
26
26
  DEFAULT_APPROVE_ACTIONS,
@@ -1,5 +1,5 @@
1
- export { i as RobotRockAiContext, j as RobotRockAiMode, k as RobotRockAiPollingContext, l as RobotRockAiTriggerContext, t as applyRobotRockToolApprovalToTools, a as approveByHumanTool, o as createRobotRockAiTools, p as createRobotRockAiTriggerContext, v as createRobotRockNeedsApproval, w as createRobotRockToolApproval, e as createSendToHumanTool, x as resolveToolApprovalsViaRobotRock, y as runWithRobotRockApprovals } from '../workflow-BYeIZgD0.js';
1
+ export { i as RobotRockAiContext, j as RobotRockAiMode, k as RobotRockAiPollingContext, l as RobotRockAiTriggerContext, t as applyRobotRockToolApprovalToTools, a as approveByHumanTool, o as createRobotRockAiTools, p as createRobotRockAiTriggerContext, v as createRobotRockNeedsApproval, w as createRobotRockToolApproval, e as createSendToHumanTool, x as resolveToolApprovalsViaRobotRock, y as runWithRobotRockApprovals } from '../workflow-iDk0Hlyg.js';
2
2
  import 'ai';
3
3
  import 'zod';
4
- import '../client-Dhk9qxhL.js';
4
+ import '../client-BOm2Ce2f.js';
5
5
  import '../schemas/index.js';
@@ -8,8 +8,8 @@ import {
8
8
  createSendToHumanTool,
9
9
  resolveToolApprovalsViaRobotRock,
10
10
  runWithRobotRockApprovals
11
- } from "../chunk-DSZ3GMT4.js";
12
- import "../chunk-LXM7VS4Q.js";
11
+ } from "../chunk-RW2CQQZU.js";
12
+ import "../chunk-2KFY7ZJV.js";
13
13
  export {
14
14
  applyRobotRockToolApprovalToTools,
15
15
  approveByHumanTool,
@@ -1,5 +1,5 @@
1
- export { i as RobotRockAiContext, j as RobotRockAiMode, k as RobotRockAiPollingContext, l as RobotRockAiTriggerContext, m as RobotRockAiWorkflowContext, t as applyRobotRockToolApprovalToTools, a as approveByHumanTool, o as createRobotRockAiTools, q as createRobotRockAiWorkflowContext, v as createRobotRockNeedsApproval, w as createRobotRockToolApproval, e as createSendToHumanTool, x as resolveToolApprovalsViaRobotRock, y as runWithRobotRockApprovals } from '../workflow-BYeIZgD0.js';
1
+ export { i as RobotRockAiContext, j as RobotRockAiMode, k as RobotRockAiPollingContext, l as RobotRockAiTriggerContext, m as RobotRockAiWorkflowContext, t as applyRobotRockToolApprovalToTools, a as approveByHumanTool, o as createRobotRockAiTools, q as createRobotRockAiWorkflowContext, v as createRobotRockNeedsApproval, w as createRobotRockToolApproval, e as createSendToHumanTool, x as resolveToolApprovalsViaRobotRock, y as runWithRobotRockApprovals } from '../workflow-iDk0Hlyg.js';
2
2
  import 'ai';
3
3
  import 'zod';
4
- import '../client-Dhk9qxhL.js';
4
+ import '../client-BOm2Ce2f.js';
5
5
  import '../schemas/index.js';
@@ -8,8 +8,8 @@ import {
8
8
  createSendToHumanTool,
9
9
  resolveToolApprovalsViaRobotRock,
10
10
  runWithRobotRockApprovals
11
- } from "../chunk-DSZ3GMT4.js";
12
- import "../chunk-LXM7VS4Q.js";
11
+ } from "../chunk-RW2CQQZU.js";
12
+ import "../chunk-2KFY7ZJV.js";
13
13
  export {
14
14
  applyRobotRockToolApprovalToTools,
15
15
  approveByHumanTool,
@@ -110,20 +110,48 @@ var assignToSchema = z.object({
110
110
  },
111
111
  { message: 'Cannot combine "all" with other group slugs' }
112
112
  );
113
+ var threadUpdateMessageSchema = z.string().min(1).max(500);
114
+ var threadUpdateStatuses = [
115
+ "info",
116
+ "queued",
117
+ "running",
118
+ "waiting",
119
+ "succeeded",
120
+ "failed",
121
+ "cancelled"
122
+ ];
123
+ var threadUpdateStatusSchema = z.enum(threadUpdateStatuses);
124
+ var DEFAULT_THREAD_UPDATE_STATUS = "info";
125
+ var threadUpdateInputSchema = z.object({
126
+ message: threadUpdateMessageSchema,
127
+ status: threadUpdateStatusSchema.optional()
128
+ });
113
129
  var createTaskBodySchema = taskContextSchema.extend({
114
130
  assignTo: assignToSchema.optional(),
115
131
  /**
116
132
  * Groups related tasks together. When omitted, the server generates one and
117
133
  * returns it so the caller can reuse it on later tasks in the same thread.
118
134
  */
119
- threadId: z.string().min(1).optional()
135
+ threadId: z.string().min(1).optional(),
136
+ /**
137
+ * Optional initial status update logged against the task's thread. Shows in
138
+ * the inbox status bar and the thread update log.
139
+ */
140
+ update: threadUpdateInputSchema.optional()
120
141
  });
142
+ var threadUpdateBodySchema = threadUpdateInputSchema;
121
143
 
122
144
  export {
123
145
  __using,
124
146
  __callDispose,
125
147
  taskContextSchema,
126
148
  assignToSchema,
127
- createTaskBodySchema
149
+ threadUpdateMessageSchema,
150
+ threadUpdateStatuses,
151
+ threadUpdateStatusSchema,
152
+ DEFAULT_THREAD_UPDATE_STATUS,
153
+ threadUpdateInputSchema,
154
+ createTaskBodySchema,
155
+ threadUpdateBodySchema
128
156
  };
129
- //# sourceMappingURL=chunk-LXM7VS4Q.js.map
157
+ //# sourceMappingURL=chunk-2KFY7ZJV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schemas/index.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport interface JSONSchema7 {\n $id?: string;\n $ref?: string;\n $schema?: string;\n $comment?: string;\n type?: JSONSchema7TypeName | JSONSchema7TypeName[];\n enum?: unknown[];\n const?: unknown;\n multipleOf?: number;\n maximum?: number;\n exclusiveMaximum?: number;\n minimum?: number;\n exclusiveMinimum?: number;\n maxLength?: number;\n minLength?: number;\n pattern?: string;\n format?: string;\n items?: JSONSchema7 | JSONSchema7[];\n additionalItems?: JSONSchema7 | boolean;\n maxItems?: number;\n minItems?: number;\n uniqueItems?: boolean;\n contains?: JSONSchema7;\n maxProperties?: number;\n minProperties?: number;\n required?: string[];\n properties?: Record<string, JSONSchema7>;\n patternProperties?: Record<string, JSONSchema7>;\n additionalProperties?: JSONSchema7 | boolean;\n dependencies?: Record<string, JSONSchema7 | string[]>;\n propertyNames?: JSONSchema7;\n if?: JSONSchema7;\n then?: JSONSchema7;\n else?: JSONSchema7;\n allOf?: JSONSchema7[];\n anyOf?: JSONSchema7[];\n oneOf?: JSONSchema7[];\n not?: JSONSchema7;\n title?: string;\n description?: string;\n default?: unknown;\n readOnly?: boolean;\n writeOnly?: boolean;\n examples?: unknown[];\n}\n\nexport type JSONSchema7TypeName =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\nexport type ExtendedJSONSchema7 = JSONSchema7 & {\n enumNames?: string[];\n [key: string]: unknown;\n};\n\nexport type UiSchema = {\n \"ui:widget\"?: string;\n \"ui:title\"?: string;\n \"ui:description\"?: string;\n \"ui:placeholder\"?: string;\n \"ui:options\"?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nconst safeUrlSchema = z\n .string()\n .refine((url) => url.startsWith(\"http://\") || url.startsWith(\"https://\"), {\n message: \"URL must start with http:// or https://\",\n });\n\nconst jsonSchema7Schema = z.custom<ExtendedJSONSchema7>(\n (val) => typeof val === \"object\" && val !== null,\n { message: \"Must be a valid JSON Schema object\" }\n);\n\nconst uiSchemaSchema = z.custom<UiSchema>((val) => typeof val === \"object\" && val !== null, {\n message: \"Must be a valid UiSchema object\",\n});\n\nconst webhookHandlerSchema = z.object({\n type: z.literal(\"webhook\"),\n url: safeUrlSchema,\n headers: z.record(z.string()),\n});\n\nconst triggerHandlerSchema = webhookHandlerSchema.extend({\n type: z.literal(\"trigger\"),\n tokenId: z.string().min(1),\n});\n\nconst handlerSchema = z.discriminatedUnion(\"type\", [webhookHandlerSchema, triggerHandlerSchema]);\n\nconst taskActionSchema = z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n description: z.string().optional(),\n schema: jsonSchema7Schema.optional(),\n ui: uiSchemaSchema.optional(),\n data: z.record(z.unknown()).optional(),\n handlers: z.array(handlerSchema).min(1).optional(),\n});\n\nconst uiFieldSchemaSchema: z.ZodType<Record<string, unknown>> = z\n .object({\n \"ui:widget\": z.string().optional(),\n \"ui:title\": z.string().optional(),\n \"ui:description\": z.string().optional(),\n \"ui:options\": z.record(z.unknown()).optional(),\n items: z.lazy(() => z.record(uiFieldSchemaSchema)).optional(),\n })\n .passthrough();\n\nconst contextUiSchema = z.record(uiFieldSchemaSchema).optional();\n\nconst contextDataSchema = z\n .object({\n data: z.record(z.unknown()),\n ui: contextUiSchema,\n })\n .optional();\n\nexport const taskContextSchema = z.object({\n app: z.string().min(1).optional(),\n type: z.string().min(1),\n name: z.string().min(1),\n description: z.string().optional(),\n validUntil: z.string().optional(),\n context: contextDataSchema,\n version: z.literal(2).optional(),\n actions: z.array(taskActionSchema).min(1, \"At least one action is required\"),\n});\n\n/**\n * Assignment targets at task create (not stored in task context JSON).\n * Unknown user emails are auto-provisioned as assignee memberships (not full team seats).\n */\nexport const assignToSchema = z\n .object({\n users: z.array(z.string().email()).optional(),\n groups: z.array(z.string().min(1)).optional(),\n })\n .refine(\n (data) => {\n const groups = data.groups ?? [];\n if (groups.includes(\"all\") && groups.length > 1) {\n return false;\n }\n return true;\n },\n { message: 'Cannot combine \"all\" with other group slugs' }\n );\n\n/** A short thread-scoped status update message (1-2 sentences). */\nexport const threadUpdateMessageSchema = z.string().min(1).max(500);\n\n/**\n * Lifecycle status carried by a thread update. Drives the icon and color shown\n * in the inbox status bar. Defaults to `info` when omitted.\n */\nexport const threadUpdateStatuses = [\n \"info\",\n \"queued\",\n \"running\",\n \"waiting\",\n \"succeeded\",\n \"failed\",\n \"cancelled\",\n] as const;\n\nexport const threadUpdateStatusSchema = z.enum(threadUpdateStatuses);\n\n/** The default status applied when an update omits one. */\nexport const DEFAULT_THREAD_UPDATE_STATUS: ThreadUpdateStatus = \"info\";\n\n/** Shared shape for a thread update (standalone and at task creation). */\nexport const threadUpdateInputSchema = z.object({\n message: threadUpdateMessageSchema,\n status: threadUpdateStatusSchema.optional(),\n});\n\nexport const createTaskBodySchema = taskContextSchema.extend({\n assignTo: assignToSchema.optional(),\n /**\n * Groups related tasks together. When omitted, the server generates one and\n * returns it so the caller can reuse it on later tasks in the same thread.\n */\n threadId: z.string().min(1).optional(),\n /**\n * Optional initial status update logged against the task's thread. Shows in\n * the inbox status bar and the thread update log.\n */\n update: threadUpdateInputSchema.optional(),\n});\n\n/** POST /v1/threads/:threadId/updates body: a standalone thread update. */\nexport const threadUpdateBodySchema = threadUpdateInputSchema;\n\n/** Where a thread update originated. */\nexport type ThreadUpdateSource = \"api\" | \"task_create\" | \"dashboard\";\n\n/** Lifecycle status carried by a thread update. */\nexport type ThreadUpdateStatus = (typeof threadUpdateStatuses)[number];\n\n/** A logged thread update as returned by the API. */\nexport interface ThreadUpdate {\n id: string;\n threadId: string;\n message: string;\n status: ThreadUpdateStatus;\n source: ThreadUpdateSource;\n createdAt: number;\n}\n\nexport type AssignToInput = z.infer<typeof assignToSchema>;\nexport type CreateTaskBodyInput = z.input<typeof createTaskBodySchema>;\nexport type CreateTaskBody = z.output<typeof createTaskBodySchema>;\nexport type ThreadUpdateBodyInput = z.input<typeof threadUpdateBodySchema>;\nexport type ThreadUpdateBody = z.output<typeof threadUpdateBodySchema>;\nexport type ThreadUpdateInput = z.input<typeof threadUpdateInputSchema>;\nexport type TaskContextInput = z.input<typeof taskContextSchema>;\nexport type TaskContextOutput = z.output<typeof taskContextSchema>;\nexport type TaskContext = TaskContextOutput;\nexport type TaskAction = z.infer<typeof taskActionSchema>;\nexport type WebhookHandler = z.infer<typeof webhookHandlerSchema>;\nexport type TriggerHandler = z.infer<typeof triggerHandlerSchema>;\nexport type Handler = z.infer<typeof handlerSchema>;\n\ntype InferObjectProperties<\n Props,\n Req extends PropertyKey,\n> = Props extends Record<string, unknown>\n ? ({\n [K in keyof Props as K extends Req ? K : never]-?: InferJsonSchema7<Props[K]>;\n } & {\n [K in keyof Props as K extends Req ? never : K]?: InferJsonSchema7<Props[K]>;\n } extends infer O\n ? { [K in keyof O]: O[K] }\n : never)\n : Record<string, unknown>;\n\ntype RequiredKeys<S> =\n S extends { readonly required: readonly string[] } ? S[\"required\"][number] : never;\n\nexport type InferJsonSchema7<S> = [S] extends [undefined]\n ? Record<string, never>\n : S extends { readonly const: infer C }\n ? C\n : S extends {\n readonly enum: readonly (infer E)[];\n }\n ? E\n : S extends {\n readonly type: \"object\";\n readonly properties?: infer Props;\n }\n ? InferObjectProperties<Props, RequiredKeys<S>>\n : S extends {\n readonly type: \"object\";\n readonly properties?: undefined;\n }\n ? Record<string, unknown>\n : S extends {\n readonly type: \"array\";\n readonly items?: infer Items;\n }\n ? Items extends readonly unknown[]\n ? InferJsonSchema7<Items[number]>[]\n : Items extends object\n ? InferJsonSchema7<Items>[]\n : unknown[]\n : S extends { readonly type: \"string\" }\n ? string\n : S extends { readonly type: \"number\" } | { readonly type: \"integer\" }\n ? number\n : S extends { readonly type: \"boolean\" }\n ? boolean\n : unknown;\n\nexport type TaskStatus = \"pending\" | \"open\" | \"handled\" | \"expired\";\n\nexport interface TaskResponse {\n success: boolean;\n task: {\n taskId: string;\n threadId: string;\n status: \"pending\" | \"open\";\n context: TaskContext;\n validUntil: string;\n submittedAt: string;\n };\n message: string;\n}\n\nexport interface ThreadUpdateResponse {\n success: boolean;\n update: ThreadUpdate;\n message: string;\n}\n\nexport interface Task {\n id: string;\n threadId?: string;\n createdAt: Date;\n status: TaskStatus;\n context: TaskContext;\n validUntil: number;\n handledAt?: number;\n handled?: {\n action: {\n id: string;\n data: unknown;\n };\n handledBy?: string;\n userId?: string;\n token?: string;\n };\n}\n\nexport type InferActionData<T extends { schema?: unknown }> = [\n Exclude<T[\"schema\"], undefined>,\n] extends [\n never,\n]\n ? Record<string, never>\n : Exclude<T[\"schema\"], undefined> extends infer S\n ? InferJsonSchema7<S>\n : Record<string, never>;\n\nexport type TupleElementIndices<T extends readonly unknown[]> = T extends readonly [\n unknown,\n ...unknown[],\n]\n ? Exclude<keyof T, keyof unknown[]>\n : number;\n\nexport interface TaskResult<T = Record<string, unknown>> {\n actionId: string;\n data: T;\n handledBy?: string;\n handledAt: Date;\n}\n\nexport interface ApprovalResult<T = Record<string, unknown>> extends TaskResult<T> {\n taskId: string;\n}\n\nexport type DiscriminatedApprovalResult<\n TActions extends readonly { id: string; schema?: unknown }[],\n> = {\n [I in TupleElementIndices<TActions>]: TActions[I] extends { id: string; schema?: unknown }\n ? Omit<ApprovalResult<InferActionData<TActions[I]>>, \"actionId\" | \"data\"> & {\n actionId: TActions[I][\"id\"];\n data: InferActionData<TActions[I]>;\n }\n : never\n}[TupleElementIndices<TActions>];\n"],"mappings":"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","names":[]}
@@ -1,6 +1,7 @@
1
1
  import {
2
- createTaskBodySchema
3
- } from "./chunk-LXM7VS4Q.js";
2
+ createTaskBodySchema,
3
+ threadUpdateBodySchema
4
+ } from "./chunk-2KFY7ZJV.js";
4
5
 
5
6
  // src/approval-result.ts
6
7
  var TaskTimeoutError = class extends Error {
@@ -109,7 +110,8 @@ var RobotRock = class {
109
110
  const bodyPayload = {
110
111
  ...normalizedTask,
111
112
  ...task.assignTo !== void 0 ? { assignTo: task.assignTo } : {},
112
- ...task.threadId !== void 0 ? { threadId: task.threadId } : {}
113
+ ...task.threadId !== void 0 ? { threadId: task.threadId } : {},
114
+ ...task.update !== void 0 ? { update: task.update } : {}
113
115
  };
114
116
  const validation = createTaskBodySchema.safeParse(bodyPayload);
115
117
  if (!validation.success) {
@@ -209,6 +211,43 @@ var RobotRock = class {
209
211
  }
210
212
  return data;
211
213
  }
214
+ /**
215
+ * Log a status update against a thread. The update shows in the inbox status
216
+ * bar and thread update log for every task in the thread.
217
+ */
218
+ async sendUpdate({ threadId, message, status }) {
219
+ if (!threadId) {
220
+ throw new RobotRockError("threadId is required to send an update", 400);
221
+ }
222
+ const validation = threadUpdateBodySchema.safeParse({ message, status });
223
+ if (!validation.success) {
224
+ throw new RobotRockError(
225
+ `Invalid update: ${validation.error.errors[0]?.message}`,
226
+ 400,
227
+ validation.error.errors
228
+ );
229
+ }
230
+ const response = await fetch(
231
+ `${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,
232
+ {
233
+ method: "POST",
234
+ headers: {
235
+ "Content-Type": "application/json",
236
+ "X-Api-Key": this.apiKey
237
+ },
238
+ body: JSON.stringify(validation.data)
239
+ }
240
+ );
241
+ const data = await parseResponseBody(response);
242
+ if (!response.ok) {
243
+ throw new RobotRockError(
244
+ getErrorMessage(data, "Failed to send update"),
245
+ response.status,
246
+ data
247
+ );
248
+ }
249
+ return data.update;
250
+ }
212
251
  async cancelTask(taskId) {
213
252
  const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
214
253
  method: "POST",
@@ -250,6 +289,7 @@ function normalizeSendToHumanInput(task, clientDefaults) {
250
289
  idempotencyKey: _idempotencyKey,
251
290
  assignTo: _assignTo,
252
291
  threadId: _threadId,
292
+ update: _update,
253
293
  validUntil,
254
294
  app: taskApp,
255
295
  ...rest
@@ -329,4 +369,4 @@ export {
329
369
  resolveRobotRockConfig,
330
370
  resolveRobotRockClient
331
371
  };
332
- //# sourceMappingURL=chunk-KOXJCIST.js.map
372
+ //# sourceMappingURL=chunk-PZTTI6MW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/approval-result.ts","../src/client.ts","../src/env.ts"],"sourcesContent":["import type { DiscriminatedApprovalResult, Task } from \"./schemas/index.js\";\n\nexport class TaskTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TaskTimeoutError\";\n }\n}\n\nexport class TaskExpiredError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TaskExpiredError\";\n }\n}\n\n/**\n * Map a handled API task to a discriminated approval result.\n * Runtime validation is minimal; TypeScript narrows via `task.actions` at the call site.\n */\nexport function toDiscriminatedApprovalResult<A extends readonly { id: string; schema?: unknown }[]>(\n actions: A,\n task: Task\n): DiscriminatedApprovalResult<A> {\n void actions;\n\n if (!task.handled) {\n throw new Error(\"Task has no handled result\");\n }\n\n return {\n actionId: task.handled.action.id,\n data: task.handled.action.data,\n handledBy: task.handled.handledBy,\n handledAt: new Date(task.handledAt ?? Date.now()),\n taskId: task.id,\n } as DiscriminatedApprovalResult<A>;\n}\n","import {\n type AssignToInput,\n type TaskContextInput,\n createTaskBodySchema,\n threadUpdateBodySchema,\n} from \"./schemas/index.js\";\nimport {\n TaskExpiredError,\n TaskTimeoutError,\n toDiscriminatedApprovalResult,\n} from \"./approval-result.js\";\nimport type {\n DiscriminatedApprovalResult,\n Task,\n TaskResponse,\n ThreadUpdate,\n ThreadUpdateResponse,\n ThreadUpdateStatus,\n} from \"./schemas/index.js\";\n\nexport type RobotRockWebhookConfig = {\n url: string;\n headers?: Record<string, string>;\n};\n\nexport interface RobotRockPollingOptions {\n /** Poll interval when no webhook is configured (ms). @default 2000 */\n intervalMs?: number;\n /**\n * Max time to poll when no webhook is configured (ms).\n * Polling also stops when the task's `validUntil` passes, whichever is sooner.\n * @default 86400000 (24h)\n */\n timeoutMs?: number;\n}\n\ntype RobotRockClientBaseConfig = {\n /** Optional override for API key. Falls back to ROBOTROCK_API_KEY. */\n apiKey?: string;\n /**\n * Base URL for the RobotRock API\n * @default \"https://api.robotrock.io/v1\"\n */\n baseUrl?: string;\n /**\n * Default inbox app bucket for every task from this client.\n * When omitted, the API uses your API key name.\n */\n app?: string;\n /**\n * Task context format version sent on every `sendToHuman` request.\n * @default 2\n */\n version?: 2;\n};\n\n/** Client config with a webhook (mutually exclusive with `polling`). */\nexport type RobotRockWebhookClientConfig = RobotRockClientBaseConfig & {\n webhook: RobotRockWebhookConfig;\n polling?: never;\n};\n\n/** Client config without a webhook; optional `polling` controls the wait loop. */\nexport type RobotRockPollingClientConfig = RobotRockClientBaseConfig & {\n webhook?: never;\n polling?: RobotRockPollingOptions;\n};\n\nexport type RobotRockConfig = RobotRockWebhookClientConfig | RobotRockPollingClientConfig;\n\nexport type SendToHumanActionInput = Omit<TaskContextInput[\"actions\"][number], \"handlers\">;\n\nexport type SendToHumanValidUntil = Date | string;\n\nexport type SendToHumanInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = Omit<TaskContextInput, \"app\" | \"actions\" | \"version\" | \"validUntil\"> & {\n actions: A;\n /** Task deadline; serialized to an ISO 8601 string on the wire. */\n validUntil?: SendToHumanValidUntil;\n /** Optional idempotency key to prevent duplicate tasks */\n idempotencyKey?: string;\n /** Assign to tenant users (email) and/or groups (slug). Narrows inbox visibility. */\n assignTo?: AssignToInput;\n /**\n * Groups related tasks together in the inbox. Omit to let the server generate\n * one (returned as `task.threadId`) and reuse it on later tasks in the thread.\n */\n threadId?: string;\n /**\n * Optional initial status update logged against the task's thread. Shows in\n * the inbox status bar and the thread update log.\n */\n update?: {\n /** A short status update (1-2 sentences). */\n message: string;\n /** Lifecycle status for the icon/color in the status bar. @default \"info\" */\n status?: ThreadUpdateStatus;\n };\n};\n\ntype SendToHumanWithAppInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = (SendToHumanInput<A> | Readonly<SendToHumanInput<A>>) & {\n /** Inbox app bucket. Overrides the client `app` when set. */\n app?: string;\n};\n\nexport type SendUpdateInput = {\n /** The thread to log the update against (from `task.threadId`). */\n threadId: string;\n /** A short status update (1-2 sentences). */\n message: string;\n /** Lifecycle status for the icon/color in the status bar. @default \"info\" */\n status?: ThreadUpdateStatus;\n};\n\nexport type SendToHumanResult<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> =\n | {\n mode: \"created\";\n task: TaskResponse[\"task\"];\n }\n | ({\n mode: \"handled\";\n task: TaskResponse[\"task\"];\n } & DiscriminatedApprovalResult<A>);\n\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseValidUntilMs(value: string | number | Date | undefined): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (value instanceof Date) {\n const ms = value.getTime();\n return Number.isNaN(ms) ? undefined : ms;\n }\n\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : undefined;\n }\n\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction serializeValidUntil(value: SendToHumanValidUntil): string {\n if (value instanceof Date) {\n const ms = value.getTime();\n if (Number.isNaN(ms)) {\n throw new RobotRockError(\"Invalid validUntil: Date is invalid\", 400);\n }\n return value.toISOString();\n }\n\n if (typeof value === \"string\" && !Number.isNaN(Date.parse(value))) {\n return new Date(value).toISOString();\n }\n\n throw new RobotRockError(\"Invalid validUntil: expected a Date or parseable date string\", 400);\n}\n\nexport class RobotRockError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly response?: unknown\n ) {\n super(message);\n this.name = \"RobotRockError\";\n }\n}\n\n/**\n * RobotRock API client for creating and querying human-in-the-loop tasks.\n */\nexport class RobotRock {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly app?: string;\n private readonly version: 2;\n private readonly webhook?: RobotRockWebhookConfig;\n private readonly polling: RobotRockPollingOptions;\n\n constructor(config: RobotRockConfig) {\n if (config.webhook && config.polling) {\n throw new Error(\n \"RobotRock client cannot configure both webhook and polling. Use webhook for callbacks or polling to block until handled.\"\n );\n }\n\n const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client.\"\n );\n }\n this.apiKey = apiKey;\n const rawBase = config.baseUrl ?? \"https://api.robotrock.io/v1\";\n this.baseUrl = rawBase.replace(/\\/+$/, \"\");\n this.app = config.app;\n this.version = config.version ?? 2;\n this.webhook = config.webhook;\n this.polling = config.polling ?? {};\n }\n\n /**\n * Create a task via POST /v1 without waiting for a human response.\n */\n async createTask<const A extends readonly SendToHumanActionInput[]>(\n task: SendToHumanWithAppInput<A>\n ): Promise<TaskResponse[\"task\"]> {\n const normalizedTask = normalizeSendToHumanInput(task, {\n webhook: this.webhook,\n app: this.app,\n version: this.version,\n });\n const bodyPayload = {\n ...normalizedTask,\n ...(task.assignTo !== undefined ? { assignTo: task.assignTo } : {}),\n ...(task.threadId !== undefined ? { threadId: task.threadId } : {}),\n ...(task.update !== undefined ? { update: task.update } : {}),\n };\n const validation = createTaskBodySchema.safeParse(bodyPayload);\n if (!validation.success) {\n throw new RobotRockError(\n `Invalid task: ${validation.error.errors[0]?.message}`,\n 400,\n validation.error.errors\n );\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n };\n\n if (task.idempotencyKey) {\n headers[\"Idempotency-Key\"] = task.idempotencyKey;\n }\n\n const response = await fetch(`${this.baseUrl}/`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(validation.data),\n });\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to create task\"),\n response.status,\n data\n );\n }\n\n return (data as unknown as TaskResponse).task;\n }\n\n async sendToHuman<const A extends readonly SendToHumanActionInput[]>(\n task: SendToHumanWithAppInput<A>\n ): Promise<SendToHumanResult<A>> {\n const normalizedTask = normalizeSendToHumanInput(task, {\n webhook: this.webhook,\n app: this.app,\n version: this.version,\n });\n const createdTaskTask = await this.createTask(task);\n const hasHandlers = normalizedTask.actions.some(\n (action) => Array.isArray(action.handlers) && action.handlers.length > 0\n );\n\n if (hasHandlers) {\n return {\n mode: \"created\",\n task: createdTaskTask,\n };\n }\n\n const timeoutMs = this.polling.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pollIntervalMs = this.polling.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const pollingDeadline = Date.now() + timeoutMs;\n const validUntilMs = parseValidUntilMs(createdTaskTask.validUntil);\n const deadline =\n validUntilMs !== undefined ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;\n const taskId = createdTaskTask.taskId;\n\n while (Date.now() < deadline) {\n const existing = await this.getTask(taskId);\n\n if (existing?.status === \"handled\" && existing.handled) {\n return {\n mode: \"handled\",\n task: createdTaskTask,\n ...(toDiscriminatedApprovalResult(\n normalizedTask.actions as unknown as A,\n existing\n ) as DiscriminatedApprovalResult<A>),\n };\n }\n\n if (existing?.status === \"expired\" || (existing && Date.now() >= existing.validUntil)) {\n throw new TaskExpiredError(\"Task reached validUntil before a human completed it\");\n }\n\n const remainingMs = deadline - Date.now();\n await sleep(Math.min(pollIntervalMs, Math.max(0, remainingMs)));\n }\n\n if (validUntilMs !== undefined && Date.now() >= validUntilMs) {\n throw new TaskExpiredError(\"Task reached validUntil before a human completed it\");\n }\n\n throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);\n }\n\n /**\n * Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).\n */\n async getTask(taskId: string): Promise<Task | null> {\n const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {\n method: \"GET\",\n headers: {\n \"X-Api-Key\": this.apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to get task\"),\n response.status,\n data\n );\n }\n\n return data as unknown as Task;\n }\n\n /**\n * Log a status update against a thread. The update shows in the inbox status\n * bar and thread update log for every task in the thread.\n */\n async sendUpdate({ threadId, message, status }: SendUpdateInput): Promise<ThreadUpdate> {\n if (!threadId) {\n throw new RobotRockError(\"threadId is required to send an update\", 400);\n }\n\n const validation = threadUpdateBodySchema.safeParse({ message, status });\n if (!validation.success) {\n throw new RobotRockError(\n `Invalid update: ${validation.error.errors[0]?.message}`,\n 400,\n validation.error.errors\n );\n }\n\n const response = await fetch(\n `${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n },\n body: JSON.stringify(validation.data),\n }\n );\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to send update\"),\n response.status,\n data\n );\n }\n\n return (data as unknown as ThreadUpdateResponse).update;\n }\n\n async cancelTask(taskId: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {\n method: \"POST\",\n headers: {\n \"X-Api-Key\": this.apiKey,\n },\n });\n\n if (!response.ok) {\n const data = await parseResponseBody(response);\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to cancel task\"),\n response.status,\n data\n );\n }\n }\n}\n\nexport function createClient(config: RobotRockConfig): RobotRock {\n return new RobotRock(config);\n}\n\nexport function attachWebhookToActions(\n actions: readonly SendToHumanActionInput[],\n webhook: RobotRockWebhookConfig\n): TaskContextInput[\"actions\"] {\n return actions.map((action) => ({\n ...action,\n handlers: webhookToHandlers(webhook),\n }));\n}\n\nfunction webhookToHandlers(\n webhook: RobotRockWebhookConfig\n): TaskContextInput[\"actions\"][number][\"handlers\"] {\n return [\n {\n type: \"webhook\" as const,\n url: webhook.url,\n headers: webhook.headers ?? {},\n },\n ];\n}\n\nfunction normalizeSendToHumanInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n>(\n task: SendToHumanWithAppInput<A>,\n clientDefaults: { webhook?: RobotRockWebhookConfig; app?: string; version: 2 }\n): TaskContextInput {\n const {\n actions,\n idempotencyKey: _idempotencyKey,\n assignTo: _assignTo,\n threadId: _threadId,\n update: _update,\n validUntil,\n app: taskApp,\n ...rest\n } = task;\n\n const webhook = clientDefaults.webhook;\n const normalizedActions: TaskContextInput[\"actions\"] = webhook\n ? attachWebhookToActions(actions, webhook)\n : (actions as unknown as TaskContextInput[\"actions\"]);\n\n const app = taskApp ?? clientDefaults.app;\n\n return {\n ...rest,\n version: clientDefaults.version,\n ...(app ? { app } : {}),\n ...(validUntil !== undefined ? { validUntil: serializeValidUntil(validUntil) } : {}),\n actions: normalizedActions,\n };\n}\n\ntype ParsedResponseBody = Record<string, unknown> | unknown[] | string | null;\n\nasync function parseResponseBody(response: Response): Promise<ParsedResponseBody> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const bodyText = await response.text();\n\n if (!bodyText) {\n return null;\n }\n\n if (contentType.toLowerCase().includes(\"application/json\")) {\n try {\n return JSON.parse(bodyText) as ParsedResponseBody;\n } catch {\n // Fall through and return text body below so error messages stay useful.\n }\n }\n\n try {\n return JSON.parse(bodyText) as ParsedResponseBody;\n } catch {\n return bodyText;\n }\n}\n\nfunction getErrorMessage(data: ParsedResponseBody, fallback: string): string {\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n const maybeMessage = (data as Record<string, unknown>).message;\n if (typeof maybeMessage === \"string\" && maybeMessage.trim()) {\n return maybeMessage;\n }\n }\n\n if (typeof data === \"string\" && data.trim()) {\n const compact = data.replace(/\\s+/g, \" \").trim();\n const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;\n return `${fallback}. Server returned non-JSON response: ${snippet}`;\n }\n\n return fallback;\n}\n","import { createClient, type RobotRock, type RobotRockConfig } from \"./client.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.robotrock.io/v1\";\n\n/**\n * Read RobotRock client config from environment variables.\n *\n * - `ROBOTROCK_API_KEY` (required when not passed explicitly)\n * - `ROBOTROCK_BASE_URL` or `ROBOTROCK_API_URL` (optional)\n * - `ROBOTROCK_APP` (optional inbox app bucket)\n */\nexport function resolveRobotRockConfig(\n overrides?: Partial<RobotRockConfig>\n): RobotRockConfig {\n const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client.\"\n );\n }\n\n const baseUrl =\n overrides?.baseUrl ??\n process.env.ROBOTROCK_BASE_URL ??\n process.env.ROBOTROCK_API_URL ??\n DEFAULT_BASE_URL;\n\n const app = overrides?.app ?? process.env.ROBOTROCK_APP;\n\n return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };\n}\n\n/** Use an explicit client or create one from env / optional config overrides. */\nexport function resolveRobotRockClient(\n client?: RobotRock,\n configOverrides?: Partial<RobotRockConfig>\n): RobotRock {\n if (client) {\n return client;\n }\n return createClient(resolveRobotRockConfig(configOverrides));\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  assignToSchema
3
- } from "./chunk-LXM7VS4Q.js";
3
+ } from "./chunk-2KFY7ZJV.js";
4
4
 
5
5
  // src/ai/context.ts
6
6
  var APPROVE_BY_HUMAN_ACTIONS = [
@@ -515,4 +515,4 @@ export {
515
515
  resolveToolApprovalsViaRobotRock,
516
516
  runWithRobotRockApprovals
517
517
  };
518
- //# sourceMappingURL=chunk-DSZ3GMT4.js.map
518
+ //# sourceMappingURL=chunk-RW2CQQZU.js.map
@@ -1,4 +1,4 @@
1
- import { TaskContextInput, AssignToInput, TaskResponse, DiscriminatedApprovalResult, Task } from './schemas/index.js';
1
+ import { TaskContextInput, AssignToInput, ThreadUpdateStatus, TaskResponse, DiscriminatedApprovalResult, Task, ThreadUpdate } from './schemas/index.js';
2
2
 
3
3
  type RobotRockWebhookConfig = {
4
4
  url: string;
@@ -59,11 +59,29 @@ type SendToHumanInput<A extends readonly SendToHumanActionInput[] = readonly Sen
59
59
  * one (returned as `task.threadId`) and reuse it on later tasks in the thread.
60
60
  */
61
61
  threadId?: string;
62
+ /**
63
+ * Optional initial status update logged against the task's thread. Shows in
64
+ * the inbox status bar and the thread update log.
65
+ */
66
+ update?: {
67
+ /** A short status update (1-2 sentences). */
68
+ message: string;
69
+ /** Lifecycle status for the icon/color in the status bar. @default "info" */
70
+ status?: ThreadUpdateStatus;
71
+ };
62
72
  };
63
73
  type SendToHumanWithAppInput<A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[]> = (SendToHumanInput<A> | Readonly<SendToHumanInput<A>>) & {
64
74
  /** Inbox app bucket. Overrides the client `app` when set. */
65
75
  app?: string;
66
76
  };
77
+ type SendUpdateInput = {
78
+ /** The thread to log the update against (from `task.threadId`). */
79
+ threadId: string;
80
+ /** A short status update (1-2 sentences). */
81
+ message: string;
82
+ /** Lifecycle status for the icon/color in the status bar. @default "info" */
83
+ status?: ThreadUpdateStatus;
84
+ };
67
85
  type SendToHumanResult<A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[]> = {
68
86
  mode: "created";
69
87
  task: TaskResponse["task"];
@@ -96,9 +114,14 @@ declare class RobotRock {
96
114
  * Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
97
115
  */
98
116
  getTask(taskId: string): Promise<Task | null>;
117
+ /**
118
+ * Log a status update against a thread. The update shows in the inbox status
119
+ * bar and thread update log for every task in the thread.
120
+ */
121
+ sendUpdate({ threadId, message, status }: SendUpdateInput): Promise<ThreadUpdate>;
99
122
  cancelTask(taskId: string): Promise<void>;
100
123
  }
101
124
  declare function createClient(config: RobotRockConfig): RobotRock;
102
125
  declare function attachWebhookToActions(actions: readonly SendToHumanActionInput[], webhook: RobotRockWebhookConfig): TaskContextInput["actions"];
103
126
 
104
- export { type RobotRockConfig as R, type SendToHumanActionInput as S, type SendToHumanInput as a, RobotRock as b, RobotRockError as c, attachWebhookToActions as d, createClient as e, type RobotRockWebhookClientConfig as f, type RobotRockPollingClientConfig as g, type RobotRockWebhookConfig as h, type RobotRockPollingOptions as i, type SendToHumanValidUntil as j, type SendToHumanResult as k };
127
+ export { type RobotRockConfig as R, type SendToHumanActionInput as S, type SendToHumanInput as a, RobotRock as b, RobotRockError as c, attachWebhookToActions as d, createClient as e, type RobotRockWebhookClientConfig as f, type RobotRockPollingClientConfig as g, type RobotRockWebhookConfig as h, type RobotRockPollingOptions as i, type SendToHumanValidUntil as j, type SendToHumanResult as k, type SendUpdateInput as l };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { R as RobotRockConfig, b as RobotRock } from './client-Dhk9qxhL.js';
2
- export { c as RobotRockError, g as RobotRockPollingClientConfig, i as RobotRockPollingOptions, f as RobotRockWebhookClientConfig, h as RobotRockWebhookConfig, S as SendToHumanActionInput, a as SendToHumanInput, k as SendToHumanResult, j as SendToHumanValidUntil, d as attachWebhookToActions, e as createClient } from './client-Dhk9qxhL.js';
1
+ import { R as RobotRockConfig, b as RobotRock } from './client-BOm2Ce2f.js';
2
+ export { c as RobotRockError, g as RobotRockPollingClientConfig, i as RobotRockPollingOptions, f as RobotRockWebhookClientConfig, h as RobotRockWebhookConfig, S as SendToHumanActionInput, a as SendToHumanInput, k as SendToHumanResult, j as SendToHumanValidUntil, l as SendUpdateInput, d as attachWebhookToActions, e as createClient } from './client-BOm2Ce2f.js';
3
3
  import { Task, DiscriminatedApprovalResult } from './schemas/index.js';
4
- export { ApprovalResult, AssignToInput, CreateTaskBody, CreateTaskBodyInput, Handler, InferActionData, TaskAction, TaskContext, TaskContextInput, TaskResponse, TaskResult, TaskStatus, TriggerHandler, TupleElementIndices, WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema } from './schemas/index.js';
4
+ export { ApprovalResult, AssignToInput, CreateTaskBody, CreateTaskBodyInput, DEFAULT_THREAD_UPDATE_STATUS, Handler, InferActionData, TaskAction, TaskContext, TaskContextInput, TaskResponse, TaskResult, TaskStatus, ThreadUpdate, ThreadUpdateBody, ThreadUpdateBodyInput, ThreadUpdateInput, ThreadUpdateResponse, ThreadUpdateSource, ThreadUpdateStatus, TriggerHandler, TupleElementIndices, WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateStatusSchema, threadUpdateStatuses } from './schemas/index.js';
5
5
  import { z } from 'zod';
6
6
  export { R as RobotRockHandlerWebhookPayload } from './handler-webhook-BqEi6Bk-.js';
7
7
 
package/dist/index.js CHANGED
@@ -8,12 +8,17 @@ import {
8
8
  resolveRobotRockClient,
9
9
  resolveRobotRockConfig,
10
10
  toDiscriminatedApprovalResult
11
- } from "./chunk-KOXJCIST.js";
11
+ } from "./chunk-PZTTI6MW.js";
12
12
  import {
13
+ DEFAULT_THREAD_UPDATE_STATUS,
13
14
  assignToSchema,
14
15
  createTaskBodySchema,
15
- taskContextSchema
16
- } from "./chunk-LXM7VS4Q.js";
16
+ taskContextSchema,
17
+ threadUpdateBodySchema,
18
+ threadUpdateInputSchema,
19
+ threadUpdateStatusSchema,
20
+ threadUpdateStatuses
21
+ } from "./chunk-2KFY7ZJV.js";
17
22
 
18
23
  // src/webhook.ts
19
24
  import { createHmac, timingSafeEqual } from "crypto";
@@ -121,6 +126,7 @@ function normalizeHeaders(headers) {
121
126
  return result;
122
127
  }
123
128
  export {
129
+ DEFAULT_THREAD_UPDATE_STATUS,
124
130
  RobotRock,
125
131
  RobotRockError,
126
132
  RobotRockWebhookError,
@@ -133,6 +139,10 @@ export {
133
139
  resolveRobotRockClient,
134
140
  resolveRobotRockConfig,
135
141
  taskContextSchema,
142
+ threadUpdateBodySchema,
143
+ threadUpdateInputSchema,
144
+ threadUpdateStatusSchema,
145
+ threadUpdateStatuses,
136
146
  toDiscriminatedApprovalResult,
137
147
  verifyRobotRockWebhook
138
148
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/webhook.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\n\nconst ROBOTROCK_SIGNATURE_HEADER = \"x-robotrock-signature\";\n\nconst robotRockWebhookPayloadBodySchema = z.object({\n taskId: z.string().min(1),\n action: z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n data: z.unknown(),\n }),\n handledBy: z.string().min(1).optional(),\n handledAt: z.string().min(1),\n handlerType: z.string().min(1),\n});\n\nconst robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({\n headers: z.record(z.string()),\n});\n\nexport type RobotRockWebhookErrorCode =\n | \"MISSING_WEBHOOK_SECRET\"\n | \"MISSING_SIGNATURE\"\n | \"INVALID_SIGNATURE\"\n | \"INVALID_JSON\"\n | \"INVALID_PAYLOAD\";\n\nexport class RobotRockWebhookError extends Error {\n constructor(\n message: string,\n public readonly code: RobotRockWebhookErrorCode,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = \"RobotRockWebhookError\";\n }\n}\n\nexport type RobotRockWebhookPayload = z.infer<typeof robotRockWebhookPayloadSchema>;\n\nexport interface VerifyRobotRockWebhookOptions {\n /**\n * Override shared secret (defaults to ROBOTROCK_WEBHOOK_SECRET).\n * Keep undefined in production to enforce the canonical env var.\n */\n secret?: string;\n /**\n * Resolve the tenant signing secret by public task id (hosted MCP uses Convex).\n * Used when secret is not passed explicitly.\n */\n resolveSecret?: (taskId: string) => Promise<string | undefined>;\n /** Signature header to read. @default \"x-robotrock-signature\" */\n signatureHeader?: string;\n}\n\n/**\n * Verify a RobotRock webhook request and return a validated payload.\n * Throws RobotRockWebhookError with machine-readable `code` for audit logging.\n */\nexport async function verifyRobotRockWebhook(\n request: Request,\n options: VerifyRobotRockWebhookOptions = {}\n): Promise<RobotRockWebhookPayload> {\n const signatureHeaderName = options.signatureHeader ?? ROBOTROCK_SIGNATURE_HEADER;\n const signature = request.headers.get(signatureHeaderName);\n\n if (!signature) {\n throw new RobotRockWebhookError(\n `Missing webhook signature header: ${signatureHeaderName}`,\n \"MISSING_SIGNATURE\"\n );\n }\n\n const rawBody = await request.text();\n const secret = await resolveWebhookSigningSecret(rawBody, options);\n\n if (!secret) {\n throw new RobotRockWebhookError(\n \"Missing webhook signing secret for verification\",\n \"MISSING_WEBHOOK_SECRET\"\n );\n }\n\n assertValidSignature(rawBody, signature, secret);\n\n let parsedBody: unknown;\n try {\n parsedBody = JSON.parse(rawBody);\n } catch (error) {\n throw new RobotRockWebhookError(\"Webhook body is not valid JSON\", \"INVALID_JSON\", {\n cause: error instanceof Error ? error.message : String(error),\n });\n }\n\n const payloadResult = robotRockWebhookPayloadBodySchema.safeParse(parsedBody);\n if (!payloadResult.success) {\n throw new RobotRockWebhookError(\n \"Webhook payload schema validation failed\",\n \"INVALID_PAYLOAD\",\n payloadResult.error.flatten()\n );\n }\n\n return {\n ...payloadResult.data,\n headers: normalizeHeaders(request.headers),\n };\n}\n\nasync function resolveWebhookSigningSecret(\n rawBody: string,\n options: VerifyRobotRockWebhookOptions\n): Promise<string | undefined> {\n if (options.secret) {\n return options.secret;\n }\n\n if (options.resolveSecret) {\n const taskId = peekWebhookTaskId(rawBody);\n if (taskId) {\n const resolved = await options.resolveSecret(taskId);\n if (resolved) {\n return resolved;\n }\n }\n }\n\n return process.env.ROBOTROCK_WEBHOOK_SECRET;\n}\n\nfunction peekWebhookTaskId(rawBody: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(rawBody);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n \"taskId\" in parsed &&\n typeof (parsed as { taskId: unknown }).taskId === \"string\"\n ) {\n return (parsed as { taskId: string }).taskId;\n }\n } catch {\n // fall through\n }\n return undefined;\n}\n\nfunction assertValidSignature(rawBody: string, signature: string, secret: string): void {\n const expected = `sha256=${createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\")}`;\n const expectedBuffer = Buffer.from(expected);\n const receivedBuffer = Buffer.from(signature);\n\n if (\n expectedBuffer.length !== receivedBuffer.length ||\n !timingSafeEqual(expectedBuffer, receivedBuffer)\n ) {\n throw new RobotRockWebhookError(\"Webhook signature verification failed\", \"INVALID_SIGNATURE\");\n }\n}\n\nfunction normalizeHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/webhook.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\n\nconst ROBOTROCK_SIGNATURE_HEADER = \"x-robotrock-signature\";\n\nconst robotRockWebhookPayloadBodySchema = z.object({\n taskId: z.string().min(1),\n action: z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n data: z.unknown(),\n }),\n handledBy: z.string().min(1).optional(),\n handledAt: z.string().min(1),\n handlerType: z.string().min(1),\n});\n\nconst robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({\n headers: z.record(z.string()),\n});\n\nexport type RobotRockWebhookErrorCode =\n | \"MISSING_WEBHOOK_SECRET\"\n | \"MISSING_SIGNATURE\"\n | \"INVALID_SIGNATURE\"\n | \"INVALID_JSON\"\n | \"INVALID_PAYLOAD\";\n\nexport class RobotRockWebhookError extends Error {\n constructor(\n message: string,\n public readonly code: RobotRockWebhookErrorCode,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = \"RobotRockWebhookError\";\n }\n}\n\nexport type RobotRockWebhookPayload = z.infer<typeof robotRockWebhookPayloadSchema>;\n\nexport interface VerifyRobotRockWebhookOptions {\n /**\n * Override shared secret (defaults to ROBOTROCK_WEBHOOK_SECRET).\n * Keep undefined in production to enforce the canonical env var.\n */\n secret?: string;\n /**\n * Resolve the tenant signing secret by public task id (hosted MCP uses Convex).\n * Used when secret is not passed explicitly.\n */\n resolveSecret?: (taskId: string) => Promise<string | undefined>;\n /** Signature header to read. @default \"x-robotrock-signature\" */\n signatureHeader?: string;\n}\n\n/**\n * Verify a RobotRock webhook request and return a validated payload.\n * Throws RobotRockWebhookError with machine-readable `code` for audit logging.\n */\nexport async function verifyRobotRockWebhook(\n request: Request,\n options: VerifyRobotRockWebhookOptions = {}\n): Promise<RobotRockWebhookPayload> {\n const signatureHeaderName = options.signatureHeader ?? ROBOTROCK_SIGNATURE_HEADER;\n const signature = request.headers.get(signatureHeaderName);\n\n if (!signature) {\n throw new RobotRockWebhookError(\n `Missing webhook signature header: ${signatureHeaderName}`,\n \"MISSING_SIGNATURE\"\n );\n }\n\n const rawBody = await request.text();\n const secret = await resolveWebhookSigningSecret(rawBody, options);\n\n if (!secret) {\n throw new RobotRockWebhookError(\n \"Missing webhook signing secret for verification\",\n \"MISSING_WEBHOOK_SECRET\"\n );\n }\n\n assertValidSignature(rawBody, signature, secret);\n\n let parsedBody: unknown;\n try {\n parsedBody = JSON.parse(rawBody);\n } catch (error) {\n throw new RobotRockWebhookError(\"Webhook body is not valid JSON\", \"INVALID_JSON\", {\n cause: error instanceof Error ? error.message : String(error),\n });\n }\n\n const payloadResult = robotRockWebhookPayloadBodySchema.safeParse(parsedBody);\n if (!payloadResult.success) {\n throw new RobotRockWebhookError(\n \"Webhook payload schema validation failed\",\n \"INVALID_PAYLOAD\",\n payloadResult.error.flatten()\n );\n }\n\n return {\n ...payloadResult.data,\n headers: normalizeHeaders(request.headers),\n };\n}\n\nasync function resolveWebhookSigningSecret(\n rawBody: string,\n options: VerifyRobotRockWebhookOptions\n): Promise<string | undefined> {\n if (options.secret) {\n return options.secret;\n }\n\n if (options.resolveSecret) {\n const taskId = peekWebhookTaskId(rawBody);\n if (taskId) {\n const resolved = await options.resolveSecret(taskId);\n if (resolved) {\n return resolved;\n }\n }\n }\n\n return process.env.ROBOTROCK_WEBHOOK_SECRET;\n}\n\nfunction peekWebhookTaskId(rawBody: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(rawBody);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n \"taskId\" in parsed &&\n typeof (parsed as { taskId: unknown }).taskId === \"string\"\n ) {\n return (parsed as { taskId: string }).taskId;\n }\n } catch {\n // fall through\n }\n return undefined;\n}\n\nfunction assertValidSignature(rawBody: string, signature: string, secret: string): void {\n const expected = `sha256=${createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\")}`;\n const expectedBuffer = Buffer.from(expected);\n const receivedBuffer = Buffer.from(signature);\n\n if (\n expectedBuffer.length !== receivedBuffer.length ||\n !timingSafeEqual(expectedBuffer, receivedBuffer)\n ) {\n throw new RobotRockWebhookError(\"Webhook signature verification failed\", \"INVALID_SIGNATURE\");\n }\n}\n\nfunction normalizeHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n"],"mappings":"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","names":[]}
@@ -355,6 +355,27 @@ declare const assignToSchema: z.ZodEffects<z.ZodObject<{
355
355
  users?: string[] | undefined;
356
356
  groups?: string[] | undefined;
357
357
  }>;
358
+ /** A short thread-scoped status update message (1-2 sentences). */
359
+ declare const threadUpdateMessageSchema: z.ZodString;
360
+ /**
361
+ * Lifecycle status carried by a thread update. Drives the icon and color shown
362
+ * in the inbox status bar. Defaults to `info` when omitted.
363
+ */
364
+ declare const threadUpdateStatuses: readonly ["info", "queued", "running", "waiting", "succeeded", "failed", "cancelled"];
365
+ declare const threadUpdateStatusSchema: z.ZodEnum<["info", "queued", "running", "waiting", "succeeded", "failed", "cancelled"]>;
366
+ /** The default status applied when an update omits one. */
367
+ declare const DEFAULT_THREAD_UPDATE_STATUS: ThreadUpdateStatus;
368
+ /** Shared shape for a thread update (standalone and at task creation). */
369
+ declare const threadUpdateInputSchema: z.ZodObject<{
370
+ message: z.ZodString;
371
+ status: z.ZodOptional<z.ZodEnum<["info", "queued", "running", "waiting", "succeeded", "failed", "cancelled"]>>;
372
+ }, "strip", z.ZodTypeAny, {
373
+ message: string;
374
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
375
+ }, {
376
+ message: string;
377
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
378
+ }>;
358
379
  declare const createTaskBodySchema: z.ZodObject<{
359
380
  app: z.ZodOptional<z.ZodString>;
360
381
  type: z.ZodString;
@@ -465,6 +486,20 @@ declare const createTaskBodySchema: z.ZodObject<{
465
486
  * returns it so the caller can reuse it on later tasks in the same thread.
466
487
  */
467
488
  threadId: z.ZodOptional<z.ZodString>;
489
+ /**
490
+ * Optional initial status update logged against the task's thread. Shows in
491
+ * the inbox status bar and the thread update log.
492
+ */
493
+ update: z.ZodOptional<z.ZodObject<{
494
+ message: z.ZodString;
495
+ status: z.ZodOptional<z.ZodEnum<["info", "queued", "running", "waiting", "succeeded", "failed", "cancelled"]>>;
496
+ }, "strip", z.ZodTypeAny, {
497
+ message: string;
498
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
499
+ }, {
500
+ message: string;
501
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
502
+ }>>;
468
503
  }, "strip", z.ZodTypeAny, {
469
504
  type: string;
470
505
  name: string;
@@ -499,6 +534,10 @@ declare const createTaskBodySchema: z.ZodObject<{
499
534
  groups?: string[] | undefined;
500
535
  } | undefined;
501
536
  threadId?: string | undefined;
537
+ update?: {
538
+ message: string;
539
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
540
+ } | undefined;
502
541
  }, {
503
542
  type: string;
504
543
  name: string;
@@ -533,10 +572,41 @@ declare const createTaskBodySchema: z.ZodObject<{
533
572
  groups?: string[] | undefined;
534
573
  } | undefined;
535
574
  threadId?: string | undefined;
575
+ update?: {
576
+ message: string;
577
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
578
+ } | undefined;
579
+ }>;
580
+ /** POST /v1/threads/:threadId/updates body: a standalone thread update. */
581
+ declare const threadUpdateBodySchema: z.ZodObject<{
582
+ message: z.ZodString;
583
+ status: z.ZodOptional<z.ZodEnum<["info", "queued", "running", "waiting", "succeeded", "failed", "cancelled"]>>;
584
+ }, "strip", z.ZodTypeAny, {
585
+ message: string;
586
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
587
+ }, {
588
+ message: string;
589
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
536
590
  }>;
591
+ /** Where a thread update originated. */
592
+ type ThreadUpdateSource = "api" | "task_create" | "dashboard";
593
+ /** Lifecycle status carried by a thread update. */
594
+ type ThreadUpdateStatus = (typeof threadUpdateStatuses)[number];
595
+ /** A logged thread update as returned by the API. */
596
+ interface ThreadUpdate {
597
+ id: string;
598
+ threadId: string;
599
+ message: string;
600
+ status: ThreadUpdateStatus;
601
+ source: ThreadUpdateSource;
602
+ createdAt: number;
603
+ }
537
604
  type AssignToInput = z.infer<typeof assignToSchema>;
538
605
  type CreateTaskBodyInput = z.input<typeof createTaskBodySchema>;
539
606
  type CreateTaskBody = z.output<typeof createTaskBodySchema>;
607
+ type ThreadUpdateBodyInput = z.input<typeof threadUpdateBodySchema>;
608
+ type ThreadUpdateBody = z.output<typeof threadUpdateBodySchema>;
609
+ type ThreadUpdateInput = z.input<typeof threadUpdateInputSchema>;
540
610
  type TaskContextInput = z.input<typeof taskContextSchema>;
541
611
  type TaskContextOutput = z.output<typeof taskContextSchema>;
542
612
  type TaskContext = TaskContextOutput;
@@ -589,6 +659,11 @@ interface TaskResponse {
589
659
  };
590
660
  message: string;
591
661
  }
662
+ interface ThreadUpdateResponse {
663
+ success: boolean;
664
+ update: ThreadUpdate;
665
+ message: string;
666
+ }
592
667
  interface Task {
593
668
  id: string;
594
669
  threadId?: string;
@@ -640,4 +715,4 @@ type DiscriminatedApprovalResult<TActions extends readonly {
640
715
  } : never;
641
716
  }[TupleElementIndices<TActions>];
642
717
 
643
- export { type ApprovalResult, type AssignToInput, type CreateTaskBody, type CreateTaskBodyInput, type DiscriminatedApprovalResult, type ExtendedJSONSchema7, type Handler, type InferActionData, type InferJsonSchema7, type JSONSchema7, type JSONSchema7TypeName, type Task, type TaskAction, type TaskContext, type TaskContextInput, type TaskContextOutput, type TaskResponse, type TaskResult, type TaskStatus, type TriggerHandler, type TupleElementIndices, type UiSchema, type WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema };
718
+ export { type ApprovalResult, type AssignToInput, type CreateTaskBody, type CreateTaskBodyInput, DEFAULT_THREAD_UPDATE_STATUS, type DiscriminatedApprovalResult, type ExtendedJSONSchema7, type Handler, type InferActionData, type InferJsonSchema7, type JSONSchema7, type JSONSchema7TypeName, type Task, type TaskAction, type TaskContext, type TaskContextInput, type TaskContextOutput, type TaskResponse, type TaskResult, type TaskStatus, type ThreadUpdate, type ThreadUpdateBody, type ThreadUpdateBodyInput, type ThreadUpdateInput, type ThreadUpdateResponse, type ThreadUpdateSource, type ThreadUpdateStatus, type TriggerHandler, type TupleElementIndices, type UiSchema, type WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateMessageSchema, threadUpdateStatusSchema, threadUpdateStatuses };
@@ -1,11 +1,23 @@
1
1
  import {
2
+ DEFAULT_THREAD_UPDATE_STATUS,
2
3
  assignToSchema,
3
4
  createTaskBodySchema,
4
- taskContextSchema
5
- } from "../chunk-LXM7VS4Q.js";
5
+ taskContextSchema,
6
+ threadUpdateBodySchema,
7
+ threadUpdateInputSchema,
8
+ threadUpdateMessageSchema,
9
+ threadUpdateStatusSchema,
10
+ threadUpdateStatuses
11
+ } from "../chunk-2KFY7ZJV.js";
6
12
  export {
13
+ DEFAULT_THREAD_UPDATE_STATUS,
7
14
  assignToSchema,
8
15
  createTaskBodySchema,
9
- taskContextSchema
16
+ taskContextSchema,
17
+ threadUpdateBodySchema,
18
+ threadUpdateInputSchema,
19
+ threadUpdateMessageSchema,
20
+ threadUpdateStatusSchema,
21
+ threadUpdateStatuses
10
22
  };
11
23
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
1
  import * as _trigger_dev_sdk from '@trigger.dev/sdk';
2
- import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-Dhk9qxhL.js';
2
+ import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-BOm2Ce2f.js';
3
3
  export { R as RobotRockHandlerWebhookPayload } from '../handler-webhook-BqEi6Bk-.js';
4
4
  export { ApprovalResult, DiscriminatedApprovalResult, TaskContextInput, TaskResult } from '../schemas/index.js';
5
5
  import 'zod';
@@ -6,8 +6,8 @@ import {
6
6
  createClient,
7
7
  resolveRobotRockConfig,
8
8
  toDiscriminatedApprovalResult
9
- } from "../chunk-KOXJCIST.js";
10
- import "../chunk-LXM7VS4Q.js";
9
+ } from "../chunk-PZTTI6MW.js";
10
+ import "../chunk-2KFY7ZJV.js";
11
11
 
12
12
  // src/trigger/index.ts
13
13
  import { task, wait } from "@trigger.dev/sdk";
@@ -1,6 +1,6 @@
1
1
  import { DiscriminatedApprovalResult } from '../schemas/index.js';
2
2
  export { ApprovalResult, TaskContextInput, TaskResult } from '../schemas/index.js';
3
- import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-Dhk9qxhL.js';
3
+ import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-BOm2Ce2f.js';
4
4
  export { R as RobotRockHandlerWebhookPayload } from '../handler-webhook-BqEi6Bk-.js';
5
5
  import 'zod';
6
6
 
@@ -7,11 +7,11 @@ import {
7
7
  createClient,
8
8
  resolveRobotRockConfig,
9
9
  toDiscriminatedApprovalResult
10
- } from "../chunk-KOXJCIST.js";
10
+ } from "../chunk-PZTTI6MW.js";
11
11
  import {
12
12
  __callDispose,
13
13
  __using
14
- } from "../chunk-LXM7VS4Q.js";
14
+ } from "../chunk-2KFY7ZJV.js";
15
15
 
16
16
  // src/workflow/index.ts
17
17
  import { createWebhook, sleep } from "workflow";
@@ -1,7 +1,7 @@
1
1
  import * as ai from 'ai';
2
2
  import { ToolApprovalResponse } from 'ai';
3
3
  import { z } from 'zod';
4
- import { b as RobotRock, a as SendToHumanInput, S as SendToHumanActionInput } from './client-Dhk9qxhL.js';
4
+ import { b as RobotRock, a as SendToHumanInput, S as SendToHumanActionInput } from './client-BOm2Ce2f.js';
5
5
  import { DiscriminatedApprovalResult } from './schemas/index.js';
6
6
 
7
7
  declare const APPROVE_BY_HUMAN_ACTIONS$1: readonly [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robotrock",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Human-in-the-loop approval workflows for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/approval-result.ts","../src/client.ts","../src/env.ts"],"sourcesContent":["import type { DiscriminatedApprovalResult, Task } from \"./schemas/index.js\";\n\nexport class TaskTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TaskTimeoutError\";\n }\n}\n\nexport class TaskExpiredError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TaskExpiredError\";\n }\n}\n\n/**\n * Map a handled API task to a discriminated approval result.\n * Runtime validation is minimal; TypeScript narrows via `task.actions` at the call site.\n */\nexport function toDiscriminatedApprovalResult<A extends readonly { id: string; schema?: unknown }[]>(\n actions: A,\n task: Task\n): DiscriminatedApprovalResult<A> {\n void actions;\n\n if (!task.handled) {\n throw new Error(\"Task has no handled result\");\n }\n\n return {\n actionId: task.handled.action.id,\n data: task.handled.action.data,\n handledBy: task.handled.handledBy,\n handledAt: new Date(task.handledAt ?? Date.now()),\n taskId: task.id,\n } as DiscriminatedApprovalResult<A>;\n}\n","import {\n type AssignToInput,\n type TaskContextInput,\n createTaskBodySchema,\n} from \"./schemas/index.js\";\nimport {\n TaskExpiredError,\n TaskTimeoutError,\n toDiscriminatedApprovalResult,\n} from \"./approval-result.js\";\nimport type { DiscriminatedApprovalResult, Task, TaskResponse } from \"./schemas/index.js\";\n\nexport type RobotRockWebhookConfig = {\n url: string;\n headers?: Record<string, string>;\n};\n\nexport interface RobotRockPollingOptions {\n /** Poll interval when no webhook is configured (ms). @default 2000 */\n intervalMs?: number;\n /**\n * Max time to poll when no webhook is configured (ms).\n * Polling also stops when the task's `validUntil` passes, whichever is sooner.\n * @default 86400000 (24h)\n */\n timeoutMs?: number;\n}\n\ntype RobotRockClientBaseConfig = {\n /** Optional override for API key. Falls back to ROBOTROCK_API_KEY. */\n apiKey?: string;\n /**\n * Base URL for the RobotRock API\n * @default \"https://api.robotrock.io/v1\"\n */\n baseUrl?: string;\n /**\n * Default inbox app bucket for every task from this client.\n * When omitted, the API uses your API key name.\n */\n app?: string;\n /**\n * Task context format version sent on every `sendToHuman` request.\n * @default 2\n */\n version?: 2;\n};\n\n/** Client config with a webhook (mutually exclusive with `polling`). */\nexport type RobotRockWebhookClientConfig = RobotRockClientBaseConfig & {\n webhook: RobotRockWebhookConfig;\n polling?: never;\n};\n\n/** Client config without a webhook; optional `polling` controls the wait loop. */\nexport type RobotRockPollingClientConfig = RobotRockClientBaseConfig & {\n webhook?: never;\n polling?: RobotRockPollingOptions;\n};\n\nexport type RobotRockConfig = RobotRockWebhookClientConfig | RobotRockPollingClientConfig;\n\nexport type SendToHumanActionInput = Omit<TaskContextInput[\"actions\"][number], \"handlers\">;\n\nexport type SendToHumanValidUntil = Date | string;\n\nexport type SendToHumanInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = Omit<TaskContextInput, \"app\" | \"actions\" | \"version\" | \"validUntil\"> & {\n actions: A;\n /** Task deadline; serialized to an ISO 8601 string on the wire. */\n validUntil?: SendToHumanValidUntil;\n /** Optional idempotency key to prevent duplicate tasks */\n idempotencyKey?: string;\n /** Assign to tenant users (email) and/or groups (slug). Narrows inbox visibility. */\n assignTo?: AssignToInput;\n /**\n * Groups related tasks together in the inbox. Omit to let the server generate\n * one (returned as `task.threadId`) and reuse it on later tasks in the thread.\n */\n threadId?: string;\n};\n\ntype SendToHumanWithAppInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = (SendToHumanInput<A> | Readonly<SendToHumanInput<A>>) & {\n /** Inbox app bucket. Overrides the client `app` when set. */\n app?: string;\n};\n\nexport type SendToHumanResult<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> =\n | {\n mode: \"created\";\n task: TaskResponse[\"task\"];\n }\n | ({\n mode: \"handled\";\n task: TaskResponse[\"task\"];\n } & DiscriminatedApprovalResult<A>);\n\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseValidUntilMs(value: string | number | Date | undefined): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (value instanceof Date) {\n const ms = value.getTime();\n return Number.isNaN(ms) ? undefined : ms;\n }\n\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : undefined;\n }\n\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction serializeValidUntil(value: SendToHumanValidUntil): string {\n if (value instanceof Date) {\n const ms = value.getTime();\n if (Number.isNaN(ms)) {\n throw new RobotRockError(\"Invalid validUntil: Date is invalid\", 400);\n }\n return value.toISOString();\n }\n\n if (typeof value === \"string\" && !Number.isNaN(Date.parse(value))) {\n return new Date(value).toISOString();\n }\n\n throw new RobotRockError(\"Invalid validUntil: expected a Date or parseable date string\", 400);\n}\n\nexport class RobotRockError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly response?: unknown\n ) {\n super(message);\n this.name = \"RobotRockError\";\n }\n}\n\n/**\n * RobotRock API client for creating and querying human-in-the-loop tasks.\n */\nexport class RobotRock {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly app?: string;\n private readonly version: 2;\n private readonly webhook?: RobotRockWebhookConfig;\n private readonly polling: RobotRockPollingOptions;\n\n constructor(config: RobotRockConfig) {\n if (config.webhook && config.polling) {\n throw new Error(\n \"RobotRock client cannot configure both webhook and polling. Use webhook for callbacks or polling to block until handled.\"\n );\n }\n\n const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client.\"\n );\n }\n this.apiKey = apiKey;\n const rawBase = config.baseUrl ?? \"https://api.robotrock.io/v1\";\n this.baseUrl = rawBase.replace(/\\/+$/, \"\");\n this.app = config.app;\n this.version = config.version ?? 2;\n this.webhook = config.webhook;\n this.polling = config.polling ?? {};\n }\n\n /**\n * Create a task via POST /v1 without waiting for a human response.\n */\n async createTask<const A extends readonly SendToHumanActionInput[]>(\n task: SendToHumanWithAppInput<A>\n ): Promise<TaskResponse[\"task\"]> {\n const normalizedTask = normalizeSendToHumanInput(task, {\n webhook: this.webhook,\n app: this.app,\n version: this.version,\n });\n const bodyPayload = {\n ...normalizedTask,\n ...(task.assignTo !== undefined ? { assignTo: task.assignTo } : {}),\n ...(task.threadId !== undefined ? { threadId: task.threadId } : {}),\n };\n const validation = createTaskBodySchema.safeParse(bodyPayload);\n if (!validation.success) {\n throw new RobotRockError(\n `Invalid task: ${validation.error.errors[0]?.message}`,\n 400,\n validation.error.errors\n );\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n };\n\n if (task.idempotencyKey) {\n headers[\"Idempotency-Key\"] = task.idempotencyKey;\n }\n\n const response = await fetch(`${this.baseUrl}/`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(validation.data),\n });\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to create task\"),\n response.status,\n data\n );\n }\n\n return (data as unknown as TaskResponse).task;\n }\n\n async sendToHuman<const A extends readonly SendToHumanActionInput[]>(\n task: SendToHumanWithAppInput<A>\n ): Promise<SendToHumanResult<A>> {\n const normalizedTask = normalizeSendToHumanInput(task, {\n webhook: this.webhook,\n app: this.app,\n version: this.version,\n });\n const createdTaskTask = await this.createTask(task);\n const hasHandlers = normalizedTask.actions.some(\n (action) => Array.isArray(action.handlers) && action.handlers.length > 0\n );\n\n if (hasHandlers) {\n return {\n mode: \"created\",\n task: createdTaskTask,\n };\n }\n\n const timeoutMs = this.polling.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pollIntervalMs = this.polling.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const pollingDeadline = Date.now() + timeoutMs;\n const validUntilMs = parseValidUntilMs(createdTaskTask.validUntil);\n const deadline =\n validUntilMs !== undefined ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;\n const taskId = createdTaskTask.taskId;\n\n while (Date.now() < deadline) {\n const existing = await this.getTask(taskId);\n\n if (existing?.status === \"handled\" && existing.handled) {\n return {\n mode: \"handled\",\n task: createdTaskTask,\n ...(toDiscriminatedApprovalResult(\n normalizedTask.actions as unknown as A,\n existing\n ) as DiscriminatedApprovalResult<A>),\n };\n }\n\n if (existing?.status === \"expired\" || (existing && Date.now() >= existing.validUntil)) {\n throw new TaskExpiredError(\"Task reached validUntil before a human completed it\");\n }\n\n const remainingMs = deadline - Date.now();\n await sleep(Math.min(pollIntervalMs, Math.max(0, remainingMs)));\n }\n\n if (validUntilMs !== undefined && Date.now() >= validUntilMs) {\n throw new TaskExpiredError(\"Task reached validUntil before a human completed it\");\n }\n\n throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);\n }\n\n /**\n * Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).\n */\n async getTask(taskId: string): Promise<Task | null> {\n const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {\n method: \"GET\",\n headers: {\n \"X-Api-Key\": this.apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to get task\"),\n response.status,\n data\n );\n }\n\n return data as unknown as Task;\n }\n\n async cancelTask(taskId: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {\n method: \"POST\",\n headers: {\n \"X-Api-Key\": this.apiKey,\n },\n });\n\n if (!response.ok) {\n const data = await parseResponseBody(response);\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to cancel task\"),\n response.status,\n data\n );\n }\n }\n}\n\nexport function createClient(config: RobotRockConfig): RobotRock {\n return new RobotRock(config);\n}\n\nexport function attachWebhookToActions(\n actions: readonly SendToHumanActionInput[],\n webhook: RobotRockWebhookConfig\n): TaskContextInput[\"actions\"] {\n return actions.map((action) => ({\n ...action,\n handlers: webhookToHandlers(webhook),\n }));\n}\n\nfunction webhookToHandlers(\n webhook: RobotRockWebhookConfig\n): TaskContextInput[\"actions\"][number][\"handlers\"] {\n return [\n {\n type: \"webhook\" as const,\n url: webhook.url,\n headers: webhook.headers ?? {},\n },\n ];\n}\n\nfunction normalizeSendToHumanInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n>(\n task: SendToHumanWithAppInput<A>,\n clientDefaults: { webhook?: RobotRockWebhookConfig; app?: string; version: 2 }\n): TaskContextInput {\n const {\n actions,\n idempotencyKey: _idempotencyKey,\n assignTo: _assignTo,\n threadId: _threadId,\n validUntil,\n app: taskApp,\n ...rest\n } = task;\n\n const webhook = clientDefaults.webhook;\n const normalizedActions: TaskContextInput[\"actions\"] = webhook\n ? attachWebhookToActions(actions, webhook)\n : (actions as unknown as TaskContextInput[\"actions\"]);\n\n const app = taskApp ?? clientDefaults.app;\n\n return {\n ...rest,\n version: clientDefaults.version,\n ...(app ? { app } : {}),\n ...(validUntil !== undefined ? { validUntil: serializeValidUntil(validUntil) } : {}),\n actions: normalizedActions,\n };\n}\n\ntype ParsedResponseBody = Record<string, unknown> | unknown[] | string | null;\n\nasync function parseResponseBody(response: Response): Promise<ParsedResponseBody> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const bodyText = await response.text();\n\n if (!bodyText) {\n return null;\n }\n\n if (contentType.toLowerCase().includes(\"application/json\")) {\n try {\n return JSON.parse(bodyText) as ParsedResponseBody;\n } catch {\n // Fall through and return text body below so error messages stay useful.\n }\n }\n\n try {\n return JSON.parse(bodyText) as ParsedResponseBody;\n } catch {\n return bodyText;\n }\n}\n\nfunction getErrorMessage(data: ParsedResponseBody, fallback: string): string {\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n const maybeMessage = (data as Record<string, unknown>).message;\n if (typeof maybeMessage === \"string\" && maybeMessage.trim()) {\n return maybeMessage;\n }\n }\n\n if (typeof data === \"string\" && data.trim()) {\n const compact = data.replace(/\\s+/g, \" \").trim();\n const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;\n return `${fallback}. Server returned non-JSON response: ${snippet}`;\n }\n\n return fallback;\n}\n","import { createClient, type RobotRock, type RobotRockConfig } from \"./client.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.robotrock.io/v1\";\n\n/**\n * Read RobotRock client config from environment variables.\n *\n * - `ROBOTROCK_API_KEY` (required when not passed explicitly)\n * - `ROBOTROCK_BASE_URL` or `ROBOTROCK_API_URL` (optional)\n * - `ROBOTROCK_APP` (optional inbox app bucket)\n */\nexport function resolveRobotRockConfig(\n overrides?: Partial<RobotRockConfig>\n): RobotRockConfig {\n const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client.\"\n );\n }\n\n const baseUrl =\n overrides?.baseUrl ??\n process.env.ROBOTROCK_BASE_URL ??\n process.env.ROBOTROCK_API_URL ??\n DEFAULT_BASE_URL;\n\n const app = overrides?.app ?? process.env.ROBOTROCK_APP;\n\n return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };\n}\n\n/** Use an explicit client or create one from env / optional config overrides. */\nexport function resolveRobotRockClient(\n client?: RobotRock,\n configOverrides?: Partial<RobotRockConfig>\n): RobotRock {\n if (client) {\n return client;\n }\n return createClient(resolveRobotRockConfig(configOverrides));\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/schemas/index.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport interface JSONSchema7 {\n $id?: string;\n $ref?: string;\n $schema?: string;\n $comment?: string;\n type?: JSONSchema7TypeName | JSONSchema7TypeName[];\n enum?: unknown[];\n const?: unknown;\n multipleOf?: number;\n maximum?: number;\n exclusiveMaximum?: number;\n minimum?: number;\n exclusiveMinimum?: number;\n maxLength?: number;\n minLength?: number;\n pattern?: string;\n format?: string;\n items?: JSONSchema7 | JSONSchema7[];\n additionalItems?: JSONSchema7 | boolean;\n maxItems?: number;\n minItems?: number;\n uniqueItems?: boolean;\n contains?: JSONSchema7;\n maxProperties?: number;\n minProperties?: number;\n required?: string[];\n properties?: Record<string, JSONSchema7>;\n patternProperties?: Record<string, JSONSchema7>;\n additionalProperties?: JSONSchema7 | boolean;\n dependencies?: Record<string, JSONSchema7 | string[]>;\n propertyNames?: JSONSchema7;\n if?: JSONSchema7;\n then?: JSONSchema7;\n else?: JSONSchema7;\n allOf?: JSONSchema7[];\n anyOf?: JSONSchema7[];\n oneOf?: JSONSchema7[];\n not?: JSONSchema7;\n title?: string;\n description?: string;\n default?: unknown;\n readOnly?: boolean;\n writeOnly?: boolean;\n examples?: unknown[];\n}\n\nexport type JSONSchema7TypeName =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\nexport type ExtendedJSONSchema7 = JSONSchema7 & {\n enumNames?: string[];\n [key: string]: unknown;\n};\n\nexport type UiSchema = {\n \"ui:widget\"?: string;\n \"ui:title\"?: string;\n \"ui:description\"?: string;\n \"ui:placeholder\"?: string;\n \"ui:options\"?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nconst safeUrlSchema = z\n .string()\n .refine((url) => url.startsWith(\"http://\") || url.startsWith(\"https://\"), {\n message: \"URL must start with http:// or https://\",\n });\n\nconst jsonSchema7Schema = z.custom<ExtendedJSONSchema7>(\n (val) => typeof val === \"object\" && val !== null,\n { message: \"Must be a valid JSON Schema object\" }\n);\n\nconst uiSchemaSchema = z.custom<UiSchema>((val) => typeof val === \"object\" && val !== null, {\n message: \"Must be a valid UiSchema object\",\n});\n\nconst webhookHandlerSchema = z.object({\n type: z.literal(\"webhook\"),\n url: safeUrlSchema,\n headers: z.record(z.string()),\n});\n\nconst triggerHandlerSchema = webhookHandlerSchema.extend({\n type: z.literal(\"trigger\"),\n tokenId: z.string().min(1),\n});\n\nconst handlerSchema = z.discriminatedUnion(\"type\", [webhookHandlerSchema, triggerHandlerSchema]);\n\nconst taskActionSchema = z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n description: z.string().optional(),\n schema: jsonSchema7Schema.optional(),\n ui: uiSchemaSchema.optional(),\n data: z.record(z.unknown()).optional(),\n handlers: z.array(handlerSchema).min(1).optional(),\n});\n\nconst uiFieldSchemaSchema: z.ZodType<Record<string, unknown>> = z\n .object({\n \"ui:widget\": z.string().optional(),\n \"ui:title\": z.string().optional(),\n \"ui:description\": z.string().optional(),\n \"ui:options\": z.record(z.unknown()).optional(),\n items: z.lazy(() => z.record(uiFieldSchemaSchema)).optional(),\n })\n .passthrough();\n\nconst contextUiSchema = z.record(uiFieldSchemaSchema).optional();\n\nconst contextDataSchema = z\n .object({\n data: z.record(z.unknown()),\n ui: contextUiSchema,\n })\n .optional();\n\nexport const taskContextSchema = z.object({\n app: z.string().min(1).optional(),\n type: z.string().min(1),\n name: z.string().min(1),\n description: z.string().optional(),\n validUntil: z.string().optional(),\n context: contextDataSchema,\n version: z.literal(2).optional(),\n actions: z.array(taskActionSchema).min(1, \"At least one action is required\"),\n});\n\n/**\n * Assignment targets at task create (not stored in task context JSON).\n * Unknown user emails are auto-provisioned as assignee memberships (not full team seats).\n */\nexport const assignToSchema = z\n .object({\n users: z.array(z.string().email()).optional(),\n groups: z.array(z.string().min(1)).optional(),\n })\n .refine(\n (data) => {\n const groups = data.groups ?? [];\n if (groups.includes(\"all\") && groups.length > 1) {\n return false;\n }\n return true;\n },\n { message: 'Cannot combine \"all\" with other group slugs' }\n );\n\nexport const createTaskBodySchema = taskContextSchema.extend({\n assignTo: assignToSchema.optional(),\n /**\n * Groups related tasks together. When omitted, the server generates one and\n * returns it so the caller can reuse it on later tasks in the same thread.\n */\n threadId: z.string().min(1).optional(),\n});\n\nexport type AssignToInput = z.infer<typeof assignToSchema>;\nexport type CreateTaskBodyInput = z.input<typeof createTaskBodySchema>;\nexport type CreateTaskBody = z.output<typeof createTaskBodySchema>;\nexport type TaskContextInput = z.input<typeof taskContextSchema>;\nexport type TaskContextOutput = z.output<typeof taskContextSchema>;\nexport type TaskContext = TaskContextOutput;\nexport type TaskAction = z.infer<typeof taskActionSchema>;\nexport type WebhookHandler = z.infer<typeof webhookHandlerSchema>;\nexport type TriggerHandler = z.infer<typeof triggerHandlerSchema>;\nexport type Handler = z.infer<typeof handlerSchema>;\n\ntype InferObjectProperties<\n Props,\n Req extends PropertyKey,\n> = Props extends Record<string, unknown>\n ? ({\n [K in keyof Props as K extends Req ? K : never]-?: InferJsonSchema7<Props[K]>;\n } & {\n [K in keyof Props as K extends Req ? never : K]?: InferJsonSchema7<Props[K]>;\n } extends infer O\n ? { [K in keyof O]: O[K] }\n : never)\n : Record<string, unknown>;\n\ntype RequiredKeys<S> =\n S extends { readonly required: readonly string[] } ? S[\"required\"][number] : never;\n\nexport type InferJsonSchema7<S> = [S] extends [undefined]\n ? Record<string, never>\n : S extends { readonly const: infer C }\n ? C\n : S extends {\n readonly enum: readonly (infer E)[];\n }\n ? E\n : S extends {\n readonly type: \"object\";\n readonly properties?: infer Props;\n }\n ? InferObjectProperties<Props, RequiredKeys<S>>\n : S extends {\n readonly type: \"object\";\n readonly properties?: undefined;\n }\n ? Record<string, unknown>\n : S extends {\n readonly type: \"array\";\n readonly items?: infer Items;\n }\n ? Items extends readonly unknown[]\n ? InferJsonSchema7<Items[number]>[]\n : Items extends object\n ? InferJsonSchema7<Items>[]\n : unknown[]\n : S extends { readonly type: \"string\" }\n ? string\n : S extends { readonly type: \"number\" } | { readonly type: \"integer\" }\n ? number\n : S extends { readonly type: \"boolean\" }\n ? boolean\n : unknown;\n\nexport type TaskStatus = \"pending\" | \"open\" | \"handled\" | \"expired\";\n\nexport interface TaskResponse {\n success: boolean;\n task: {\n taskId: string;\n threadId: string;\n status: \"pending\" | \"open\";\n context: TaskContext;\n validUntil: string;\n submittedAt: string;\n };\n message: string;\n}\n\nexport interface Task {\n id: string;\n threadId?: string;\n createdAt: Date;\n status: TaskStatus;\n context: TaskContext;\n validUntil: number;\n handledAt?: number;\n handled?: {\n action: {\n id: string;\n data: unknown;\n };\n handledBy?: string;\n userId?: string;\n token?: string;\n };\n}\n\nexport type InferActionData<T extends { schema?: unknown }> = [\n Exclude<T[\"schema\"], undefined>,\n] extends [\n never,\n]\n ? Record<string, never>\n : Exclude<T[\"schema\"], undefined> extends infer S\n ? InferJsonSchema7<S>\n : Record<string, never>;\n\nexport type TupleElementIndices<T extends readonly unknown[]> = T extends readonly [\n unknown,\n ...unknown[],\n]\n ? Exclude<keyof T, keyof unknown[]>\n : number;\n\nexport interface TaskResult<T = Record<string, unknown>> {\n actionId: string;\n data: T;\n handledBy?: string;\n handledAt: Date;\n}\n\nexport interface ApprovalResult<T = Record<string, unknown>> extends TaskResult<T> {\n taskId: string;\n}\n\nexport type DiscriminatedApprovalResult<\n TActions extends readonly { id: string; schema?: unknown }[],\n> = {\n [I in TupleElementIndices<TActions>]: TActions[I] extends { id: string; schema?: unknown }\n ? Omit<ApprovalResult<InferActionData<TActions[I]>>, \"actionId\" | \"data\"> & {\n actionId: TActions[I][\"id\"];\n data: InferActionData<TActions[I]>;\n }\n : never\n}[TupleElementIndices<TActions>];\n"],"mappings":"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","names":[]}