which-url 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,12 +22,15 @@ Production https://myapp.com "production"
22
22
 
23
23
  Works across environments (local, preview, production), browser bundles, Node/Bun servers, and edge runtimes that expose compatible env vars through `process.env` or build-time public env replacement.
24
24
 
25
+ For browser bundles, framework-prefixed env vars must be referenced statically so the bundler can inline them at build time. `which-url` includes literal references such as `process.env.NEXT_PUBLIC_APP_URL` and `process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL`; dynamic lookup like `process.env["NEXT_PUBLIC_" + name]` cannot be inlined by Next.js.
26
+
25
27
  The default export gives you everything as an object:
26
28
 
27
29
  ```typescript
28
30
  import appUrl from 'which-url'
29
31
 
30
32
  appUrl.origin // "https://myapp.com"
33
+ appUrl.productionOrigin // "https://myapp.com"
31
34
  appUrl.hostname // "myapp.com"
32
35
  appUrl.protocol // "https:"
33
36
  appUrl.env // "production"
@@ -89,6 +92,10 @@ When you call `createUrl({ env })`, the passed object replaces `process.env` as
89
92
 
90
93
  If nothing is detected in production, the default singleton returns empty URL strings so imports stay safe in tests, client bundles, and build tools. Call `createUrl()` directly when a missing URL should throw.
91
94
 
95
+ `origin` is the current environment origin. In a preview deployment, it should point at the preview. In production, it should point at production. Locally, it should point at local dev.
96
+
97
+ `productionOrigin` is the canonical production origin when configured or detectable. Use it for things that should still point at the public production site from previews, such as canonical metadata, social cards, and "view live site" links.
98
+
92
99
  ## Strict mode with `createUrl()`
93
100
 
94
101
  Use the default export or named constants for convenience:
@@ -122,7 +129,28 @@ APP_URL=https://myapp.com
122
129
 
123
130
  Works with or without protocol (`APP_URL=myapp.com` → `https://myapp.com`).
124
131
 
125
- **Client-side frameworks:** All framework prefixes are supported automatically — `NEXT_PUBLIC_APP_URL`, `VITE_APP_URL`, `PUBLIC_APP_URL`, `NUXT_ENV_APP_URL`, etc.
132
+ **Client-side frameworks:** All framework prefixes are supported automatically — `NEXT_PUBLIC_APP_URL`, `VITE_APP_URL`, `PUBLIC_APP_URL`, `NUXT_ENV_APP_URL`, etc. These are build-time values in browser bundles.
133
+
134
+ ## Production URL
135
+
136
+ Use `APP_PRODUCTION_URL` when the canonical production URL is different from the current environment URL:
137
+
138
+ ```bash
139
+ APP_PRODUCTION_URL=https://myapp.com
140
+ ```
141
+
142
+ ```typescript
143
+ import { origin, productionOrigin } from 'which-url'
144
+
145
+ origin // current environment origin
146
+ productionOrigin // canonical production origin, when available
147
+ ```
148
+
149
+ On Vercel, `productionOrigin` is detected from `VERCEL_PROJECT_PRODUCTION_URL`, even in preview deployments.
150
+
151
+ In Next.js browser bundles on Vercel deployments, it is detected from `NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL`. Vercel adds these framework-prefixed vars for production and preview deployments based on the framework preset, but `vercel env pull` does not create the prefixed local versions automatically.
152
+
153
+ **Client-side frameworks:** Framework prefixes are supported here too — `NEXT_PUBLIC_APP_PRODUCTION_URL`, `VITE_APP_PRODUCTION_URL`, `PUBLIC_APP_PRODUCTION_URL`, etc. These are build-time values in browser bundles.
126
154
 
127
155
  ## Platform support
128
156
 
@@ -255,6 +283,7 @@ Strict resolver function. It resolves when called and throws if no URL can be de
255
283
  | `href` | `string` | Same as `origin` |
256
284
  | `protocol` | `string` | `"https:"` |
257
285
  | `port` | `string` | `""` or `"3000"` |
286
+ | `productionOrigin` | `string` | `"https://myapp.com"` |
258
287
  | `env` | `AppEnv` | `"production"` \| `"preview"` \| `"local"` |
259
288
  | `platform` | `Platform` | `"vercel"` \| `"netlify"` \| ... \| `null` |
