@diegoaltoworks/chatter 0.60.0 → 0.61.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.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The `/sync` long-poll loop, isolated from both the HTTP client and the
3
+ * channel so its failure behaviour is testable without either — the same
4
+ * shape as `../telegram/poll.ts`'s `runLongPoll`, adapted to Matrix's
5
+ * `since`-token pagination instead of an acknowledged offset.
6
+ *
7
+ * The property that matters: a homeserver that is down, rate-limiting, or
8
+ * rejecting the token must never turn into a tight retry loop. Every
9
+ * failure backs off exponentially, and `M_LIMIT_EXCEEDED`'s own
10
+ * `retry_after_ms` wins over that backoff when the homeserver sends one.
11
+ */
12
+ import { type Logger } from "../../core/logger";
13
+ import { type MatrixSyncResponse } from "./api";
14
+ /** Exponential backoff: 2s, 4s, 8s ... capped at a minute. `failures` is the count including the one just seen. */
15
+ export declare function syncBackoffMs(failures: number): number;
16
+ /**
17
+ * How long to wait after a failed sync. `M_LIMIT_EXCEEDED`'s
18
+ * `retry_after_ms` is an instruction, not a hint — honour it verbatim even
19
+ * when it exceeds the backoff cap, because syncing again sooner just
20
+ * extends the rate-limit window.
21
+ */
22
+ export declare function retryDelayMs(error: unknown, failures: number): number;
23
+ export interface MatrixSyncLoopDeps {
24
+ /** One `/sync` call. Rejections are backed off; they never end the loop. */
25
+ sync(since: string | undefined): Promise<MatrixSyncResponse>;
26
+ /** Per-batch work. A throw is logged and skipped — one bad batch never stops the loop. */
27
+ handleSync(response: MatrixSyncResponse): Promise<void>;
28
+ /** Checked before every sync, and again after a failure, so `stop()` cuts the loop instead of sleeping out a backoff first. */
29
+ isStopped(): boolean;
30
+ /** Overridable for tests; a real channel passes a `setTimeout`-based sleep. */
31
+ sleep(ms: number): Promise<void>;
32
+ /** Where this loop's `since` token resumes from. Omitted = an initial full sync. */
33
+ initialSince?: string;
34
+ /** Called with each newly acknowledged `since` token, for a host that persists it. */
35
+ onSince?(since: string): void;
36
+ logger?: Logger;
37
+ /** Prefix for log lines, e.g. `Matrix[@bot:example.org]`. */
38
+ label?: string;
39
+ }
40
+ /**
41
+ * Syncs until `isStopped()`, resolving with the last `since` token reached
42
+ * (what a restart would resume from).
43
+ *
44
+ * The token advances BEFORE the batch is handled, matching the Telegram
45
+ * poll loop's offset-first ordering: a handler that throws on one bad
46
+ * batch must not make the homeserver redeliver it forever, which would
47
+ * wedge the loop on a single poison event and starve every later one.
48
+ */
49
+ export declare function runMatrixSyncLoop(deps: MatrixSyncLoopDeps): Promise<string | undefined>;
50
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAKhE,mHAAmH;AACnH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7D,0FAA0F;IAC1F,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,+HAA+H;IAC/H,SAAS,IAAI,OAAO,CAAC;IACrB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiC7F"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Matrix room event -> {@link ChannelMessage}: the transport's own half of
3
+ * the channel contract (see docs/build-a-channel.md), kept pure so mention,
4
+ * reply-to and DM detection are testable without a network or a running
5
+ * channel.
6
+ *
7
+ * Addressing parity with the other built-in channels is the point of this
8
+ * module. WhatsApp and Telegram both resolve "was the bot addressed?" from
9
+ * transport-native structures; Matrix resolves it from the stable
10
+ * `m.mentions` field (MSC3952, in the spec since v1.7) with a pill-in-HTML
11
+ * fallback for clients that only set that. The gate policy that consumes
12
+ * those booleans (`decideChannelAction`) is identical for every channel.
13
+ */
14
+ import type { ChannelMessage } from "../gates";
15
+ import type { MatrixAccountDataEvent, MatrixEvent } from "./api";
16
+ /** The bot's own identity, as `whoami` reports it. */
17
+ export interface MatrixIdentity {
18
+ userId: string;
19
+ }
20
+ interface MatrixMentions {
21
+ user_ids?: string[];
22
+ room?: boolean;
23
+ }
24
+ interface MatrixInReplyTo {
25
+ event_id?: string;
26
+ }
27
+ interface MatrixMessageContent {
28
+ msgtype?: string;
29
+ body?: string;
30
+ format?: string;
31
+ formatted_body?: string;
32
+ "m.mentions"?: MatrixMentions;
33
+ "m.relates_to"?: {
34
+ "m.in_reply_to"?: MatrixInReplyTo;
35
+ };
36
+ }
37
+ /** The message text, or "" for an event this channel doesn't render as text (a redaction, a non-text msgtype with no body). */
38
+ export declare function messageText(content: MatrixMessageContent): string;
39
+ export declare function mentionsBot(content: MatrixMessageContent, me: MatrixIdentity): boolean;
40
+ /**
41
+ * Was this message a reply to one the bot sent? `sentEventIds` is the
42
+ * session's own record of event ids it has sent (see `./channel`) — Matrix
43
+ * has no cheap "who sent event X" lookup without fetching that event, and a
44
+ * bot only ever needs to recognise its OWN messages, which it already knows
45
+ * without asking the server.
46
+ */
47
+ export declare function isReplyToBot(content: MatrixMessageContent, sentEventIds: ReadonlySet<string>): boolean;
48
+ /** How many of the session's own sent event ids {@link isReplyToBot} remembers — bounded so a long-running bot's memory doesn't grow with every message it ever sent. */
49
+ export declare const MAX_TRACKED_SENT_EVENTS = 500;
50
+ /** Records `eventId` as one of ours, evicting the oldest entry first once the set is at capacity (`Set` iterates in insertion order, so the first value is the oldest). */
51
+ export declare function recordSentEventId(sentEventIds: Set<string>, eventId: string): void;
52
+ /**
53
+ * Room ids the homeserver's `m.direct` account data lists as direct
54
+ * messages, across every peer — the canonical way a Matrix client (and so a
55
+ * bot) tells a DM from a group: there is no per-room "this is a DM" flag.
56
+ * A room absent from this set is treated as a group and needs addressing,
57
+ * the safer default when a client never populated `m.direct` for it.
58
+ */
59
+ export declare function directRoomIds(accountDataEvents: MatrixAccountDataEvent[]): Set<string>;
60
+ /**
61
+ * The {@link ChannelMessage} for a timeline event, or `undefined` when
62
+ * there is nothing for a chat pipeline to look at: not an `m.room.message`
63
+ * (a reaction, a membership change, an encrypted event this channel can't
64
+ * decrypt), or one with no `msgtype` at all (a redacted message).
65
+ */
66
+ export declare function toChannelMessage(roomId: string, event: MatrixEvent, me: MatrixIdentity, directRooms: ReadonlySet<string>, sentEventIds: ReadonlySet<string>): ChannelMessage | undefined;
67
+ /**
68
+ * A stable identity key for `bucketsFor`/`personaResolver`/`answerFn`.
69
+ * Namespaced so a bare Matrix user id (which is itself already `@user:
70
+ * server.tld`, unlike Telegram's bare numeral) never collides with another
71
+ * channel's key when a host shares persona/spend state across channels.
72
+ */
73
+ export declare function matrixSenderKey(userId: string): string;
74
+ export {};
75
+ //# sourceMappingURL=updates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/updates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEjE,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,cAAc;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,eAAe;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,cAAc,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,eAAe,CAAA;KAAE,CAAC;CACxD;AAED,+HAA+H;AAC/H,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAEjE;AAiCD,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,EAAE,cAAc,GAAG,OAAO,CAQtF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,oBAAoB,EAC7B,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,OAAO,CAGT;AAED,yKAAyK;AACzK,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,2KAA2K;AAC3K,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAMlF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,iBAAiB,EAAE,sBAAsB,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAYtF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,EAClB,EAAE,EAAE,cAAc,EAClB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,cAAc,GAAG,SAAS,CAe5B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegoaltoworks/chatter",
3
- "version": "0.60.0",
3
+ "version": "0.61.0",
4
4
  "description": "Embeddable AI chatbot framework with RAG, authentication, and customizable widgets",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -68,6 +68,11 @@
