public-ip

Fetches your public IP from a list of HTTP endpoints and exposes it as global atoms, with stale-while-revalidate caching. publicIpAtom resolves to the IP (Promise<string> on first read, then string).

Async atom
publicIpAtom suspends on first read. Wrap consumers in <Suspense>, or read the non-suspending publicIpValueAtom / publicIpStatusAtom instead.

Install

bun add @valdres/public-ip

Live example

Loading demo…

Usage

import { createValue } from "valdres-solid"
import { publicIpValueAtom, publicIpStatusAtom } from "@valdres/public-ip"

function Ip() {
    const ip = createValue(publicIpValueAtom) // () => string | null
    const status = createValue(publicIpStatusAtom)
    return <span>{status() === "ok" ? ip() : "Loading…"}</span>
}

Exports

ExportKindType
publicIpAtomatom (read-only)Promise<string> | string
publicIpStatusAtomatom (read-only)PublicIpStatus
publicIpErrorAtomatom (read-only)Error | null
publicIpValueAtomatom (read-only)string | null
publicIpV4Atomatom (read-only)Promise<string> | string
publicIpV4StatusAtomatom (read-only)PublicIpStatus
publicIpV4ErrorAtomatom (read-only)Error | null
publicIpV4ValueAtomatom (read-only)string | null
publicIpV6Atomatom (read-only)Promise<string> | string
publicIpV6StatusAtomatom (read-only)PublicIpStatus
publicIpV6ErrorAtomatom (read-only)Error | null
publicIpV6ValueAtomatom (read-only)string | null
publicIpEndpointsAtomatom (settable)string[]
publicIpV4EndpointsAtomatom (settable)string[]
publicIpV6EndpointsAtomatom (settable)string[]
publicIpMaxAgeAtomatom (settable)number (ms)
publicIpStaleWhileRevalidateAtomatom (settable)number (ms)
publicIpStaleIfErrorAtomatom (settable)number (ms)
fetchPublicIputil fn(endpoints: string[], validate?: (v: string) => boolean, timeoutMs?: number) => Promise<string>
PublicIpStatustype"idle" | "loading" | "revalidating" | "ok" | "error"

The V4 / V6 atoms are the same shape, fetching from IPv4- and IPv6-only endpoints. Endpoint, maxAge, staleWhileRevalidate, and staleIfError atoms are settable to tune fetching.

Cross-framework

Atoms are global: the fetch starts on the first subscriber and the result is shared across every store. Only the read primitive changes per framework (useValue, createValue, injectValue, watch, or store.get / store.sub in plain JS).