better-convex-nuxt 0.2.10 → 0.2.11

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/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.2.10",
7
+ "version": "0.2.11",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"eef8f4c6-ec70-441c-804f-295e75e27afa",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771233813088,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"4441cf51-019c-4d8d-b387-2c168e8d08e3",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1772107968698,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"eef8f4c6-ec70-441c-804f-295e75e27afa",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771233813089,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"4441cf51-019c-4d8d-b387-2c168e8d08e3",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1772107968699,false]</script></body></html>
@@ -1 +1 @@
1
- {"id":"eef8f4c6-ec70-441c-804f-295e75e27afa","timestamp":1771233810781}
1
+ {"id":"4441cf51-019c-4d8d-b387-2c168e8d08e3","timestamp":1772107966161}
@@ -0,0 +1 @@
1
+ {"id":"4441cf51-019c-4d8d-b387-2c168e8d08e3","timestamp":1772107966161,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"eef8f4c6-ec70-441c-804f-295e75e27afa",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771233813089,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"4441cf51-019c-4d8d-b387-2c168e8d08e3",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1772107968699,false]</script></body></html>
@@ -8,6 +8,7 @@ import {
8
8
  send
9
9
  } from "h3";
10
10
  import { useRuntimeConfig } from "#imports";
11
+ import { fetchWithCanonicalRedirects } from "./redirect-utils.js";
11
12
  async function recordAuthProxyRequestInDev(request) {
12
13
  if (!import.meta.dev) return;
13
14
  const { recordAuthProxyRequest } = await import("../../../devtools/auth-proxy-registry.js");
@@ -96,12 +97,11 @@ export default defineEventHandler(async (event) => {
96
97
  if (["POST", "PUT", "PATCH"].includes(event.method)) {
97
98
  body = await readRawBody(event, "utf8") || void 0;
98
99
  }
99
- const response = await fetch(target, {
100
+ const response = await fetchWithCanonicalRedirects({
101
+ target,
100
102
  method: event.method,
101
103
  headers: forwardHeaders,
102
- body,
103
- redirect: "manual"
104
- // Don't follow redirects - let browser handle them
104
+ body
105
105
  });
106
106
  if (import.meta.dev) {
107
107
  await recordAuthProxyRequestInDev({
@@ -0,0 +1,18 @@
1
+ export declare function normalizePathname(pathname: string): string;
2
+ /**
3
+ * Follow only canonical redirects (e.g. apex -> www) where path + query stay identical.
4
+ * This avoids leaking auth XHR/fetch requests to the browser as cross-origin redirects,
5
+ * while still preserving intentional redirects (like OAuth provider redirects).
6
+ */
7
+ export declare function getCanonicalRedirectTarget(currentTarget: string, locationHeader: string | null): string | null;
8
+ type FetchLike = typeof fetch;
9
+ interface FetchWithCanonicalRedirectsOptions {
10
+ target: string;
11
+ method: string;
12
+ headers: Record<string, string>;
13
+ body?: string;
14
+ maxRedirects?: number;
15
+ fetchImpl?: FetchLike;
16
+ }
17
+ export declare function fetchWithCanonicalRedirects({ target, method, headers, body, maxRedirects, fetchImpl, }: FetchWithCanonicalRedirectsOptions): Promise<Response>;
18
+ export {};
@@ -0,0 +1,57 @@
1
+ export function normalizePathname(pathname) {
2
+ const normalized = pathname.replace(/\/+$/, "");
3
+ return normalized.length > 0 ? normalized : "/";
4
+ }
5
+ export function getCanonicalRedirectTarget(currentTarget, locationHeader) {
6
+ if (!locationHeader) {
7
+ return null;
8
+ }
9
+ try {
10
+ const fromUrl = new URL(currentTarget);
11
+ const toUrl = new URL(locationHeader, fromUrl);
12
+ if (!["http:", "https:"].includes(toUrl.protocol)) {
13
+ return null;
14
+ }
15
+ const samePath = normalizePathname(toUrl.pathname) === normalizePathname(fromUrl.pathname);
16
+ const sameQuery = toUrl.search === fromUrl.search;
17
+ const isCrossOrigin = toUrl.origin !== fromUrl.origin;
18
+ if (samePath && sameQuery && isCrossOrigin) {
19
+ return toUrl.toString();
20
+ }
21
+ } catch {
22
+ return null;
23
+ }
24
+ return null;
25
+ }
26
+ export async function fetchWithCanonicalRedirects({
27
+ target,
28
+ method,
29
+ headers,
30
+ body,
31
+ maxRedirects = 2,
32
+ fetchImpl = fetch
33
+ }) {
34
+ let resolvedTarget = target;
35
+ let response = await fetchImpl(resolvedTarget, {
36
+ method,
37
+ headers,
38
+ body,
39
+ redirect: "manual"
40
+ });
41
+ let canonicalRedirectsFollowed = 0;
42
+ while (response.status >= 300 && response.status < 400 && canonicalRedirectsFollowed < maxRedirects) {
43
+ const canonicalTarget = getCanonicalRedirectTarget(resolvedTarget, response.headers.get("location"));
44
+ if (!canonicalTarget) {
45
+ break;
46
+ }
47
+ resolvedTarget = canonicalTarget;
48
+ canonicalRedirectsFollowed += 1;
49
+ response = await fetchImpl(resolvedTarget, {
50
+ method,
51
+ headers,
52
+ body,
53
+ redirect: "manual"
54
+ });
55
+ }
56
+ return response;
57
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-convex-nuxt",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Full-featured Convex integration for Nuxt with SSR, real-time subscriptions, authentication, and permissions",
5
5
  "keywords": [
6
6
  "authentication",
@@ -1 +0,0 @@
1
- {"id":"eef8f4c6-ec70-441c-804f-295e75e27afa","timestamp":1771233810781,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}