robotrock 0.3.0 → 0.5.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.
Files changed (39) hide show
  1. package/README.md +41 -2
  2. package/dist/ai/index.d.ts +3 -3
  3. package/dist/ai/{index.js → index.mjs} +10 -3
  4. package/dist/ai/trigger.d.ts +2 -2
  5. package/dist/ai/{trigger.js → trigger.mjs} +6 -3
  6. package/dist/ai/workflow.d.ts +2 -2
  7. package/dist/ai/{workflow.js → workflow.mjs} +6 -3
  8. package/dist/{chunk-D2FBSEZK.js → chunk-3ZYQE5LF.mjs} +1 -1
  9. package/dist/{chunk-DSZ3GMT4.js → chunk-CWQTNK24.mjs} +117 -24
  10. package/dist/chunk-CWQTNK24.mjs.map +1 -0
  11. package/dist/{chunk-KOXJCIST.js → chunk-E7ZWBFZ6.mjs} +44 -4
  12. package/dist/chunk-E7ZWBFZ6.mjs.map +1 -0
  13. package/dist/chunk-VNXWLPRV.mjs +4203 -0
  14. package/dist/chunk-VNXWLPRV.mjs.map +1 -0
  15. package/dist/{client-Dhk9qxhL.d.ts → client-BOm2Ce2f.d.ts} +25 -2
  16. package/dist/index.d.ts +3 -3
  17. package/dist/{index.js → index.mjs} +25 -15
  18. package/dist/{index.js.map → index.mjs.map} +1 -1
  19. package/dist/schemas/index.d.ts +76 -1
  20. package/dist/schemas/index.mjs +23 -0
  21. package/dist/trigger/index.d.ts +1 -1
  22. package/dist/trigger/{index.js → index.mjs} +4 -4
  23. package/dist/workflow/index.d.ts +23 -3
  24. package/dist/workflow/{index.js → index.mjs} +21 -5
  25. package/dist/workflow/index.mjs.map +1 -0
  26. package/dist/{workflow-BYeIZgD0.d.ts → workflow-CUkzjf6m.d.ts} +97 -13
  27. package/package.json +6 -2
  28. package/dist/chunk-DSZ3GMT4.js.map +0 -1
  29. package/dist/chunk-KOXJCIST.js.map +0 -1
  30. package/dist/chunk-LXM7VS4Q.js +0 -129
  31. package/dist/chunk-LXM7VS4Q.js.map +0 -1
  32. package/dist/schemas/index.js +0 -11
  33. package/dist/workflow/index.js.map +0 -1
  34. /package/dist/ai/{index.js.map → index.mjs.map} +0 -0
  35. /package/dist/ai/{trigger.js.map → trigger.mjs.map} +0 -0
  36. /package/dist/ai/{workflow.js.map → workflow.mjs.map} +0 -0
  37. /package/dist/{chunk-D2FBSEZK.js.map → chunk-3ZYQE5LF.mjs.map} +0 -0
  38. /package/dist/schemas/{index.js.map → index.mjs.map} +0 -0
  39. /package/dist/trigger/{index.js.map → index.mjs.map} +0 -0
@@ -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
 
@@ -8,30 +8,35 @@ import {
8
8
  resolveRobotRockClient,
9
9
  resolveRobotRockConfig,
10
10
  toDiscriminatedApprovalResult
11
- } from "./chunk-KOXJCIST.js";
11
+ } from "./chunk-E7ZWBFZ6.mjs";
12
12
  import {
13
+ DEFAULT_THREAD_UPDATE_STATUS,
13
14
  assignToSchema,
14
15
  createTaskBodySchema,
15
- taskContextSchema
16
- } from "./chunk-LXM7VS4Q.js";
16
+ external_exports,
17
+ taskContextSchema,
18
+ threadUpdateBodySchema,
19
+ threadUpdateInputSchema,
20
+ threadUpdateStatusSchema,
21
+ threadUpdateStatuses
22
+ } from "./chunk-VNXWLPRV.mjs";
17
23
 
18
24
  // src/webhook.ts
19
25
  import { createHmac, timingSafeEqual } from "crypto";
20
- import { z } from "zod";
21
26
  var ROBOTROCK_SIGNATURE_HEADER = "x-robotrock-signature";
