Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ This repository provides:
<!-- BEGIN PLUGIN CATALOG -->
| Plugin | Description | Version | Status |
| ------ | ----------- | ------- | ------ |
| [`after-hours`](./after-hours) | Auto-replies with a configurable away/closing message to messages received outside business hours. | 0.1.1 | stable |
| [`after-hours`](./after-hours) | Auto-replies with a configurable away/closing message to messages received outside business hours. | 0.1.2 | stable |
| [`chat-flow`](./chat-flow) | Interactive, stateful auto-reply: a trigger word starts a greeting + numbered menu, replies traverse a configurable menu tree, and per-chat state expires after 15 minutes. | 1.0.2 | stable |
| [`faq-bot`](./faq-bot) | Auto-replies to inbound WhatsApp messages from configurable FAQ keyword/regex rules. | 0.1.1 | stable |
| [`group-translate`](./group-translate) | Auto-translates group messages between participants' languages via a LibreTranslate backend. Configure in-chat with /tr commands. Admin-gated; disabled until enabled. | 1.0.2 | stable |
Expand Down
8 changes: 8 additions & 0 deletions after-hours/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ The version here always matches `manifest.json`'s `version`.

## [Unreleased]

## [0.1.2] — 2026-06-23

### Changed

- The per-chat cooldown map now evicts least-recently-used entries (re-inserting a chat on each reply)
instead of first-seen order, so a continuously-active chat keeps its cooldown when the map reaches its
cap rather than being evicted and allowed to bypass the throttle.

## [0.1.1] — 2026-06-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion after-hours/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
| Field | Value |
| ----- | ----- |
| **Identifier** | `after-hours` |
| **Version** | 0.1.1 |
| **Version** | 0.1.2 |
| **Released** | 2026-06-23 |
| **Status** | stable |
| **Author** | Yudhi Armyndharis |
Expand Down
10 changes: 10 additions & 0 deletions after-hours/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,13 @@ test('allowReply enforces the per-chat cooldown and caps the map', () => {
assert.equal(big.size, 5000);
assert.equal(big.has('k-0'), false);
});

test('allowReply eviction is recency-aware: re-touching a key protects it', () => {
const map = new Map<string, number>();
for (let i = 0; i < 5000; i++) allowReply(map, `k-${i}`, i, 0);
allowReply(map, 'k-0', 10000, 0); // re-touch -> most recently used
allowReply(map, 'k-new', 10001, 0); // overflow -> evict genuinely-oldest
assert.equal(map.size, 5000);
assert.equal(map.has('k-0'), true); // protected by recent touch
assert.equal(map.has('k-1'), false); // now the oldest, evicted
});
5 changes: 3 additions & 2 deletions after-hours/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ export function parseConfig(raw: Record<string, unknown>): { config: AfterHoursC
}

/**
* Decide whether an after-hours reply may go to `key` now. On allow, records `nowMs` and caps the map
* (drop oldest). `cooldownMs` of 0 always allows.
* Decide whether an after-hours reply may go to `key` now. On allow, records `nowMs` (re-inserting so
* the map evicts least-recently-used) and caps the map by dropping the LRU entry. `cooldownMs` of 0 always allows.
*/
export function allowReply(map: Map<string, number>, key: string, nowMs: number, cooldownMs: number): boolean {
const last = map.get(key);
if (last !== undefined && nowMs - last < cooldownMs) return false;
map.delete(key); // re-insert so iteration order tracks recency (LRU by touch)
map.set(key, nowMs);
if (map.size > MAX_COOLDOWN_ENTRIES) {
const oldest = map.keys().next().value as string | undefined;
Expand Down
2 changes: 1 addition & 1 deletion after-hours/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "after-hours",
"name": "After-Hours Auto-Reply",
"version": "0.1.1",
"version": "0.1.2",
"type": "extension",
"main": "dist/index.js",
"description": "Auto-replies with a configurable away/closing message to messages received outside business hours.",
Expand Down
4 changes: 2 additions & 2 deletions plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"id": "after-hours",
"name": "After-Hours Auto-Reply",
"version": "0.1.1",
"version": "0.1.2",
"type": "extension",
"status": "stable",
"description": "Auto-replies with a configurable away/closing message to messages received outside business hours.",
Expand All @@ -22,7 +22,7 @@
"repoPath": "after-hours",
"repoUrl": "https://github.com/rmyndharis/OpenWA-plugins",
"homepage": "https://github.com/rmyndharis/OpenWA-plugins/tree/main/after-hours",
"download": "https://github.com/rmyndharis/OpenWA-plugins/releases/download/after-hours-v0.1.1/after-hours.zip",
"download": "https://github.com/rmyndharis/OpenWA-plugins/releases/download/after-hours-v0.1.2/after-hours.zip",
"i18n": {
"es": {
"name": "Respuesta Automática Fuera de Horario",
Expand Down
Loading