better-convex-nuxt 0.2.9 → 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.9",
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:"df213a49-93a4-44f1-863e-5dc7de19c884",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771229435100,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:"df213a49-93a4-44f1-863e-5dc7de19c884",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771229435101,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":"df213a49-93a4-44f1-863e-5dc7de19c884","timestamp":1771229432599}
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:"df213a49-93a4-44f1-863e-5dc7de19c884",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771229435101,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,7 +8,12 @@ import {
8
8
  send
9
9
  } from "h3";
10
10
  import { useRuntimeConfig } from "#imports";
11
- import { recordAuthProxyRequest } from "../../../devtools/auth-proxy-registry.js";
11
+ import { fetchWithCanonicalRedirects } from "./redirect-utils.js";
12
+ async function recordAuthProxyRequestInDev(request) {
13
+ if (!import.meta.dev) return;
14
+ const { recordAuthProxyRequest } = await import("../../../devtools/auth-proxy-registry.js");
15
+ recordAuthProxyRequest(request);
16
+ }
12
17
  function isOriginAllowed(origin, requestHost, trustedOrigins) {
13
18
  try {
14
19
  const originUrl = new URL(origin);
@@ -92,15 +97,14 @@ export default defineEventHandler(async (event) => {
92
97
  if (["POST", "PUT", "PATCH"].includes(event.method)) {
93
98
  body = await readRawBody(event, "utf8") || void 0;
94
99
  }
95
- const response = await fetch(target, {
100
+ const response = await fetchWithCanonicalRedirects({
101
+ target,
96
102
  method: event.method,
97
103
  headers: forwardHeaders,
98
- body,
99
- redirect: "manual"
100
- // Don't follow redirects - let browser handle them
104
+ body
101
105
  });
102
106
  if (import.meta.dev) {
103
- recordAuthProxyRequest({
107
+ await recordAuthProxyRequestInDev({
104
108
  id: requestId,
105
109
  path,
106
110
  method: event.method,
@@ -129,7 +133,7 @@ export default defineEventHandler(async (event) => {
129
133
  return send(event, responseBody);
130
134
  } catch (error) {
131
135
  if (import.meta.dev) {
132
- recordAuthProxyRequest({
136
+ await recordAuthProxyRequestInDev({
133
137
  id: requestId,
134
138
  path,
135
139
  method: event.method,
@@ -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.9",
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":"df213a49-93a4-44f1-863e-5dc7de19c884","timestamp":1771229432599,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}