22
- var robotRockWebhookPayloadBodySchema = z.object({
23
- taskId: z.string().min(1),
24
- action: z.object({
25
- id: z.string().min(1),
26
- title: z.string().min(1),
27
- data: z.unknown()
27
+ var robotRockWebhookPayloadBodySchema = external_exports.object({
28
+ taskId: external_exports.string().min(1),
29
+ action: external_exports.object({
30
+ id: external_exports.string().min(1),
31
+ title: external_exports.string().min(1),
32
+ data: external_exports.unknown()
28
33
  }),
29
- handledBy: z.string().min(1).optional(),
30
- handledAt: z.string().min(1),
31
- handlerType: z.string().min(1)
34
+ handledBy: external_exports.string().min(1).optional(),
35
+ handledAt: external_exports.string().min(1),
36
+ handlerType: external_exports.string().min(1)
32
37
  });
33
38
  var robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({
34
- headers: z.record(z.string())
39
+ headers: external_exports.record(external_exports.string())
35
40
  });
36
41
  var RobotRockWebhookError = class extends Error {
37
42
  constructor(message, code, details) {
@@ -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,7 +139,11 @@ 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
  };
139
- //# sourceMappingURL=index.js.map
149
+ //# sourceMappingURL=index.mjs.map
@@ -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 };
@@ -0,0 +1,23 @@
1
+ import {
2
+ DEFAULT_THREAD_UPDATE_STATUS,
3
+ assignToSchema,
4
+ createTaskBodySchema,
5
+ taskContextSchema,
6
+ threadUpdateBodySchema,
7
+ threadUpdateInputSchema,
8
+ threadUpdateMessageSchema,
9
+ threadUpdateStatusSchema,
10
+ threadUpdateStatuses
11
+ } from "../chunk-VNXWLPRV.mjs";
12
+ export {
13
+ DEFAULT_THREAD_UPDATE_STATUS,
14
+ assignToSchema,
15
+ createTaskBodySchema,
16
+ taskContextSchema,
17
+ threadUpdateBodySchema,
18
+ threadUpdateInputSchema,
19
+ threadUpdateMessageSchema,
20
+ threadUpdateStatusSchema,
21
+ threadUpdateStatuses
22
+ };
23
+ //# sourceMappingURL=index.mjs.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';
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  isRobotRockHandlerWebhookPayload,
3
3
  resolveWaitTiming
4
- } from "../chunk-D2FBSEZK.js";
4
+ } from "../chunk-3ZYQE5LF.mjs";
5
5
  import {
6
6
  createClient,
7
7
  resolveRobotRockConfig,
8
8
  toDiscriminatedApprovalResult
9
- } from "../chunk-KOXJCIST.js";
10
- import "../chunk-LXM7VS4Q.js";
9
+ } from "../chunk-E7ZWBFZ6.mjs";
10
+ import "../chunk-VNXWLPRV.mjs";
11
11
 
12
12
  // src/trigger/index.ts
13
13
  import { task, wait } from "@trigger.dev/sdk";
@@ -75,4 +75,4 @@ export {
75
75
  approveByHumanTask,
76
76
  sendToHumanTask
77
77
  };
78
- //# sourceMappingURL=index.js.map
78
+ //# sourceMappingURL=index.mjs.map
@@ -1,6 +1,6 @@
1
- import { DiscriminatedApprovalResult } from '../schemas/index.js';
1
+ import { DiscriminatedApprovalResult, ThreadUpdateStatus, ThreadUpdate } 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
 
@@ -31,5 +31,25 @@ declare function sendToHumanInWorkflow<const A extends readonly SendToHumanActio
31
31
  * Approve / decline gate for Vercel Workflow (`sendToHumanInWorkflow` with fixed actions).
32
32
  */
33
33
  declare function approveByHumanInWorkflow(payload: ApproveByHumanWorkflowPayload): Promise<Expand<DiscriminatedApprovalResult<typeof APPROVE_BY_HUMAN_ACTIONS>>>;
34
+ type SendUpdateWorkflowPayload = {
35
+ /** Thread to log the update against (from a prior task's `threadId`). */
36
+ threadId: string;
37
+ /** Short status update (1-2 sentences) shown in the inbox status bar. */
38
+ message: string;
39
+ /** Lifecycle status driving the status-bar icon/color. @default "info" */
40
+ status?: ThreadUpdateStatus;
41
+ /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */
42
+ app?: string;
43
+ };
44
+ /**
45
+ * Durable thread update for Vercel Workflow.
46
+ *
47
+ * Wraps {@link createClient}'s `sendUpdate` in a `"use step"` so progress
48
+ * reports are retried and recorded in the run. Fire-and-forget: returns the
49
+ * created update without suspending the workflow (no human wait involved).
50
+ *
51
+ * Call from a function with `"use workflow"` as its first statement.
52
+ */
53
+ declare function sendUpdateInWorkflow(payload: SendUpdateWorkflowPayload): Promise<ThreadUpdate>;
34
54
 
35
- export { type ApproveByHumanWorkflowPayload, DiscriminatedApprovalResult, type SendToHumanWorkflowPayload, approveByHumanInWorkflow, sendToHumanInWorkflow };
55
+ export { type ApproveByHumanWorkflowPayload, DiscriminatedApprovalResult, type SendToHumanWorkflowPayload, type SendUpdateWorkflowPayload, ThreadUpdate, ThreadUpdateStatus, approveByHumanInWorkflow, sendToHumanInWorkflow, sendUpdateInWorkflow };
@@ -2,16 +2,16 @@ import {
2
2
  isRobotRockHandlerWebhookPayload,
3
3
  parseValidUntilMs,
4
4
  resolveWaitTiming
5
- } from "../chunk-D2FBSEZK.js";
5
+ } from "../chunk-3ZYQE5LF.mjs";
6
6
  import {
7
7
  createClient,
8
8
  resolveRobotRockConfig,
9
9
  toDiscriminatedApprovalResult
10
- } from "../chunk-KOXJCIST.js";
10
+ } from "../chunk-E7ZWBFZ6.mjs";
11
11
  import {
12
12
  __callDispose,
13
13
  __using
14
- } from "../chunk-LXM7VS4Q.js";
14
+ } from "../chunk-VNXWLPRV.mjs";
15
15
 
