{"_id":"@dmytromykhailiuk/location-context-resolver","_rev":"2-0b0e95397985e211e5c987503808723e","name":"@dmytromykhailiuk/location-context-resolver","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@dmytromykhailiuk/location-context-resolver","version":"1.0.0","keywords":["location","url","pathname","base-path","basepath","query-params","micro-frontend","microfrontend","module-federation","remote","typescript","type-safe","ssr","zero-dependencies"],"author":{"name":"Dmytro Mykhailiuk","email":"dimamykhayluk@gmail.com"},"license":"MIT","_id":"@dmytromykhailiuk/location-context-resolver@1.0.0","maintainers":[{"name":"dmytromykhailiuk","email":"dimamykhayluk@gmail.com"}],"homepage":"https://github.com/dmytromykhailiuk/location-context-resolver#readme","bugs":{"url":"https://github.com/dmytromykhailiuk/location-context-resolver/issues"},"dist":{"shasum":"5d7d4f7e73c719f485007f3bde04b705698263ef","tarball":"https://registry.npmjs.org/@dmytromykhailiuk/location-context-resolver/-/location-context-resolver-1.0.0.tgz","fileCount":9,"integrity":"sha512-faEMnCQw7PrzbvG+a64n+FP7ENU32ceNYOzvjbGDyDD56RebjOrJJv0KcE8TJduBN4JxANJC4FEpfjvrLR3UNA==","signatures":[{"sig":"MEUCIQCmrA1NynTO6J77opMhridRB5Kqr2pSWW2UJI2DqDKtIgIgJdIO7qQj78IJHYl3YQ1AU5FJGbcOnSJ5q+N3cXT/s9c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33502},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"gitHead":"1bd9de19fa630c46621e317ce94e9718be269634","scripts":{"dev":"tsup --watch","lint":"biome check .","test":"vitest run","build":"tsup","format":"biome format --write .","lint:fix":"biome check --write .","typecheck":"tsc --noEmit","playground":"vite --config vite.playground.config.ts","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"dmytromykhailiuk","email":"dimamykhayluk@gmail.com"},"repository":{"url":"git+https://github.com/dmytromykhailiuk/location-context-resolver.git","type":"git"},"_npmVersion":"11.6.2","description":"Resolve where your app runs — origin, base-path-relative pathname, query params — and where its remote counterpart lives. Typed, SSR-friendly, zero dependencies.","directories":{},"sideEffects":false,"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vite":"^5.4.11","jsdom":"^25.0.1","vitest":"^2.1.8","typescript":"^5.7.3","@types/node":"^22.10.5","@biomejs/biome":"^1.9.4"},"_npmOperationalInternal":{"tmp":"tmp/location-context-resolver_1.0.0_1785186542634_0.86825798543847","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@dmytromykhailiuk/location-context-resolver","version":"1.0.1","description":"Resolve where your app runs — origin, base-path-relative pathname, query params — and where its remote counterpart lives. Typed, SSR-friendly, zero dependencies.","type":"module","sideEffects":false,"author":{"name":"Dmytro Mykhailiuk","email":"dimamykhayluk@gmail.com"},"license":"MIT","keywords":["location","url","pathname","base-path","basepath","query-params","micro-frontend","microfrontend","module-federation","remote","typescript","type-safe","ssr","zero-dependencies"],"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"scripts":{"build":"tsup","dev":"tsup --watch","playground":"vite --config vite.playground.config.ts","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","lint":"biome check .","lint:fix":"biome check --write .","format":"biome format --write .","prepublishOnly":"npm run build"},"engines":{"node":">=18"},"devDependencies":{"@biomejs/biome":"^1.9.4","@types/node":"^22.10.5","jsdom":"^25.0.1","tsup":"^8.3.5","typescript":"^5.7.3","vite":"^5.4.11","vitest":"^2.1.8"},"repository":{"type":"git","url":"git+https://github.com/dmytromykhailiuk/location-context-resolver.git"},"bugs":{"url":"https://github.com/dmytromykhailiuk/location-context-resolver/issues"},"homepage":"https://dmytromykhailiuk.github.io/location-context-resolver/","gitHead":"79f684de41a5b611f6f98cc2ccd5ce9dc30fde16","_id":"@dmytromykhailiuk/location-context-resolver@1.0.1","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-3cdY3s/xHQO3hbVWfMPSTLsA3x3OH8ziYtq8EFFXs02lG+8TZkOmlTa8UNUH5JmLcGTd1ZzUyG276twhrYS/eQ==","shasum":"eda32b9b9d583569cd1caca6a47bcce4ed3df1e7","tarball":"https://registry.npmjs.org/@dmytromykhailiuk/location-context-resolver/-/location-context-resolver-1.0.1.tgz","fileCount":9,"unpackedSize":33495,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHlfzT4EDWIRxSrMqA5+VgbBnet6I3HFMr3mNoTYBEp2AiBOw/2QGx0VOsOGhZy01P/y4+qlzup5ED0egkl2M1TubA=="}]},"_npmUser":{"name":"dmytromykhailiuk","email":"dimamykhayluk@gmail.com"},"directories":{},"maintainers":[{"name":"dmytromykhailiuk","email":"dimamykhayluk@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/location-context-resolver_1.0.1_1786638558376_0.9252942440551744"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T21:09:02.502Z","modified":"2026-08-13T16:29:18.715Z","1.0.0":"2026-07-27T21:09:02.805Z","1.0.1":"2026-08-13T16:29:18.554Z"},"bugs":{"url":"https://github.com/dmytromykhailiuk/location-context-resolver/issues"},"author":{"name":"Dmytro Mykhailiuk","email":"dimamykhayluk@gmail.com"},"license":"MIT","homepage":"https://dmytromykhailiuk.github.io/location-context-resolver/","keywords":["location","url","pathname","base-path","basepath","query-params","micro-frontend","microfrontend","module-federation","remote","typescript","type-safe","ssr","zero-dependencies"],"repository":{"type":"git","url":"git+https://github.com/dmytromykhailiuk/location-context-resolver.git"},"description":"Resolve where your app runs — origin, base-path-relative pathname, query params — and where its remote counterpart lives. Typed, SSR-friendly, zero dependencies.","maintainers":[{"name":"dmytromykhailiuk","email":"dimamykhayluk@gmail.com"}],"readme":"# @dmytromykhailiuk/location-context-resolver\n\nResolve where your app runs — origin, base-path-relative pathname, query params — and where\nits remote counterpart lives. Typed, SSR-friendly, zero dependencies.\n\n> **Full documentation:** open [Docs](https://dmytromykhailiuk.github.io/location-context-resolver/)\n> in a browser — every option, with examples, a table of contents and cross-links. This README is\n> the short form.\n\nBuilt for apps that are **served from more than one place** — a micro-frontend mounted under\n`/my-app` on a host shell, mirrored on its own remote origin; a white-label product deployed\nunder different base paths per customer; any setup where \"what is my URL?\" has two answers. At\nthat point hand-rolled `window.location` parsing starts to hurt: base-path stripping via\n`split()` breaks on paths it doesn't expect, remote URLs are glued together with fragile string\nconcatenation, and none of it runs during SSR.\n\nThis library answers with one small, deliberate API. You declare the topology **once** — the\nremote origin and the base path — and get back a resolver: a function that, at call time, reads\nthe location and returns a typed, frozen **context**: both origins, both application origins,\nthe pathname *relative to the base path*, and parsed query params.\n\n## Install\n\n```sh\nnpm i @dmytromykhailiuk/location-context-resolver\n```\n\n## Quick start\n\n```ts\nimport { createLocationContextResolver } from \"@dmytromykhailiuk/location-context-resolver\";\n\nconst resolveLocationContext = createLocationContextResolver({\n  remoteOrigin: \"https://remote.example.com\",\n  applicationBasePath: \"/my-app\",\n});\n\n// current URL: https://host.example.com/my-app/users/42?tab=posts\nconst context = resolveLocationContext();\n\ncontext.origin;                  // \"https://host.example.com\"\ncontext.remoteOrigin;            // \"https://remote.example.com\"\ncontext.applicationOrigin;       // \"https://host.example.com/my-app\"\ncontext.remoteApplicationOrigin; // \"https://remote.example.com/my-app\"\ncontext.pathname;                // \"/users/42\" — relative to the base path\ncontext.queryParams.get(\"tab\");  // \"posts\"\n```\n\n- The resolver reads the location **at call time** — every call is a fresh snapshot.\n- The context is **frozen** (`Object.freeze`) — a snapshot can't drift after the fact.\n- Creating a resolver never touches the location — module scope is safe everywhere, SSR\n  included.\n\n## API\n\n```ts\nconst resolve = createLocationContextResolver({\n  remoteOrigin: string;              // required, non-empty; trailing slashes ignored\n  applicationBasePath?: string;      // \"/my-app\" — slashes on both ends optional\n  location?: LocationLike | (() => LocationLike);  // defaults to the browser's location\n  onBasePathMismatch?: (pathname, basePath) => void;  // defaults to console.warn\n});\n\nconst context = resolve();\ncontext.origin;                  // where the document is served from right now\ncontext.remoteOrigin;            // normalized remote origin\ncontext.applicationOrigin;       // origin + base path\ncontext.remoteApplicationOrigin; // remote origin + base path\ncontext.pathname;                // relative to the base path, leading slash kept\ncontext.queryParams;             // fresh URLSearchParams per resolve\n```\n\nAn empty `remoteOrigin` throws **at creation** — a resolver that can't name its remote is a\nconfiguration bug worth failing loudly on.\n\n## Base path\n\n`applicationBasePath` is normalized — `/my-app`, `my-app`, `my-app/` and `/my-app/` all mean\nthe same thing. Stripping happens only at a **segment boundary**:\n\n```ts\n// applicationBasePath: \"/my-app\"\n\"/my-app/users/42\"  → \"/users/42\"\n\"/my-app\"           → \"/\"\n\"/my-app-admin/x\"   → \"/my-app-admin/x\"   // different app — not stripped\n\"/other/users\"      → \"/other/users\"      // mismatch — reported, returned unchanged\n```\n\nA pathname outside the base path is **never mangled**: it is returned unchanged and reported\nthrough `onBasePathMismatch` (default: `console.warn`), so a misconfigured mount is visible in\ndevelopment without breaking navigation.\n\n## SSR & custom locations\n\nThe resolver reads `globalThis.location` by default. Where there is none — Node during SSR,\ntests, workers — pass the location explicitly: an **object** for a fixed snapshot (the request\nURL), or a **function** for a live source read on every resolve.\n\n```ts\nconst resolve = createLocationContextResolver({\n  remoteOrigin: \"https://remote.example.com\",\n  applicationBasePath: \"/my-app\",\n  location: { origin: requestOrigin, pathname: requestPath, search: requestSearch },\n});\n```\n\nCreating a resolver is always safe; only *calling* it without any location throws — with a\nclear message naming the fix.\n\n## TypeScript\n\nEverything is typed end to end: `LocationContext` fields are `readonly`, `LocationLike` is the\nthree-field subset of `Location` (so the browser's `location` satisfies it, and so does any\nplain object), and `remoteOrigin` is required by the types — forgetting it is a compile error.\n\n```ts\nimport type {\n  LocationContext,\n  LocationContextResolver,\n  LocationContextResolverOptions,\n  LocationLike,\n} from \"@dmytromykhailiuk/location-context-resolver\";\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}