#17897: refactor: extract firstDefined utility from telegram/line/slack
channel: slack
channel: telegram
stale
size: S
Cluster:
Signal and Discord Fixes
## Summary
- Problem: `firstDefined<T>(...values)` utility duplicated identically in 3 files across telegram, LINE, and slack channel modules (3 definitions, 14 call sites).
- Why it matters: Identical utility logic copied per-channel increases maintenance surface and risks divergence.
- What changed: Extracted `firstDefined` to `src/utils.ts` and updated all 8 consumer files to import from the shared location.
- What did NOT change (scope boundary): Channel-specific logic (`normalizeAllowFrom`, `isSenderAllowed`) remains in each channel's `bot-access.ts` — those have intentional behavioral differences per channel.
## Change Type (select all)
- [ ] Bug fix
- [ ] Feature
- [x] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Related #17770 #17793 #17865 #17878 #17887 (cross-channel dedup refactor series)
## User-visible / Behavior Changes
None
## Security Impact (required)
- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No`
- New/changed network calls? `No`
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
## Repro + Verification
### Environment
- OS: macOS (darwin)
- Runtime/container: Node 22+ / Bun
- Model/provider: N/A (refactor)
- Integration/channel (if any): Telegram, LINE, Slack
### Steps
1. `corepack pnpm tsgo` — type check passes
2. `corepack pnpm build` — build passes
3. `corepack pnpm test -- src/telegram/bot.test.ts src/telegram/bot/helpers.test.ts src/telegram/bot-message-context.dm-threads.test.ts src/line/bot-handlers.test.ts src/slack/monitor/monitor.test.ts` — 81 tests pass
### Expected
- All tests pass, no behavior changes
### Actual
- 5 test files, 81 tests, all pass
## Evidence
- [x] Failing test/log before + passing after
- [x] Trace/log snippets
```
✓ src/line/bot-handlers.test.ts (4 tests) 55ms
✓ src/telegram/bot/helpers.test.ts (26 tests) 4ms
✓ src/slack/monitor/monitor.test.ts (16 tests) 36ms
✓ src/telegram/bot.test.ts (30 tests) 62ms
✓ src/telegram/bot-message-context.dm-threads.test.ts (5 tests) 21ms
Test Files 5 passed (5)
Tests 81 passed (81)
```
## Human Verification (required)
- Verified scenarios: Type check, build, unit tests for all 3 channel modules (telegram, LINE, slack)
- Edge cases checked: All 14 call sites continue to resolve the shared import; no re-export needed since consumers import directly
- What you did **not** verify: Runtime behavior on live channels (import-only change — no logic change)
## Compatibility / Migration
- Backward compatible? `Yes`
- Config/env changes? `No`
- Migration needed? `No`
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly: Revert this PR (4 commits)
- Files/config to restore: `src/utils.ts`, `src/telegram/bot-access.ts`, `src/line/bot-access.ts`, `src/slack/monitor/channel-config.ts`, and 5 consumer files
- Known bad symptoms reviewers should watch for: Import resolution errors at build time (would surface immediately in CI)
## Risks and Mitigations
None — pure import refactor of an identical utility function.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Clean refactoring that extracts the `firstDefined<T>` utility function from three identical copies (in `src/telegram/bot-access.ts`, `src/line/bot-access.ts`, and `src/slack/monitor/channel-config.ts`) into a single shared definition in `src/utils.ts`. All 8 consumer files are updated to import from the shared location.
- All three original implementations were functionally identical — the shared version adds only an explicit `T | undefined` return type annotation
- All 14 call sites across telegram, LINE, and slack modules now import from `src/utils.ts`
- No stale imports remain; no logic or behavioral changes
- Channel-specific access-control functions (`normalizeAllowFrom`, `isSenderAllowed`) correctly remain in each channel's `bot-access.ts`
- Well-structured as 4 incremental commits: extract → update telegram → update LINE → update slack
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — it is a pure import refactor with no logic changes.
- All three original `firstDefined` implementations were verified to be functionally identical. The shared version in `src/utils.ts` has the same logic with an added explicit return type. All 14 call sites and 8 consumer files correctly import from the new location. No stale imports or missing references exist. Tests pass. The change is entirely mechanical.
- No files require special attention.
<sub>Last reviewed commit: 9ccc43a</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#17878: Refactor: share allowlist normalization
by iyoda · 2026-02-16
84.2%
#17900: refactor(security): extract shared normalizeAllowFromList into audi...
by iyoda · 2026-02-16
81.2%
#17865: Refactor: centralize dm/group policy resolution
by iyoda · 2026-02-16
80.3%
#17770: refactor(cli): reuse shared option builders
by iyoda · 2026-02-16
80.2%
#23727: Fix Telegram channel resolution drift across announce + message sen...
by SmithLabsLLC · 2026-02-22
77.2%
#23175: feat(security): runtime safety — transcript retention, tool call bu...
by ihsanmokhlisse · 2026-02-22
76.8%
#21271: fix(commands): pass channel/capabilities/shell/os to runtime in com...
by evansantos · 2026-02-19
76.2%
#7141: fix(telegram): unify network error detection to prevent poll crashes
by hclsys · 2026-02-02
75.2%
#23320: fix(slack): respect replyToMode when incomingThreadTs is auto-created
by dorukardahan · 2026-02-22
75.0%
#17337: fix(delivery): keep route fields paired to channel during context m...
by Glucksberg · 2026-02-15
74.9%