Files
Evandro Fonseca Junior d1d04001d0
Release / release (push) Failing after 5s
Validate / validate (push) Failing after 5m21s
chore: fork @llblab/[email protected] as @evandrodevbr/oh-my-pi-telegram
Fork of upstream llblab/[email protected].0 (SHA afe09c5) repackaged as a
drop-in extension for can1357/oh-my-pi (omp >= 16.5.2).

Changes vs upstream:
- Rename package: @llblab/pi-telegram -> @evandrodevbr/oh-my-pi-telegram
- Bump version: 0.22.0 -> 0.22.0-evandro.1
- Update repository/homepage/bugs URLs to evandrodevbr
- Add omp field in package.json (displayName + compatibleWith)
- README: prepend 'Oh My Pi (omp) Compatibility' section with install
  commands, verified-components table, upstream lineage, and rationale
- CHANGELOG: add '0.22.0-evandro.1' entry under Unreleased
- docs/: rename @llblab/pi-telegram imports to @evandrodevbr/oh-my-pi-telegram
- tests/public-api.test.ts: rename package import paths

Gates re-run on the fork:
- npm run typecheck  -> tsc --noEmit (success)
- npm test           -> 1229 pass / 0 fail / 1 platform-only skip
- npm run audit      -> found 0 vulnerabilities
- npm run pack:check -> evandrodevbr-oh-my-pi-telegram-0.22.0-evandro.1.tgz

Verified:
- omp install --link ./pi-telegram -> Linked OK
- omp plugin list -> @evandrodevbr/[email protected].0-evandro.1

Upstream lineage: badlogic/pi-telegram -> llblab/pi-telegram (0.22.0) -> evandrodevbr/oh-my-pi-telegram (this fork)
2026-07-15 14:18:16 -03:00

183 lines
4.8 KiB
TypeScript

/**
* Regression tests for Telegram message ownership helpers
* Covers live message-id to target/instance ownership used by multi-instance bus routing
*/
import assert from "node:assert/strict";
import test from "node:test";
import {
createTelegramBusMessageOwnershipRuntime,
createTelegramMessageOwnershipStore,
} from "../lib/ownership.ts";
import { createTelegramThreadTarget } from "../lib/target.ts";
test("Bus ownership runtime scopes follower authority to registration generation", () => {
let followers = [
{
instanceId: "follower-a",
connectedAtMs: 10,
registrationGeneration: "generation-a",
},
];
const runtime = createTelegramBusMessageOwnershipRuntime({
instanceId: "leader",
getProfileKey: () => "default",
listFollowers: () => followers,
});
runtime.recordRouted({
chatId: 7,
messageId: 9,
target: { chatId: 7, threadId: 11 },
instanceId: "follower-a",
});
assert.equal(
runtime.isOwnedByFollower({
chatId: 7,
messageId: 9,
follower: followers[0]!,
}),
true,
);
followers = [
{
instanceId: "follower-a",
connectedAtMs: 20,
registrationGeneration: "generation-b",
},
];
assert.equal(runtime.store.get(7, 9), undefined);
assert.equal(
runtime.isOwnedByFollower({
chatId: 7,
messageId: 9,
follower: followers[0]!,
}),
false,
);
});
test("Message ownership records default private targets", () => {
const store = createTelegramMessageOwnershipStore();
const record = store.record({
chatId: 7,
messageId: 9,
instanceId: "instance-a",
now: 100,
});
assert.deepEqual(record, {
chatId: 7,
messageId: 9,
target: { chatId: 7 },
instanceId: "instance-a",
createdAt: 100,
updatedAt: 100,
});
assert.deepEqual(store.get(7, 9), record);
});
test("Message ownership preserves createdAt when ownership is refreshed", () => {
const store = createTelegramMessageOwnershipStore();
store.record({
chatId: -1007,
messageId: 11,
target: createTelegramThreadTarget(-1007, 42),
instanceId: "instance-a",
now: 100,
});
const refreshed = store.record({
chatId: -1007,
messageId: 11,
target: createTelegramThreadTarget(-1007, 43),
instanceId: "instance-b",
now: 150,
});
assert.deepEqual(refreshed, {
chatId: -1007,
messageId: 11,
target: createTelegramThreadTarget(-1007, 43),
instanceId: "instance-b",
createdAt: 100,
updatedAt: 150,
});
});
test("Message ownership can forget a whole target", () => {
const store = createTelegramMessageOwnershipStore();
store.record({
chatId: -1007,
messageId: 1,
target: createTelegramThreadTarget(-1007, 42),
instanceId: "instance-a",
now: 1,
});
store.record({
chatId: -1007,
messageId: 2,
target: createTelegramThreadTarget(-1007, 42),
instanceId: "instance-a",
now: 2,
});
store.record({
chatId: -1007,
messageId: 3,
target: createTelegramThreadTarget(-1007, 43),
instanceId: "instance-b",
now: 3,
});
assert.equal(store.forgetTarget(createTelegramThreadTarget(-1007, 42)), 2);
assert.equal(store.get(-1007, 1), undefined);
assert.equal(store.get(-1007, 2), undefined);
assert.equal(store.get(-1007, 3)?.instanceId, "instance-b");
});
test("Message ownership isolates bot profiles and rejects stale follower generations", () => {
let profileKey = "work";
let liveGeneration = "follower-a:100";
const store = createTelegramMessageOwnershipStore({
getProfileKey: () => profileKey,
isOwnerGenerationLive: (record) =>
record.ownerGeneration === liveGeneration,
});
store.record({
chatId: 7,
messageId: 9,
instanceId: "follower-a",
ownerGeneration: "follower-a:100",
now: 100,
});
assert.equal(store.get(7, 9)?.instanceId, "follower-a");
profileKey = "personal";
assert.equal(store.get(7, 9), undefined);
store.record({
chatId: 7,
messageId: 9,
instanceId: "follower-b",
ownerGeneration: "follower-b:200",
now: 200,
});
liveGeneration = "follower-b:200";
assert.equal(store.get(7, 9)?.instanceId, "follower-b");
profileKey = "work";
liveGeneration = "follower-a:101";
assert.equal(store.get(7, 9), undefined);
assert.equal(store.entries().length, 2);
});
test("Message ownership prunes by age and record count", () => {
const store = createTelegramMessageOwnershipStore();
store.record({ chatId: 7, messageId: 1, instanceId: "a", now: 10 });
store.record({ chatId: 7, messageId: 2, instanceId: "a", now: 20 });
store.record({ chatId: 7, messageId: 3, instanceId: "a", now: 30 });
assert.equal(store.prune({ now: 40, maxAgeMs: 25 }), 1);
assert.equal(store.get(7, 1), undefined);
assert.equal(store.prune({ now: 40, maxRecords: 1 }), 1);
assert.deepEqual(
store.entries().map((record) => record.messageId),
[3],
);
});