@relaymessenger/sdk 0.2.0 → 0.3.0-staging.1

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/Apache-2.0.txt +201 -0
  3. package/NOTICE +6 -0
  4. package/README.md +189 -17
  5. package/dist/client.d.ts +135 -57
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +520 -144
  8. package/dist/client.js.map +1 -1
  9. package/dist/errors.d.ts +26 -19
  10. package/dist/errors.d.ts.map +1 -0
  11. package/dist/errors.js +28 -37
  12. package/dist/errors.js.map +1 -1
  13. package/dist/index.d.ts +9 -9
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +7 -8
  16. package/dist/index.js.map +1 -1
  17. package/dist/operations.d.ts +144 -0
  18. package/dist/operations.d.ts.map +1 -0
  19. package/dist/operations.js +190 -0
  20. package/dist/operations.js.map +1 -0
  21. package/dist/pagination.d.ts +24 -0
  22. package/dist/pagination.d.ts.map +1 -0
  23. package/dist/pagination.js +48 -0
  24. package/dist/pagination.js.map +1 -0
  25. package/dist/types.d.ts +436 -74
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +0 -1
  28. package/dist/types.js.map +1 -1
  29. package/dist/webhooks.d.ts +19 -0
  30. package/dist/webhooks.d.ts.map +1 -0
  31. package/dist/webhooks.js +36 -0
  32. package/dist/webhooks.js.map +1 -0
  33. package/dist/websocket.d.ts +38 -0
  34. package/dist/websocket.d.ts.map +1 -0
  35. package/dist/websocket.js +547 -0
  36. package/dist/websocket.js.map +1 -0
  37. package/package.json +22 -15
  38. package/dist/file-cursor.d.ts +0 -10
  39. package/dist/file-cursor.js +0 -53
  40. package/dist/file-cursor.js.map +0 -1
  41. package/dist/idempotency.d.ts +0 -8
  42. package/dist/idempotency.js +0 -35
  43. package/dist/idempotency.js.map +0 -1
  44. package/dist/memory-dedupe.d.ts +0 -13
  45. package/dist/memory-dedupe.js +0 -25
  46. package/dist/memory-dedupe.js.map +0 -1
  47. package/dist/poll-loop.d.ts +0 -43
  48. package/dist/poll-loop.js +0 -164
  49. package/dist/poll-loop.js.map +0 -1
  50. package/dist/signature.d.ts +0 -18
  51. package/dist/signature.js +0 -61
  52. package/dist/signature.js.map +0 -1
  53. package/dist/url.d.ts +0 -6
  54. package/dist/url.js +0 -40
  55. package/dist/url.js.map +0 -1
package/package.json CHANGED
@@ -1,48 +1,55 @@
1
1
  {
2
2
  "name": "@relaymessenger/sdk",
3
- "version": "0.2.0",
4
- "description": "Relay transport library: HTTPS client, Standard Webhooks verify, durable long-poll, idempotent sends.",
3
+ "version": "0.3.0-staging.1",
4
+ "description": "TypeScript SDK for the Relay v1 messaging API and signed webhooks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- }
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./package.json": "./package.json"
13
15
  },
14
16
  "files": [
15
- "dist",
17
+ "dist/",
16
18
  "LICENSE",
19
+ "LICENSES/",
20
+ "NOTICE",
17
21
  "README.md"
18
22
  ],
19
23
  "scripts": {
24
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
20
25
  "build": "tsc -p tsconfig.json",
21
26
  "check": "tsc -p tsconfig.json --noEmit",
22
- "test": "vitest run --config vitest.config.ts",
27
+ "test": "vitest run",
23
28
  "prepack": "npm run build"
24
29
  },
25
30
  "engines": {
26
- "node": ">=22.18"
31
+ "node": ">=22.22.3"
27
32
  },
28
33
  "license": "MIT",
34
+ "dependencies": {
35
+ "standardwebhooks": "^1.0.0",
36
+ "ws": "^8.21.0"
37
+ },
29
38
  "publishConfig": {
30
- "access": "public"
39
+ "access": "public",
40
+ "registry": "https://registry.npmjs.org/",
41
+ "tag": "staging"
31
42
  },
32
43
  "repository": {
33
44
  "type": "git",
34
- "url": "git+https://github.com/relaymessenger/Relay-SDK.git",
45
+ "url": "git+https://github.com/RelayMessenger/Relay-SDK.git",
35
46
  "directory": "packages/sdk"
36
47
  },
37
48
  "homepage": "https://docs.relayapp.im",
