robotrock 0.1.0 → 0.2.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 +190 -33
- package/dist/ai/index.d.ts +24 -0
- package/dist/ai/index.js +46 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/trigger.d.ts +5 -0
- package/dist/ai/trigger.js +24 -0
- package/dist/ai/trigger.js.map +1 -0
- package/dist/ai/workflow.d.ts +5 -0
- package/dist/ai/workflow.js +24 -0
- package/dist/ai/workflow.js.map +1 -0
- package/dist/chunk-7FVE6OYZ.js +124 -0
- package/dist/chunk-7FVE6OYZ.js.map +1 -0
- package/dist/chunk-D2FBSEZK.js +67 -0
- package/dist/chunk-D2FBSEZK.js.map +1 -0
- package/dist/chunk-OJ57M3RW.js +518 -0
- package/dist/chunk-OJ57M3RW.js.map +1 -0
- package/dist/chunk-THVGHUTX.js +330 -0
- package/dist/chunk-THVGHUTX.js.map +1 -0
- package/dist/client-agOgTJob.d.ts +99 -0
- package/dist/handler-webhook-BqEi6Bk-.d.ts +16 -0
- package/dist/index.d.ts +79 -33
- package/dist/index.js +94 -40
- package/dist/index.js.map +1 -1
- package/dist/schemas/index.d.ts +631 -0
- package/dist/schemas/index.js +11 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/trigger/index.d.ts +34 -37
- package/dist/trigger/index.js +44 -72
- package/dist/trigger/index.js.map +1 -1
- package/dist/workflow/index.d.ts +35 -0
- package/dist/workflow/index.js +99 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow-CHWiRPU9.d.ts +309 -0
- package/package.json +36 -7
- package/dist/chunk-TUQXDKV6.js +0 -209
- package/dist/chunk-TUQXDKV6.js.map +0 -1
- package/dist/client-BQ-j7q68.d.ts +0 -37
package/dist/index.js
CHANGED
|
@@ -1,60 +1,114 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AskHumanExpiredError,
|
|
3
|
-
AskHumanTimeoutError,
|
|
4
2
|
RobotRock,
|
|
5
3
|
RobotRockError,
|
|
4
|
+
TaskExpiredError,
|
|
5
|
+
TaskTimeoutError,
|
|
6
|
+
attachWebhookToActions,
|
|
6
7
|
createClient,
|
|
7
8
|
resolveRobotRockClient,
|
|
8
9
|
resolveRobotRockConfig,
|
|
9
|
-
taskContextSchema,
|
|
10
10
|
toDiscriminatedApprovalResult
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-THVGHUTX.js";
|
|
12
|
+
import {
|
|
13
|
+
assignToSchema,
|
|
14
|
+
createTaskBodySchema,
|
|
15
|
+
taskContextSchema
|
|
16
|
+
} from "./chunk-7FVE6OYZ.js";
|
|
12
17
|
|
|
13
|
-
// src/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
// src/webhook.ts
|
|
19
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
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()
|
|
28
|
+
}),
|
|
29
|
+
handledBy: z.string().min(1).optional(),
|
|
30
|
+
handledAt: z.string().min(1),
|
|
31
|
+
handlerType: z.string().min(1)
|
|
32
|
+
});
|
|
33
|
+
var robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({
|
|
34
|
+
headers: z.record(z.string())
|
|
35
|
+
});
|
|
36
|
+
var RobotRockWebhookError = class extends Error {
|
|
37
|
+
constructor(message, code, details) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.code = code;
|
|
40
|
+
this.details = details;
|
|
41
|
+
this.name = "RobotRockWebhookError";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
async function verifyRobotRockWebhook(request, options = {}) {
|
|
45
|
+
const signatureHeaderName = options.signatureHeader ?? ROBOTROCK_SIGNATURE_HEADER;
|
|
46
|
+
const signature = request.headers.get(signatureHeaderName);
|
|
47
|
+
const secret = options.secret ?? process.env.ROBOTROCK_WEBHOOK_SECRET;
|
|
48
|
+
if (!secret) {
|
|
49
|
+
throw new RobotRockWebhookError(
|
|
50
|
+
"Missing ROBOTROCK_WEBHOOK_SECRET for webhook verification",
|
|
51
|
+
"MISSING_WEBHOOK_SECRET"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (!signature) {
|
|
55
|
+
throw new RobotRockWebhookError(
|
|
56
|
+
`Missing webhook signature header: ${signatureHeaderName}`,
|
|
57
|
+
"MISSING_SIGNATURE"
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
const rawBody = await request.text();
|
|
61
|
+
assertValidSignature(rawBody, signature, secret);
|
|
62
|
+
let parsedBody;
|
|
63
|
+
try {
|
|
64
|
+
parsedBody = JSON.parse(rawBody);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new RobotRockWebhookError("Webhook body is not valid JSON", "INVALID_JSON", {
|
|
67
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const payloadResult = robotRockWebhookPayloadBodySchema.safeParse(parsedBody);
|
|
71
|
+
if (!payloadResult.success) {
|
|
72
|
+
throw new RobotRockWebhookError(
|
|
73
|
+
"Webhook payload schema validation failed",
|
|
74
|
+
"INVALID_PAYLOAD",
|
|
75
|
+
payloadResult.error.flatten()
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...payloadResult.data,
|
|
80
|
+
headers: normalizeHeaders(request.headers)
|
|
81
|
+
};
|
|
18
82
|
}
|
|
19
|
-
|
|
20
|
-
const {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
pollInterval = DEFAULT_POLL_INTERVAL_MS,
|
|
26
|
-
timeout = DEFAULT_TIMEOUT_MS,
|
|
27
|
-
idempotencyKey
|
|
28
|
-
} = params;
|
|
29
|
-
const client = resolveRobotRockClient(explicitClient, { apiKey, baseUrl });
|
|
30
|
-
const response = await client.createTask(
|
|
31
|
-
task,
|
|
32
|
-
{ idempotencyKey }
|
|
33
|
-
);
|
|
34
|
-
const streamId = response.task.streamId;
|
|
35
|
-
const deadline = Date.now() + timeout;
|
|
36
|
-
while (Date.now() < deadline) {
|
|
37
|
-
const existing = await client.getTask(streamId);
|
|
38
|
-
if (existing?.status === "handled" && existing.handled) {
|
|
39
|
-
return toDiscriminatedApprovalResult(task.actions, existing, streamId);
|
|
40
|
-
}
|
|
41
|
-
if (existing?.status === "expired") {
|
|
42
|
-
throw new AskHumanExpiredError("Task expired before a human completed it");
|
|
43
|
-
}
|
|
44
|
-
await sleep(pollInterval);
|
|
83
|
+
function assertValidSignature(rawBody, signature, secret) {
|
|
84
|
+
const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`;
|
|
85
|
+
const expectedBuffer = Buffer.from(expected);
|
|
86
|
+
const receivedBuffer = Buffer.from(signature);
|
|
87
|
+
if (expectedBuffer.length !== receivedBuffer.length || !timingSafeEqual(expectedBuffer, receivedBuffer)) {
|
|
88
|
+
throw new RobotRockWebhookError("Webhook signature verification failed", "INVALID_SIGNATURE");
|
|
45
89
|
}
|
|
46
|
-
|
|
90
|
+
}
|
|
91
|
+
function normalizeHeaders(headers) {
|
|
92
|
+
const result = {};
|
|
93
|
+
headers.forEach((value, key) => {
|
|
94
|
+
result[key] = value;
|
|
95
|
+
});
|
|
96
|
+
return result;
|
|
47
97
|
}
|
|
48
98
|
export {
|
|
49
|
-
AskHumanExpiredError,
|
|
50
|
-
AskHumanTimeoutError,
|
|
51
99
|
RobotRock,
|
|
52
100
|
RobotRockError,
|
|
53
|
-
|
|
101
|
+
RobotRockWebhookError,
|
|
102
|
+
TaskExpiredError,
|
|
103
|
+
TaskTimeoutError,
|
|
104
|
+
assignToSchema,
|
|
105
|
+
attachWebhookToActions,
|
|
54
106
|
createClient,
|
|
107
|
+
createTaskBodySchema,
|
|
55
108
|
resolveRobotRockClient,
|
|
56
109
|
resolveRobotRockConfig,
|
|
57
110
|
taskContextSchema,
|
|
58
|
-
toDiscriminatedApprovalResult
|
|
111
|
+
toDiscriminatedApprovalResult,
|
|
112
|
+
verifyRobotRockWebhook
|
|
59
113
|
};
|
|
60
114
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
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 /** 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 const secret = options.secret ?? process.env.ROBOTROCK_WEBHOOK_SECRET;\n\n if (!secret) {\n throw new RobotRockWebhookError(\n \"Missing ROBOTROCK_WEBHOOK_SECRET for webhook verification\",\n \"MISSING_WEBHOOK_SECRET\"\n );\n }\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 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\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":";;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,uBAAuB;AAC5C,SAAS,SAAS;AAElB,IAAM,6BAA6B;AAEnC,IAAM,oCAAoC,EAAE,OAAO;AAAA,EACjD,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,QAAQ,EAAE,OAAO;AAAA,IACf,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACpB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACvB,MAAM,EAAE,QAAQ;AAAA,EAClB,CAAC;AAAA,EACD,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACtC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAC/B,CAAC;AAED,IAAM,gCAAgC,kCAAkC,OAAO;AAAA,EAC7E,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC;AAC9B,CAAC;AASM,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACE,SACgB,MACA,SAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAkBA,eAAsB,uBACpB,SACA,UAAyC,CAAC,GACR;AAClC,QAAM,sBAAsB,QAAQ,mBAAmB;AACvD,QAAM,YAAY,QAAQ,QAAQ,IAAI,mBAAmB;AACzD,QAAM,SAAS,QAAQ,UAAU,QAAQ,IAAI;AAE7C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR,qCAAqC,mBAAmB;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,uBAAqB,SAAS,WAAW,MAAM;AAE/C,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,MAAM,OAAO;AAAA,EACjC,SAAS,OAAO;AACd,UAAM,IAAI,sBAAsB,kCAAkC,gBAAgB;AAAA,MAChF,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,kCAAkC,UAAU,UAAU;AAC5E,MAAI,CAAC,cAAc,SAAS;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,cAAc,MAAM,QAAQ;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG,cAAc;AAAA,IACjB,SAAS,iBAAiB,QAAQ,OAAO;AAAA,EAC3C;AACF;AAEA,SAAS,qBAAqB,SAAiB,WAAmB,QAAsB;AACtF,QAAM,WAAW,UAAU,WAAW,UAAU,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC;AACrF,QAAM,iBAAiB,OAAO,KAAK,QAAQ;AAC3C,QAAM,iBAAiB,OAAO,KAAK,SAAS;AAE5C,MACE,eAAe,WAAW,eAAe,UACzC,CAAC,gBAAgB,gBAAgB,cAAc,GAC/C;AACA,UAAM,IAAI,sBAAsB,yCAAyC,mBAAmB;AAAA,EAC9F;AACF;AAEA,SAAS,iBAAiB,SAA0C;AAClE,QAAM,SAAiC,CAAC;AACxC,UAAQ,QAAQ,CAAC,OAAO,QAAQ;AAC9B,WAAO,GAAG,IAAI;AAAA,EAChB,CAAC;AACD,SAAO;AACT;","names":[]}
|