@palai/sdk 0.4.0 → 0.6.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 (54) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +2 -2
  3. package/dist/client.d.ts +2 -0
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +3 -0
  6. package/dist/client.js.map +1 -1
  7. package/dist/errors.d.ts +3 -1
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/errors.js +10 -0
  10. package/dist/errors.js.map +1 -1
  11. package/dist/events.d.ts +45 -0
  12. package/dist/events.d.ts.map +1 -0
  13. package/dist/events.js +23 -0
  14. package/dist/events.js.map +1 -0
  15. package/dist/generated/tools.d.ts +6 -2
  16. package/dist/generated/tools.d.ts.map +1 -1
  17. package/dist/generated/tools.js +6 -2
  18. package/dist/generated/tools.js.map +1 -1
  19. package/dist/generated/types.d.ts +4 -0
  20. package/dist/generated/types.d.ts.map +1 -1
  21. package/dist/index.browser.d.ts +2 -0
  22. package/dist/index.browser.d.ts.map +1 -1
  23. package/dist/index.browser.js +5 -3
  24. package/dist/index.browser.js.map +1 -1
  25. package/dist/index.d.ts +6 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +5 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/resources/model-routes.d.ts +7 -0
  30. package/dist/resources/model-routes.d.ts.map +1 -1
  31. package/dist/resources/model-routes.js.map +1 -1
  32. package/dist/resources/responses.d.ts.map +1 -1
  33. package/dist/resources/responses.js +10 -0
  34. package/dist/resources/responses.js.map +1 -1
  35. package/dist/resources/sessions.d.ts +26 -0
  36. package/dist/resources/sessions.d.ts.map +1 -1
  37. package/dist/resources/sessions.js +28 -1
  38. package/dist/resources/sessions.js.map +1 -1
  39. package/dist/resources/webhook-endpoints.d.ts +45 -0
  40. package/dist/resources/webhook-endpoints.d.ts.map +1 -0
  41. package/dist/resources/webhook-endpoints.js +28 -0
  42. package/dist/resources/webhook-endpoints.js.map +1 -0
  43. package/dist/resources/workspaces.d.ts +1 -1
  44. package/dist/resources/workspaces.js +5 -5
  45. package/dist/resources/workspaces.js.map +1 -1
  46. package/dist/stream.d.ts +6 -0
  47. package/dist/stream.d.ts.map +1 -1
  48. package/dist/stream.js +34 -5
  49. package/dist/stream.js.map +1 -1
  50. package/dist/webhooks.d.ts +55 -0
  51. package/dist/webhooks.d.ts.map +1 -0
  52. package/dist/webhooks.js +77 -0
  53. package/dist/webhooks.js.map +1 -0
  54. package/package.json +1 -1
@@ -0,0 +1,77 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ // Receiving the plane's webhooks (spec §21.5, §23.10): the receiver-side half of what every delivery carries. It mirrors
3
+ // the server's signer (adapters/integrations/webhook) byte for byte, as the Go and Python SDKs do: the signed input is
4
+ // "v1." + delivery id + "." + unix seconds + "." followed by the EXACT raw body, HMAC-SHA-256, hex. A rotation header
5
+ // carries several space-separated v1= values, so a receiver on either the old or the new secret verifies during the
6
+ // overlap.
7
+ //
8
+ // ‼️ VERIFY THE RAW BODY, NOT A RE-SERIALISED ONE. The MAC is over the bytes the plane sent; parsing and stringifying
9
+ // the JSON before checking changes key order and whitespace and turns every delivery into a forgery.
10
+ const VERSION = "v1";
11
+ /** The default replay window around now, in seconds (spec §21.5). */
12
+ export const WEBHOOK_TOLERANCE_SECONDS = 300;
13
+ /** The hex HMAC-SHA-256 the plane puts after `v1=` for one delivery. */
14
+ export function signWebhook(secret, deliveryId, timestamp, body) {
15
+ return createHmac("sha256", secret).update(`${VERSION}.${deliveryId}.${timestamp}.`).update(body).digest("hex");
16
+ }
17
+ /** Whether a delivery was signed with `secret` and sent within the replay window. Constant-time. */
18
+ export function verifyWebhook(params) {
19
+ const now = params.now ?? Math.floor(Date.now() / 1000);
20
+ const tolerance = params.toleranceSeconds ?? WEBHOOK_TOLERANCE_SECONDS;
21
+ const skew = now - params.timestamp;
22
+ if (!Number.isFinite(skew) || skew > tolerance || skew < -tolerance)
23
+ return false;
24
+ const want = Buffer.from(signWebhook(params.secret, params.id, params.timestamp, params.body));
25
+ for (const field of params.signature.split(/\s+/)) {
26
+ if (!field.startsWith(`${VERSION}=`))
27
+ continue;
28
+ const given = Buffer.from(field.slice(VERSION.length + 1));
29
+ // Equal lengths first: timingSafeEqual throws on a length mismatch, and the header is the sender's to write.
30
+ if (given.length === want.length && timingSafeEqual(given, want))
31
+ return true;
32
+ }
33
+ return false;
34
+ }
35
+ /** A delivery that did not verify: a missing header, a bad signature, or a timestamp outside the window. */
36
+ export class WebhookVerificationError extends Error {
37
+ constructor(message) {
38
+ super(message);
39
+ this.name = "WebhookVerificationError";
40
+ }
41
+ }
42
+ /**
43
+ * Verifies a delivery from its headers and raw body and returns its event. Throws WebhookVerificationError for
44
+ * anything that does not verify — answer those 400 and the plane stops retrying them only when its window closes.
45
+ */
46
+ export function parseWebhook(params) {
47
+ const header = (name) => {
48
+ if (params.headers instanceof Headers)
49
+ return params.headers.get(name) ?? undefined;
50
+ const found = Object.entries(params.headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
51
+ return Array.isArray(found) ? found[0] : found;
52
+ };
53
+ const id = header("webhook-id"), stamp = header("webhook-timestamp"), signature = header("webhook-signature");
54
+ if (!id || !stamp || !signature)
55
+ throw new WebhookVerificationError("the delivery is missing its Webhook-Id, Webhook-Timestamp or Webhook-Signature header");
56
+ const timestamp = Number(stamp);
57
+ if (!Number.isSafeInteger(timestamp))
58
+ throw new WebhookVerificationError("the Webhook-Timestamp header is not unix seconds");
59
+ const secrets = Array.isArray(params.secret) ? params.secret : [params.secret];
60
+ const verified = secrets.some((secret) => verifyWebhook({
61
+ secret, id, timestamp, body: params.body, signature,
62
+ ...(params.now !== undefined ? { now: params.now } : {}),
63
+ ...(params.toleranceSeconds !== undefined ? { toleranceSeconds: params.toleranceSeconds } : {}),
64
+ }));
65
+ if (!verified)
66
+ throw new WebhookVerificationError("the delivery's signature does not verify, or it was sent outside the replay window");
67
+ const text = typeof params.body === "string" ? params.body : new TextDecoder().decode(params.body);
68
+ let envelope;
69
+ try {
70
+ envelope = JSON.parse(text);
71
+ }
72
+ catch {
73
+ throw new WebhookVerificationError("the delivery's body is not JSON");
74
+ }
75
+ return { ...envelope, deliveryId: id };
76
+ }
77
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palai/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "TypeScript client for the Palai API: responses, sessions, agents, approvals, artifacts and streaming.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",