68
68
  "import": "./dist/channels/telegram/index.mjs",
69
69
  "require": "./dist/channels/telegram/index.js"
70
70
  },
71
+ "./matrix": {
72
+ "types": "./dist/channels/matrix/index.d.ts",
73
+ "import": "./dist/channels/matrix/index.mjs",
74
+ "require": "./dist/channels/matrix/index.js"
75
+ },
71
76
  "./images": {
72
77
  "types": "./dist/images/index.d.ts",
73
78
  "import": "./dist/images/index.mjs",
@@ -88,7 +93,7 @@
88
93
  ],
89
94
  "scripts": {
90
95
  "dev": "bun --watch src/index.ts",
91
- "build": "bun run build:clean && bun run build:types && bun run build:esm && bun run build:cjs && bun run build:server && bun run build:mcp && bun run build:usage && bun run build:history && bun run build:personas && bun run build:channels && bun run build:whatsapp && bun run build:telegram && bun run build:flows && bun run build:images && bun run build:scheduler && bun run build:bin && bun run build:client && bun run build:copy-client",
96
+ "build": "bun run build:clean && bun run build:types && bun run build:esm && bun run build:cjs && bun run build:server && bun run build:mcp && bun run build:usage && bun run build:history && bun run build:personas && bun run build:channels && bun run build:whatsapp && bun run build:telegram && bun run build:matrix && bun run build:flows && bun run build:images && bun run build:scheduler && bun run build:bin && bun run build:client && bun run build:copy-client",
92
97
  "build:clean": "rm -rf dist",
93
98
  "build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
94
99
  "build:esm": "esbuild src/index.ts --bundle --format=esm --outfile=dist/index.mjs --external:@hono/node-server --external:hono --external:openai --external:@libsql/client --external:jose --external:@modelcontextprotocol/sdk --external:zod --platform=node --target=node24",
@@ -101,6 +106,7 @@
101
106
  "build:channels": "esbuild src/channels/index.ts --bundle --format=esm --outfile=dist/channels/index.mjs --external:hono --external:openai --external:@libsql/client --platform=node --target=node24 && esbuild src/channels/index.ts --bundle --format=cjs --outfile=dist/channels/index.js --external:hono --external:openai --external:@libsql/client --platform=node --target=node24",
102
107
  "build:whatsapp": "esbuild src/channels/whatsapp/index.ts --bundle --format=esm --outfile=dist/channels/whatsapp/index.mjs --external:@libsql/client --external:@whiskeysockets/baileys --platform=node --target=node24 && esbuild src/channels/whatsapp/index.ts --bundle --format=cjs --outfile=dist/channels/whatsapp/index.js --external:@libsql/client --external:@whiskeysockets/baileys --platform=node --target=node24",
103
108
  "build:telegram": "esbuild src/channels/telegram/index.ts --bundle --format=esm --outfile=dist/channels/telegram/index.mjs --external:@libsql/client --external:openai --platform=node --target=node24 && esbuild src/channels/telegram/index.ts --bundle --format=cjs --outfile=dist/channels/telegram/index.js --external:@libsql/client --external:openai --platform=node --target=node24",
109
+ "build:matrix": "esbuild src/channels/matrix/index.ts --bundle --format=esm --outfile=dist/channels/matrix/index.mjs --external:@libsql/client --external:openai --platform=node --target=node24 && esbuild src/channels/matrix/index.ts --bundle --format=cjs --outfile=dist/channels/matrix/index.js --external:@libsql/client --external:openai --platform=node --target=node24",
104
110
  "build:flows": "esbuild src/flows/index.ts --bundle --format=esm --outfile=dist/flows/index.mjs --external:@libsql/client --external:openai --platform=node --target=node24 && esbuild src/flows/index.ts --bundle --format=cjs --outfile=dist/flows/index.js --external:@libsql/client --external:openai --platform=node --target=node24",
105
111
  "build:images": "esbuild src/images/index.ts --bundle --format=esm --outfile=dist/images/index.mjs --external:@libsql/client --external:openai --platform=node --target=node24 && esbuild src/images/index.ts --bundle --format=cjs --outfile=dist/images/index.js --external:@libsql/client --external:openai --platform=node --target=node24",
106
112
  "build:scheduler": "esbuild src/scheduler/index.ts --bundle --format=esm --outfile=dist/scheduler/index.mjs --external:@libsql/client --external:openai --platform=node --target=node24 && esbuild src/scheduler/index.ts --bundle --format=cjs --outfile=dist/scheduler/index.js --external:@libsql/client --external:openai --platform=node --target=node24",