@pontive/pontkit-loader 1.0.1 → 1.0.3
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/dist/proxy/index.d.ts +20 -0
- package/dist/proxy/target.d.ts +67 -0
- package/dist/proxy/vite.d.ts +38 -0
- package/dist/proxy.cjs +2 -0
- package/dist/proxy.cjs.map +1 -0
- package/dist/proxy.js +58 -0
- package/dist/proxy.js.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The framework-neutral half of the auth proxy.
|
|
3
|
+
*
|
|
4
|
+
* An app is cross-site with its auth server unless the auth endpoints are
|
|
5
|
+
* served from the app's own origin, and a cross-site refresh cookie is a
|
|
6
|
+
* third-party cookie: dropped by Safari outright, withheld everywhere under
|
|
7
|
+
* SameSite=Lax. A proxy on the app's origin is what makes those cookies
|
|
8
|
+
* first-party.
|
|
9
|
+
*
|
|
10
|
+
* None of this is Next-specific, and the Vite adapter is here rather than in
|
|
11
|
+
* @pontive/pontkit-nextjs because a Vite app depending on a package named for
|
|
12
|
+
* another meta-framework is a wart, not a design. @pontive/pontkit-nextjs keeps
|
|
13
|
+
* only its own adapter and imports these primitives.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here imports Vite: the proxy entry is described structurally, so a
|
|
16
|
+
* consumer's Vite version is not part of this package's types.
|
|
17
|
+
*/
|
|
18
|
+
export { DEFAULT_BASE_PATH, DEFAULT_FORWARDED_PATHS, authOrigin, isUnder, normaliseBasePath, } from './target';
|
|
19
|
+
export { viteAuthProxy } from './vite';
|
|
20
|
+
export type { ViteAuthProxyOptions, ViteProxyEntry } from './vite';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a proxied request is sent, and which requests are sent at all.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately not shared with `resolveAuthBaseUrl` in the SDK, which answers a
|
|
5
|
+
* different question. That one resolves what the BROWSER should call and its
|
|
6
|
+
* most useful answer — a bare path like `/__auth` — is meaningless here: a
|
|
7
|
+
* proxy runs on a server, where there is no page origin for a path to be
|
|
8
|
+
* relative to. Sharing them would mean one function with a mode flag, and the
|
|
9
|
+
* mode that is wrong in either direction is silent.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The endpoints an app-level proxy has to carry, and the reason the list is
|
|
13
|
+
* short.
|
|
14
|
+
*
|
|
15
|
+
* These are the requests the browser makes with `fetch` — the auth flow, the
|
|
16
|
+
* token endpoint, userinfo, logout, branding CSS. They are the ones that need
|
|
17
|
+
* to be same-origin, because they are the ones carrying cookies under
|
|
18
|
+
* `SameSite=Lax`.
|
|
19
|
+
*
|
|
20
|
+
* Everything else on the auth server is a top-level navigation — `/authorize`,
|
|
21
|
+
* the hosted sign-in page, `/end_session` as a redirect — and a `Lax` cookie is
|
|
22
|
+
* sent on those already, whatever origin they are served from. Proxying them
|
|
23
|
+
* would not help, and it would break: the authorization server builds those
|
|
24
|
+
* URLs absolute, on its own hostname, so the browser leaves the proxy at the
|
|
25
|
+
* first redirect anyway.
|
|
26
|
+
*
|
|
27
|
+
* The two prefixes are the same pair the dev-server proxy uses (auth-api,
|
|
28
|
+
* `docs/auth-domains-and-token-storage.md` §3). That is not a coincidence to be
|
|
29
|
+
* tidied away: local development against a shared sandbox domain is the same
|
|
30
|
+
* cross-site problem this solves in production, and the two configurations
|
|
31
|
+
* being identical is what makes the local one a rehearsal.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_FORWARDED_PATHS: readonly ["/auth/v1", "/oauth2"];
|
|
34
|
+
/**
|
|
35
|
+
* Where the endpoints hang off the app's own origin.
|
|
36
|
+
*
|
|
37
|
+
* `__`-prefixed by convention — Clerk uses `/__clerk`, Firebase `/__/auth` —
|
|
38
|
+
* because it has to be a path no real route of the app will ever want.
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_BASE_PATH = "/__auth";
|
|
41
|
+
/**
|
|
42
|
+
* The auth server, as an origin.
|
|
43
|
+
*
|
|
44
|
+
* Accepts `tenant.idp.us.pontive.app` or `https://tenant.idp.us.pontive.app`,
|
|
45
|
+
* and nothing with a path: the upstream path comes from the incoming request,
|
|
46
|
+
* and a base path here would be silently prepended to endpoints the auth server
|
|
47
|
+
* does not serve.
|
|
48
|
+
*
|
|
49
|
+
* `http://` is inferred for loopback only, and accepted only there. A proxy is
|
|
50
|
+
* the one hop a refresh token cannot be carried over in the clear — it is the
|
|
51
|
+
* hop that exists precisely so the cookie is first-party — and the failure is
|
|
52
|
+
* invisible from the browser, which sees its own `https://` origin either way.
|
|
53
|
+
*/
|
|
54
|
+
export declare function authOrigin(authHost: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* A base path with a leading slash and no trailing one, so joining is
|
|
57
|
+
* unambiguous.
|
|
58
|
+
*
|
|
59
|
+
* `"/"` normalises to `""`, which mounts the endpoints at the origin root —
|
|
60
|
+
* `/auth/v1/...` and `/oauth2/...` where the app itself is served. That is the
|
|
61
|
+
* shape a Vite dev server has always used, and it stays available because in
|
|
62
|
+
* development the app owns the whole origin and there is nothing to collide
|
|
63
|
+
* with. A deployed app usually does not, which is what the prefix is for.
|
|
64
|
+
*/
|
|
65
|
+
export declare function normaliseBasePath(basePath: string): string;
|
|
66
|
+
/** Whether `pathname` is `prefix` itself or something under it. */
|
|
67
|
+
export declare function isUnder(pathname: string, prefix: string): boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shape of one entry in Vite's `server.proxy`.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than imported from Vite so that nothing which imports
|
|
5
|
+
* this module needs Vite installed, and so the published types do not depend on
|
|
6
|
+
* a particular version of it. It is structural: Vite accepts this object.
|
|
7
|
+
*/
|
|
8
|
+
export interface ViteProxyEntry {
|
|
9
|
+
target: string;
|
|
10
|
+
changeOrigin: boolean;
|
|
11
|
+
rewrite: (path: string) => string;
|
|
12
|
+
}
|
|
13
|
+
export interface ViteAuthProxyOptions {
|
|
14
|
+
authHost: string;
|
|
15
|
+
basePath?: string;
|
|
16
|
+
paths?: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The auth endpoints, proxied through a Vite dev server.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* // vite.config.ts
|
|
23
|
+
* server: { proxy: viteAuthProxy({ authHost: env.VITE_SB_AUTH_DOMAIN }) }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Vite already has a proxy; what it does not have is the knowledge of which
|
|
27
|
+
* paths to carry and what to do with Host, and both of those are easy to get
|
|
28
|
+
* wrong in ways that fail silently. So this is a config generator rather than a
|
|
29
|
+
* request handler — `createAuthProxy` is for runtimes that have no proxy of
|
|
30
|
+
* their own.
|
|
31
|
+
*
|
|
32
|
+
* Worth doing even where the browser would tolerate the cross-site setup,
|
|
33
|
+
* because it is the same topology production runs on: a dev server that proxies
|
|
34
|
+
* is rehearsing the deployment, and a dev server that does not is testing a
|
|
35
|
+
* configuration no user will ever have. It is also the only way an embedded
|
|
36
|
+
* sign-in flow works in Safari, which blocks third-party cookies outright.
|
|
37
|
+
*/
|
|
38
|
+
export declare function viteAuthProxy(options: ViteAuthProxyOptions): Record<string, ViteProxyEntry>;
|
package/dist/proxy.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=["/auth/v1","/oauth2"],a="/__auth";function h(r){const t=(r??"").trim();if(!t)throw new TypeError("authHost is required");const o=/^(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/i.test(t.replace(/^https?:\/\//i,"").split("/")[0]),s=/^https?:\/\//i.test(t)?"":`${o?"http":"https"}://`;let e;try{e=new URL(`${s}${t}`)}catch{throw new TypeError(`authHost "${t}" is not a hostname or an origin`)}if(e.pathname!=="/"||e.search||e.hash)throw new TypeError(`authHost "${t}" must be a bare origin — the path comes from the request being proxied`);if(e.protocol!=="https:"&&!o)throw new TypeError(`authHost "${t}" must be https outside loopback`);return e.origin}function u(r){const t=(r??"").trim().replace(/\/+$/,"");if(t==="")return"";if(!t.startsWith("/"))throw new TypeError(`basePath "${r}" must start with "/"`);return t}function p(r,t){return r===t||r.startsWith(`${t}/`)}function l(r){const t=h(r.authHost),o=u(r.basePath??a),s=r.paths??n,e={};for(const c of s)e[`${o}${c}`]={target:t,changeOrigin:!0,rewrite:i=>o?i.replace(o,""):i};return e}exports.DEFAULT_BASE_PATH=a;exports.DEFAULT_FORWARDED_PATHS=n;exports.authOrigin=h;exports.isUnder=p;exports.normaliseBasePath=u;exports.viteAuthProxy=l;
|
|
2
|
+
//# sourceMappingURL=proxy.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.cjs","sources":["../src/proxy/target.ts","../src/proxy/vite.ts"],"sourcesContent":["/**\n * Where a proxied request is sent, and which requests are sent at all.\n *\n * Deliberately not shared with `resolveAuthBaseUrl` in the SDK, which answers a\n * different question. That one resolves what the BROWSER should call and its\n * most useful answer — a bare path like `/__auth` — is meaningless here: a\n * proxy runs on a server, where there is no page origin for a path to be\n * relative to. Sharing them would mean one function with a mode flag, and the\n * mode that is wrong in either direction is silent.\n */\n\n/**\n * The endpoints an app-level proxy has to carry, and the reason the list is\n * short.\n *\n * These are the requests the browser makes with `fetch` — the auth flow, the\n * token endpoint, userinfo, logout, branding CSS. They are the ones that need\n * to be same-origin, because they are the ones carrying cookies under\n * `SameSite=Lax`.\n *\n * Everything else on the auth server is a top-level navigation — `/authorize`,\n * the hosted sign-in page, `/end_session` as a redirect — and a `Lax` cookie is\n * sent on those already, whatever origin they are served from. Proxying them\n * would not help, and it would break: the authorization server builds those\n * URLs absolute, on its own hostname, so the browser leaves the proxy at the\n * first redirect anyway.\n *\n * The two prefixes are the same pair the dev-server proxy uses (auth-api,\n * `docs/auth-domains-and-token-storage.md` §3). That is not a coincidence to be\n * tidied away: local development against a shared sandbox domain is the same\n * cross-site problem this solves in production, and the two configurations\n * being identical is what makes the local one a rehearsal.\n */\nexport const DEFAULT_FORWARDED_PATHS = [\"/auth/v1\", \"/oauth2\"] as const;\n\n/**\n * Where the endpoints hang off the app's own origin.\n *\n * `__`-prefixed by convention — Clerk uses `/__clerk`, Firebase `/__/auth` —\n * because it has to be a path no real route of the app will ever want.\n */\nexport const DEFAULT_BASE_PATH = \"/__auth\";\n\n/**\n * The auth server, as an origin.\n *\n * Accepts `tenant.idp.us.pontive.app` or `https://tenant.idp.us.pontive.app`,\n * and nothing with a path: the upstream path comes from the incoming request,\n * and a base path here would be silently prepended to endpoints the auth server\n * does not serve.\n *\n * `http://` is inferred for loopback only, and accepted only there. A proxy is\n * the one hop a refresh token cannot be carried over in the clear — it is the\n * hop that exists precisely so the cookie is first-party — and the failure is\n * invisible from the browser, which sees its own `https://` origin either way.\n */\nexport function authOrigin(authHost: string): string {\n const configured = (authHost ?? \"\").trim();\n\n if (!configured) {\n throw new TypeError(\"authHost is required\");\n }\n\n const loopback = /^(localhost|127\\.0\\.0\\.1|\\[::1\\])(:\\d+)?$/i.test(\n configured.replace(/^https?:\\/\\//i, \"\").split(\"/\")[0],\n );\n\n const scheme = /^https?:\\/\\//i.test(configured) ? \"\" : `${loopback ? \"http\" : \"https\"}://`;\n\n let url: URL;\n try {\n url = new URL(`${scheme}${configured}`);\n } catch {\n throw new TypeError(`authHost \"${configured}\" is not a hostname or an origin`);\n }\n\n if (url.pathname !== \"/\" || url.search || url.hash) {\n throw new TypeError(\n `authHost \"${configured}\" must be a bare origin — the path comes from the request being proxied`,\n );\n }\n\n if (url.protocol !== \"https:\" && !loopback) {\n throw new TypeError(`authHost \"${configured}\" must be https outside loopback`);\n }\n\n return url.origin;\n}\n\n/**\n * A base path with a leading slash and no trailing one, so joining is\n * unambiguous.\n *\n * `\"/\"` normalises to `\"\"`, which mounts the endpoints at the origin root —\n * `/auth/v1/...` and `/oauth2/...` where the app itself is served. That is the\n * shape a Vite dev server has always used, and it stays available because in\n * development the app owns the whole origin and there is nothing to collide\n * with. A deployed app usually does not, which is what the prefix is for.\n */\nexport function normaliseBasePath(basePath: string): string {\n const trimmed = (basePath ?? \"\").trim().replace(/\\/+$/, \"\");\n\n if (trimmed === \"\") {\n return \"\";\n }\n\n if (!trimmed.startsWith(\"/\")) {\n throw new TypeError(`basePath \"${basePath}\" must start with \"/\"`);\n }\n\n return trimmed;\n}\n\n/** Whether `pathname` is `prefix` itself or something under it. */\nexport function isUnder(pathname: string, prefix: string): boolean {\n return pathname === prefix || pathname.startsWith(`${prefix}/`);\n}\n","import {\n DEFAULT_BASE_PATH,\n DEFAULT_FORWARDED_PATHS,\n authOrigin,\n normaliseBasePath,\n} from \"./target\";\n\n/**\n * The shape of one entry in Vite's `server.proxy`.\n *\n * Declared here rather than imported from Vite so that nothing which imports\n * this module needs Vite installed, and so the published types do not depend on\n * a particular version of it. It is structural: Vite accepts this object.\n */\nexport interface ViteProxyEntry {\n target: string;\n changeOrigin: boolean;\n rewrite: (path: string) => string;\n}\n\nexport interface ViteAuthProxyOptions {\n authHost: string;\n basePath?: string;\n paths?: readonly string[];\n}\n\n/**\n * The auth endpoints, proxied through a Vite dev server.\n *\n * ```ts\n * // vite.config.ts\n * server: { proxy: viteAuthProxy({ authHost: env.VITE_SB_AUTH_DOMAIN }) }\n * ```\n *\n * Vite already has a proxy; what it does not have is the knowledge of which\n * paths to carry and what to do with Host, and both of those are easy to get\n * wrong in ways that fail silently. So this is a config generator rather than a\n * request handler — `createAuthProxy` is for runtimes that have no proxy of\n * their own.\n *\n * Worth doing even where the browser would tolerate the cross-site setup,\n * because it is the same topology production runs on: a dev server that proxies\n * is rehearsing the deployment, and a dev server that does not is testing a\n * configuration no user will ever have. It is also the only way an embedded\n * sign-in flow works in Safari, which blocks third-party cookies outright.\n */\nexport function viteAuthProxy(\n options: ViteAuthProxyOptions,\n): Record<string, ViteProxyEntry> {\n const target = authOrigin(options.authHost);\n const basePath = normaliseBasePath(options.basePath ?? DEFAULT_BASE_PATH);\n const paths = options.paths ?? DEFAULT_FORWARDED_PATHS;\n\n const proxy: Record<string, ViteProxyEntry> = {};\n\n for (const prefix of paths) {\n proxy[`${basePath}${prefix}`] = {\n target,\n // The single most important line, and the one a hand-written config\n // leaves out. Without it the auth server is asked to answer as\n // `localhost:5173` — a Host it has no project for — and the reply is a\n // CORS refusal and an empty issuer rather than anything that says so.\n changeOrigin: true,\n // Only the base path comes off. The prefix below it is the path the auth\n // server actually serves.\n rewrite: (path: string) => (basePath ? path.replace(basePath, \"\") : path),\n };\n }\n\n return proxy;\n}\n"],"names":["DEFAULT_FORWARDED_PATHS","DEFAULT_BASE_PATH","authOrigin","authHost","configured","loopback","scheme","url","normaliseBasePath","basePath","trimmed","isUnder","pathname","prefix","viteAuthProxy","options","target","paths","proxy","path"],"mappings":"gFAiCO,MAAMA,EAA0B,CAAC,WAAY,SAAS,EAQhDC,EAAoB,UAe1B,SAASC,EAAWC,EAA0B,CACnD,MAAMC,GAAcD,GAAY,IAAI,KAAA,EAEpC,GAAI,CAACC,EACH,MAAM,IAAI,UAAU,sBAAsB,EAG5C,MAAMC,EAAW,6CAA6C,KAC5DD,EAAW,QAAQ,gBAAiB,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,CAAA,EAGhDE,EAAS,gBAAgB,KAAKF,CAAU,EAAI,GAAK,GAAGC,EAAW,OAAS,OAAO,MAErF,IAAIE,EACJ,GAAI,CACFA,EAAM,IAAI,IAAI,GAAGD,CAAM,GAAGF,CAAU,EAAE,CACxC,MAAQ,CACN,MAAM,IAAI,UAAU,aAAaA,CAAU,kCAAkC,CAC/E,CAEA,GAAIG,EAAI,WAAa,KAAOA,EAAI,QAAUA,EAAI,KAC5C,MAAM,IAAI,UACR,aAAaH,CAAU,yEAAA,EAI3B,GAAIG,EAAI,WAAa,UAAY,CAACF,EAChC,MAAM,IAAI,UAAU,aAAaD,CAAU,kCAAkC,EAG/E,OAAOG,EAAI,MACb,CAYO,SAASC,EAAkBC,EAA0B,CAC1D,MAAMC,GAAWD,GAAY,IAAI,OAAO,QAAQ,OAAQ,EAAE,EAE1D,GAAIC,IAAY,GACd,MAAO,GAGT,GAAI,CAACA,EAAQ,WAAW,GAAG,EACzB,MAAM,IAAI,UAAU,aAAaD,CAAQ,uBAAuB,EAGlE,OAAOC,CACT,CAGO,SAASC,EAAQC,EAAkBC,EAAyB,CACjE,OAAOD,IAAaC,GAAUD,EAAS,WAAW,GAAGC,CAAM,GAAG,CAChE,CCtEO,SAASC,EACdC,EACgC,CAChC,MAAMC,EAASd,EAAWa,EAAQ,QAAQ,EACpCN,EAAWD,EAAkBO,EAAQ,UAAYd,CAAiB,EAClEgB,EAAQF,EAAQ,OAASf,EAEzBkB,EAAwC,CAAA,EAE9C,UAAWL,KAAUI,EACnBC,EAAM,GAAGT,CAAQ,GAAGI,CAAM,EAAE,EAAI,CAC9B,OAAAG,EAKA,aAAc,GAGd,QAAUG,GAAkBV,EAAWU,EAAK,QAAQV,EAAU,EAAE,EAAIU,CAAA,EAIxE,OAAOD,CACT"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const i = ["/auth/v1", "/oauth2"], a = "/__auth";
|
|
2
|
+
function c(r) {
|
|
3
|
+
const t = (r ?? "").trim();
|
|
4
|
+
if (!t)
|
|
5
|
+
throw new TypeError("authHost is required");
|
|
6
|
+
const o = /^(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/i.test(
|
|
7
|
+
t.replace(/^https?:\/\//i, "").split("/")[0]
|
|
8
|
+
), s = /^https?:\/\//i.test(t) ? "" : `${o ? "http" : "https"}://`;
|
|
9
|
+
let e;
|
|
10
|
+
try {
|
|
11
|
+
e = new URL(`${s}${t}`);
|
|
12
|
+
} catch {
|
|
13
|
+
throw new TypeError(`authHost "${t}" is not a hostname or an origin`);
|
|
14
|
+
}
|
|
15
|
+
if (e.pathname !== "/" || e.search || e.hash)
|
|
16
|
+
throw new TypeError(
|
|
17
|
+
`authHost "${t}" must be a bare origin — the path comes from the request being proxied`
|
|
18
|
+
);
|
|
19
|
+
if (e.protocol !== "https:" && !o)
|
|
20
|
+
throw new TypeError(`authHost "${t}" must be https outside loopback`);
|
|
21
|
+
return e.origin;
|
|
22
|
+
}
|
|
23
|
+
function u(r) {
|
|
24
|
+
const t = (r ?? "").trim().replace(/\/+$/, "");
|
|
25
|
+
if (t === "")
|
|
26
|
+
return "";
|
|
27
|
+
if (!t.startsWith("/"))
|
|
28
|
+
throw new TypeError(`basePath "${r}" must start with "/"`);
|
|
29
|
+
return t;
|
|
30
|
+
}
|
|
31
|
+
function p(r, t) {
|
|
32
|
+
return r === t || r.startsWith(`${t}/`);
|
|
33
|
+
}
|
|
34
|
+
function f(r) {
|
|
35
|
+
const t = c(r.authHost), o = u(r.basePath ?? a), s = r.paths ?? i, e = {};
|
|
36
|
+
for (const h of s)
|
|
37
|
+
e[`${o}${h}`] = {
|
|
38
|
+
target: t,
|
|
39
|
+
// The single most important line, and the one a hand-written config
|
|
40
|
+
// leaves out. Without it the auth server is asked to answer as
|
|
41
|
+
// `localhost:5173` — a Host it has no project for — and the reply is a
|
|
42
|
+
// CORS refusal and an empty issuer rather than anything that says so.
|
|
43
|
+
changeOrigin: !0,
|
|
44
|
+
// Only the base path comes off. The prefix below it is the path the auth
|
|
45
|
+
// server actually serves.
|
|
46
|
+
rewrite: (n) => o ? n.replace(o, "") : n
|
|
47
|
+
};
|
|
48
|
+
return e;
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
a as DEFAULT_BASE_PATH,
|
|
52
|
+
i as DEFAULT_FORWARDED_PATHS,
|
|
53
|
+
c as authOrigin,
|
|
54
|
+
p as isUnder,
|
|
55
|
+
u as normaliseBasePath,
|
|
56
|
+
f as viteAuthProxy
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sources":["../src/proxy/target.ts","../src/proxy/vite.ts"],"sourcesContent":["/**\n * Where a proxied request is sent, and which requests are sent at all.\n *\n * Deliberately not shared with `resolveAuthBaseUrl` in the SDK, which answers a\n * different question. That one resolves what the BROWSER should call and its\n * most useful answer — a bare path like `/__auth` — is meaningless here: a\n * proxy runs on a server, where there is no page origin for a path to be\n * relative to. Sharing them would mean one function with a mode flag, and the\n * mode that is wrong in either direction is silent.\n */\n\n/**\n * The endpoints an app-level proxy has to carry, and the reason the list is\n * short.\n *\n * These are the requests the browser makes with `fetch` — the auth flow, the\n * token endpoint, userinfo, logout, branding CSS. They are the ones that need\n * to be same-origin, because they are the ones carrying cookies under\n * `SameSite=Lax`.\n *\n * Everything else on the auth server is a top-level navigation — `/authorize`,\n * the hosted sign-in page, `/end_session` as a redirect — and a `Lax` cookie is\n * sent on those already, whatever origin they are served from. Proxying them\n * would not help, and it would break: the authorization server builds those\n * URLs absolute, on its own hostname, so the browser leaves the proxy at the\n * first redirect anyway.\n *\n * The two prefixes are the same pair the dev-server proxy uses (auth-api,\n * `docs/auth-domains-and-token-storage.md` §3). That is not a coincidence to be\n * tidied away: local development against a shared sandbox domain is the same\n * cross-site problem this solves in production, and the two configurations\n * being identical is what makes the local one a rehearsal.\n */\nexport const DEFAULT_FORWARDED_PATHS = [\"/auth/v1\", \"/oauth2\"] as const;\n\n/**\n * Where the endpoints hang off the app's own origin.\n *\n * `__`-prefixed by convention — Clerk uses `/__clerk`, Firebase `/__/auth` —\n * because it has to be a path no real route of the app will ever want.\n */\nexport const DEFAULT_BASE_PATH = \"/__auth\";\n\n/**\n * The auth server, as an origin.\n *\n * Accepts `tenant.idp.us.pontive.app` or `https://tenant.idp.us.pontive.app`,\n * and nothing with a path: the upstream path comes from the incoming request,\n * and a base path here would be silently prepended to endpoints the auth server\n * does not serve.\n *\n * `http://` is inferred for loopback only, and accepted only there. A proxy is\n * the one hop a refresh token cannot be carried over in the clear — it is the\n * hop that exists precisely so the cookie is first-party — and the failure is\n * invisible from the browser, which sees its own `https://` origin either way.\n */\nexport function authOrigin(authHost: string): string {\n const configured = (authHost ?? \"\").trim();\n\n if (!configured) {\n throw new TypeError(\"authHost is required\");\n }\n\n const loopback = /^(localhost|127\\.0\\.0\\.1|\\[::1\\])(:\\d+)?$/i.test(\n configured.replace(/^https?:\\/\\//i, \"\").split(\"/\")[0],\n );\n\n const scheme = /^https?:\\/\\//i.test(configured) ? \"\" : `${loopback ? \"http\" : \"https\"}://`;\n\n let url: URL;\n try {\n url = new URL(`${scheme}${configured}`);\n } catch {\n throw new TypeError(`authHost \"${configured}\" is not a hostname or an origin`);\n }\n\n if (url.pathname !== \"/\" || url.search || url.hash) {\n throw new TypeError(\n `authHost \"${configured}\" must be a bare origin — the path comes from the request being proxied`,\n );\n }\n\n if (url.protocol !== \"https:\" && !loopback) {\n throw new TypeError(`authHost \"${configured}\" must be https outside loopback`);\n }\n\n return url.origin;\n}\n\n/**\n * A base path with a leading slash and no trailing one, so joining is\n * unambiguous.\n *\n * `\"/\"` normalises to `\"\"`, which mounts the endpoints at the origin root —\n * `/auth/v1/...` and `/oauth2/...` where the app itself is served. That is the\n * shape a Vite dev server has always used, and it stays available because in\n * development the app owns the whole origin and there is nothing to collide\n * with. A deployed app usually does not, which is what the prefix is for.\n */\nexport function normaliseBasePath(basePath: string): string {\n const trimmed = (basePath ?? \"\").trim().replace(/\\/+$/, \"\");\n\n if (trimmed === \"\") {\n return \"\";\n }\n\n if (!trimmed.startsWith(\"/\")) {\n throw new TypeError(`basePath \"${basePath}\" must start with \"/\"`);\n }\n\n return trimmed;\n}\n\n/** Whether `pathname` is `prefix` itself or something under it. */\nexport function isUnder(pathname: string, prefix: string): boolean {\n return pathname === prefix || pathname.startsWith(`${prefix}/`);\n}\n","import {\n DEFAULT_BASE_PATH,\n DEFAULT_FORWARDED_PATHS,\n authOrigin,\n normaliseBasePath,\n} from \"./target\";\n\n/**\n * The shape of one entry in Vite's `server.proxy`.\n *\n * Declared here rather than imported from Vite so that nothing which imports\n * this module needs Vite installed, and so the published types do not depend on\n * a particular version of it. It is structural: Vite accepts this object.\n */\nexport interface ViteProxyEntry {\n target: string;\n changeOrigin: boolean;\n rewrite: (path: string) => string;\n}\n\nexport interface ViteAuthProxyOptions {\n authHost: string;\n basePath?: string;\n paths?: readonly string[];\n}\n\n/**\n * The auth endpoints, proxied through a Vite dev server.\n *\n * ```ts\n * // vite.config.ts\n * server: { proxy: viteAuthProxy({ authHost: env.VITE_SB_AUTH_DOMAIN }) }\n * ```\n *\n * Vite already has a proxy; what it does not have is the knowledge of which\n * paths to carry and what to do with Host, and both of those are easy to get\n * wrong in ways that fail silently. So this is a config generator rather than a\n * request handler — `createAuthProxy` is for runtimes that have no proxy of\n * their own.\n *\n * Worth doing even where the browser would tolerate the cross-site setup,\n * because it is the same topology production runs on: a dev server that proxies\n * is rehearsing the deployment, and a dev server that does not is testing a\n * configuration no user will ever have. It is also the only way an embedded\n * sign-in flow works in Safari, which blocks third-party cookies outright.\n */\nexport function viteAuthProxy(\n options: ViteAuthProxyOptions,\n): Record<string, ViteProxyEntry> {\n const target = authOrigin(options.authHost);\n const basePath = normaliseBasePath(options.basePath ?? DEFAULT_BASE_PATH);\n const paths = options.paths ?? DEFAULT_FORWARDED_PATHS;\n\n const proxy: Record<string, ViteProxyEntry> = {};\n\n for (const prefix of paths) {\n proxy[`${basePath}${prefix}`] = {\n target,\n // The single most important line, and the one a hand-written config\n // leaves out. Without it the auth server is asked to answer as\n // `localhost:5173` — a Host it has no project for — and the reply is a\n // CORS refusal and an empty issuer rather than anything that says so.\n changeOrigin: true,\n // Only the base path comes off. The prefix below it is the path the auth\n // server actually serves.\n rewrite: (path: string) => (basePath ? path.replace(basePath, \"\") : path),\n };\n }\n\n return proxy;\n}\n"],"names":["DEFAULT_FORWARDED_PATHS","DEFAULT_BASE_PATH","authOrigin","authHost","configured","loopback","scheme","url","normaliseBasePath","basePath","trimmed","isUnder","pathname","prefix","viteAuthProxy","options","target","paths","proxy","path"],"mappings":"AAiCO,MAAMA,IAA0B,CAAC,YAAY,SAAS,GAQhDC,IAAoB;AAe1B,SAASC,EAAWC,GAA0B;AACnD,QAAMC,KAAcD,KAAY,IAAI,KAAA;AAEpC,MAAI,CAACC;AACH,UAAM,IAAI,UAAU,sBAAsB;AAG5C,QAAMC,IAAW,6CAA6C;AAAA,IAC5DD,EAAW,QAAQ,iBAAiB,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EAAA,GAGhDE,IAAS,gBAAgB,KAAKF,CAAU,IAAI,KAAK,GAAGC,IAAW,SAAS,OAAO;AAErF,MAAIE;AACJ,MAAI;AACF,IAAAA,IAAM,IAAI,IAAI,GAAGD,CAAM,GAAGF,CAAU,EAAE;AAAA,EACxC,QAAQ;AACN,UAAM,IAAI,UAAU,aAAaA,CAAU,kCAAkC;AAAA,EAC/E;AAEA,MAAIG,EAAI,aAAa,OAAOA,EAAI,UAAUA,EAAI;AAC5C,UAAM,IAAI;AAAA,MACR,aAAaH,CAAU;AAAA,IAAA;AAI3B,MAAIG,EAAI,aAAa,YAAY,CAACF;AAChC,UAAM,IAAI,UAAU,aAAaD,CAAU,kCAAkC;AAG/E,SAAOG,EAAI;AACb;AAYO,SAASC,EAAkBC,GAA0B;AAC1D,QAAMC,KAAWD,KAAY,IAAI,OAAO,QAAQ,QAAQ,EAAE;AAE1D,MAAIC,MAAY;AACd,WAAO;AAGT,MAAI,CAACA,EAAQ,WAAW,GAAG;AACzB,UAAM,IAAI,UAAU,aAAaD,CAAQ,uBAAuB;AAGlE,SAAOC;AACT;AAGO,SAASC,EAAQC,GAAkBC,GAAyB;AACjE,SAAOD,MAAaC,KAAUD,EAAS,WAAW,GAAGC,CAAM,GAAG;AAChE;ACtEO,SAASC,EACdC,GACgC;AAChC,QAAMC,IAASd,EAAWa,EAAQ,QAAQ,GACpCN,IAAWD,EAAkBO,EAAQ,YAAYd,CAAiB,GAClEgB,IAAQF,EAAQ,SAASf,GAEzBkB,IAAwC,CAAA;AAE9C,aAAWL,KAAUI;AACnB,IAAAC,EAAM,GAAGT,CAAQ,GAAGI,CAAM,EAAE,IAAI;AAAA,MAC9B,QAAAG;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,cAAc;AAAA;AAAA;AAAA,MAGd,SAAS,CAACG,MAAkBV,IAAWU,EAAK,QAAQV,GAAU,EAAE,IAAIU;AAAA,IAAA;AAIxE,SAAOD;AACT;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pontive/pontkit-loader",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Loads @pontive/pontkit-core from the CDN at the release the platform decides.",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./proxy": {
|
|
17
|
+
"types": "./dist/proxy/index.d.ts",
|
|
18
|
+
"import": "./dist/proxy.js",
|
|
19
|
+
"require": "./dist/proxy.cjs"
|
|
15
20
|
}
|
|
16
21
|
},
|
|
17
22
|
"files": [
|