UnENVerse 0.42.6
Local-first desktop secrets manager — TypeScript frontend
Loading...
Searching...
No Matches
ratelimit.ts File Reference

Rate limits: parsing the free-text form, and rendering the structured one. More...

import type;
Include dependency graph for ratelimit.ts:

Functions

function export parseRateLimit (raw:unknown)
 Read a free-text rate limit into a count and a period.
 
 if (countOk &&periodOk)
 
 if (parsed)
 Parses an expression.
 

Variables

export const RATE_LIMIT_PERIODS
 The canonical periods, in ascending order of length.
 
export const minute
 
export const hour
 
export const day
 
export const week
 
export const month
 
export const year
 
export const const PERIOD_ALIASES
 Every spelling of a period this parser accepts, mapped to its canonical form.
 
export const const RateLimitPeriod
 
const NOISE = /^(?:req|reqs|request|requests|call|calls|hit|hits|api)$/
 Noise words that may sit between the number and the period: 100 req/min, 5000 requests per hour, 60 calls/minute.
 
export interface StructuredRateLimit
 A limit that could be read as a number and a window.
 
period __pad0__
 
const rawPeriod = entry.rate_limit_period
 
const countOk = typeof rawCount === 'number' && Number.isSafeInteger(rawCount) && rawCount >= 0
 
const periodOk
 
const parsed = parseRateLimit(entry.rate_limit)
 
const legacy = typeof entry.rate_limit === 'string' ? entry.rate_limit.trim() : ''
 
 return
 

Detailed Description

Rate limits: parsing the free-text form, and rendering the structured one.

A VaultEntry carries the limit twice on purpose. rate_limit_count + rate_limit_period are the structured pair everything reads; rate_limit is a human string kept alongside it so that a vault edited by a current build still means something to an older one, and so a limit nobody can express as <n> per <period> ("varies by endpoint") is not thrown away.

This module is the only thing that converts between the two. It has a twin — unv-cli/src/ratelimit.rs — and the two are pinned against the same golden table in tests/fixtures/parity/rate-limit.json, for the same reason the config exporters are: two implementations of one format drift silently.

Function Documentation

◆ parseRateLimit()

function export parseRateLimit (   raw:unknown)

Read a free-text rate limit into a count and a period.

Returns null for anything it cannot read with confidence — including a count with no period, which is not a rate limit but a number.

Vault data is untrusted input, so this takes unknown: an old vault, a remote server, or an imported backup can put anything in the field, and the TypeScript type saying string | null is erased at runtime. Render the structured pair as the canonical human string.

Uses the full period name rather than an abbreviation so the output round trips through parseRateLimit — a format that cannot read its own output is how the two halves of an entry drift apart. Normalise whatever an entry carries into the three fields it should carry.

This is the migration, and it runs on read rather than as a one-off pass over the vault: an entry can arrive from an older desktop build, from a remote server running a different version, or from a backup restored years later, and there is no single moment when "the vault has been migrated" is true.

Precedence is structured-wins. If a caller has set count/period those are authoritative and the legacy string is regenerated from them; only when they are absent is the string consulted. Otherwise editing the number in the UI would be silently reverted by a stale string sitting beside it.

◆ if() [1/2]

if ( countOk &&  periodOk)

◆ if() [2/2]

if ( pos !  pos ! = =toks.length)
new

Parses an expression.

Throws with a readable message on malformed input.

Variable Documentation

◆ RATE_LIMIT_PERIODS

export const RATE_LIMIT_PERIODS

The canonical periods, in ascending order of length.

◆ minute

export const minute

◆ hour

export const hour

◆ day

export const day

◆ week

export const week

◆ month

export const month

◆ year

export const year

◆ PERIOD_ALIASES

export const const PERIOD_ALIASES

Every spelling of a period this parser accepts, mapped to its canonical form.

Deliberately generous on input and strict on output. The strings already in people's vaults were typed by hand over years — /min, per hr, a day, req/mo — and a migration that only understood its own output would drop most of them into parseRateLimit's null branch.

◆ RateLimitPeriod

export const const RateLimitPeriod

◆ NOISE

const NOISE = /^(?:req|reqs|request|requests|call|calls|hit|hits|api)$/

Noise words that may sit between the number and the period: 100 req/min, 5000 requests per hour, 60 calls/minute.

request and call are here; a unit that changes the meaning — tokens, GB — deliberately is not, because "40000 tokens/min" is not a request limit and silently recording it as one would be wrong. Those fall through to parseRateLimit returning null and are preserved verbatim as a note.

◆ StructuredRateLimit

export interface StructuredRateLimit
Initial value:
{
count: number

A limit that could be read as a number and a window.

◆ __pad0__

period __pad0__

◆ rawPeriod

const rawPeriod = entry.rate_limit_period

◆ countOk

const countOk = typeof rawCount === 'number' && Number.isSafeInteger(rawCount) && rawCount >= 0

◆ periodOk

const periodOk
Initial value:
=
typeof rawPeriod === 'string' && (RATE_LIMIT_PERIODS as readonly string[]).includes(rawPeriod)
export const RATE_LIMIT_PERIODS
The canonical periods, in ascending order of length.
Definition ratelimit.ts:21
const rawPeriod
Definition ratelimit.ts:171

◆ parsed

const parsed = parseRateLimit(entry.rate_limit)

◆ legacy

const legacy = typeof entry.rate_limit === 'string' ? entry.rate_limit.trim() : ''

◆ return

return
Initial value:
{
rate_limit: legacy || null,
rate_limit_count: null,
rate_limit_period: null,
rate_limit_note: legacy || null,
}
const legacy
Definition ratelimit.ts:208