chore(repo): prune dead code and duplicate abstractions (#3413)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-12 13:09:42 +02:00
1 parent c17091768c
commit c9fdf8fead
2937 files changed
+42233 -176793

No files matched your search

@@ -54,3 +54,17 @@ export async function mapWithConcurrency<T, TResult>(
if (failure) throw failure.error;
return results;
}
export async function allSettledWithConcurrency<T, TResult>(
items: ReadonlyArray<T>,
concurrency: number,
mapper: (item: T, index: number) => Promise<TResult>,
): Promise<Array<PromiseSettledResult<TResult>>> {
return mapWithConcurrency(items, concurrency, async (item, index): Promise<PromiseSettledResult<TResult>> => {
try {
return {status: 'fulfilled', value: await mapper(item, index)};
} catch (reason) {
return {status: 'rejected', reason};
}
});
}
+1 -1
View File
@@ -108,7 +108,7 @@ function collectEmojiMatches(content: string, isInEscapedContext: (index: number
return matches;
}
async function checkUserGlobalExpressions(
export async function checkUserGlobalExpressions(
userId: UserID,
userRepository: EmojiUserRepository,
limitConfigService: LimitConfigService,
+6 -89
View File
@@ -1,8 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {isIP} from 'node:net';
import type {IpAddressFamily} from '@fluxer/ip_utils/src/IpAddress';
import {normalizeIpString} from '@fluxer/ip_utils/src/IpAddress';
import {type IpAddressFamily, ipToBytes, normalizeIpString} from '@fluxer/ip_utils/src/IpAddress';
interface ParsedBase {
canonical: string;
@@ -101,26 +100,11 @@ function parseSingle(value: string): ParsedIpSingle | null {
function parseIP(value: string): ParsedIP | null {
const ipWithoutZone = value.split('%', 1)[0].trim();
if (!ipWithoutZone) return null;
const family = isIP(ipWithoutZone);
if (!family) return null;
if (family === 4) {
const bytes = parseIPv4(ipWithoutZone);
if (!bytes) return null;
return {family: 'ipv4', bytes, mappedIpv4Bytes: null};
}
let ipv6Address = ipWithoutZone;
if (ipWithoutZone.includes('.')) {
const converted = convertEmbeddedIpv4(ipWithoutZone);
if (!converted) return null;
ipv6Address = converted;
}
const bytes = parseIPv6(ipv6Address);
if (!bytes) return null;
return {
family: 'ipv6',
bytes,
mappedIpv4Bytes: extractMappedIpv4(bytes),
};
if (!isIP(ipWithoutZone)) return null;
const parsed = ipToBytes(ipWithoutZone);
if (!parsed) return null;
const bytes = Buffer.from(parsed.bytes);
return {family: parsed.family, bytes, mappedIpv4Bytes: parsed.family === 'ipv6' ? extractMappedIpv4(bytes) : null};
}
function resolveMappedIpv4(parsed: ParsedIP): {
@@ -142,73 +126,6 @@ function extractMappedIpv4(bytes: Buffer): Buffer | null {
return Buffer.from(bytes.subarray(12, 16));
}
function convertEmbeddedIpv4(value: string): string | null {
const lastColon = value.lastIndexOf(':');
if (lastColon === -1) return null;
const ipv4Part = value.slice(lastColon + 1);
const ipv4Bytes = parseIPv4(ipv4Part);
if (!ipv4Bytes) return null;
const high = ((ipv4Bytes[0] << 8) | ipv4Bytes[1]).toString(16);
const low = ((ipv4Bytes[2] << 8) | ipv4Bytes[3]).toString(16);
return `${value.slice(0, lastColon + 1)}${high}:${low}`;
}
function parseIPv4(ip: string): Buffer | null {
const parts = ip.split('.');
if (parts.length !== 4) return null;
const bytes = Buffer.alloc(4);
for (let i = 0; i < 4; i++) {
const part = parts[i];
if (!/^\d+$/.test(part)) return null;
const octet = Number(part);
if (!Number.isInteger(octet) || octet < 0 || octet > 255) return null;
bytes[i] = octet;
}
return bytes;
}
function parseIPv6(ip: string): Buffer | null {
const addr = ip.trim();
const doubleColonIndex = addr.indexOf('::');
let headPart = '';
let tailPart = '';
if (doubleColonIndex !== -1) {
const parts = addr.split('::');
if (parts.length !== 2) return null;
[headPart, tailPart] = parts;
} else {
headPart = addr;
tailPart = '';
}
const headGroups = headPart ? headPart.split(':').filter((g) => g.length > 0) : [];
const tailGroups = tailPart ? tailPart.split(':').filter((g) => g.length > 0) : [];
if (doubleColonIndex === -1 && headGroups.length !== 8) return null;
const totalGroups = headGroups.length + tailGroups.length;
if (totalGroups > 8) return null;
const zerosToInsert = 8 - totalGroups;
const groups: Array<number> = [];
for (const group of headGroups) {
const value = parseInt(group, 16);
if (!Number.isFinite(value) || value < 0 || value > 0xffff) return null;
groups.push(value);
}
for (let i = 0; i < zerosToInsert; i++) {
groups.push(0);
}
for (const group of tailGroups) {
const value = parseInt(group, 16);
if (!Number.isFinite(value) || value < 0 || value > 0xffff) return null;
groups.push(value);
}
if (groups.length !== 8) return null;
const bytes = Buffer.alloc(16);
for (let i = 0; i < 8; i++) {
bytes[i * 2] = (groups[i] >> 8) & 0xff;
bytes[i * 2 + 1] = groups[i] & 0xff;
}
return bytes;
}
function parseCIDR(cidr: string): ParsedCIDR | null {
const trimmed = cidr.trim();
if (!trimmed) return null;
@@ -27,3 +27,15 @@ export function parseJsonWithGuard<T>(text: string, guard: (value: unknown) => v
return null;
}
}
export function isStringArray(value: unknown): value is Array<string> {
return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
}
export function parseJsonOrNull(raw: string): unknown {
try {
return parseJsonUnknown(raw);
} catch {
return null;
}
}
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {buildPhraseMatchForms, canonicalizeStoredPhrase} from '@app/api/utils/PhraseBlocklistNormalization';
import {SubstringMatcher} from '@app/api/utils/SubstringMatcher';
export class PhraseMatcherSet {
private rawPhrases: Array<string> = [];
private rawPhraseSet = new Set<string>();
private rawMatcher: SubstringMatcher | null = null;
private wordMatcher: SubstringMatcher | null = null;
private compactMatcher: SubstringMatcher | null = null;
private asciiWordMatcher: SubstringMatcher | null = null;
private asciiCompactMatcher: SubstringMatcher | null = null;
containsBannedPhrase(text: string): boolean {
if (this.rawPhrases.length === 0) return false;
const forms = buildPhraseMatchForms(text);
return (
this.rawMatcher?.test(forms.raw) === true ||
this.wordMatcher?.test(forms.words) === true ||
this.compactMatcher?.test(forms.compact) === true ||
this.asciiWordMatcher?.test(forms.asciiWords) === true ||
this.asciiCompactMatcher?.test(forms.asciiCompact) === true
);
}
private rebuildMatchers(): void {
const rawPhraseSet = new Set<string>();
const wordPhraseSet = new Set<string>();
const compactPhraseSet = new Set<string>();
const asciiWordPhraseSet = new Set<string>();
const asciiCompactPhraseSet = new Set<string>();
for (const phrase of this.rawPhrases) {
const canonical = canonicalizeStoredPhrase(phrase);
if (!canonical) continue;
const forms = buildPhraseMatchForms(canonical);
rawPhraseSet.add(forms.raw);
if (forms.words) wordPhraseSet.add(forms.words);
if (forms.compact) compactPhraseSet.add(forms.compact);
if (forms.asciiWords) asciiWordPhraseSet.add(forms.asciiWords);
if (forms.asciiCompact) asciiCompactPhraseSet.add(forms.asciiCompact);
}
this.rawPhraseSet = rawPhraseSet;
this.rawPhrases = Array.from(rawPhraseSet);
this.rawMatcher = SubstringMatcher.fromPatterns(rawPhraseSet);
this.wordMatcher = SubstringMatcher.fromPatterns(wordPhraseSet);
this.compactMatcher = SubstringMatcher.fromPatterns(compactPhraseSet);
this.asciiWordMatcher = SubstringMatcher.fromPatterns(asciiWordPhraseSet);
this.asciiCompactMatcher = SubstringMatcher.fromPatterns(asciiCompactPhraseSet);
}
isPhraseBanned(phrase: string): boolean {
const canonical = canonicalizeStoredPhrase(phrase);
return !!canonical && this.rawPhraseSet.has(canonical);
}
add(phrase: string): void {
const canonical = canonicalizeStoredPhrase(phrase);
if (!canonical || this.rawPhraseSet.has(canonical)) return;
this.rawPhrases.push(canonical);
this.rebuildMatchers();
}
remove(phrase: string): void {
const canonical = canonicalizeStoredPhrase(phrase);
if (!canonical || !this.rawPhraseSet.has(canonical)) return;
this.rawPhrases = this.rawPhrases.filter((item) => item !== canonical);
this.rebuildMatchers();
}
get size(): number {
return this.rawPhraseSet.size;
}
replaceAll(phrases: Iterable<string>): void {
this.rawPhrases = Array.from(phrases);
this.rebuildMatchers();
}
}
@@ -1,12 +1,17 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {Logger} from '@app/api/Logger';
import type {IKVProvider, IKVSubscription} from '@pkgs/kv_client/src/IKVProvider';
type RefreshTrigger = 'notification' | 'periodic';
interface RefreshSubscriptionOptions {
export interface RefreshSubscriptionOptions {
name: string;
channels: ReadonlyArray<string>;
refresh: () => Promise<void>;
onRefreshError: (error: unknown, trigger: RefreshTrigger) => void;
onRefreshError?: (error: unknown, trigger: RefreshTrigger) => void;
onPeriodicRefreshError?: (error: unknown) => void;
escalateAfterConsecutiveFailures?: number;
shouldRefresh?: (channel: string, message: string) => boolean;
drainInitialNotifications?: boolean;
periodicIntervalMs?: () => number | null;
@@ -21,6 +26,10 @@ export class RefreshSubscriptionUnavailableError extends Error {
}
export class RefreshSubscription {
resetFailures(): void {
this.session?.resetFailures();
}
private session: RefreshSubscriptionSession | null = null;
constructor(private readonly options: RefreshSubscriptionOptions) {}
@@ -62,6 +71,28 @@ export class RefreshSubscription {
}
class RefreshSubscriptionSession {
private consecutiveFailures = 0;
resetFailures(): void {
this.consecutiveFailures = 0;
}
private reportRefreshError(error: unknown, trigger: RefreshTrigger): void {
if (trigger === 'periodic' && this.options.onPeriodicRefreshError) {
this.options.onPeriodicRefreshError(error);
return;
}
if (this.options.onRefreshError) {
this.options.onRefreshError(error, trigger);
return;
}
this.consecutiveFailures++;
const details = {error: error instanceof Error ? error.message : String(error)};
const message = `Failed to refresh ${this.options.name} after notification`;
if (this.consecutiveFailures >= (this.options.escalateAfterConsecutiveFailures ?? 5))
Logger.error(details, message);
else Logger.warn(details, message);
}
private readonly subscription: IKVSubscription | null;
private phase: 'starting' | 'running' | 'stopping' | 'stopped' = 'starting';
private startCompletion: Promise<void> | null = null;
@@ -117,10 +148,12 @@ class RefreshSubscriptionSession {
}
}
await this.options.refresh();
this.resetFailures();
this.assertActive();
while (this.options.drainInitialNotifications && this.pendingRefresh !== null) {
this.pendingRefresh = null;
await this.options.refresh();
this.resetFailures();
this.assertActive();
}
this.phase = 'running';
@@ -160,8 +193,9 @@ class RefreshSubscriptionSession {
this.pendingRefresh = null;
try {
await this.options.refresh();
this.resetFailures();
} catch (error) {
this.options.onRefreshError(error, trigger);
this.reportRefreshError(error, trigger);
}
}
}
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {Logger} from '@app/api/Logger';
import {RefreshSubscription, type RefreshSubscriptionOptions} from '@app/api/utils/RefreshSubscription';
import type {IKVProvider} from '@pkgs/kv_client/src/IKVProvider';
export abstract class RefreshedCache {
private kvClient: IKVProvider | null = null;
private readonly refreshSubscription: RefreshSubscription;
constructor(
private readonly options: Pick<
RefreshSubscriptionOptions,
'name' | 'channels' | 'periodicIntervalMs' | 'onPeriodicRefreshError'
>,
) {
this.refreshSubscription = new RefreshSubscription({
...options,
refresh: () => this.refresh(),
escalateAfterConsecutiveFailures: 5,
});
}
protected abstract load(): Promise<void>;
async refresh(): Promise<void> {
await this.load();
this.refreshSubscription.resetFailures();
}
setRefreshSubscriber(kvClient: IKVProvider | null): void {
this.kvClient = kvClient;
}
initialize(): Promise<void> {
return this.refreshSubscription.start(this.kvClient);
}
shutdown(): Promise<void> {
return this.refreshSubscription.stop();
}
protected resetRefreshState(): void {
void this.shutdown().catch((error) => Logger.error({error}, `Failed to shut down ${this.options.name}`));
this.kvClient = null;
this.refreshSubscription.resetFailures();
}
}
+27
View File
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {createHash, randomBytes, timingSafeEqual} from 'node:crypto';
export function sha256Hex(value: string): string {
return createHash('sha256').update(value).digest('hex');
}
export function secretMatchesHash(
presented: string | null | undefined,
storedHash: string | null | undefined,
): boolean {
if (presented == null || !storedHash) return false;
const presentedBuffer = Buffer.from(sha256Hex(presented), 'hex');
const storedBuffer = Buffer.from(storedHash, 'hex');
return presentedBuffer.length === storedBuffer.length && timingSafeEqual(presentedBuffer, storedBuffer);
}
export function constantTimeEquals(a: string, b: string): boolean {
const bufferA = Buffer.from(a);
const bufferB = Buffer.from(b);
return bufferA.length === bufferB.length && timingSafeEqual(bufferA, bufferB);
}
export function randomBase64Url(bytes: number): string {
return randomBytes(bytes).toString('base64url');
}
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {createHmac, timingSafeEqual} from 'node:crypto';
import {parseJsonWithGuard} from '@app/api/utils/JsonBoundaryUtils';
interface ExpiringPayload {
expiresAt: number;
}
function computeSignature(payloadBase64: string, key: string | Buffer): Buffer {
return createHmac('sha256', key).update(payloadBase64).digest();
}
export function signExpiringToken<T extends ExpiringPayload>(payload: T, key: string | Buffer): string {
const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
const signature = computeSignature(payloadBase64, key).toString('base64url');
return `${payloadBase64}.${signature}`;
}
export function verifyExpiringToken<T extends ExpiringPayload>(
token: string,
key: string | Buffer,
guard: (value: unknown) => value is T,
): T | null {
const dotIndex = token.indexOf('.');
if (dotIndex === -1) return null;
const payloadBase64 = token.slice(0, dotIndex);
const signatureBase64 = token.slice(dotIndex + 1);
const expectedSignature = computeSignature(payloadBase64, key);
let providedSignature: Buffer;
try {
providedSignature = Buffer.from(signatureBase64, 'base64url');
} catch {
return null;
}
if (expectedSignature.length !== providedSignature.length) return null;
if (!timingSafeEqual(expectedSignature, providedSignature)) return null;
let payload: T | null;
try {
const payloadJson = Buffer.from(payloadBase64, 'base64url').toString('utf-8');
payload = parseJsonWithGuard(payloadJson, guard);
} catch {
return null;
}
if (!payload || Date.now() > payload.expiresAt) return null;
return payload;
}
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {parseString} from '@app/api/utils/StringUtils';
import {describe, expect, it} from 'vitest';
describe('parseString', () => {
it('keeps family emoji intact at the webhook title truncation boundary', () => {
expect(parseString('ab👨‍👩‍👧cdefghij', 6)).toBe('ab👨‍👩‍👧...');
expect(parseString(`${'👨‍👩‍👧‍👦'.repeat(5)}abcdef`, 6)).toBe(`${'👨‍👩‍👧‍👦'.repeat(3)}...`);
});
it('keeps combining marks and flags together and decodes entities before truncating', () => {
expect(parseString('e\u0301🇸🇪&amp;more text', 6)).toBe('e\u0301🇸🇪&...');
expect(parseString(' &amp;🇸🇪 ', 2)).toBe('&🇸🇪');
});
});
+4 -38
View File
@@ -2,47 +2,13 @@
import {URLType} from '@fluxer/schema/src/primitives/UrlValidators';
import {decode} from 'html-entities';
import _ from 'lodash';
function isInvisibleContentCodePoint(codePoint: number): boolean {
return (
codePoint === 0x0000 ||
codePoint === 0x00ad ||
codePoint === 0x034f ||
codePoint === 0x061c ||
codePoint === 0x115f ||
codePoint === 0x1160 ||
codePoint === 0x17b4 ||
codePoint === 0x17b5 ||
codePoint === 0x180e ||
(codePoint >= 0x200b && codePoint <= 0x200f) ||
(codePoint >= 0x202a && codePoint <= 0x202e) ||
(codePoint >= 0x2060 && codePoint <= 0x2069) ||
codePoint === 0x2800 ||
codePoint === 0x3164 ||
(codePoint >= 0xfe00 && codePoint <= 0xfe0f) ||
codePoint === 0xfeff ||
codePoint === 0xffa0 ||
(codePoint >= 0xe0100 && codePoint <= 0xe01ef)
);
}
export function hasVisibleContent(value: string): boolean {
for (const char of value) {
if (char.trim().length === 0) {
continue;
}
const codePoint = char.codePointAt(0);
if (codePoint == null || isInvisibleContentCodePoint(codePoint)) {
continue;
}
return true;
}
return false;
}
const graphemeSegmenter = new Intl.Segmenter('en', {granularity: 'grapheme'});
export function parseString(value: string, maxLength: number) {
return _.truncate(decode(value).trim(), {length: maxLength});
const decoded = decode(value).trim();
const graphemes = Array.from(graphemeSegmenter.segment(decoded), ({segment}) => segment);
return graphemes.length > maxLength ? `${graphemes.slice(0, Math.max(0, maxLength - 3)).join('')}...` : decoded;
}
export function safeUrl(value: unknown): string | undefined {
@@ -6,7 +6,6 @@ import {Config} from '@app/api/Config';
import {Logger} from '@app/api/Logger';
import * as InviteUtils from '@app/api/utils/InviteUtils';
import {URL_REGEX} from '@fluxer/constants/src/Core';
import * as idna from 'idna-uts46-hx';
const CLIENT_ROUTE_PATH_PREFIXES = ['/channels/', '/theme/', '/invite/', '/gift/', '/oauth2/', '/users/'];
@@ -60,8 +59,6 @@ function getExcludedLinkBases(): Array<ExcludedLinkBase> {
function idnaEncodeURL(url: string) {
try {
const parsedUrl = new URL(url);
const encodedDomain = idna.toAscii(parsedUrl.hostname).toLowerCase();
parsedUrl.hostname = encodedDomain;
parsedUrl.username = '';
parsedUrl.password = '';
return parsedUrl.toString();
+5
View File
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
export function trimTrailingSlash(url: string): string {
return url.replace(/\/+$/u, '');
}
@@ -3,7 +3,6 @@
import type {GuildID, UserID} from '@app/api/BrandedTypes';
import type {GuildRepository} from '@app/api/guild/repositories/GuildRepository';
import type {Guild} from '@app/api/models/Guild';
import type {Relationship} from '@app/api/models/Relationship';
import type {UserRepository} from '@app/api/user/repositories/UserRepository';
import {FriendSourceFlags, GroupDmAddPermissionFlags, RelationshipTypes} from '@fluxer/constants/src/UserConstants';
import {MissingAccessError} from '@fluxer/errors/src/domains/core/MissingAccessError';
@@ -127,21 +126,4 @@ export class UserPermissionUtils {
const userGuildIdSet = new Set(userGuildIds.map((id) => id.toString()));
return targetGuildIds.some((id) => userGuildIdSet.has(id.toString()));
}
async getMutualFriends({userId, targetId}: {userId: UserID; targetId: UserID}): Promise<Array<Relationship>> {
const userFriends = await this.userRepository.listRelationships(userId);
const targetFriends = await this.userRepository.listRelationships(targetId);
const targetFriendIds = new Set(
targetFriends.filter((rel) => rel.type === RelationshipTypes.FRIEND).map((rel) => rel.targetUserId.toString()),
);
return userFriends.filter(
(rel) => rel.type === RelationshipTypes.FRIEND && targetFriendIds.has(rel.targetUserId.toString()),
);
}
async getMutualGuildIds({userId, targetId}: {userId: UserID; targetId: UserID}): Promise<Array<GuildID>> {
const {userGuildIds, targetGuildIds} = await this.fetchGuildIdsForUsers({userId, targetId});
const targetGuildIdSet = new Set(targetGuildIds.map((guildId) => guildId.toString()));
return userGuildIds.filter((guildId) => targetGuildIdSet.has(guildId.toString()));
}
}
+3 -4
View File
@@ -7,7 +7,7 @@ import {THREAD_AWARE_ALL_PERMISSIONS, THREAD_PERMISSIONS} from '@fluxer/constant
export const CLIENT_FEATURES_HEADER = Headers.X_FLUXER_FEATURES;
export const CHANNEL_THREADS_CLIENT_FEATURE = 'channel_threads';
export type ThreadPermissionMode = 'control' | 'active' | 'retired';
export type ThreadPermissionMode = 'active';
export interface ProtectedBitActor {
clientFeatures: ReadonlySet<string>;
@@ -16,8 +16,7 @@ export interface ProtectedBitActor {
function threadBitsWritable(actor: ProtectedBitActor): boolean {
const threadBits = actor.threadBits;
if (!threadBits || threadBits.mode === 'control') return true;
return threadBits.mode === 'active' && threadBits.writer;
return !threadBits || threadBits.writer;
}
export function protectedThreadBits(actor: ProtectedBitActor): bigint {
@@ -25,7 +24,7 @@ export function protectedThreadBits(actor: ProtectedBitActor): bigint {
}
export function permissionWriteMask(actor: ProtectedBitActor): bigint {
return !actor.threadBits || actor.threadBits.mode === 'control' ? ALL_PERMISSIONS : THREAD_AWARE_ALL_PERMISSIONS;
return !actor.threadBits ? ALL_PERMISSIONS : THREAD_AWARE_ALL_PERMISSIONS;
}
const PERMISSION_BIT_CLIENT_FEATURES: ReadonlyArray<{
@@ -1,4 +1,4 @@
import {mapWithConcurrency} from '@app/api/utils/ConcurrencyUtils';
import {allSettledWithConcurrency, mapWithConcurrency} from '@app/api/utils/ConcurrencyUtils';
import {describe, expect, it} from 'vitest';
describe('mapWithConcurrency', () => {
@@ -115,3 +115,43 @@ describe('mapWithConcurrency', () => {
expect(started).toEqual([1]);
});
});
describe('allSettledWithConcurrency', () => {
it('continues queued work after synchronous and asynchronous failures and retains input order', async () => {
const syncFailure = new Error('synchronous');
const asyncFailure = new Error('asynchronous');
const started: Array<number> = [];
const results = await allSettledWithConcurrency([0, 1, 2, 3], 1, (item, index) => {
started.push(index);
if (item === 0) throw syncFailure;
if (item === 1) return Promise.reject(asyncFailure);
return Promise.resolve(item * 10);
});
expect(started).toEqual([0, 1, 2, 3]);
expect(results).toEqual([
{status: 'rejected', reason: syncFailure},
{status: 'rejected', reason: asyncFailure},
{status: 'fulfilled', value: 20},
{status: 'fulfilled', value: 30},
]);
});
it('waits for every in-flight result when a later item fails first', async () => {
const first = Promise.withResolvers<number>();
const second = Promise.withResolvers<number>();
const failure = new Error('later failure');
let completed = false;
const results = allSettledWithConcurrency([first.promise, second.promise], 2, (item) => item).then((value) => {
completed = true;
return value;
});
second.reject(failure);
await new Promise<void>((resolve) => setImmediate(resolve));
expect(completed).toBe(false);
first.resolve(10);
await expect(results).resolves.toEqual([
{status: 'fulfilled', value: 10},
{status: 'rejected', reason: failure},
]);
});
});
@@ -9,25 +9,8 @@ import {
import {describe, expect, it} from 'vitest';
describe('getCurrencyPreferences first choice', () => {
describe('returns USD for non-EEA countries', () => {
it('returns USD for United States', () => {
expect(getCurrencyPreferences('US')[0]).toBe('USD');
});
it('returns USD for Canada', () => {
expect(getCurrencyPreferences('CA')[0]).toBe('USD');
});
it('returns USD for United Kingdom', () => {
expect(getCurrencyPreferences('GB')[0]).toBe('USD');
});
it('returns USD for Japan', () => {
expect(getCurrencyPreferences('JP')[0]).toBe('USD');
});
it('returns USD for Australia', () => {
expect(getCurrencyPreferences('AU')[0]).toBe('USD');
});
it('returns USD for Switzerland', () => {
expect(getCurrencyPreferences('CH')[0]).toBe('USD');
});
it.each(['US', 'CA', 'GB', 'JP', 'AU', 'CH'])('returns USD for non-EEA country %s', (country) => {
expect(getCurrencyPreferences(country)[0]).toBe('USD');
});
describe('handles case insensitivity', () => {
it('returns EUR for lowercase country code', () => {
@@ -12,18 +12,6 @@ describe('parseIpBanEntry', () => {
expect(result?.family).toBe('ipv4');
expect(result?.canonical).toBe('192.168.1.1');
});
it('parses IPv4 address 0.0.0.0', () => {
const result = parseIpBanEntry('0.0.0.0');
expect(result).not.toBeNull();
expect(result?.type).toBe('single');
expect(result?.canonical).toBe('0.0.0.0');
});
it('parses IPv4 address 255.255.255.255', () => {
const result = parseIpBanEntry('255.255.255.255');
expect(result).not.toBeNull();
expect(result?.type).toBe('single');
expect(result?.canonical).toBe('255.255.255.255');
});
it('rejects IPv4 with leading zeros (octal ambiguity)', () => {
const result = parseIpBanEntry('192.168.001.001');
expect(result).toBeNull();
@@ -42,12 +30,6 @@ describe('parseIpBanEntry', () => {
expect(result?.type).toBe('single');
expect(result?.family).toBe('ipv6');
});
it('parses IPv6 loopback address', () => {
const result = parseIpBanEntry('::1');
expect(result).not.toBeNull();
expect(result?.type).toBe('single');
expect(result?.family).toBe('ipv6');
});
it('parses IPv6 unspecified address', () => {
const result = parseIpBanEntry('::');
expect(result).not.toBeNull();
@@ -98,32 +80,6 @@ describe('parseIpBanEntry', () => {
expect(result.end - result.start).toBe(255n);
}
});
it('parses /16 (65536 hosts)', () => {
const result = parseIpBanEntry('192.168.0.0/16');
expect(result).not.toBeNull();
expect(result?.type).toBe('range');
if (result?.type === 'range') {
expect(result.family).toBe('ipv4');
expect(result.prefixLength).toBe(16);
expect(result.end - result.start).toBe(65535n);
}
});
it('parses /8 (class A)', () => {
const result = parseIpBanEntry('10.0.0.0/8');
expect(result).not.toBeNull();
expect(result?.type).toBe('range');
if (result?.type === 'range') {
expect(result.prefixLength).toBe(8);
}
});
it('parses /0 (all addresses)', () => {
const result = parseIpBanEntry('0.0.0.0/0');
expect(result).not.toBeNull();
expect(result?.type).toBe('range');
if (result?.type === 'range') {
expect(result.prefixLength).toBe(0);
}
});
it('normalizes network address in CIDR', () => {
const result = parseIpBanEntry('192.168.1.100/24');
expect(result).not.toBeNull();
@@ -144,23 +100,6 @@ describe('parseIpBanEntry', () => {
expect(result.start).toBe(result.end);
}
});
it('parses /64 (common subnet)', () => {
const result = parseIpBanEntry('2001:db8::/64');
expect(result).not.toBeNull();
expect(result?.type).toBe('range');
if (result?.type === 'range') {
expect(result.family).toBe('ipv6');
expect(result.prefixLength).toBe(64);
}
});
it('parses /48 (site prefix)', () => {
const result = parseIpBanEntry('2001:db8:abcd::/48');
expect(result).not.toBeNull();
expect(result?.type).toBe('range');
if (result?.type === 'range') {
expect(result.prefixLength).toBe(48);
}
});
it('parses /0 (all addresses)', () => {
const result = parseIpBanEntry('::/0');
expect(result).not.toBeNull();
@@ -193,6 +132,9 @@ describe('parseIpBanEntry', () => {
});
});
describe('invalid inputs', () => {
it('rejects bracketed IPv6 CIDR addresses', () => {
expect(parseIpBanEntry('[::ffff:192.0.2.1]/120')).toBeNull();
});
it('returns null for empty string', () => {
expect(parseIpBanEntry('')).toBeNull();
});
@@ -223,11 +165,6 @@ describe('parseIpBanEntry', () => {
expect(result).not.toBeNull();
expect(result?.type).toBe('single');
});
it('handles whitespace around CIDR', () => {
const result = parseIpBanEntry(' 192.168.1.0/24 ');
expect(result).not.toBeNull();
expect(result?.type).toBe('range');
});
it('handles bracketed IPv6', () => {
const result = parseIpBanEntry('[2001:db8::1]');
expect(result).not.toBeNull();
@@ -242,11 +179,6 @@ describe('tryParseSingleIp', () => {
expect(result).not.toBeNull();
expect(result?.type).toBe('single');
});
it('returns parsed result for single IPv6', () => {
const result = tryParseSingleIp('2001:db8::1');
expect(result).not.toBeNull();
expect(result?.type).toBe('single');
});
it('returns null for CIDR range', () => {
expect(tryParseSingleIp('192.168.1.0/24')).toBeNull();
});
@@ -95,11 +95,6 @@ function toResult(parse: () => unknown): ParseResult {
}
}
function parseWithDigitRunGate(jsonText: string, digitRun: number): ParseResult {
const gate = new RegExp(String.raw`\d{${digitRun}}`);
return toResult(() => JSON.parse(gate.test(jsonText) ? coerceUnsafeIntegersToStrings(jsonText) : jsonText));
}
function parseUngated(jsonText: string): ParseResult {
return toResult(() => JSON.parse(coerceUnsafeIntegersToStrings(jsonText)));
}
@@ -113,11 +108,6 @@ describe('parseJsonPreservingLargeIntegers digit-run gate', () => {
).toEqual(parseUngated(body));
}
});
it('exercises both the fast path and the scan', () => {
const gate = /\d{16}/;
expect(CORPUS.some((body) => !gate.test(body))).toBe(true);
expect(CORPUS.some((body) => gate.test(body))).toBe(true);
});
it('rejects malformed bodies identically on both paths', () => {
for (const body of ['{"id":00}', '{"id":0001472109478688579732}']) {
const gated = toResult(() => parseJsonPreservingLargeIntegers(body));
@@ -125,19 +115,4 @@ describe('parseJsonPreservingLargeIntegers digit-run gate', () => {
expect(gated, body).toEqual(parseUngated(body));
}
});
it('diverges from the ungated scanner when the gate is loosened to 17 digits', () => {
const broken = CORPUS.filter((body) => {
const loosened = parseWithDigitRunGate(body, 17);
const ungated = parseUngated(body);
return JSON.stringify(loosened) !== JSON.stringify(ungated);
});
expect(broken).toContain('{"id":9007199254740992}');
expect(broken).toContain('{"id":9999999999999999}');
expect(broken).toContain('{"id":-9007199254740992}');
});
it('agrees with the ungated scanner when the gate is tightened to 15 digits', () => {
for (const body of CORPUS) {
expect(parseWithDigitRunGate(body, 15), body).toEqual(parseUngated(body));
}
});
});
@@ -28,27 +28,6 @@ function createCountingRequest(headers: Record<string, string>): CountingRequest
}
describe('RequestClientIp', () => {
it('resolves the client ip once and hands the same value to every consumer', async () => {
const {request, countReads} = createCountingRequest({'x-forwarded-for': '203.0.113.10, 10.0.0.1'});
const seen: Array<string | null> = [];
const app = new Hono<HonoEnv>();
app.use(async (ctx, next) => {
seen.push(getRequestClientIp(ctx));
await next();
});
app.use(async (ctx, next) => {
seen.push(getRequestClientIp(ctx));
await next();
});
app.get('/v1/messages', (ctx) => {
seen.push(requireRequestClientIp(ctx));
return ctx.text('ok');
});
const response = await app.request(request);
expect(response.status).toBe(200);
expect(seen).toEqual(['203.0.113.10', '203.0.113.10', '203.0.113.10']);
expect(countReads('x-forwarded-for')).toBe(1);
});
it('normalizes the resolved address the same way for every consumer', async () => {
const seen: Array<string | null> = [];
const app = new Hono<HonoEnv>();
@@ -86,20 +65,6 @@ describe('RequestClientIp', () => {
expect(errors[0]).toBeInstanceOf(MissingClientIpError);
expect(countReads('x-forwarded-for')).toBe(1);
});
it('reports a malformed client ip header exactly as before', async () => {
const seen: Array<string | null> = [];
const app = new Hono<HonoEnv>();
app.use(async (ctx, next) => {
seen.push(getRequestClientIp(ctx));
await next();
});
app.get('/v1/messages', (ctx) => {
seen.push(getRequestClientIp(ctx));
return ctx.text('ok');
});
await app.request('http://localhost/v1/messages', {headers: {'x-forwarded-for': 'not-an-ip'}});
expect(seen).toEqual([null, null]);
});
it('never reuses a resolution made under a different header name', async () => {
const seen: Array<string | null> = [];
const app = new Hono<HonoEnv>();
@@ -14,39 +14,6 @@ describe('canonicalizeUrl', () => {
it('preserves path', () => {
expect(canonicalizeUrl('https://example.com/foo/bar')).toBe('https://example.com/foo/bar');
});
it('strips utm_source tracking param', () => {
expect(canonicalizeUrl('https://example.com/?utm_source=twitter')).toBe('https://example.com/');
});
it('strips utm_medium tracking param', () => {
expect(canonicalizeUrl('https://example.com/?utm_medium=social')).toBe('https://example.com/');
});
it('strips utm_campaign tracking param', () => {
expect(canonicalizeUrl('https://example.com/?utm_campaign=spring')).toBe('https://example.com/');
});
it('strips fbclid tracking param', () => {
expect(canonicalizeUrl('https://example.com/?fbclid=abc123')).toBe('https://example.com/');
});
it('strips gclid tracking param', () => {
expect(canonicalizeUrl('https://example.com/?gclid=xyz')).toBe('https://example.com/');
});
it('strips mc_cid tracking param', () => {
expect(canonicalizeUrl('https://example.com/?mc_cid=abc')).toBe('https://example.com/');
});
it('strips mc_eid tracking param', () => {
expect(canonicalizeUrl('https://example.com/?mc_eid=def')).toBe('https://example.com/');
});
it('strips msclkid tracking param', () => {
expect(canonicalizeUrl('https://example.com/?msclkid=bing')).toBe('https://example.com/');
});
it('strips _ga tracking param', () => {
expect(canonicalizeUrl('https://example.com/?_ga=123')).toBe('https://example.com/');
});
it('strips _gl tracking param', () => {
expect(canonicalizeUrl('https://example.com/?_gl=456')).toBe('https://example.com/');
});
it('strips igshid tracking param', () => {
expect(canonicalizeUrl('https://example.com/?igshid=abc')).toBe('https://example.com/');
});
it('strips ref_src and ref_url tracking params', () => {
expect(canonicalizeUrl('https://example.com/?ref_src=twsrc&ref_url=https://t.co')).toBe('https://example.com/');
});
@@ -61,9 +28,6 @@ describe('canonicalizeUrl', () => {
it('strips fragment', () => {
expect(canonicalizeUrl('https://example.com/page#section')).toBe('https://example.com/page');
});
it('strips fragment along with tracking params', () => {
expect(canonicalizeUrl('https://example.com/?utm_source=tw#top')).toBe('https://example.com/');
});
it('strips default port 80 for http', () => {
expect(canonicalizeUrl('http://example.com:80/path')).toBe('http://example.com/path');
});
@@ -85,9 +49,6 @@ describe('canonicalizeUrl', () => {
it('rejects ftp scheme', () => {
expect(canonicalizeUrl('ftp://example.com/file')).toBeNull();
});
it('rejects tel scheme', () => {
expect(canonicalizeUrl('tel:+1234567890')).toBeNull();
});
it('rejects invalid URLs', () => {
expect(canonicalizeUrl('not-a-url')).toBeNull();
});
@@ -145,16 +106,6 @@ describe('extractUrlCandidates', () => {
expect(result).toHaveLength(1);
expect(result[0]).toBe('https://example.com/page');
});
it('strips trailing comma', () => {
const result = extractUrlCandidates('see https://example.com/page, then');
expect(result).toHaveLength(1);
expect(result[0]).toBe('https://example.com/page');
});
it('strips trailing exclamation mark', () => {
const result = extractUrlCandidates('wow https://example.com/page!');
expect(result).toHaveLength(1);
expect(result[0]).toBe('https://example.com/page');
});
it('does not match full email addresses as URLs', () => {
const result = extractUrlCandidates('contact [email protected]');
for (const url of result) {