URLs
Absolute URLs that leave an app, parsed and built in one place by @workspace/shared/url — the branded AbsoluteUrl, parse, build and origin.
An absolute URL that leaves an app — a public share link, a checkout or portal return URL, a link to another app, an analytics endpoint — goes through @workspace/shared/url. The module validates with new URL() in a try/catch, never URL.canParse, which older Safari versions in the player's audience lack.
AbsoluteUrl
AbsoluteUrl is a branded string: an absolute http: or https: URL in its normalized form (url.href). Only the module produces one, so a signature that needs an already-validated URL takes AbsoluteUrl, and passing a raw string is a type error. It stays a string for every consumer that only reads it.
| Function | Use |
|---|---|
parseAbsoluteUrl(value) | Untrusted input (a request body, a runtime env value, a form field): AbsoluteUrl, or null when relative, malformed or of another scheme (javascript:, mailto:, data:). |
requireAbsoluteUrl(value) | A value that cannot be anything else (window.location.origin, a constant default): throws a TypeError otherwise. |
buildUrl(base, path, query?) | path appended to the path of base with a single slash between them, query set on the search, undefined values left out. |
withQuery(url, query) | url with query set on its search, its path, other parameters and fragment kept: a deal code on a page, a return URL on a link. |
originOf(url) | Scheme, host and port, as browsers send it in Origin, for allow-lists. |
import { buildUrl, originOf, parseAbsoluteUrl, withQuery } from '@workspace/shared/url';
const returnUrl = parseAbsoluteUrl(body.returnUrl);
if (returnUrl === null || !allowedOrigins.includes(originOf(returnUrl))) {
throw apiErrors.returnUrlNotAllowed('returnUrl');
}
buildUrl(learnBaseUrl, '/welcome');
// https://learn.example.com/welcome
buildUrl(matomoBaseUrl, 'matomo.php', { idsite: siteId, rec: 1, e_n: undefined });
// https://example.com/analytics/matomo.php?idsite=1&rec=1
withQuery(pageUrl, { dds: dealCode });
// https://play.example.com/?intro=off&dds=AB12CD34In the apps
Each browser app builds its own links from the origin it is served from, through one helper (appUrl in the teacher app, learnUrl in the learner space); share links of public sessions and collections come from getPublicSessionUrl and getPublicCollectionUrl, never from a template string. A return link between the player and the learner space carries the page back through withReturnUrl (@workspace/shared/return-url), whose target is an AbsoluteUrl, and the learner space only trusts a return under one of its configured players (isUnderBaseUrl). The api parses the return URLs a client names before checking their origin against CORS_ORIGINS, and hands the billing service AbsoluteUrls only.
Internal navigation (a router's to) and API route paths stay out of this module.