@justfortytwo/telegram 0.1.0 → 0.1.2
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 +14 -5
- package/dist/adapter.d.ts +3 -5
- package/dist/adapter.js +7 -22
- package/dist/adapter.js.map +1 -1
- package/dist/bindings.d.ts +24 -1
- package/dist/bindings.js +45 -0
- package/dist/bindings.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -39,6 +39,10 @@ channel side: /login <code> -> verify(chatId, code) -> bindin
|
|
|
39
39
|
owner chat reach the bridge before any binding exists; it is not required once
|
|
40
40
|
bindings exist.
|
|
41
41
|
|
|
42
|
+
Pending challenges are **persisted in the binding store** (not in process
|
|
43
|
+
memory), so a code minted by one process — e.g. the `fortytwo pair` CLI — is
|
|
44
|
+
redeemable by the separately-running bridge. They are single-use and short-TTL.
|
|
45
|
+
|
|
42
46
|
The contract is intentionally **channel-agnostic** (`ChannelAdapter` in
|
|
43
47
|
`src/adapter.ts`) so a future Slack / email / SMS adapter implements the same
|
|
44
48
|
`issueChallenge` / `verify` shape.
|
|
@@ -49,8 +53,9 @@ Authorization must work **even when the memory package is absent**, so the
|
|
|
49
53
|
binding store is **self-owned** and does not assume the `@justfortytwo/memory`
|
|
50
54
|
sqlite db exists:
|
|
51
55
|
|
|
52
|
-
- `SqliteBindingStore` — default; a tiny `better-sqlite3`
|
|
53
|
-
|
|
56
|
+
- `SqliteBindingStore` — default; a tiny `better-sqlite3` db in its own file
|
|
57
|
+
(`state/telegram-bindings.db` by default) holding **bindings + pending
|
|
58
|
+
challenges**, so a CLI-issued pairing code reaches the bridge.
|
|
54
59
|
- `MemoryBindingStore` — in-process Map, for tests / ephemeral use.
|
|
55
60
|
- `BindingStore` — the injectable interface. Supply a memory-backed
|
|
56
61
|
implementation later without touching the login flow.
|
|
@@ -75,9 +80,13 @@ Install them alongside this package:
|
|
|
75
80
|
npm install @justfortytwo/telegram @justfortytwo/memory @justfortytwo/gate
|
|
76
81
|
```
|
|
77
82
|
|
|
78
|
-
The
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
The **memory** data path is wired: the bridge opens + migrates the memory DB at
|
|
84
|
+
startup and **persists each channel event** to `@justfortytwo/memory`; recall
|
|
85
|
+
happens inside the headless `claude` turn via the Memory MCP tools. If the memory
|
|
86
|
+
peer is absent, the bridge degrades to **channel-only** (messages relay but are
|
|
87
|
+
not persisted) rather than refusing to start. The **gate** "Allow _N_h" path
|
|
88
|
+
still uses a local bash-allowlist fallback; wiring it to `@justfortytwo/gate`'s
|
|
89
|
+
exact-command allowlist is the remaining seam.
|
|
81
90
|
|
|
82
91
|
## Environment
|
|
83
92
|
|
package/dist/adapter.d.ts
CHANGED
|
@@ -25,14 +25,13 @@ export interface ChallengeOptions {
|
|
|
25
25
|
now?: () => number;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Telegram implementation of ChannelAdapter.
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* Telegram implementation of ChannelAdapter. Pending codes AND verified bindings
|
|
29
|
+
* persist via the injected BindingStore, so a code minted in one process (the
|
|
30
|
+
* `fortytwo pair` CLI) is redeemable in another (the running bridge).
|
|
31
31
|
*/
|
|
32
32
|
export declare class TelegramAdapter implements ChannelAdapter {
|
|
33
33
|
private readonly store;
|
|
34
34
|
readonly channelType: ChannelType;
|
|
35
|
-
private readonly pending;
|
|
36
35
|
private readonly ttlSeconds;
|
|
37
36
|
private readonly digits;
|
|
38
37
|
private readonly now;
|
|
@@ -43,5 +42,4 @@ export declare class TelegramAdapter implements ChannelAdapter {
|
|
|
43
42
|
bindingFor(channelUserId: string): Binding | null;
|
|
44
43
|
/** Remove a persisted binding (logout). */
|
|
45
44
|
unbind(channelUserId: string): void;
|
|
46
|
-
private sweepExpired;
|
|
47
45
|
}
|
package/dist/adapter.js
CHANGED
|
@@ -15,14 +15,13 @@
|
|
|
15
15
|
// email / SMS adapter implements the same contract.
|
|
16
16
|
import { randomInt } from 'node:crypto';
|
|
17
17
|
/**
|
|
18
|
-
* Telegram implementation of ChannelAdapter.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Telegram implementation of ChannelAdapter. Pending codes AND verified bindings
|
|
19
|
+
* persist via the injected BindingStore, so a code minted in one process (the
|
|
20
|
+
* `fortytwo pair` CLI) is redeemable in another (the running bridge).
|
|
21
21
|
*/
|
|
22
22
|
export class TelegramAdapter {
|
|
23
23
|
store;
|
|
24
24
|
channelType = 'telegram';
|
|
25
|
-
pending = new Map(); // code -> challenge
|
|
26
25
|
ttlSeconds;
|
|
27
26
|
digits;
|
|
28
27
|
now;
|
|
@@ -33,24 +32,17 @@ export class TelegramAdapter {
|
|
|
33
32
|
this.now = opts.now ?? (() => Date.now());
|
|
34
33
|
}
|
|
35
34
|
issueChallenge(owner) {
|
|
36
|
-
this.
|
|
35
|
+
this.store.sweepChallenges(this.now());
|
|
37
36
|
const max = 10 ** this.digits;
|
|
38
37
|
const code = String(randomInt(0, max)).padStart(this.digits, '0');
|
|
39
|
-
this.
|
|
38
|
+
this.store.putChallenge({ code, owner, expiresAt: this.now() + this.ttlSeconds * 1000 });
|
|
40
39
|
return { code, ttl: this.ttlSeconds };
|
|
41
40
|
}
|
|
42
41
|
verify(channelUserId, proof) {
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
const challenge = this.pending.get(code);
|
|
42
|
+
// Single-use + expiry are enforced by the store's atomic takeChallenge.
|
|
43
|
+
const challenge = this.store.takeChallenge(proof.trim(), this.now());
|
|
46
44
|
if (!challenge)
|
|
47
45
|
return null;
|
|
48
|
-
if (challenge.expiresAt <= this.now()) {
|
|
49
|
-
this.pending.delete(code);
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
// Single-use: consume the code regardless of downstream outcome.
|
|
53
|
-
this.pending.delete(code);
|
|
54
46
|
const binding = {
|
|
55
47
|
channelType: this.channelType,
|
|
56
48
|
channelUserId,
|
|
@@ -68,12 +60,5 @@ export class TelegramAdapter {
|
|
|
68
60
|
unbind(channelUserId) {
|
|
69
61
|
this.store.remove(this.channelType, channelUserId);
|
|
70
62
|
}
|
|
71
|
-
sweepExpired() {
|
|
72
|
-
const t = this.now();
|
|
73
|
-
for (const [code, c] of this.pending) {
|
|
74
|
-
if (c.expiresAt <= t)
|
|
75
|
-
this.pending.delete(code);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
63
|
}
|
|
79
64
|
//# sourceMappingURL=adapter.js.map
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,sEAAsE;AACtE,EAAE;AACF,8CAA8C;AAC9C,iFAAiF;AACjF,sEAAsE;AACtE,0BAA0B;AAC1B,sDAAsD;AACtD,8EAA8E;AAC9E,oEAAoE;AACpE,EAAE;AACF,+EAA+E;AAC/E,oDAAoD;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,sEAAsE;AACtE,EAAE;AACF,8CAA8C;AAC9C,iFAAiF;AACjF,sEAAsE;AACtE,0BAA0B;AAC1B,sDAAsD;AACtD,8EAA8E;AAC9E,oEAAoE;AACpE,EAAE;AACF,+EAA+E;AAC/E,oDAAoD;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA+BxC;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAMG;IALpB,WAAW,GAAgB,UAAU,CAAC;IAC9B,UAAU,CAAS;IACnB,MAAM,CAAS;IACf,GAAG,CAAe;IAEnC,YAA6B,KAAmB,EAAE,OAAyB,EAAE;QAAhD,UAAK,GAAL,KAAK,CAAc;QAC9C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,cAAc,CAAC,KAAa;QAC1B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAClE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,EAAE,CAAC,CAAC;QACzF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IACxC,CAAC;IAED,MAAM,CAAC,aAAqB,EAAE,KAAa;QACzC,wEAAwE;QACxE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAC5B,MAAM,OAAO,GAAY;YACvB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,aAAa;YACb,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE;SAC5C,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,wEAAwE;IACxE,UAAU,CAAC,aAAqB;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACzD,CAAC;IAED,2CAA2C;IAC3C,MAAM,CAAC,aAAqB;QAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACrD,CAAC;CACF"}
|
package/dist/bindings.d.ts
CHANGED
|
@@ -5,21 +5,41 @@ export interface Binding {
|
|
|
5
5
|
owner: string;
|
|
6
6
|
boundAt: string;
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* A pending pairing challenge. Persisted in the store (not in adapter memory) so
|
|
10
|
+
* a code minted in one process (e.g. `fortytwo pair`) is redeemable in another
|
|
11
|
+
* (the running bridge).
|
|
12
|
+
*/
|
|
13
|
+
export interface PendingChallenge {
|
|
14
|
+
code: string;
|
|
15
|
+
owner: string;
|
|
16
|
+
expiresAt: number;
|
|
17
|
+
}
|
|
18
|
+
/** The seam. Persists channel-id -> owner bindings + pending challenges; everything else injects this. */
|
|
9
19
|
export interface BindingStore {
|
|
10
20
|
get(channelType: ChannelType, channelUserId: string): Binding | null;
|
|
11
21
|
put(binding: Binding): void;
|
|
12
22
|
remove(channelType: ChannelType, channelUserId: string): void;
|
|
13
23
|
list(channelType?: ChannelType): Binding[];
|
|
24
|
+
/** Persist a pending pairing challenge so any process sharing the store can redeem it. */
|
|
25
|
+
putChallenge(challenge: PendingChallenge): void;
|
|
26
|
+
/** Fetch + CONSUME a challenge by code (single-use); null if absent or expired. */
|
|
27
|
+
takeChallenge(code: string, now: number): PendingChallenge | null;
|
|
28
|
+
/** Drop expired challenges. */
|
|
29
|
+
sweepChallenges(now: number): void;
|
|
14
30
|
}
|
|
15
31
|
/** In-memory store — ideal for tests and ephemeral deployments. */
|
|
16
32
|
export declare class MemoryBindingStore implements BindingStore {
|
|
17
33
|
private readonly map;
|
|
34
|
+
private readonly challenges;
|
|
18
35
|
private key;
|
|
19
36
|
get(channelType: ChannelType, channelUserId: string): Binding | null;
|
|
20
37
|
put(binding: Binding): void;
|
|
21
38
|
remove(channelType: ChannelType, channelUserId: string): void;
|
|
22
39
|
list(channelType?: ChannelType): Binding[];
|
|
40
|
+
putChallenge(challenge: PendingChallenge): void;
|
|
41
|
+
takeChallenge(code: string, now: number): PendingChallenge | null;
|
|
42
|
+
sweepChallenges(now: number): void;
|
|
23
43
|
}
|
|
24
44
|
/**
|
|
25
45
|
* Self-owned sqlite-backed binding store. Uses its own small db file so it does
|
|
@@ -33,4 +53,7 @@ export declare class SqliteBindingStore implements BindingStore {
|
|
|
33
53
|
put(binding: Binding): void;
|
|
34
54
|
remove(channelType: ChannelType, channelUserId: string): void;
|
|
35
55
|
list(channelType?: ChannelType): Binding[];
|
|
56
|
+
putChallenge(challenge: PendingChallenge): void;
|
|
57
|
+
takeChallenge(code: string, now: number): PendingChallenge | null;
|
|
58
|
+
sweepChallenges(now: number): void;
|
|
36
59
|
}
|
package/dist/bindings.js
CHANGED
|
@@ -16,6 +16,7 @@ import { createRequire } from 'node:module';
|
|
|
16
16
|
/** In-memory store — ideal for tests and ephemeral deployments. */
|
|
17
17
|
export class MemoryBindingStore {
|
|
18
18
|
map = new Map();
|
|
19
|
+
challenges = new Map();
|
|
19
20
|
key(t, u) { return `${t} ${u}`; }
|
|
20
21
|
get(channelType, channelUserId) {
|
|
21
22
|
return this.map.get(this.key(channelType, channelUserId)) ?? null;
|
|
@@ -30,6 +31,21 @@ export class MemoryBindingStore {
|
|
|
30
31
|
const all = [...this.map.values()];
|
|
31
32
|
return channelType ? all.filter((b) => b.channelType === channelType) : all;
|
|
32
33
|
}
|
|
34
|
+
putChallenge(challenge) {
|
|
35
|
+
this.challenges.set(challenge.code, challenge);
|
|
36
|
+
}
|
|
37
|
+
takeChallenge(code, now) {
|
|
38
|
+
const c = this.challenges.get(code);
|
|
39
|
+
if (!c)
|
|
40
|
+
return null;
|
|
41
|
+
this.challenges.delete(code); // single-use: consume regardless of expiry
|
|
42
|
+
return c.expiresAt > now ? c : null;
|
|
43
|
+
}
|
|
44
|
+
sweepChallenges(now) {
|
|
45
|
+
for (const [code, c] of this.challenges)
|
|
46
|
+
if (c.expiresAt <= now)
|
|
47
|
+
this.challenges.delete(code);
|
|
48
|
+
}
|
|
33
49
|
}
|
|
34
50
|
// Load the native sqlite driver via createRequire so this ESM module can pull a
|
|
35
51
|
// CommonJS addon without a top-level static import (which would force the native
|
|
@@ -54,6 +70,11 @@ export class SqliteBindingStore {
|
|
|
54
70
|
bound_at TEXT NOT NULL,
|
|
55
71
|
PRIMARY KEY (channel_type, channel_user_id)
|
|
56
72
|
);
|
|
73
|
+
CREATE TABLE IF NOT EXISTS pending_challenges (
|
|
74
|
+
code TEXT PRIMARY KEY,
|
|
75
|
+
owner TEXT NOT NULL,
|
|
76
|
+
expires_at INTEGER NOT NULL
|
|
77
|
+
);
|
|
57
78
|
`);
|
|
58
79
|
}
|
|
59
80
|
get(channelType, channelUserId) {
|
|
@@ -83,5 +104,29 @@ export class SqliteBindingStore {
|
|
|
83
104
|
: this.db.prepare('SELECT channel_type, channel_user_id, owner, bound_at FROM channel_bindings').all());
|
|
84
105
|
return rows.map((r) => ({ channelType: r.channel_type, channelUserId: r.channel_user_id, owner: r.owner, boundAt: r.bound_at }));
|
|
85
106
|
}
|
|
107
|
+
putChallenge(challenge) {
|
|
108
|
+
this.db
|
|
109
|
+
.prepare(`
|
|
110
|
+
INSERT INTO pending_challenges (code, owner, expires_at)
|
|
111
|
+
VALUES (@code, @owner, @expiresAt)
|
|
112
|
+
ON CONFLICT(code) DO UPDATE SET owner = excluded.owner, expires_at = excluded.expires_at
|
|
113
|
+
`)
|
|
114
|
+
.run(challenge);
|
|
115
|
+
}
|
|
116
|
+
takeChallenge(code, now) {
|
|
117
|
+
// Fetch + delete in one transaction so a code is single-use even under a race.
|
|
118
|
+
const consume = this.db.transaction((c) => {
|
|
119
|
+
const row = this.db.prepare('SELECT code, owner, expires_at FROM pending_challenges WHERE code = ?').get(c);
|
|
120
|
+
this.db.prepare('DELETE FROM pending_challenges WHERE code = ?').run(c);
|
|
121
|
+
return row;
|
|
122
|
+
});
|
|
123
|
+
const row = consume(code);
|
|
124
|
+
if (!row)
|
|
125
|
+
return null;
|
|
126
|
+
return row.expires_at > now ? { code: row.code, owner: row.owner, expiresAt: row.expires_at } : null;
|
|
127
|
+
}
|
|
128
|
+
sweepChallenges(now) {
|
|
129
|
+
this.db.prepare('DELETE FROM pending_challenges WHERE expires_at <= ?').run(now);
|
|
130
|
+
}
|
|
86
131
|
}
|
|
87
132
|
//# sourceMappingURL=bindings.js.map
|
package/dist/bindings.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bindings.js","sourceRoot":"","sources":["../src/bindings.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,WAAW;AACX,gFAAgF;AAChF,2EAA2E;AAC3E,+EAA+E;AAC/E,sEAAsE;AACtE,iFAAiF;AACjF,EAAE;AACF,0EAA0E;AAC1E,mEAAmE;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"bindings.js","sourceRoot":"","sources":["../src/bindings.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justfortytwo/telegram",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Telegram channel adapter for fortytwo: a long-polling bridge that drives a headless `claude` turn loop per chat, surfaces gate approvals as inline keyboards, and gates inbound access behind a login/pairing binding flow.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"type": "module",
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": ">=
|
|
17
|
+
"node": ">=20"
|
|
18
18
|
},
|
|
19
19
|
"main": "./dist/index.js",
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"./bridge": "./dist/bridge.js"
|
|
27
27
|
},
|
|
28
28
|
"bin": {
|
|
29
|
-
"fortytwo-telegram-bridge": "
|
|
29
|
+
"fortytwo-telegram-bridge": "dist/bridge.js"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"better-sqlite3": "^
|
|
64
|
+
"better-sqlite3": "^12.0.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/better-sqlite3": "^7.6.0",
|