16
16
  // src/workflow/index.ts
17
17
  import { createWebhook, sleep } from "workflow";
@@ -92,8 +92,24 @@ async function approveByHumanInWorkflow(payload) {
92
92
  actions: APPROVE_BY_HUMAN_ACTIONS
93
93
  });
94
94
  }
95
+ async function sendRobotRockUpdate(payload) {
96
+ "use step";
97
+ const { app, ...update } = payload;
98
+ const baseConfig = resolveRobotRockConfig();
99
+ const client = createClient({
100
+ apiKey: baseConfig.apiKey,
101
+ baseUrl: baseConfig.baseUrl,
102
+ ...app ?? baseConfig.app ? { app: app ?? baseConfig.app } : {},
103
+ ...baseConfig.version ? { version: baseConfig.version } : {}
104
+ });
105
+ return client.sendUpdate(update);
106
+ }
107
+ async function sendUpdateInWorkflow(payload) {
108
+ return sendRobotRockUpdate(payload);
109
+ }
95
110
  export {
96
111
  approveByHumanInWorkflow,
97
- sendToHumanInWorkflow
112
+ sendToHumanInWorkflow,
113
+ sendUpdateInWorkflow
98
114
  };
99
- //# sourceMappingURL=index.js.map
115
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/workflow/index.ts"],"sourcesContent":["import { createWebhook, sleep } from \"workflow\";\nimport type {\n DiscriminatedApprovalResult,\n ThreadUpdate,\n ThreadUpdateStatus,\n} from \"../schemas/index.js\";\nimport {\n createClient,\n type SendToHumanActionInput,\n type SendToHumanInput,\n} from \"../client.js\";\nimport { resolveRobotRockConfig } from \"../env.js\";\nimport { toDiscriminatedApprovalResult } from \"../approval-result.js\";\nimport {\n isRobotRockHandlerWebhookPayload,\n type RobotRockHandlerWebhookPayload,\n} from \"../handler-webhook.js\";\nimport { parseValidUntilMs, resolveWaitTiming } from \"../wait-timing.js\";\n\nexport type SendToHumanWorkflowPayload<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = SendToHumanInput<A> & {\n /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */\n app?: string;\n};\n\nexport type ApproveByHumanWorkflowPayload = Omit<SendToHumanWorkflowPayload, \"actions\">;\n\ntype Expand<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;\n\nconst APPROVE_BY_HUMAN_ACTIONS = [\n { id: \"approve\", title: \"Approve\" },\n { id: \"decline\", title: \"Decline\" },\n] as const;\n\ntype CreateTaskStepInput = {\n webhookUrl: string;\n app?: string;\n validUntil: Date | string;\n taskInput: Omit<SendToHumanWorkflowPayload, \"validUntil\" | \"app\">;\n};\n\n/**\n * Creates the RobotRock inbox task with the workflow webhook URL as the handler.\n * Marked as a step so API calls run in full Node.js with retries.\n */\nasync function createRobotRockTaskForWebhook(input: CreateTaskStepInput) {\n \"use step\";\n\n const baseConfig = resolveRobotRockConfig();\n const client = createClient({\n apiKey: baseConfig.apiKey,\n baseUrl: baseConfig.baseUrl,\n ...((input.app ?? baseConfig.app) ? { app: input.app ?? baseConfig.app } : {}),\n ...(baseConfig.version ? { version: baseConfig.version } : {}),\n webhook: { url: input.webhookUrl },\n });\n\n return client.sendToHuman({\n ...input.taskInput,\n validUntil: input.validUntil,\n });\n}\n\nasync function parseRobotRockWebhookRequest(request: Request) {\n \"use step\";\n\n const body: unknown = await request.json();\n if (!isRobotRockHandlerWebhookPayload(body)) {\n throw new Error(\n \"Workflow webhook completed with unexpected payload; expected RobotRock handler body (taskId, action.id, action.data).\"\n );\n }\n\n return body;\n}\n\n/**\n * Durable human-in-the-loop wait for Vercel Workflow.\n *\n * Call from a function with `\"use workflow\"` as its first statement. Creates a\n * {@link createWebhook} URL, registers it as the RobotRock task webhook, and\n * suspends until a human handles an action or `validUntil` passes.\n */\nexport async function sendToHumanInWorkflow<\n const A extends readonly SendToHumanActionInput[],\n>(\n payload: SendToHumanWorkflowPayload<A>\n): Promise<Expand<DiscriminatedApprovalResult<A>>> {\n const { validUntil: validUntilInput, app, ...taskInput } = payload;\n const { validUntil, timeout } = resolveWaitTiming(validUntilInput);\n const timeoutMs = parseValidUntilMs(validUntil) - Date.now();\n\n using webhook = createWebhook();\n\n const sendResult = await createRobotRockTaskForWebhook({\n webhookUrl: webhook.url,\n app,\n validUntil,\n taskInput,\n });\n\n const outcome = await Promise.race([\n webhook.then((request) => parseRobotRockWebhookRequest(request)),\n sleep(timeoutMs).then(() => ({ timedOut: true }) as const),\n ]);\n\n if (\"timedOut\" in outcome) {\n throw new Error(`Human response timed out before validUntil (${timeout})`);\n }\n\n const output: RobotRockHandlerWebhookPayload = outcome;\n\n return toDiscriminatedApprovalResult(payload.actions, {\n id: output.taskId,\n createdAt: new Date(),\n status: \"handled\",\n context: sendResult.task.context,\n validUntil: Date.now(),\n handledAt: new Date(output.handledAt).getTime(),\n handled: {\n action: {\n id: output.action.id,\n data: output.action.data,\n },\n handledBy: output.handledBy,\n },\n }) as unknown as Expand<DiscriminatedApprovalResult<A>>;\n}\n\n/**\n * Approve / decline gate for Vercel Workflow (`sendToHumanInWorkflow` with fixed actions).\n */\nexport async function approveByHumanInWorkflow(\n payload: ApproveByHumanWorkflowPayload\n): Promise<Expand<DiscriminatedApprovalResult<typeof APPROVE_BY_HUMAN_ACTIONS>>> {\n return sendToHumanInWorkflow({\n ...payload,\n actions: APPROVE_BY_HUMAN_ACTIONS,\n });\n}\n\nexport type SendUpdateWorkflowPayload = {\n /** Thread to log the update against (from a prior task's `threadId`). */\n threadId: string;\n /** Short status update (1-2 sentences) shown in the inbox status bar. */\n message: string;\n /** Lifecycle status driving the status-bar icon/color. @default \"info\" */\n status?: ThreadUpdateStatus;\n /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */\n app?: string;\n};\n\n/**\n * Posts a thread update via `client.sendUpdate()`. Marked as a step so the API\n * call runs in full Node.js with retries and is recorded in the workflow run.\n */\nasync function sendRobotRockUpdate(payload: SendUpdateWorkflowPayload): Promise<ThreadUpdate> {\n \"use step\";\n\n const { app, ...update } = payload;\n const baseConfig = resolveRobotRockConfig();\n const client = createClient({\n apiKey: baseConfig.apiKey,\n baseUrl: baseConfig.baseUrl,\n ...((app ?? baseConfig.app) ? { app: app ?? baseConfig.app } : {}),\n ...(baseConfig.version ? { version: baseConfig.version } : {}),\n });\n\n return client.sendUpdate(update);\n}\n\n/**\n * Durable thread update for Vercel Workflow.\n *\n * Wraps {@link createClient}'s `sendUpdate` in a `\"use step\"` so progress\n * reports are retried and recorded in the run. Fire-and-forget: returns the\n * created update without suspending the workflow (no human wait involved).\n *\n * Call from a function with `\"use workflow\"` as its first statement.\n */\nexport async function sendUpdateInWorkflow(\n payload: SendUpdateWorkflowPayload\n): Promise<ThreadUpdate> {\n return sendRobotRockUpdate(payload);\n}\n\nexport type { RobotRockHandlerWebhookPayload } from \"../handler-webhook.js\";\nexport type {\n ApprovalResult,\n DiscriminatedApprovalResult,\n TaskContextInput,\n TaskResult,\n ThreadUpdate,\n ThreadUpdateStatus,\n} from \"../schemas/index.js\";\n"],"mappings":"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","names":[]}