Deterministic shortlink resolution for Deno.
This library resolves shortlinks (compact path aliases) into fully-qualified URLs. It supports:
- Absolute destinations (e.g.,
example -> https://example.com) - Origin-relative internal redirects with loop protection (e.g.,
docs -> /documentation) - Path appending (e.g.,
/github/denoland/denoresolves againstgithub -> https://github.com) - Deterministic query parameter merging and fragment selection
The resolution algorithm is documented as an Internet-Draft: see “A Deterministic Algorithm for Resolving Shortlinks with Internal Redirects” (IETF Datatracker, spec repo).
Many organizations maintain internal "go/" links (e.g., go/docs) for knowledge
sharing. The need is portability: define shortlinks as a simple, static
Record<string, string> (JSON) and get identical behavior across Cloudflare
Workers, Vercel Edge, Deno servers, or static sites. Without a standard,
behaviors diverge, especially around query params, fragments, and internal
redirects.
This project and its Internet-Draft standardize the deterministic resolution algorithm so a single ruleset behaves the same everywhere.
- Simplicity: ruleset is a plain key-value map
- Determinism: longest-prefix match, well-defined query/fragment precedence
- Portability: no runtime-specific features; works on any platform
- Safety: loop protection for internal redirects
- No regex or wildcards
- No user-agent or conditional logic
- No complex rule engines
Rationale: allowing regex/wildcards transforms the data model into
Record<regex, substitution> and forces O(n) scans with engine-specific
semantics, undermining portability and the “simple JSON file” anchor. If you
need advanced routing, use tools like Nginx, Caddy, or Cloudflare Rules; this
library standardizes the "fiddly bits" for simple maps.
type Shortlinks = Record<string, string>;
// Example
const shortlinks = {
"github": "https://github.com",
"docs": "/documentation",
"docs/api": "/documentation/reference",
};- Stateless resolution from a provided ruleset
- Storage is out of scope (KV, JSON, DB all fine)
- Works anywhere a
URLand aRecord<string, string>are available
Teams and OSS orgs running internal go-links who want consistent behavior across platforms. This library is in production use across several open-source projects and sites.
Use via JSR in Deno:
import { go } from "jsr:@fartlabs/go";
// Given an incoming request URL and a shortlink ruleset
const url = new URL("https://example.com/docs/api/v1/users");
const shortlinks = {
docs: "/documentation",
"docs/api": "/documentation/reference",
};
const destination = go(url, shortlinks);
console.log(destination.href); // https://example.com/documentation/reference/v1/usersJSR documentation: https://jsr.io/@fartlabs/go
See the Getting Started example above for basic usage. The function signature is:
function go(url: URL, shortlinks: Record<string, string>): URL;Ruleset value types:
"https://..."→ absolute destination"/path"→ internal redirect (origin-relative), supports chained redirects with loop protection (256 max)
Query and fragment handling:
- Query parameters merge in this order: destination base query, then any query embedded in the matched pathname, then the request query (later values overwrite earlier ones)
- Fragment precedence: request
#hashif present, else matched-path#hashif present, else destination#hash
Absolute destination with path appending:
go(new URL("https://example.com/github/ietf/guidelines"), {
github: "https://github.com",
});
// => https://github.com/ietf/guidelinesInternal redirect chain:
go(new URL("https://example.com/docs/api/v1/users"), {
docs: "/documentation",
"docs/api": "/documentation/reference",
});
// => https://example.com/documentation/reference/v1/usersQuery merging and fragment precedence:
go(new URL("https://example.com/example?foo=bar#yang"), {
example: "https://example.com?baz=qux#yin",
});
// => https://example.com/?baz=qux&foo=bar#yangBackwards compatibility (keeping old links alive):
Version migration without breaking old links:
go(new URL("https://example.com/docs/v1/getting-started"), {
// Old version path now redirects to the stable location
"docs/v1": "/docs/latest",
});
// => https://example.com/docs/latest/getting-startedAlias rename while preserving existing references:
go(new URL("https://example.com/handbook/intro"), {
// Keep old alias but forward it internally to the new one
handbook: "/guide",
guide: "https://docs.example.com",
});
// => https://docs.example.com/introDeprecate a whole section but keep deep links working via longest-prefix:
go(new URL("https://example.com/blog/2023/launch"), {
blog: "https://news.example.com",
});
// => https://news.example.com/2023/launch- Deno latest
- Format:
deno fmt - Lint:
deno lint - Test:
deno test
This project is licensed under the Do What The Fuck You Want To Public License
(WTFPL). See LICENSE for details.
- JSR package: https://jsr.io/@fartlabs/go
- Internet-Draft: IETF Datatracker
- Protocol spec repo: https://github.com/EthanThatOneKid/go-protocol/
- Prior art: Deno's official documentation (Deno's implementation) implements a similar go-link pattern, demonstrating institutional demand for a standardized go-link protocol.
This repo ships a minimal web UI and API backed by Deno KV to manage shortlinks.
deno task startRequires Deno and --unstable-kv.
GO_TOKEN(optional): when set, this token is required for POST/DELETE requests to/api.
Uses Deno KV; data is stored under the "go" namespace key.
All write operations require the header Authorization: Token ${GO_TOKEN}.
-
GET
/api(read)- Returns the current shortlink map
{ [alias: string]: string }.
- Returns the current shortlink map
-
POST
/api(write)- Body:
{ alias: string; destination: string; force?: boolean } - Creates a shortlink. If alias exists and
forceis not set, returns an error.
- Body:
-
DELETE
/api(write)- Body:
{ alias: string } - Deletes a shortlink.
- Body:
Any Deno-compatible environment. The server is a simple Deno.serve app using
Deno KV. Ensure --unstable-kv is available and set GO_TOKEN for write
protection.
Run deno fmt to format the code.
Run deno lint to lint the code.
Run deno test to run the tests.
Run deno task start to start the server.
Developed with ❤️ @FartLabs