38
- "bugs": {
39
- "url": "https://github.com/relaymessenger/Relay-SDK/issues"
40
- },
41
49
  "keywords": [
42
50
  "relay",
43
- "relaymessenger",
51
+ "messaging",
44
52
  "agents",
45
- "webhooks",
46
- "long-poll"
53
+ "webhooks"
47
54
  ]
48
55
  }
@@ -1,10 +0,0 @@
1
- export type FileCursorStore = {
2
- load(): number;
3
- current(): number;
4
- advance(next: number): void;
5
- };
6
- /**
7
- * Simple durable cursor file for long-poll consumers.
8
- * Advances are monotonic; a corrupt file refuses to reset to zero silently.
9
- */
10
- export declare function createFileCursorStore(path: string): FileCursorStore;
@@ -1,53 +0,0 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname } from "node:path";
3
- /**
4
- * Simple durable cursor file for long-poll consumers.
5
- * Advances are monotonic; a corrupt file refuses to reset to zero silently.
6
- */
7
- export function createFileCursorStore(path) {
8
- let cursor = 0;
9
- let loaded = false;
10
- const read = () => {
11
- try {
12
- const raw = readFileSync(path, "utf8");
13
- const parsed = JSON.parse(raw);
14
- if (typeof parsed.cursor !== "number" ||
15
- !Number.isSafeInteger(parsed.cursor) ||
16
- parsed.cursor < 0) {
17
- throw new Error(`corrupt cursor file: ${path}`);
18
- }
19
- return parsed.cursor;
20
- }
21
- catch (error) {
22
- const code = error.code;
23
- if (code === "ENOENT")
24
- return 0;
25
- throw error;
26
- }
27
- };
28
- const write = (value) => {
29
- mkdirSync(dirname(path), { recursive: true });
30
- writeFileSync(path, `${JSON.stringify({ cursor: value })}\n`, { mode: 0o600 });
31
- };
32
- return {
33
- load: () => {
34
- cursor = read();
35
- loaded = true;
36
- return cursor;
37
- },
38
- current: () => {
39
- if (!loaded)
40
- throw new Error("relay cursor: current() before load()");
41
- return cursor;
42
- },
43
- advance: (next) => {
44
- if (!loaded)
45
- throw new Error("relay cursor: advance() before load()");
46
- if (!Number.isSafeInteger(next) || next < 0 || next <= cursor)
47
- return;
48
- write(next);
49
- cursor = next;
50
- },
51
- };
52
- }
53
- //# sourceMappingURL=file-cursor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-cursor.js","sourceRoot":"","sources":["../src/file-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,IAAI,GAAG,GAAW,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;YACvD,IACE,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;gBACjC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;gBACpC,MAAM,CAAC,MAAM,GAAG,CAAC,EACjB,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;YACnD,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,CAAC,CAAC;YAChC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE;QAC9B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,GAAG,EAAE;YACT,MAAM,GAAG,IAAI,EAAE,CAAC;YAChB,MAAM,GAAG,IAAI,CAAC;YACd,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACtE,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAChB,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACtE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,MAAM;gBAAE,OAAO;YACtE,KAAK,CAAC,IAAI,CAAC,CAAC;YACZ,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,8 +0,0 @@
1
- /**
2
- * Deterministic Idempotency-Key for one reply attempt.
3
- * Includes a content digest so a redelivery that produces different text does
4
- * not collide with a prior body under the same event id.
5
- */
6
- export declare function deriveIdempotencyKey(eventId: string, ordinal: number, content: unknown): Promise<string>;
7
- /** Simple key when the reply body is fixed for the event. */
8
- export declare function replyIdempotencyKey(eventId: string, suffix?: string): string;
@@ -1,35 +0,0 @@
1
- function canonicalJson(value) {
2
- if (value === null || typeof value !== "object") {
3
- return JSON.stringify(value) ?? "null";
4
- }
5
- const withToJson = value;
6
- if (typeof withToJson.toJSON === "function") {
7
- return canonicalJson(withToJson.toJSON());
8
- }
9
- if (Array.isArray(value)) {
10
- return `[${value.map(canonicalJson).join(",")}]`;
11
- }
12
- const entries = Object.entries(value)
13
- .filter(([, entry]) => entry !== undefined)
14
- .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
15
- return `{${entries
16
- .map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`)
17
- .join(",")}}`;
18
- }
19
- /**
20
- * Deterministic Idempotency-Key for one reply attempt.
21
- * Includes a content digest so a redelivery that produces different text does
22
- * not collide with a prior body under the same event id.
23
- */
24
- export async function deriveIdempotencyKey(eventId, ordinal, content) {
25
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalJson(content)));
26
- const hex = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0"))
27
- .join("")
28
- .slice(0, 32);
29
- return `${eventId.slice(0, 180)}:${ordinal}:${hex}`;
30
- }
31
- /** Simple key when the reply body is fixed for the event. */
32
- export function replyIdempotencyKey(eventId, suffix = "0") {
33
- return `reply-${eventId}-${suffix}`;
34
- }
35
- //# sourceMappingURL=idempotency.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"AAAA,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC;IACzC,CAAC;IACD,MAAM,UAAU,GAAG,KAAmC,CAAC;IACvD,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC5C,OAAO,aAAa,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACnD,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;SAC7D,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;SAC1C,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,IAAI,OAAO;SACf,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;SACvE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAe,EACf,OAAe,EACf,OAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CACvC,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CACjD,CAAC;IACF,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACtD,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CACnC;SACE,IAAI,CAAC,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;AACtD,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAM,GAAG,GAAG;IAC/D,OAAO,SAAS,OAAO,IAAI,MAAM,EAAE,CAAC;AACtC,CAAC"}
@@ -1,13 +0,0 @@
1
- /** In-memory event_id window for at-least-once delivery. */
2
- export type EventDedupe = {
3
- has(eventId: string): boolean;
4
- /** Record only after the event was durably handled. */
5
- record(eventId: string): void;
6
- };
7
- export declare class MemoryDedupe implements EventDedupe {
8
- private readonly capacity;
9
- private readonly seen;
10
- constructor(capacity?: number);
11
- has(eventId: string): boolean;
12
- record(eventId: string): void;
13
- }
@@ -1,25 +0,0 @@
1
- /** In-memory event_id window for at-least-once delivery. */
2
- export class MemoryDedupe {
3
- capacity;
4
- seen = new Set();
5
- constructor(capacity = 4096) {
6
- this.capacity = capacity;
7
- if (!Number.isSafeInteger(capacity) || capacity < 1) {
8
- throw new Error("relay dedupe capacity must be a positive safe integer");
9
- }
10
- }
11
- has(eventId) {
12
- return this.seen.has(eventId);
13
- }
14
- record(eventId) {
15
- if (!eventId)
16
- return;
17
- this.seen.add(eventId);
18
- if (this.seen.size > this.capacity) {
19
- const oldest = this.seen.values().next().value;
20
- if (oldest !== undefined)
21
- this.seen.delete(oldest);
22
- }
23
- }
24
- }
25
- //# sourceMappingURL=memory-dedupe.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-dedupe.js","sourceRoot":"","sources":["../src/memory-dedupe.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAQ5D,MAAM,OAAO,YAAY;IAGM,QAAQ;IAFpB,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,YAA6B,QAAQ,GAAG,IAAI;wBAAf,QAAQ;QACnC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,GAAG,CAAC,OAAe;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,OAAe;QACpB,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC/C,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;CACF"}
@@ -1,43 +0,0 @@
1
- import type { RelayClient } from "./client.js";
2
- import type { EventDedupe } from "./memory-dedupe.js";
3
- import type { MessageReceivedData, MessageReceivedEvent, RelayEventEnvelope, RelayOutgoingPart, RelaySendResult } from "./types.js";
4
- export type ReplyOptions = {
5
- /**
6
- * Render the reply as a quoted reply bubble referencing the inbound message.
7
- * Off by default: plain sends match the shipped OpenClaw integration.
8
- */
9
- quote?: boolean;
10
- };
11
- export type MessageHandlerContext = {
12
- event: MessageReceivedEvent;
13
- message: MessageReceivedData["message"];
14
- invocationId?: string;
15
- client: RelayClient;
16
- reply: {
17
- text: (text: string, options?: ReplyOptions) => Promise<RelaySendResult>;
18
- parts: (parts: RelayOutgoingPart[], options?: ReplyOptions) => Promise<RelaySendResult>;
19
- };
20
- responding: (label?: string) => Promise<void>;
21
- typing: (started?: boolean, label?: string) => Promise<void>;
22
- };
23
- export type PollLoopParams = {
24
- client: RelayClient;
25
- getCursor: () => number;
26
- setCursor: (cursor: number) => void | Promise<void>;
27
- dedupe: EventDedupe;
28
- onMessage: (ctx: MessageHandlerContext) => Promise<void> | void;
29
- /** Drop events whose sender is not allowed. Default: allow all users. */
30
- allowSender?: (senderId: string) => boolean;
31
- shouldProcess?: (event: RelayEventEnvelope) => boolean;
32
- timeoutSeconds?: number;
33
- limit?: number;
34
- abortSignal?: AbortSignal;
35
- log?: (line: string) => void;
36
- sleep?: (ms: number, signal: AbortSignal) => Promise<void>;
37
- random?: () => number;
38
- };
39
- /**
40
- * Long-poll receive loop for hosts that cannot expose a public webhook URL.
41
- * Webhooks and long polling are mutually exclusive per Agent Token.
42
- */
43
- export declare function runPollLoop(params: PollLoopParams): Promise<void>;
package/dist/poll-loop.js DELETED
@@ -1,164 +0,0 @@
1
- import { RelayApiError, isAbortError } from "./errors.js";
2
- import { replyIdempotencyKey } from "./idempotency.js";
3
- const TRANSIENT_BASE_DELAY_MS = 500;
4
- const TRANSIENT_MAX_DELAY_MS = 30_000;
5
- function defaultSleep(ms, signal) {
6
- return new Promise((resolve) => {
7
- if (signal.aborted) {
8
- resolve();
9
- return;
10
- }
11
- const timer = setTimeout(() => {
12
- signal.removeEventListener("abort", onAbort);
13
- resolve();
14
- }, ms);
15
- const onAbort = () => {
16
- clearTimeout(timer);
17
- resolve();
18
- };
19
- signal.addEventListener("abort", onAbort, { once: true });
20
- });
21
- }
22
- function isMessageReceived(event) {
23
- return (event.event_type === "message.received" &&
24
- typeof event.data === "object" &&
25
- event.data !== null &&
26
- "message" in event.data &&
27
- typeof event.data.message === "object");
28
- }
29
- function buildContext(client, event) {
30
- const message = event.data.message;
31
- const invocationId = event.data.invocation_id;
32
- let ordinal = 0;
33
- const ctx = {
34
- event,
35
- message,
36
- client,
37
- reply: {
38
- text: async (text, options) => {
39
- const key = replyIdempotencyKey(event.event_id, String(ordinal++));
40
- return client.sendText({
41
- conversationId: message.conversation_id,
42
- text,
43
- idempotencyKey: key,
44
- ...(invocationId ? { invocationId } : {}),
45
- ...(options?.quote
46
- ? { replyTo: { message_id: message.id } }
47
- : {}),
48
- });
49
- },
50
- parts: async (parts, options) => {
51
- const key = replyIdempotencyKey(event.event_id, String(ordinal++));
52
- return client.sendMessage({
53
- conversationId: message.conversation_id,
54
- parts,
55
- idempotencyKey: key,
56
- ...(invocationId ? { invocationId } : {}),
57
- ...(options?.quote
58
- ? { replyTo: { message_id: message.id } }
59
- : {}),
60
- });
61
- },
62
- },
63
- responding: async (label) => {
64
- await client.setResponding({
65
- conversationId: message.conversation_id,
66
- messageId: message.id,
67
- ...(label ? { label } : {}),
68
- ...(invocationId ? { invocationId } : {}),
69
- });
70
- },
71
- typing: async (started = true, label) => {
72
- await client.setTyping({
73
- conversationId: message.conversation_id,
74
- started,
75
- ...(label ? { label } : {}),
76
- ...(invocationId ? { invocationId } : {}),
77
- });
78
- },
79
- };
80
- if (invocationId)
81
- ctx.invocationId = invocationId;
82
- return ctx;
83
- }
84
- /**
85
- * Long-poll receive loop for hosts that cannot expose a public webhook URL.
86
- * Webhooks and long polling are mutually exclusive per Agent Token.
87
- */
88
- export async function runPollLoop(params) {
89
- const signal = params.abortSignal ?? new AbortController().signal;
90
- const sleep = params.sleep ?? defaultSleep;
91
- const random = params.random ?? Math.random;
92
- const log = params.log ?? (() => { });
93
- let transientAttempts = 0;
94
- const transientDelayMs = () => {
95
- const backoff = Math.min(TRANSIENT_MAX_DELAY_MS, TRANSIENT_BASE_DELAY_MS * 2 ** Math.min(transientAttempts, 6));
96
- return backoff + Math.floor(random() * 250);
97
- };
98
- while (!signal.aborted) {
99
- let page;
100
- try {
101
- page = await params.client.pollEvents({
102
- cursor: params.getCursor(),
103
- timeoutSeconds: params.timeoutSeconds ?? 30,
104
- ...(params.limit === undefined ? {} : { limit: params.limit }),
105
- signal,
106
- });
107
- }
108
- catch (error) {
109
- if (signal.aborted || isAbortError(error))
110
- return;
111
- if (error instanceof RelayApiError && error.terminal) {
112
- // Retrying cannot fix these; surface them to the operator.
113
- if (error.status === 410) {
114
- log("[relay] cursor expired (410): the cursor is behind the seven-day " +
115
- "retention ceiling. Reconcile from conversation history; do not " +
116
- "reset the cursor to zero.");
117
- }
118
- else if (error.status === 422) {
119
- const highest = error.details?.["highest_delivered_cursor"];
120
- log("[relay] cursor ahead of the delivered ledger (422): reconcile " +
121
- "history over REST, then resume from " +
122
- (highest === undefined
123
- ? "error.details.highest_delivered_cursor."
124
- : `cursor ${String(highest)}.`));
125
- }
126
- else if (error.kind === "conflict") {
127
- log(`[relay] long poll conflict: ${error.message}`);
128
- }
129
- throw error;
130
- }
131
- transientAttempts += 1;
132
- log(`[relay] transient poll error (attempt ${transientAttempts}): ${String(error)}`);
133
- await sleep(transientDelayMs(), signal);
134
- continue;
135
- }
136
- transientAttempts = 0;
137
- for (const event of page.events) {
138
- if (params.shouldProcess && !params.shouldProcess(event))
139
- continue;
140
- if (!isMessageReceived(event))
141
- continue;
142
- if (params.dedupe.has(event.event_id))
143
- continue;
144
- const sender = event.data.message.sender;
145
- if (sender.kind === "agent")
146
- continue;
147
- if (params.allowSender && sender.kind === "user" && !params.allowSender(sender.id)) {
148
- params.dedupe.record(event.event_id);
149
- continue;
150
- }
151
- const ctx = buildContext(params.client, event);
152
- try {
153
- await params.onMessage(ctx);
154
- params.dedupe.record(event.event_id);
155
- }
156
- catch (error) {
157
- log(`[relay] handler failed for ${event.event_id}: ${String(error)}`);
158
- throw error;
159
- }
160
- }
161
- await params.setCursor(page.nextCursor);
162
- }
163
- }
164
- //# sourceMappingURL=poll-loop.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"poll-loop.js","sourceRoot":"","sources":["../src/poll-loop.ts"],"names":[],"mappings":"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"}
@@ -1,18 +0,0 @@
1
- export type VerifyWebhookOptions = {
2
- toleranceSeconds?: number;
3
- nowSeconds?: number;
4
- };
5
- /**
6
- * Verify a Standard Webhooks signature as Relay signs deliveries:
7
- * HMAC-SHA256 over `${webhook-id}.${webhook-timestamp}.${raw body}`.
8
- */
9
- export declare function verifyWebhookSignature(input: {
10
- secret: string;
11
- payload: string;
12
- headers: {
13
- "webhook-id": string | null | undefined;
14
- "webhook-timestamp": string | null | undefined;
15
- "webhook-signature": string | null | undefined;
16
- };
17
- options?: VerifyWebhookOptions;
18
- }): Promise<void>;
package/dist/signature.js DELETED
@@ -1,61 +0,0 @@
1
- import { WebhookVerificationError } from "./errors.js";
2
- const DEFAULT_TOLERANCE_SECONDS = 5 * 60;
3
- function base64ToBytes(value) {
4
- const binary = atob(value);
5
- const bytes = new Uint8Array(binary.length);
6
- for (let i = 0; i < binary.length; i += 1)
7
- bytes[i] = binary.charCodeAt(i);
8
- return bytes;
9
- }
10
- function decodeSecret(secret) {
11
- const raw = secret.startsWith("whsec_") ? secret.slice("whsec_".length) : secret;
12
- return base64ToBytes(raw);
13
- }
14
- function constantTimeEqual(a, b) {
15
- if (a.length !== b.length)
16
- return false;
17
- let diff = 0;
18
- for (let i = 0; i < a.length; i += 1)
19
- diff |= a[i] ^ b[i];
20
- return diff === 0;
21
- }
22
- /**
23
- * Verify a Standard Webhooks signature as Relay signs deliveries:
24
- * HMAC-SHA256 over `${webhook-id}.${webhook-timestamp}.${raw body}`.
25
- */
26
- export async function verifyWebhookSignature(input) {
27
- const id = input.headers["webhook-id"];
28
- const timestamp = input.headers["webhook-timestamp"];
29
- const signatureHeader = input.headers["webhook-signature"];
30
- if (!id || !timestamp || !signatureHeader) {
31
- throw new WebhookVerificationError("missing webhook signature headers");
32
- }
33
- const tolerance = input.options?.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
34
- const now = input.options?.nowSeconds ?? Math.floor(Date.now() / 1000);
35
- const ts = Number(timestamp);
36
- if (!Number.isFinite(ts)) {
37
- throw new WebhookVerificationError("invalid webhook-timestamp");
38
- }
39
- if (Math.abs(now - ts) > tolerance) {
40
- throw new WebhookVerificationError("webhook-timestamp outside tolerance");
41
- }
42
- const key = await crypto.subtle.importKey("raw", decodeSecret(input.secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
43
- const signedContent = `${id}.${timestamp}.${input.payload}`;
44
- const expected = new Uint8Array(await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(signedContent)));
45
- for (const candidate of signatureHeader.split(" ")) {
46
- const [version, value] = candidate.split(",", 2);
47
- if (version !== "v1" || !value)
48
- continue;
49
- let provided;
50
- try {
51
- provided = base64ToBytes(value);
52
- }
53
- catch {
54
- continue;
55
- }
56
- if (constantTimeEqual(expected, provided))
57
- return;
58
- }
59
- throw new WebhookVerificationError("no matching v1 signature");
60
- }
61
- //# sourceMappingURL=signature.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"signature.js","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":"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"}
package/dist/url.d.ts DELETED
@@ -1,6 +0,0 @@
1
- export declare const DEFAULT_RELAY_BASE_URL = "https://api.relayapp.im";
2
- /**
3
- * Validate and canonicalize the API origin before a bearer token can be sent.
4
- * Remote origins must use HTTPS. Plain HTTP is allowed only on loopback.
5
- */
6
- export declare function normalizeRelayBaseUrl(raw?: string): string;
package/dist/url.js DELETED
@@ -1,40 +0,0 @@
1
- import { isIP } from "node:net";
2
- export const DEFAULT_RELAY_BASE_URL = "https://api.relayapp.im";
3
- function isLoopbackHostname(hostname) {
4
- const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
5
- const ipVersion = isIP(normalized);
6
- if (ipVersion === 4)
7
- return normalized.split(".")[0] === "127";
8
- if (ipVersion === 6)
9
- return normalized === "::1";
10
- return normalized === "localhost" || normalized.endsWith(".localhost");
11
- }
12
- /**
13
- * Validate and canonicalize the API origin before a bearer token can be sent.
14
- * Remote origins must use HTTPS. Plain HTTP is allowed only on loopback.
15
- */
16
- export function normalizeRelayBaseUrl(raw) {
17
- const candidate = raw?.trim() || DEFAULT_RELAY_BASE_URL;
18
- let url;
19
- try {
20
- url = new URL(candidate);
21
- }
22
- catch {
23
- throw new Error(`relay: invalid baseUrl ${JSON.stringify(candidate)}`);
24
- }
25
- if (url.username || url.password) {
26
- throw new Error("relay: baseUrl must not contain credentials");
27
- }
28
- if (url.search || url.hash) {
29
- throw new Error("relay: baseUrl must not contain a query or fragment");
30
- }
31
- if (!/^\/+$/u.test(url.pathname)) {
32
- throw new Error("relay: baseUrl must be an origin without a path");
33
- }
34
- if (url.protocol !== "https:" &&
35
- !(url.protocol === "http:" && isLoopbackHostname(url.hostname))) {
36
- throw new Error("relay: baseUrl must use HTTPS (HTTP is allowed only for loopback development)");
37
- }
38
- return url.origin;
39
- }
40
- //# sourceMappingURL=url.js.map
package/dist/url.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,MAAM,CAAC,MAAM,sBAAsB,GAAG,yBAAyB,CAAC;AAEhE,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IACnC,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC;IAC/D,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,UAAU,KAAK,KAAK,CAAC;IACjD,OAAO,UAAU,KAAK,WAAW,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAY;IAChD,MAAM,SAAS,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,sBAAsB,CAAC;IACxD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,IACE,GAAG,CAAC,QAAQ,KAAK,QAAQ;QACzB,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAC/D,CAAC;QACD,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC"}