260
289
  | `debug`* | `string` | `"[provider:vercel] url=myapp.com \| env=production (vercel:production)"` |
package/dist/index.d.ts CHANGED
@@ -13,6 +13,8 @@ export declare const host: string;
13
13
  export declare const protocol: string;
14
14
  /** Port string — `""` for default ports, `"3000"` for custom */
15
15
  export declare const port: string;
16
+ /** Canonical production origin when configured or detectable — `"https://myapp.com"` */
17
+ export declare const productionOrigin: string;
16
18
  /** Current environment — `"production"`, `"preview"`, or `"local"` */
17
19
  export declare const env: AppEnv;
18
20
  /** Detected hosting platform — `"vercel"`, `"netlify"`, etc. or `null` */
@@ -33,6 +35,7 @@ export declare const isLocal: boolean;
33
35
  * import appUrl from 'which-url'
34
36
  *
35
37
  * appUrl.origin // "https://myapp.com"
38
+ * appUrl.productionOrigin // "https://myapp.com"
36
39
  * appUrl.env // "production"
37
40
  * appUrl.platform // "vercel"
38
41
  * appUrl.debug // "[provider:vercel] url=myapp.com | env=production (vercel:production)"
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var F=["VERCEL_ENV","VERCEL_URL","VERCEL_BRANCH_URL","VERCEL_PROJECT_PRODUCTION_URL","APP_URL","APP_ENV"];function H(E){switch(E){case"VERCEL_ENV":return process.env.VERCEL_ENV||process.env.NEXT_PUBLIC_VERCEL_ENV||process.env.NUXT_ENV_VERCEL_ENV||process.env.VITE_VERCEL_ENV||process.env.PUBLIC_VERCEL_ENV||process.env.REACT_APP_VERCEL_ENV||process.env.GATSBY_VERCEL_ENV||process.env.VUE_APP_VERCEL_ENV||process.env.REDWOOD_ENV_VERCEL_ENV||process.env.SANITY_STUDIO_VERCEL_ENV||void 0;case"VERCEL_URL":return process.env.VERCEL_URL||process.env.NEXT_PUBLIC_VERCEL_URL||process.env.NUXT_ENV_VERCEL_URL||process.env.VITE_VERCEL_URL||process.env.PUBLIC_VERCEL_URL||process.env.REACT_APP_VERCEL_URL||process.env.GATSBY_VERCEL_URL||process.env.VUE_APP_VERCEL_URL||process.env.REDWOOD_ENV_VERCEL_URL||process.env.SANITY_STUDIO_VERCEL_URL||void 0;case"VERCEL_BRANCH_URL":return process.env.VERCEL_BRANCH_URL||process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL||process.env.NUXT_ENV_VERCEL_BRANCH_URL||process.env.VITE_VERCEL_BRANCH_URL||process.env.PUBLIC_VERCEL_BRANCH_URL||process.env.REACT_APP_VERCEL_BRANCH_URL||process.env.GATSBY_VERCEL_BRANCH_URL||process.env.VUE_APP_VERCEL_BRANCH_URL||process.env.REDWOOD_ENV_VERCEL_BRANCH_URL||process.env.SANITY_STUDIO_VERCEL_BRANCH_URL||void 0;case"VERCEL_PROJECT_PRODUCTION_URL":return process.env.VERCEL_PROJECT_PRODUCTION_URL||process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL||process.env.NUXT_ENV_VERCEL_PROJECT_PRODUCTION_URL||process.env.VITE_VERCEL_PROJECT_PRODUCTION_URL||process.env.PUBLIC_VERCEL_PROJECT_PRODUCTION_URL||process.env.REACT_APP_VERCEL_PROJECT_PRODUCTION_URL||process.env.GATSBY_VERCEL_PROJECT_PRODUCTION_URL||process.env.VUE_APP_VERCEL_PROJECT_PRODUCTION_URL||process.env.REDWOOD_ENV_VERCEL_PROJECT_PRODUCTION_URL||process.env.SANITY_STUDIO_VERCEL_PROJECT_PRODUCTION_URL||void 0;case"APP_URL":return process.env.APP_URL||process.env.NEXT_PUBLIC_APP_URL||process.env.NUXT_ENV_APP_URL||process.env.VITE_APP_URL||process.env.PUBLIC_APP_URL||process.env.REACT_APP_APP_URL||process.env.GATSBY_APP_URL||process.env.VUE_APP_APP_URL||process.env.REDWOOD_ENV_APP_URL||process.env.SANITY_STUDIO_APP_URL||void 0;case"APP_ENV":return process.env.APP_ENV||process.env.NEXT_PUBLIC_APP_ENV||process.env.NUXT_ENV_APP_ENV||process.env.VITE_APP_ENV||process.env.PUBLIC_APP_ENV||process.env.REACT_APP_APP_ENV||process.env.GATSBY_APP_ENV||process.env.VUE_APP_APP_ENV||process.env.REDWOOD_ENV_APP_ENV||process.env.SANITY_STUDIO_APP_ENV||void 0;default:return}}function C(E,R){if(typeof process<"u"&&process?.env&&E===process.env){if(F.includes(R)){let _=H(R);if(_)return _}}let A=["","NEXT_PUBLIC_","NUXT_ENV_","VITE_","PUBLIC_","REACT_APP_","GATSBY_","VUE_APP_","REDWOOD_ENV_","SANITY_STUDIO_"];for(let _ of A){let L=E[_+R];if(L)return L}return}function N(E){if(E!==void 0)return G(E);if(typeof process<"u"&&process?.env)return process.env;return{}}function G(E){let R={};for(let[A,_]of Object.entries(E))if(typeof _==="string")R[A]=_;return R}var T=[{name:"vercel",detect:(E)=>!!E.VERCEL||!!C(E,"VERCEL_ENV"),resolveUrl:(E)=>{if(C(E,"VERCEL_ENV")==="production")return C(E,"VERCEL_PROJECT_PRODUCTION_URL")||C(E,"VERCEL_URL")||null;return C(E,"VERCEL_BRANCH_URL")||C(E,"VERCEL_URL")||null},resolveEnv:(E)=>{let R=C(E,"VERCEL_ENV");if(R==="production")return"production";if(R==="preview")return"preview";return"local"}},{name:"netlify",detect:(E)=>!!E.NETLIFY,resolveUrl:(E)=>{if(E.CONTEXT==="production")return E.URL||null;return E.DEPLOY_PRIME_URL||E.DEPLOY_URL||null},resolveEnv:(E)=>{if(E.CONTEXT==="production")return"production";if(E.CONTEXT==="deploy-preview"||E.CONTEXT==="branch-deploy")return"preview";return"local"}},{name:"cloudflare",detect:(E)=>!!E.CF_PAGES,resolveUrl:(E)=>E.CF_PAGES_URL||null,resolveEnv:(E)=>{if(E.CF_PAGES_BRANCH==="main"||E.CF_PAGES_BRANCH==="master")return"production";return"preview"}},{name:"railway",detect:(E)=>!!E.RAILWAY_PUBLIC_DOMAIN,resolveUrl:(E)=>E.RAILWAY_PUBLIC_DOMAIN||null,resolveEnv:(E)=>{if(E.RAILWAY_ENVIRONMENT==="production")return"production";return"production"}},{name:"fly",detect:(E)=>!!E.FLY_APP_NAME,resolveUrl:(E)=>E.FLY_APP_NAME?`${E.FLY_APP_NAME}.fly.dev`:null,resolveEnv:()=>"production"},{name:"render",detect:(E)=>!!E.RENDER,resolveUrl:(E)=>E.RENDER_EXTERNAL_URL||null,resolveEnv:(E)=>{if(E.IS_PULL_REQUEST==="true")return"preview";return"production"}},{name:"digitalocean",detect:(E)=>!!E.DIGITALOCEAN_APP_PLATFORM,resolveUrl:(E)=>E.APP_URL||null,resolveEnv:()=>"production"},{name:"heroku",detect:(E)=>!!E.HEROKU_APP_NAME,resolveUrl:(E)=>E.HEROKU_APP_NAME?`${E.HEROKU_APP_NAME}.herokuapp.com`:null,resolveEnv:()=>"production"}];function U(E){let R=E.trim().replace(/\/+$/,"");if(R.startsWith("http://")||R.startsWith("https://"))return R;return`https://${R}`}function Y(E){let R=N(E),A=C(R,"APP_URL");if(A)return{url:U(A),debugLabel:`[override] APP_URL=${A}`};if(R.PORTLESS_TAILSCALE_URL)return{url:R.PORTLESS_TAILSCALE_URL,debugLabel:`[portless:tailscale] PORTLESS_TAILSCALE_URL=${R.PORTLESS_TAILSCALE_URL}`};if(R.PORTLESS_URL)return{url:R.PORTLESS_URL,debugLabel:`[portless] PORTLESS_URL=${R.PORTLESS_URL}`};for(let L of T)if(L.detect(R)){let t=L.resolveUrl(R);if(t)return{url:U(t),debugLabel:`[provider:${L.name}] url=${t}`}}if(typeof window<"u"&&window.location)return{url:window.location.origin,debugLabel:"[browser] window.location.origin"};if(R.NODE_ENV!=="production"){let L=R.PORT||"3000";return{url:`http://localhost:${L}`,debugLabel:`[fallback] PORT=${L}`}}throw Error("which-url: Cannot detect app URL. Set APP_URL environment variable.")}function I(E){let R=N(E);for(let A of T)if(A.detect(R))return A.name;return null}var W=["production","preview","local"];function M(E){let R=N(E),A=C(R,"APP_ENV");if(A&&W.includes(A))return{env:A,debugLabel:`APP_ENV=${A}`};if(R.NODE_ENV==="development")return{env:"local",debugLabel:"NODE_ENV=development"};for(let _ of T)if(_.detect(R)){let L=_.resolveEnv(R);return{env:L,debugLabel:`${_.name}:${L}`}}if(R.NODE_ENV==="production")return{env:"production",debugLabel:"NODE_ENV=production"};return{env:"local",debugLabel:"default"}}function c(E){return Object.defineProperty(E,"debug",{value:E.debug,enumerable:!1,configurable:!1}),E}function B(E){let R=E?.env,{url:A,debugLabel:_}=Y(R),L=new URL(A),{env:t,debugLabel:V}=M(R),u=I(R),O=`${_} | env=${t} (${V})`,f={href:L.origin,origin:L.origin,hostname:L.hostname,host:L.host,protocol:L.protocol,port:L.port,env:t,platform:u,debug:O,isProduction:t==="production",isPreview:t==="preview",isLocal:t==="local"};return c(f)}function X(E){let R=E instanceof Error?E.message:"resolution failed",A="local",_="default";try{let t=M();A=t.env,_=t.debugLabel}catch{}let L={href:"",origin:"",hostname:"",host:"",protocol:"",port:"",env:A,platform:I(),debug:`[error] ${R} | env=${A} (${_})`,isProduction:A==="production",isPreview:A==="preview",isLocal:A==="local"};return c(L)}var P;try{P=B()}catch(E){P=X(E)}var{href:z,origin:i,hostname:k,host:m,protocol:g,port:b,env:p,platform:l,debug:o,isProduction:n,isPreview:d,isLocal:s}=P,a=P;export{g as protocol,b as port,l as platform,i as origin,n as isProduction,d as isPreview,s as isLocal,z as href,k as hostname,m as host,p as env,a as default,o as debug,B as createUrl};
1
+ var u=["VERCEL_ENV","VERCEL_URL","VERCEL_BRANCH_URL","VERCEL_PROJECT_PRODUCTION_URL","APP_URL","APP_PRODUCTION_URL","APP_ENV"];function D(E){switch(E){case"VERCEL_ENV":return process.env.VERCEL_ENV||process.env.NEXT_PUBLIC_VERCEL_ENV||process.env.NUXT_ENV_VERCEL_ENV||process.env.VITE_VERCEL_ENV||process.env.PUBLIC_VERCEL_ENV||process.env.REACT_APP_VERCEL_ENV||process.env.GATSBY_VERCEL_ENV||process.env.VUE_APP_VERCEL_ENV||process.env.REDWOOD_ENV_VERCEL_ENV||process.env.SANITY_STUDIO_VERCEL_ENV||void 0;case"VERCEL_URL":return process.env.VERCEL_URL||process.env.NEXT_PUBLIC_VERCEL_URL||process.env.NUXT_ENV_VERCEL_URL||process.env.VITE_VERCEL_URL||process.env.PUBLIC_VERCEL_URL||process.env.REACT_APP_VERCEL_URL||process.env.GATSBY_VERCEL_URL||process.env.VUE_APP_VERCEL_URL||process.env.REDWOOD_ENV_VERCEL_URL||process.env.SANITY_STUDIO_VERCEL_URL||void 0;case"VERCEL_BRANCH_URL":return process.env.VERCEL_BRANCH_URL||process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL||process.env.NUXT_ENV_VERCEL_BRANCH_URL||process.env.VITE_VERCEL_BRANCH_URL||process.env.PUBLIC_VERCEL_BRANCH_URL||process.env.REACT_APP_VERCEL_BRANCH_URL||process.env.GATSBY_VERCEL_BRANCH_URL||process.env.VUE_APP_VERCEL_BRANCH_URL||process.env.REDWOOD_ENV_VERCEL_BRANCH_URL||process.env.SANITY_STUDIO_VERCEL_BRANCH_URL||void 0;case"VERCEL_PROJECT_PRODUCTION_URL":return process.env.VERCEL_PROJECT_PRODUCTION_URL||process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL||process.env.NUXT_ENV_VERCEL_PROJECT_PRODUCTION_URL||process.env.VITE_VERCEL_PROJECT_PRODUCTION_URL||process.env.PUBLIC_VERCEL_PROJECT_PRODUCTION_URL||process.env.REACT_APP_VERCEL_PROJECT_PRODUCTION_URL||process.env.GATSBY_VERCEL_PROJECT_PRODUCTION_URL||process.env.VUE_APP_VERCEL_PROJECT_PRODUCTION_URL||process.env.REDWOOD_ENV_VERCEL_PROJECT_PRODUCTION_URL||process.env.SANITY_STUDIO_VERCEL_PROJECT_PRODUCTION_URL||void 0;case"APP_URL":return process.env.APP_URL||process.env.NEXT_PUBLIC_APP_URL||process.env.NUXT_ENV_APP_URL||process.env.VITE_APP_URL||process.env.PUBLIC_APP_URL||process.env.REACT_APP_APP_URL||process.env.GATSBY_APP_URL||process.env.VUE_APP_APP_URL||process.env.REDWOOD_ENV_APP_URL||process.env.SANITY_STUDIO_APP_URL||void 0;case"APP_PRODUCTION_URL":return process.env.APP_PRODUCTION_URL||process.env.NEXT_PUBLIC_APP_PRODUCTION_URL||process.env.NUXT_ENV_APP_PRODUCTION_URL||process.env.VITE_APP_PRODUCTION_URL||process.env.PUBLIC_APP_PRODUCTION_URL||process.env.REACT_APP_APP_PRODUCTION_URL||process.env.GATSBY_APP_PRODUCTION_URL||process.env.VUE_APP_APP_PRODUCTION_URL||process.env.REDWOOD_ENV_APP_PRODUCTION_URL||process.env.SANITY_STUDIO_APP_PRODUCTION_URL||void 0;case"APP_ENV":return process.env.APP_ENV||process.env.NEXT_PUBLIC_APP_ENV||process.env.NUXT_ENV_APP_ENV||process.env.VITE_APP_ENV||process.env.PUBLIC_APP_ENV||process.env.REACT_APP_APP_ENV||process.env.GATSBY_APP_ENV||process.env.VUE_APP_APP_ENV||process.env.REDWOOD_ENV_APP_ENV||process.env.SANITY_STUDIO_APP_ENV||void 0;default:return}}function C(E,P){if(typeof process<"u"&&process?.env&&E===process.env){if(u.includes(P)){let L=D(P);if(L)return L}}let A=["","NEXT_PUBLIC_","NUXT_ENV_","VITE_","PUBLIC_","REACT_APP_","GATSBY_","VUE_APP_","REDWOOD_ENV_","SANITY_STUDIO_"];for(let L of A){let _=E[L+P];if(_)return _}return}function t(E){if(E!==void 0)return G(E);if(typeof process<"u"&&process?.env)return process.env;return{}}function G(E){let P={};for(let[A,L]of Object.entries(E))if(typeof L==="string")P[A]=L;return P}var U=[{name:"vercel",detect:(E)=>!!E.VERCEL||!!C(E,"VERCEL_ENV"),resolveUrl:(E)=>{if(C(E,"VERCEL_ENV")==="production")return C(E,"VERCEL_PROJECT_PRODUCTION_URL")||C(E,"VERCEL_URL")||null;return C(E,"VERCEL_BRANCH_URL")||C(E,"VERCEL_URL")||null},resolveProductionUrl:(E)=>C(E,"VERCEL_PROJECT_PRODUCTION_URL")||null,resolveEnv:(E)=>{let P=C(E,"VERCEL_ENV");if(P==="production")return"production";if(P==="preview")return"preview";return"local"}},{name:"netlify",detect:(E)=>!!E.NETLIFY,resolveUrl:(E)=>{if(E.CONTEXT==="production")return E.URL||null;return E.DEPLOY_PRIME_URL||E.DEPLOY_URL||null},resolveProductionUrl:(E)=>E.URL||null,resolveEnv:(E)=>{if(E.CONTEXT==="production")return"production";if(E.CONTEXT==="deploy-preview"||E.CONTEXT==="branch-deploy")return"preview";return"local"}},{name:"cloudflare",detect:(E)=>!!E.CF_PAGES,resolveUrl:(E)=>E.CF_PAGES_URL||null,resolveEnv:(E)=>{if(E.CF_PAGES_BRANCH==="main"||E.CF_PAGES_BRANCH==="master")return"production";return"preview"}},{name:"railway",detect:(E)=>!!E.RAILWAY_PUBLIC_DOMAIN,resolveUrl:(E)=>E.RAILWAY_PUBLIC_DOMAIN||null,resolveProductionUrl:(E)=>E.RAILWAY_PUBLIC_DOMAIN||null,resolveEnv:(E)=>{if(E.RAILWAY_ENVIRONMENT==="production")return"production";return"production"}},{name:"fly",detect:(E)=>!!E.FLY_APP_NAME,resolveUrl:(E)=>E.FLY_APP_NAME?`${E.FLY_APP_NAME}.fly.dev`:null,resolveProductionUrl:(E)=>E.FLY_APP_NAME?`${E.FLY_APP_NAME}.fly.dev`:null,resolveEnv:()=>"production"},{name:"render",detect:(E)=>!!E.RENDER,resolveUrl:(E)=>E.RENDER_EXTERNAL_URL||null,resolveProductionUrl:(E)=>E.IS_PULL_REQUEST==="true"?null:E.RENDER_EXTERNAL_URL||null,resolveEnv:(E)=>{if(E.IS_PULL_REQUEST==="true")return"preview";return"production"}},{name:"digitalocean",detect:(E)=>!!E.DIGITALOCEAN_APP_PLATFORM,resolveUrl:(E)=>E.APP_URL||null,resolveProductionUrl:(E)=>E.APP_URL||null,resolveEnv:()=>"production"},{name:"heroku",detect:(E)=>!!E.HEROKU_APP_NAME,resolveUrl:(E)=>E.HEROKU_APP_NAME?`${E.HEROKU_APP_NAME}.herokuapp.com`:null,resolveProductionUrl:(E)=>E.HEROKU_APP_NAME?`${E.HEROKU_APP_NAME}.herokuapp.com`:null,resolveEnv:()=>"production"}];function T(E){let P=E.trim().replace(/\/+$/,"");if(P.startsWith("http://")||P.startsWith("https://"))return P;return`https://${P}`}function f(E){let P=t(E),A=C(P,"APP_URL");if(A)return{url:T(A),debugLabel:`[override] APP_URL=${A}`};if(P.PORTLESS_TAILSCALE_URL)return{url:P.PORTLESS_TAILSCALE_URL,debugLabel:`[portless:tailscale] PORTLESS_TAILSCALE_URL=${P.PORTLESS_TAILSCALE_URL}`};if(P.PORTLESS_URL)return{url:P.PORTLESS_URL,debugLabel:`[portless] PORTLESS_URL=${P.PORTLESS_URL}`};for(let _ of U)if(_.detect(P)){let R=_.resolveUrl(P);if(R)return{url:T(R),debugLabel:`[provider:${_.name}] url=${R}`}}if(typeof window<"u"&&window.location)return{url:window.location.origin,debugLabel:"[browser] window.location.origin"};if(P.NODE_ENV!=="production"){let _=P.PORT||"3000";return{url:`http://localhost:${_}`,debugLabel:`[fallback] PORT=${_}`}}throw Error("which-url: Cannot detect app URL. Set APP_URL environment variable.")}function F(E){let P=t(E),A=C(P,"APP_PRODUCTION_URL");if(A)return{url:T(A),debugLabel:`[production:override] APP_PRODUCTION_URL=${A}`};for(let _ of U)if(_.detect(P)){let R=_.resolveProductionUrl?.(P);if(R)return{url:T(R),debugLabel:`[production:provider:${_.name}] url=${R}`}}for(let _ of U)if(_.detect(P)&&_.resolveEnv(P)==="production"){let R=_.resolveUrl(P);if(R)return{url:T(R),debugLabel:`[production:current:${_.name}] url=${R}`}}let L=C(P,"APP_URL");if(L&&P.NODE_ENV==="production")return{url:T(L),debugLabel:`[production:current] APP_URL=${L}`};return null}function M(E){let P=t(E);for(let A of U)if(A.detect(P))return A.name;return null}var K=["production","preview","local"];function c(E){let P=t(E),A=C(P,"APP_ENV");if(A&&K.includes(A))return{env:A,debugLabel:`APP_ENV=${A}`};if(P.NODE_ENV==="development")return{env:"local",debugLabel:"NODE_ENV=development"};for(let L of U)if(L.detect(P)){let _=L.resolveEnv(P);return{env:_,debugLabel:`${L.name}:${_}`}}if(P.NODE_ENV==="production")return{env:"production",debugLabel:"NODE_ENV=production"};return{env:"local",debugLabel:"default"}}function H(E){return Object.defineProperty(E,"debug",{value:E.debug,enumerable:!1,configurable:!1}),E}function X(E){let P=E?.env,{url:A,debugLabel:L}=f(P),_=new URL(A),{env:R,debugLabel:O}=c(P),V=M(P),I=F(P),Y=I?new URL(I.url).origin:"",B=I?` | production=${Y} (${I.debugLabel})`:" | production=unresolved",W=`${L} | env=${R} (${O})${B}`,$={href:_.origin,origin:_.origin,hostname:_.hostname,host:_.host,protocol:_.protocol,port:_.port,productionOrigin:Y,env:R,platform:V,debug:W,isProduction:R==="production",isPreview:R==="preview",isLocal:R==="local"};return H($)}function S(E){let P=E instanceof Error?E.message:"resolution failed",A="local",L="default";try{let R=c();A=R.env,L=R.debugLabel}catch{}let _={href:"",origin:"",hostname:"",host:"",protocol:"",port:"",productionOrigin:"",env:A,platform:M(),debug:`[error] ${P} | env=${A} (${L})`,isProduction:A==="production",isPreview:A==="preview",isLocal:A==="local"};return H(_)}var N;try{N=X()}catch(E){N=S(E)}var{href:m,origin:g,hostname:i,host:o,protocol:s,port:d,productionOrigin:n,env:p,platform:a,debug:r,isProduction:v,isPreview:e,isLocal:EE}=N,_E=N;export{s as protocol,n as productionOrigin,d as port,a as platform,g as origin,v as isProduction,e as isPreview,EE as isLocal,m as href,i as hostname,o as host,p as env,_E as default,r as debug,X as createUrl};
package/dist/types.d.ts CHANGED
@@ -14,6 +14,8 @@ export interface WhichUrl {
14
14
  readonly protocol: string;
15
15
  /** Port string — `""` for default ports, `"3000"` for custom */
16
16
  readonly port: string;
17
+ /** Canonical production origin when configured or detectable — `"https://myapp.com"` */
18
+ readonly productionOrigin: string;
17
19
  /** Current environment — `"production"`, `"preview"`, or `"local"` */
18
20
  readonly env: AppEnv;
19
21
  /** Detected hosting platform — `"vercel"`, `"netlify"`, etc. or `null` */
@@ -45,6 +47,7 @@ export interface ProviderDetector {
45
47
  name: PlatformName;
46
48
  detect: (env: Record<string, string | undefined>) => boolean;
47
49
  resolveUrl: (env: Record<string, string | undefined>) => string | null;
50
+ resolveProductionUrl?: (env: Record<string, string | undefined>) => string | null;
48
51
  resolveEnv: (env: Record<string, string | undefined>) => AppEnv;
49
52
  }
50
53
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "which-url",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Auto-detect your app's URL across hosting providers. Zero config.",
5
5
  "type": "module",
6
6
  "exports": {