nuxt-convex-module 0.0.0 → 0.9.0
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/LICENSE +1 -1
- package/README.md +51 -157
- package/dist/chunks/index.mjs +1 -1
- package/dist/devtools-client/200.html +1 -1
- package/dist/devtools-client/404.html +1 -1
- package/dist/devtools-client/_nuxt/71bSMC-_.js +2 -0
- package/dist/devtools-client/_nuxt/{CZbAGcNC.js → BAaUCl_m.js} +1 -1
- package/dist/devtools-client/_nuxt/BhmjAr2Q.js +1 -0
- package/dist/devtools-client/_nuxt/BmBQNDID.js +1 -0
- package/dist/devtools-client/_nuxt/C6YdTgGl.js +2 -0
- package/dist/devtools-client/_nuxt/{DPWXUmcI.js → CKakiU_h.js} +1 -1
- package/dist/devtools-client/_nuxt/Cm7YqZQ-.js +1 -0
- package/dist/devtools-client/_nuxt/{dy_xXcv9.js → DQmVr-EY.js} +1 -1
- package/dist/devtools-client/_nuxt/D_Rij7MD.js +1 -0
- package/dist/devtools-client/_nuxt/EZ4-8Xzm.js +3 -0
- package/dist/devtools-client/_nuxt/Kba0XpjH.js +1 -0
- package/dist/devtools-client/_nuxt/OVE7s6ty.js +1 -0
- package/dist/devtools-client/_nuxt/_Lf3mfPR.js +1 -0
- package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
- package/dist/devtools-client/_nuxt/builds/meta/7dfea6da-3eca-4a35-ba06-5e069ac7e8df.json +1 -0
- package/dist/devtools-client/_nuxt/entry.HF8C6P11.css +1 -0
- package/dist/devtools-client/_nuxt/error-404.CLlwiMp-.css +1 -0
- package/dist/devtools-client/_nuxt/error-500.Bxr6fpDU.css +1 -0
- package/dist/devtools-client/_nuxt/queries.DNBUjWk2.css +1 -0
- package/dist/devtools-client/_nuxt/vZZlEX5A.js +1 -0
- package/dist/devtools-client/auth/index.html +1 -1
- package/dist/devtools-client/index.html +1 -1
- package/dist/devtools-client/logs/index.html +1 -1
- package/dist/devtools-client/queries/index.html +1 -1
- package/dist/module.d.mts +129 -0
- package/dist/module.json +2 -2
- package/dist/module.mjs +576 -0
- package/dist/runtime/auth0/vue/index.d.ts +3 -3
- package/dist/runtime/better-auth/nuxt/middleware.d.ts +4 -2
- package/dist/runtime/better-auth/nuxt/middleware.js +15 -12
- package/dist/runtime/better-auth/nuxt/proxy.d.ts +18 -2
- package/dist/runtime/better-auth/nuxt/proxy.js +7 -7
- package/dist/runtime/better-auth/nuxt/server.d.ts +6 -6
- package/dist/runtime/better-auth/nuxt/server.js +15 -0
- package/dist/runtime/better-auth/vue/auth-boundary.d.ts +3 -1
- package/dist/runtime/better-auth/vue/client.d.ts +1 -1
- package/dist/runtime/better-auth/vue/cross-domain.d.ts +4 -5
- package/dist/runtime/better-auth/vue/cross-domain.js +11 -4
- package/dist/runtime/better-auth/vue/hydration.d.ts +1 -1
- package/dist/runtime/better-auth/vue/index.d.ts +2 -1
- package/dist/runtime/better-auth/vue/index.js +2 -1
- package/dist/runtime/better-auth/vue/plugin.client.d.ts +1 -5
- package/dist/runtime/better-auth/vue/plugin.client.js +6 -10
- package/dist/runtime/better-auth/vue/plugin.server.d.ts +5 -16
- package/dist/runtime/better-auth/vue/plugin.server.js +3 -6
- package/dist/runtime/better-auth/vue/redirect.d.ts +33 -0
- package/dist/runtime/better-auth/vue/redirect.js +14 -0
- package/dist/runtime/better-auth/vue/{use-auth.d.ts → use-better-auth.d.ts} +31 -11
- package/dist/runtime/better-auth/vue/{use-auth.js → use-better-auth.js} +4 -3
- package/dist/runtime/clerk/vue/index.d.ts +4 -4
- package/dist/runtime/devtools/bridge.js +1 -1
- package/dist/runtime/nuxt/app.d.ts +48 -0
- package/dist/runtime/nuxt/app.js +8 -0
- package/dist/runtime/nuxt/composables/use-async-paginated-query.d.ts +88 -0
- package/dist/runtime/nuxt/composables/use-async-paginated-query.js +90 -0
- package/dist/runtime/nuxt/composables/use-async-query.d.ts +7 -16
- package/dist/runtime/nuxt/composables/use-async-query.js +14 -9
- package/dist/runtime/nuxt/config.d.ts +11 -0
- package/dist/runtime/nuxt/config.js +1 -0
- package/dist/runtime/nuxt/csp.d.ts +44 -0
- package/dist/runtime/nuxt/csp.js +46 -0
- package/dist/runtime/nuxt/index.d.ts +8 -8
- package/dist/runtime/nuxt/security.d.ts +33 -0
- package/dist/runtime/nuxt/security.js +14 -0
- package/dist/runtime/polar/vue/components.d.ts +8 -1
- package/dist/runtime/polar/vue/components.js +3 -3
- package/dist/runtime/vue/auth/index.d.ts +4 -4
- package/dist/runtime/vue/auth/index.js +6 -2
- package/dist/runtime/vue/client.d.ts +5 -55
- package/dist/runtime/vue/client.js +4 -0
- package/dist/runtime/vue/components/convex-image.d.ts +50 -0
- package/dist/runtime/vue/components/convex-image.js +21 -0
- package/dist/runtime/vue/composables/use-connection-state.d.ts +1 -0
- package/dist/runtime/vue/composables/use-paginated-query.d.ts +5 -1
- package/dist/runtime/vue/composables/use-paginated-query.js +2 -2
- package/dist/runtime/vue/composables/use-query.d.ts +2 -0
- package/dist/runtime/vue/composables/use-subscription.d.ts +1 -15
- package/dist/runtime/vue/composables/use-upload-queue.d.ts +2 -3
- package/dist/runtime/vue/hydration.d.ts +3 -24
- package/dist/runtime/vue/index.d.ts +2 -2
- package/dist/runtime/vue/index.js +1 -0
- package/dist/runtime/vue/plugin.js +1 -1
- package/dist/runtime/vue/provide.d.ts +5 -5
- package/dist/types.d.mts +3 -0
- package/package.json +103 -56
- package/dist/devtools-client/_nuxt/B29GGJ5n.js +0 -1
- package/dist/devtools-client/_nuxt/BSDEpQet.js +0 -1
- package/dist/devtools-client/_nuxt/BY23OQOo.js +0 -1
- package/dist/devtools-client/_nuxt/BZYRaL-G.js +0 -1
- package/dist/devtools-client/_nuxt/Byw6FxnC.js +0 -1
- package/dist/devtools-client/_nuxt/CJJ_hcZN.js +0 -1
- package/dist/devtools-client/_nuxt/CS6WMFOx.js +0 -2
- package/dist/devtools-client/_nuxt/Cr6_aklh.js +0 -2
- package/dist/devtools-client/_nuxt/DNfpyBVU.js +0 -3
- package/dist/devtools-client/_nuxt/builds/meta/a7708498-bd09-4de2-b5ab-19b380293c77.json +0 -1
- package/dist/devtools-client/_nuxt/entry.DbTJhkHT.css +0 -1
- package/dist/devtools-client/_nuxt/error-404.CwGGO2Kz.css +0 -1
- package/dist/devtools-client/_nuxt/error-500.8ZJqCQm8.css +0 -1
- package/dist/devtools-client/_nuxt/ncgEdbEt.js +0 -1
- package/dist/devtools-client/_nuxt/queries.CE_dtt9-.css +0 -1
- package/dist/module.d.ts +0 -189
- package/dist/module.js +0 -489
- package/dist/types.d.ts +0 -3
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import { useLogger, updateTemplates, defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addServerPlugin, addPluginTemplate, addTypeTemplate, addImports, addServerImports, addComponent, addServerHandler, extendRouteRules, addRouteMiddleware } from '@nuxt/kit';
|
|
2
|
+
import { join, isAbsolute } from 'node:path';
|
|
3
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
|
|
6
|
+
function resolveIntegrationState(explicit, installed, declared = installed) {
|
|
7
|
+
if (explicit === false) return { enabled: false, missingPackage: false };
|
|
8
|
+
if (explicit === void 0) return { enabled: installed && declared, missingPackage: false };
|
|
9
|
+
return installed ? { enabled: true, missingPackage: false } : { enabled: false, missingPackage: true };
|
|
10
|
+
}
|
|
11
|
+
function isDeclaredDependency(id, rootDir) {
|
|
12
|
+
try {
|
|
13
|
+
const manifest = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"));
|
|
14
|
+
return ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"].some((field) => typeof manifest[field] === "object" && manifest[field] !== null && id in manifest[field]);
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function stripTrailingSlashes(value) {
|
|
20
|
+
let end = value.length;
|
|
21
|
+
while (end > 0 && value[end - 1] === "/") end--;
|
|
22
|
+
return value.slice(0, end);
|
|
23
|
+
}
|
|
24
|
+
function normalizeRoutePath(value, option, warnings) {
|
|
25
|
+
let path = value;
|
|
26
|
+
if (!path.startsWith("/")) {
|
|
27
|
+
path = `/${path}`;
|
|
28
|
+
warnings.push(`\`${option}\` ("${value}") must start with "/" \u2014 using "${path}".`);
|
|
29
|
+
}
|
|
30
|
+
return path.length > 1 && path.endsWith("/") ? stripTrailingSlashes(path) : path;
|
|
31
|
+
}
|
|
32
|
+
function validateModuleOptions(input) {
|
|
33
|
+
const errors = [];
|
|
34
|
+
const warnings = [];
|
|
35
|
+
if (input.url && input.url.endsWith(".convex.site")) {
|
|
36
|
+
errors.push(
|
|
37
|
+
`\`convex.url\` ("${input.url}") ends with .convex.site, which is the HTTP Actions domain \u2014 deployment URLs end with .convex.cloud. Did you mean to set \`convex.siteUrl\`?`
|
|
38
|
+
);
|
|
39
|
+
} else if (input.url && !isHttpUrl(input.url)) {
|
|
40
|
+
warnings.push(
|
|
41
|
+
`\`convex.url\` ("${input.url}") does not look like a valid http(s) URL \u2014 Convex clients will fail to connect.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (input.siteUrl && input.siteUrl.endsWith(".convex.cloud")) {
|
|
45
|
+
errors.push(
|
|
46
|
+
`\`convex.siteUrl\` ("${input.siteUrl}") ends with .convex.cloud, which is the deployment domain \u2014 site URLs (HTTP Actions) end with .convex.site. Did you swap it with \`convex.url\`?`
|
|
47
|
+
);
|
|
48
|
+
} else if (input.siteUrl && !isHttpUrl(input.siteUrl)) {
|
|
49
|
+
warnings.push(
|
|
50
|
+
`\`convex.siteUrl\` ("${input.siteUrl}") does not look like a valid http(s) URL.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const authRoute = normalizeRoutePath(input.authRoute, "convex.authRoute", warnings);
|
|
54
|
+
const loginPath = normalizeRoutePath(input.loginPath ?? "/login", "convex.betterAuth.loginPath", warnings);
|
|
55
|
+
if (authRoute !== "/api/auth" && !input.authClient) {
|
|
56
|
+
errors.push(
|
|
57
|
+
`\`convex.authRoute\` is "${authRoute}" but the bundled Better Auth client still calls /api/auth, so every auth request would 404. Keep the default route, or set \`convex.betterAuth.authClient\` to a client created with \`basePath: "${authRoute}"\`.`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
if (input.authClient && !authClientModuleExists(input.authClient, input.rootDir)) {
|
|
61
|
+
errors.push(
|
|
62
|
+
`\`convex.betterAuth.authClient\` points at "${input.authClient}", which does not exist (resolved against \`${input.rootDir}\`). The build would fail with an opaque import error \u2014 fix the path or remove the option to use the bundled client.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return { errors, warnings, authRoute, loginPath };
|
|
66
|
+
}
|
|
67
|
+
function isHttpUrl(value) {
|
|
68
|
+
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
new URL(value);
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function authClientModuleExists(authClient, rootDir) {
|
|
79
|
+
const base = isAbsolute(authClient) ? authClient : join(rootDir, authClient);
|
|
80
|
+
return ["", ".ts", ".js", ".mts", ".mjs", "/index.ts", "/index.js"].some((suffix) => {
|
|
81
|
+
const candidate = `${base}${suffix}`;
|
|
82
|
+
return existsSync(candidate) && statSync(candidate).isFile();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function integrationWarnings(flags, isInstalled) {
|
|
86
|
+
const warnings = [];
|
|
87
|
+
const rivals = [flags.clerk && "Clerk", flags.auth0 && "Auth0"].filter((name) => Boolean(name));
|
|
88
|
+
if (flags.betterAuth && rivals.length > 0) {
|
|
89
|
+
const options = rivals.map((name) => `\`convex.${name.toLowerCase()}: false\``).join(" / ");
|
|
90
|
+
warnings.push(
|
|
91
|
+
`Better Auth and ${rivals.join(" and ")} are both enabled. Better Auth's plugin owns the Convex client's auth, so the ${rivals.join(" / ")} adapter would fight it \u2014 set ${options}, or \`convex.betterAuth: false\`, to pick one.`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (flags.polar && !isInstalled("@polar-sh/checkout")) {
|
|
95
|
+
warnings.push(
|
|
96
|
+
"`@convex-dev/polar` is installed but its peer `@polar-sh/checkout` is not \u2014 `<CheckoutLink>` imports it and the build fails the moment the component is used. Run `npm install @polar-sh/checkout`."
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return warnings;
|
|
100
|
+
}
|
|
101
|
+
function formatStartupSummary(url, functionsDir, integrations) {
|
|
102
|
+
const names = {
|
|
103
|
+
betterAuth: "better-auth",
|
|
104
|
+
clerk: "clerk",
|
|
105
|
+
auth0: "auth0",
|
|
106
|
+
polar: "polar",
|
|
107
|
+
security: "nuxt-security"
|
|
108
|
+
};
|
|
109
|
+
const enabled = Object.keys(names).filter((key) => integrations[key]).map((key) => names[key]);
|
|
110
|
+
return `Convex ${url || "(no URL)"} \xB7 functions: ${functionsDir}/ \xB7 integrations: ${enabled.join(", ") || "none"}`;
|
|
111
|
+
}
|
|
112
|
+
function isPackageInstalled(id, rootDir) {
|
|
113
|
+
for (const base of [join(rootDir, "package.json"), import.meta.url]) {
|
|
114
|
+
const lookupPaths = createRequire(base).resolve.paths(id) ?? [];
|
|
115
|
+
if (lookupPaths.some((dir) => existsSync(join(dir, id, "package.json")))) return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
function resolveDeploymentUrls(options, env) {
|
|
120
|
+
return {
|
|
121
|
+
url: stripTrailingSlashes(options.url || env.NUXT_PUBLIC_CONVEX_URL || env.CONVEX_URL || ""),
|
|
122
|
+
siteUrl: stripTrailingSlashes(options.siteUrl || env.NUXT_PUBLIC_CONVEX_SITE_URL || env.CONVEX_SITE_URL || "")
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const logger$1 = useLogger("nuxt-convex-module");
|
|
127
|
+
const DEFAULT_FUNCTIONS_DIR = "convex";
|
|
128
|
+
function resolveFunctionsDir(rootDir) {
|
|
129
|
+
return readFunctionsDirFromConvexJson(join(rootDir, "convex.json")) ?? DEFAULT_FUNCTIONS_DIR;
|
|
130
|
+
}
|
|
131
|
+
function hasGeneratedApi(rootDir, functionsDir = resolveFunctionsDir(rootDir)) {
|
|
132
|
+
const generatedApi = join(rootDir, functionsDir, "_generated", "api");
|
|
133
|
+
return existsSync(`${generatedApi}.d.ts`) || existsSync(`${generatedApi}.js`);
|
|
134
|
+
}
|
|
135
|
+
function readFunctionsDirFromConvexJson(convexJsonPath) {
|
|
136
|
+
if (!existsSync(convexJsonPath)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const convexJson = JSON.parse(readFileSync(convexJsonPath, "utf-8"));
|
|
141
|
+
if (typeof convexJson.functions !== "string") {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
return normalizeFunctionsDir(convexJson.functions);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger$1.warn(`Failed to parse convex.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function normalizeFunctionsDir(functionsDir) {
|
|
150
|
+
const normalized = stripTrailingSlashes(functionsDir.replace(/^\.?\//, ""));
|
|
151
|
+
return normalized || void 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function getConvexAliases(rootDir) {
|
|
155
|
+
const functionsDir = resolveFunctionsDir(rootDir);
|
|
156
|
+
const convexDir = join(rootDir, functionsDir);
|
|
157
|
+
const generatedDir = join(convexDir, "_generated");
|
|
158
|
+
return {
|
|
159
|
+
"#convex/api": join(generatedDir, "api"),
|
|
160
|
+
"#convex/server": join(generatedDir, "server"),
|
|
161
|
+
"#convex/dataModel": join(generatedDir, "dataModel"),
|
|
162
|
+
"#convex/_generated": generatedDir,
|
|
163
|
+
"#convex": convexDir
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const CODEGEN_GUARDED_TEMPLATES = ["nuxt-convex-module-provide-api.mjs", "types/nuxt-convex-module-api-fallback.d.ts"];
|
|
168
|
+
function watchConvexCodegen(nuxt) {
|
|
169
|
+
if (!nuxt.options.dev) return;
|
|
170
|
+
const generatedDir = join(nuxt.options.rootDir, resolveFunctionsDir(nuxt.options.rootDir), "_generated");
|
|
171
|
+
if (!nuxt.options.watch.includes(generatedDir)) nuxt.options.watch.push(generatedDir);
|
|
172
|
+
nuxt.hook("builder:watch", async (_event, path) => {
|
|
173
|
+
if (!path.replace(/\\/g, "/").includes("_generated/api")) return;
|
|
174
|
+
await updateTemplates({ filter: (template) => CODEGEN_GUARDED_TEMPLATES.includes(template.filename) });
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const PLAIN_NUXT_DEV = /^(?:npx )?(?:nuxt|nuxi) dev(?: [^&|;]*)?$/;
|
|
179
|
+
function combinedDevScript(nuxtCommand) {
|
|
180
|
+
return `convex dev --start '${nuxtCommand}'`;
|
|
181
|
+
}
|
|
182
|
+
function setupDevScript(rootDir) {
|
|
183
|
+
const path = join(rootDir, "package.json");
|
|
184
|
+
let raw;
|
|
185
|
+
try {
|
|
186
|
+
raw = readFileSync(path, "utf8");
|
|
187
|
+
} catch {
|
|
188
|
+
return { changed: false };
|
|
189
|
+
}
|
|
190
|
+
let manifest;
|
|
191
|
+
try {
|
|
192
|
+
manifest = JSON.parse(raw);
|
|
193
|
+
} catch {
|
|
194
|
+
return { changed: false };
|
|
195
|
+
}
|
|
196
|
+
const scripts = manifest.scripts;
|
|
197
|
+
if (typeof scripts !== "object" || scripts === null) return { changed: false };
|
|
198
|
+
const dev = scripts.dev;
|
|
199
|
+
if (typeof dev !== "string" || !PLAIN_NUXT_DEV.test(dev.trim())) return { changed: false };
|
|
200
|
+
if (Object.values(scripts).some((s) => typeof s === "string" && s.includes("convex dev"))) return { changed: false };
|
|
201
|
+
if (!isDeclaredDependency("convex", rootDir)) return { changed: false };
|
|
202
|
+
const to = combinedDevScript(dev.trim());
|
|
203
|
+
scripts.dev = to;
|
|
204
|
+
const indent = raw.match(/^[ \t]+(?=")/m)?.[0] ?? " ";
|
|
205
|
+
const newline = raw.endsWith("\n") ? "\n" : "";
|
|
206
|
+
writeFileSync(path, JSON.stringify(manifest, null, indent) + newline);
|
|
207
|
+
return { changed: true, from: dev, to };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const vue = (file) => `runtime/vue/${file}`;
|
|
211
|
+
const composable = (file) => vue(`composables/${file}`);
|
|
212
|
+
const asyncQuery = "runtime/nuxt/composables/use-async-query";
|
|
213
|
+
const asyncPaginatedQuery = "runtime/nuxt/composables/use-async-paginated-query";
|
|
214
|
+
const APP_IMPORTS = {
|
|
215
|
+
core: [
|
|
216
|
+
{ name: "useConvex", from: vue("client") },
|
|
217
|
+
{ name: "useQuery", from: composable("use-query") },
|
|
218
|
+
{ name: "useQuery_experimental", from: composable("use-query") },
|
|
219
|
+
{ name: "useConvexQuery", from: composable("use-query") },
|
|
220
|
+
{ name: "useQueries", from: composable("use-queries") },
|
|
221
|
+
{ name: "useConvexQueries", from: composable("use-queries") },
|
|
222
|
+
{ name: "useMutation", from: composable("use-mutation") },
|
|
223
|
+
{ name: "useConvexMutation", from: composable("use-mutation") },
|
|
224
|
+
{ name: "useAction", from: composable("use-action") },
|
|
225
|
+
{ name: "useConvexAction", from: composable("use-action") },
|
|
226
|
+
{ name: "useConvexConnectionState", from: composable("use-connection-state") },
|
|
227
|
+
{ name: "useUpload", from: composable("use-upload") },
|
|
228
|
+
{ name: "useConvexUpload", from: composable("use-upload") },
|
|
229
|
+
{ name: "uploadFile", from: composable("use-upload") },
|
|
230
|
+
{ name: "useUploadQueue", from: composable("use-upload-queue") },
|
|
231
|
+
{ name: "useConvexUploadQueue", from: composable("use-upload-queue") },
|
|
232
|
+
{ name: "useStorageUrl", from: composable("use-storage-url") },
|
|
233
|
+
{ name: "useConvexStorageUrl", from: composable("use-storage-url") },
|
|
234
|
+
{ name: "useConvexAuth", from: vue("auth/index") },
|
|
235
|
+
{ name: "provideConvexAuth", from: vue("auth/index") },
|
|
236
|
+
{ name: "provideConvexApi", from: vue("provide") },
|
|
237
|
+
{ name: "useConvexApi", from: vue("provide") },
|
|
238
|
+
{ name: "useConvexNamespace", from: vue("provide") },
|
|
239
|
+
{ name: "usePreloadedQuery", from: vue("hydration") },
|
|
240
|
+
// Nuxt-only (imports `#app`), hence under runtime/nuxt/ — see PARITY.md.
|
|
241
|
+
// Its types too, so `import type { AsyncQueryReturn } from '#imports'` works
|
|
242
|
+
// without spelling out the `nuxt-convex-module/app` subpath.
|
|
243
|
+
{ name: "useAsyncQuery", from: asyncQuery },
|
|
244
|
+
{ name: "useConvexAsyncQuery", from: asyncQuery },
|
|
245
|
+
{ name: "AsyncQueryData", from: asyncQuery, type: true },
|
|
246
|
+
{ name: "AsyncQueryOptions", from: asyncQuery, type: true },
|
|
247
|
+
{ name: "AsyncQueryReturn", from: asyncQuery, type: true },
|
|
248
|
+
{ name: "AsyncQueryStatus", from: asyncQuery, type: true },
|
|
249
|
+
{ name: "usePaginatedQuery", from: composable("use-paginated-query") },
|
|
250
|
+
{ name: "useConvexPaginatedQuery", from: composable("use-paginated-query") },
|
|
251
|
+
{ name: "usePaginatedQuery_experimental", from: composable("use-paginated-query") },
|
|
252
|
+
{ name: "useAsyncPaginatedQuery", from: asyncPaginatedQuery },
|
|
253
|
+
{ name: "useConvexAsyncPaginatedQuery", from: asyncPaginatedQuery },
|
|
254
|
+
{ name: "AsyncPaginatedQueryData", from: asyncPaginatedQuery, type: true },
|
|
255
|
+
{ name: "AsyncPaginatedQueryOptions", from: asyncPaginatedQuery, type: true },
|
|
256
|
+
{ name: "AsyncPaginatedQueryReturn", from: asyncPaginatedQuery, type: true }
|
|
257
|
+
],
|
|
258
|
+
betterAuth: [
|
|
259
|
+
{ name: "useBetterAuth", from: "runtime/better-auth/vue/use-better-auth" },
|
|
260
|
+
{ name: "usePreloadedAuthQuery", from: "runtime/better-auth/vue/hydration" },
|
|
261
|
+
{ name: "resolveAuthRedirect", from: "runtime/better-auth/vue/redirect" }
|
|
262
|
+
],
|
|
263
|
+
clerk: [{ name: "provideConvexAuthFromClerk", from: "runtime/clerk/vue/index" }],
|
|
264
|
+
auth0: [{ name: "provideConvexAuthFromAuth0", from: "runtime/auth0/vue/index" }],
|
|
265
|
+
polar: []
|
|
266
|
+
};
|
|
267
|
+
const APP_COMPONENTS = {
|
|
268
|
+
core: [
|
|
269
|
+
...["Authenticated", "Unauthenticated", "AuthLoading", "AuthRefreshing"].map((name) => ({ name, from: vue("auth/helpers") })),
|
|
270
|
+
{ name: "ConvexImage", from: vue("components/convex-image") }
|
|
271
|
+
],
|
|
272
|
+
betterAuth: [{ name: "AuthBoundary", from: "runtime/better-auth/vue/auth-boundary" }],
|
|
273
|
+
clerk: [{ name: "ConvexProviderWithClerk", from: "runtime/clerk/vue/index" }],
|
|
274
|
+
auth0: [{ name: "ConvexProviderWithAuth0", from: "runtime/auth0/vue/index" }],
|
|
275
|
+
polar: ["CheckoutLink", "CustomerPortalLink"].map((name) => ({ name, from: "runtime/polar/vue/components" }))
|
|
276
|
+
};
|
|
277
|
+
const SERVER_IMPORTS = {
|
|
278
|
+
core: ["fetchQuery", "fetchMutation", "fetchAction", "preloadQuery", "preloadedQueryResult"].map((name) => ({ name, from: "runtime/nuxt/index" })),
|
|
279
|
+
betterAuth: ["convexAuth", "convexBetterAuthNuxt"].map((name) => ({ name, from: "runtime/better-auth/nuxt/server" })),
|
|
280
|
+
clerk: [],
|
|
281
|
+
auth0: [],
|
|
282
|
+
polar: []
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
function convexTypeFallbackContents(hasApi, functionsDir) {
|
|
286
|
+
if (hasApi) {
|
|
287
|
+
return "export {}\n";
|
|
288
|
+
}
|
|
289
|
+
return [
|
|
290
|
+
`// Placeholder until \`npx convex dev\` generates ${functionsDir}/_generated.`,
|
|
291
|
+
"declare module '#convex/api' {",
|
|
292
|
+
" export const api: any",
|
|
293
|
+
" export const internal: any",
|
|
294
|
+
" export const components: any",
|
|
295
|
+
"}",
|
|
296
|
+
"declare module '#convex/server' {",
|
|
297
|
+
" export const query: any",
|
|
298
|
+
" export const internalQuery: any",
|
|
299
|
+
" export const mutation: any",
|
|
300
|
+
" export const internalMutation: any",
|
|
301
|
+
" export const action: any",
|
|
302
|
+
" export const internalAction: any",
|
|
303
|
+
" export const httpAction: any",
|
|
304
|
+
" export type QueryCtx = any",
|
|
305
|
+
" export type MutationCtx = any",
|
|
306
|
+
" export type ActionCtx = any",
|
|
307
|
+
" export type DatabaseReader = any",
|
|
308
|
+
" export type DatabaseWriter = any",
|
|
309
|
+
"}",
|
|
310
|
+
"declare module '#convex/dataModel' {",
|
|
311
|
+
" export type Doc<TableName extends string = string> = any",
|
|
312
|
+
" export type Id<TableName extends string = string> = string",
|
|
313
|
+
" export type DataModel = any",
|
|
314
|
+
" export type TableNames = string",
|
|
315
|
+
"}",
|
|
316
|
+
""
|
|
317
|
+
].join("\n");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const logger = useLogger("nuxt-convex-module");
|
|
321
|
+
const module$1 = defineNuxtModule({
|
|
322
|
+
meta: {
|
|
323
|
+
name: "nuxt-convex-module",
|
|
324
|
+
configKey: "convex",
|
|
325
|
+
// Surfaced by Nuxt DevTools and the nuxt/modules registry.
|
|
326
|
+
docs: "https://nuxt-convex-module.dev",
|
|
327
|
+
// `moduleDependencies` (below) is a Nuxt >= 4.1 feature — fail fast with a
|
|
328
|
+
// clear kit error on older Nuxt instead of silently skipping nuxt-security.
|
|
329
|
+
compatibility: {
|
|
330
|
+
nuxt: ">=4.1.0"
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
defaults: {
|
|
334
|
+
authRoute: "/api/auth",
|
|
335
|
+
devtools: true,
|
|
336
|
+
devScript: true
|
|
337
|
+
},
|
|
338
|
+
// nuxt-security is optional. When the app has it installed (and hasn't
|
|
339
|
+
// switched it off), declare it as a module dependency so Nuxt's core loader
|
|
340
|
+
// registers it — deduping if it's already in `modules`, hoisting its types —
|
|
341
|
+
// with no extra entry on the consumer's side. The Convex-aware CSP is applied
|
|
342
|
+
// at runtime (see `registerSecurity`), so module order is irrelevant. Nothing
|
|
343
|
+
// is declared otherwise: kit fails the build resolving an absent package.
|
|
344
|
+
moduleDependencies: (nuxt) => resolveSecurityState(nuxt, readSecurityOption(nuxt)).enabled ? { "nuxt-security": {} } : {},
|
|
345
|
+
async setup(options, nuxt) {
|
|
346
|
+
const resolver = createResolver(import.meta.url);
|
|
347
|
+
nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
|
|
348
|
+
const { url, siteUrl } = applyRuntimeConfig(nuxt, options);
|
|
349
|
+
const diagnostics = validateModuleOptions({
|
|
350
|
+
url,
|
|
351
|
+
siteUrl,
|
|
352
|
+
authRoute: options.authRoute || "/api/auth",
|
|
353
|
+
loginPath: nuxt.options.runtimeConfig.public.convex.loginPath,
|
|
354
|
+
authClient: typeof options.betterAuth === "object" ? options.betterAuth.authClient : void 0,
|
|
355
|
+
rootDir: nuxt.options.rootDir
|
|
356
|
+
});
|
|
357
|
+
for (const message of diagnostics.errors) logger.error(message);
|
|
358
|
+
for (const message of diagnostics.warnings) logger.warn(message);
|
|
359
|
+
options.authRoute = diagnostics.authRoute;
|
|
360
|
+
nuxt.options.runtimeConfig.public.convex.loginPath = diagnostics.loginPath;
|
|
361
|
+
registerAuthClientAlias(resolver, nuxt, options);
|
|
362
|
+
registerConvexAliases(nuxt);
|
|
363
|
+
registerConvexApiPlugin(resolver, nuxt);
|
|
364
|
+
registerConvexTypeFallback(nuxt);
|
|
365
|
+
registerVueComposables(resolver);
|
|
366
|
+
registerAuthComponents(resolver);
|
|
367
|
+
const integrations = registerIntegrations(resolver, nuxt, options);
|
|
368
|
+
watchConvexCodegen(nuxt);
|
|
369
|
+
if (nuxt.options.dev && options.devtools !== false && isDevtoolsUiEnabled(nuxt)) {
|
|
370
|
+
const { setupDevtools } = await import('./chunks/index.mjs');
|
|
371
|
+
setupDevtools(resolver, nuxt, {
|
|
372
|
+
url,
|
|
373
|
+
siteUrl,
|
|
374
|
+
rootDir: nuxt.options.rootDir,
|
|
375
|
+
functionsDir: resolveFunctionsDir(nuxt.options.rootDir),
|
|
376
|
+
integrations
|
|
377
|
+
});
|
|
378
|
+
addPlugin({ src: resolver.resolve("./runtime/devtools/plugin.client"), mode: "client" }, { append: true });
|
|
379
|
+
}
|
|
380
|
+
if (nuxt.options.dev && !nuxt.options._prepare) {
|
|
381
|
+
logger.info(formatStartupSummary(url, resolveFunctionsDir(nuxt.options.rootDir), integrations));
|
|
382
|
+
}
|
|
383
|
+
if (options.devScript !== false && (nuxt.options.dev || nuxt.options._prepare)) {
|
|
384
|
+
const result = setupDevScript(nuxt.options.rootDir);
|
|
385
|
+
if (result.changed) {
|
|
386
|
+
logger.info(`Set \`scripts.dev\` to \`${result.to}\` \u2014 one command now runs Convex beside Nuxt, no .env needed locally. Set \`convex.devScript: false\` to keep your own script.`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
function isDevtoolsUiEnabled(nuxt) {
|
|
392
|
+
const devtools = nuxt.options.devtools;
|
|
393
|
+
return typeof devtools === "boolean" ? devtools : devtools?.enabled !== false;
|
|
394
|
+
}
|
|
395
|
+
function registerIntegrations(resolver, nuxt, options) {
|
|
396
|
+
const report = (key, pkg, state) => {
|
|
397
|
+
if (state.missingPackage) {
|
|
398
|
+
logger.error(`\`convex.${key}\` is enabled but \`${pkg}\` is not installed. Run \`npm install ${pkg}\` or remove the option.`);
|
|
399
|
+
}
|
|
400
|
+
return state.enabled;
|
|
401
|
+
};
|
|
402
|
+
const rootDir = nuxt.options.rootDir;
|
|
403
|
+
const resolve = (key, pkg) => report(key, pkg, resolveIntegrationState(options[key], isPackageInstalled(pkg, rootDir), isDeclaredDependency(pkg, rootDir)));
|
|
404
|
+
const betterAuth = resolve("betterAuth", "@convex-dev/better-auth");
|
|
405
|
+
if (betterAuth) {
|
|
406
|
+
registerBetterAuth(resolver, options.authRoute || "/api/auth");
|
|
407
|
+
} else {
|
|
408
|
+
registerBaseConvexClient(resolver);
|
|
409
|
+
}
|
|
410
|
+
const clerk = resolve("clerk", "@clerk/vue");
|
|
411
|
+
if (clerk) {
|
|
412
|
+
registerClerk(resolver);
|
|
413
|
+
}
|
|
414
|
+
const auth0 = resolve("auth0", "@auth0/auth0-vue");
|
|
415
|
+
if (auth0) {
|
|
416
|
+
registerAuth0(resolver);
|
|
417
|
+
}
|
|
418
|
+
const polar = resolve("polar", "@convex-dev/polar");
|
|
419
|
+
if (polar) {
|
|
420
|
+
registerPolarComponents(resolver);
|
|
421
|
+
}
|
|
422
|
+
const security = report("security", "nuxt-security", resolveSecurityState(nuxt, options.security));
|
|
423
|
+
if (security) {
|
|
424
|
+
registerSecurity(resolver);
|
|
425
|
+
}
|
|
426
|
+
const flags = { betterAuth, clerk, auth0, polar, security };
|
|
427
|
+
for (const message of integrationWarnings(flags, (pkg) => isPackageInstalled(pkg, rootDir))) logger.warn(message);
|
|
428
|
+
return flags;
|
|
429
|
+
}
|
|
430
|
+
function readSecurityOption(nuxt) {
|
|
431
|
+
const opts = nuxt.options;
|
|
432
|
+
return opts.convex?.security;
|
|
433
|
+
}
|
|
434
|
+
function resolveSecurityState(nuxt, explicit) {
|
|
435
|
+
const opts = nuxt.options;
|
|
436
|
+
if (opts.security === false) return { enabled: false, missingPackage: false };
|
|
437
|
+
const registered = hasNuxtModule("nuxt-security", nuxt);
|
|
438
|
+
const installed = registered || isPackageInstalled("nuxt-security", nuxt.options.rootDir);
|
|
439
|
+
const declared = registered || isDeclaredDependency("nuxt-security", nuxt.options.rootDir);
|
|
440
|
+
return resolveIntegrationState(explicit, installed, declared);
|
|
441
|
+
}
|
|
442
|
+
function registerSecurity(resolver) {
|
|
443
|
+
addServerPlugin(resolver.resolve("./runtime/nuxt/security"));
|
|
444
|
+
}
|
|
445
|
+
function applyRuntimeConfig(nuxt, options) {
|
|
446
|
+
const resolved = resolveDeploymentUrls(options, process.env);
|
|
447
|
+
const url = nuxt.options._prepare ? "" : resolved.url;
|
|
448
|
+
if (!url && !nuxt.options._prepare) {
|
|
449
|
+
logger.warn(
|
|
450
|
+
"No Convex deployment URL configured. Set NUXT_PUBLIC_CONVEX_URL or `convex.url` in nuxt.config. Note: `npx convex dev` writes CONVEX_URL to .env.local, which Nuxt does not read without `nuxt dev --dotenv .env.local`."
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
const siteUrl = resolved.siteUrl;
|
|
454
|
+
const crossDomainCallbackRoute = typeof options.betterAuth === "object" && options.betterAuth.crossDomainCallbackRoute || "";
|
|
455
|
+
const loginPath = typeof options.betterAuth === "object" && options.betterAuth.loginPath || "/login";
|
|
456
|
+
const runtimeConfig = nuxt.options.runtimeConfig;
|
|
457
|
+
runtimeConfig.public.convex = {
|
|
458
|
+
...runtimeConfig.public.convex,
|
|
459
|
+
url,
|
|
460
|
+
siteUrl,
|
|
461
|
+
crossDomainCallbackRoute,
|
|
462
|
+
loginPath
|
|
463
|
+
};
|
|
464
|
+
runtimeConfig.convex = { ...runtimeConfig.convex, siteUrl };
|
|
465
|
+
return { url, siteUrl };
|
|
466
|
+
}
|
|
467
|
+
function registerConvexAliases(nuxt) {
|
|
468
|
+
const aliases = getConvexAliases(nuxt.options.rootDir);
|
|
469
|
+
nuxt.options.nitro ||= {};
|
|
470
|
+
nuxt.options.nitro.alias ||= {};
|
|
471
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
472
|
+
nuxt.options.alias[alias] = target;
|
|
473
|
+
nuxt.options.nitro.alias[alias] = target;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function registerAuthClientAlias(resolver, nuxt, options) {
|
|
477
|
+
const custom = typeof options.betterAuth === "object" ? options.betterAuth.authClient : void 0;
|
|
478
|
+
const target = custom ? isAbsolute(custom) ? custom : join(nuxt.options.rootDir, custom) : resolver.resolve("./runtime/better-auth/vue/client");
|
|
479
|
+
nuxt.options.nitro ||= {};
|
|
480
|
+
nuxt.options.nitro.alias ||= {};
|
|
481
|
+
nuxt.options.alias["#convex/auth-client"] = target;
|
|
482
|
+
nuxt.options.nitro.alias["#convex/auth-client"] = target;
|
|
483
|
+
}
|
|
484
|
+
function registerConvexApiPlugin(resolver, nuxt) {
|
|
485
|
+
const functionsDir = resolveFunctionsDir(nuxt.options.rootDir);
|
|
486
|
+
const provideModule = resolver.resolve("./runtime/vue/provide");
|
|
487
|
+
let notifiedMissing = false;
|
|
488
|
+
addPluginTemplate({
|
|
489
|
+
filename: "nuxt-convex-module-provide-api.mjs",
|
|
490
|
+
getContents: () => {
|
|
491
|
+
if (!hasGeneratedApi(nuxt.options.rootDir, functionsDir)) {
|
|
492
|
+
if (nuxt.options.dev && !nuxt.options._prepare && !notifiedMissing) {
|
|
493
|
+
notifiedMissing = true;
|
|
494
|
+
logger.info(`Convex codegen not found in \`${functionsDir}/_generated\` \u2014 run \`npx convex dev\`. Convex features no-op until it exists.`);
|
|
495
|
+
}
|
|
496
|
+
return "import { defineNuxtPlugin } from '#app'\nexport default defineNuxtPlugin(() => {})\n";
|
|
497
|
+
}
|
|
498
|
+
if (notifiedMissing) {
|
|
499
|
+
notifiedMissing = false;
|
|
500
|
+
logger.success("Convex codegen detected \u2014 generated `api` wired app-wide.");
|
|
501
|
+
}
|
|
502
|
+
return [
|
|
503
|
+
"import { defineNuxtPlugin } from '#app'",
|
|
504
|
+
"import { api } from '#convex/api'",
|
|
505
|
+
`import { provideConvexApi } from ${JSON.stringify(provideModule)}`,
|
|
506
|
+
"export default defineNuxtPlugin((nuxtApp) => {",
|
|
507
|
+
" provideConvexApi(api, nuxtApp.vueApp)",
|
|
508
|
+
"})",
|
|
509
|
+
""
|
|
510
|
+
].join("\n");
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
function registerConvexTypeFallback(nuxt) {
|
|
515
|
+
const functionsDir = resolveFunctionsDir(nuxt.options.rootDir);
|
|
516
|
+
addTypeTemplate({
|
|
517
|
+
filename: "types/nuxt-convex-module-api-fallback.d.ts",
|
|
518
|
+
getContents: () => convexTypeFallbackContents(hasGeneratedApi(nuxt.options.rootDir, functionsDir), functionsDir)
|
|
519
|
+
}, { nuxt: true, nitro: true });
|
|
520
|
+
}
|
|
521
|
+
function registerVueComposables(resolver) {
|
|
522
|
+
registerIntegrationImports(resolver, "core");
|
|
523
|
+
}
|
|
524
|
+
function registerAuthComponents(resolver) {
|
|
525
|
+
registerComponents(resolver, "core");
|
|
526
|
+
}
|
|
527
|
+
function registerIntegrationImports(resolver, integration) {
|
|
528
|
+
const resolve = (entry) => ({ ...entry, from: resolver.resolve(`./${entry.from}`) });
|
|
529
|
+
if (APP_IMPORTS[integration].length > 0) addImports(APP_IMPORTS[integration].map(resolve));
|
|
530
|
+
if (SERVER_IMPORTS[integration].length > 0) addServerImports(SERVER_IMPORTS[integration].map(resolve));
|
|
531
|
+
}
|
|
532
|
+
function registerComponents(resolver, integration) {
|
|
533
|
+
for (const { name, from } of APP_COMPONENTS[integration]) {
|
|
534
|
+
addComponent({ name, filePath: resolver.resolve(`./${from}`), export: name });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
const AUTH_PROXY_SECURITY_RULES = {
|
|
538
|
+
xssValidator: false,
|
|
539
|
+
allowedMethodsRestricter: { methods: ["GET", "HEAD", "POST", "OPTIONS"] }
|
|
540
|
+
};
|
|
541
|
+
function registerBetterAuth(resolver, authRoute) {
|
|
542
|
+
addPlugin(resolver.resolve("./runtime/better-auth/vue/plugin.client"));
|
|
543
|
+
addPlugin(resolver.resolve("./runtime/better-auth/vue/plugin.server"));
|
|
544
|
+
registerIntegrationImports(resolver, "betterAuth");
|
|
545
|
+
registerComponents(resolver, "betterAuth");
|
|
546
|
+
addServerHandler({
|
|
547
|
+
route: `${authRoute}/**`,
|
|
548
|
+
handler: resolver.resolve("./runtime/better-auth/nuxt/proxy")
|
|
549
|
+
});
|
|
550
|
+
extendRouteRules(`${authRoute}/**`, {
|
|
551
|
+
cache: false,
|
|
552
|
+
prerender: false,
|
|
553
|
+
security: AUTH_PROXY_SECURITY_RULES
|
|
554
|
+
});
|
|
555
|
+
addRouteMiddleware({
|
|
556
|
+
name: "auth",
|
|
557
|
+
path: resolver.resolve("./runtime/better-auth/nuxt/middleware"),
|
|
558
|
+
global: false
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
function registerBaseConvexClient(resolver) {
|
|
562
|
+
addPlugin(resolver.resolve("./runtime/vue/plugin"));
|
|
563
|
+
}
|
|
564
|
+
function registerClerk(resolver) {
|
|
565
|
+
registerIntegrationImports(resolver, "clerk");
|
|
566
|
+
registerComponents(resolver, "clerk");
|
|
567
|
+
}
|
|
568
|
+
function registerAuth0(resolver) {
|
|
569
|
+
registerIntegrationImports(resolver, "auth0");
|
|
570
|
+
registerComponents(resolver, "auth0");
|
|
571
|
+
}
|
|
572
|
+
function registerPolarComponents(resolver) {
|
|
573
|
+
registerComponents(resolver, "polar");
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export { module$1 as default };
|
|
@@ -4,12 +4,12 @@ import { type ConvexAuthState, type IConvexVueClient } from '../../vue/auth/inde
|
|
|
4
4
|
* Options for {@link provideConvexAuthFromAuth0} / `<ConvexProviderWithAuth0>`.
|
|
5
5
|
*/
|
|
6
6
|
export interface ConvexProviderWithAuth0Options {
|
|
7
|
-
/** Convex client to authenticate. Defaults to the
|
|
7
|
+
/** Convex client to authenticate. Defaults to the client `useConvex()` returns. */
|
|
8
8
|
client?: IConvexVueClient;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* The composable form of {@link ConvexProviderWithAuth0} — provides a
|
|
12
|
-
* {@link ConvexVueClient} authenticated with Auth0.
|
|
12
|
+
* {@link client!ConvexVueClient | ConvexVueClient} authenticated with Auth0.
|
|
13
13
|
*
|
|
14
14
|
* It must be called in an app wrapped by a configured Auth0 plugin from
|
|
15
15
|
* `@auth0/auth0-vue`.
|
|
@@ -29,7 +29,7 @@ export interface ConvexProviderWithAuth0Options {
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function provideConvexAuthFromAuth0(options?: ConvexProviderWithAuth0Options): ConvexAuthState;
|
|
31
31
|
/**
|
|
32
|
-
* A wrapper Vue component which provides a {@link ConvexVueClient}
|
|
32
|
+
* A wrapper Vue component which provides a {@link client!ConvexVueClient | ConvexVueClient}
|
|
33
33
|
* authenticated with Auth0 — the component form of
|
|
34
34
|
* {@link provideConvexAuthFromAuth0}. Renders its default slot once Convex
|
|
35
35
|
* auth is wired.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auth route middleware — protects pages from unauthenticated access.
|
|
3
3
|
*
|
|
4
|
+
* Unauthenticated visitors are sent to the configured login route
|
|
5
|
+
* (`convex.betterAuth.loginPath`, default `/login`) with the original
|
|
6
|
+
* destination in a `?redirect=` query.
|
|
7
|
+
*
|
|
4
8
|
* Usage in page:
|
|
5
9
|
* ```vue
|
|
6
10
|
* <script setup>
|
|
@@ -8,7 +12,5 @@
|
|
|
8
12
|
* </script>
|
|
9
13
|
* ```
|
|
10
14
|
*/
|
|
11
|
-
/** Exported for unit tests — `import.meta.server` is compile-time. @internal */
|
|
12
|
-
export declare function serverGuard(path: string): Promise<string | false | void | import("vue-router").RouteLocationAsRelativeGeneric | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").NavigationFailure>;
|
|
13
15
|
declare const _default: import("nuxt/app").RouteMiddleware;
|
|
14
16
|
export default _default;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { defineNuxtRouteMiddleware, navigateTo, useNuxtApp, useRequestEvent } from "#app";
|
|
1
|
+
import { defineNuxtRouteMiddleware, navigateTo, useNuxtApp, useRequestEvent, useRuntimeConfig } from "#app";
|
|
2
2
|
import { watch } from "vue";
|
|
3
|
-
import {
|
|
3
|
+
import { useBetterAuth } from "../vue/use-better-auth.js";
|
|
4
4
|
import { convexAuth } from "./server.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function loginTarget(to, loginPath) {
|
|
6
|
+
return { path: loginPath, query: { redirect: to.fullPath } };
|
|
7
|
+
}
|
|
8
|
+
export async function serverGuard(to, loginPath) {
|
|
8
9
|
const nuxtApp = useNuxtApp();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const event = useRequestEvent();
|
|
11
|
+
const authed = event ? await convexAuth(event).isAuthenticated() : false;
|
|
12
|
+
if (!authed && to.path !== loginPath) {
|
|
13
|
+
return nuxtApp.runWithContext(() => navigateTo(loginTarget(to, loginPath)));
|
|
12
14
|
}
|
|
13
15
|
}
|
|
14
16
|
function waitForSession(isPending) {
|
|
@@ -26,14 +28,15 @@ function waitForSession(isPending) {
|
|
|
26
28
|
});
|
|
27
29
|
}
|
|
28
30
|
export default defineNuxtRouteMiddleware(async (to) => {
|
|
31
|
+
const loginPath = useRuntimeConfig().public.convex.loginPath || "/login";
|
|
29
32
|
if (import.meta.server) {
|
|
30
|
-
return serverGuard(to
|
|
33
|
+
return serverGuard(to, loginPath);
|
|
31
34
|
}
|
|
32
|
-
const { session } =
|
|
35
|
+
const { session } = useBetterAuth();
|
|
33
36
|
if (session.value.isPending) {
|
|
34
37
|
await waitForSession(() => session.value.isPending);
|
|
35
38
|
}
|
|
36
|
-
if (!session.value.data && to.path !==
|
|
37
|
-
return navigateTo(
|
|
39
|
+
if (!session.value.data && to.path !== loginPath) {
|
|
40
|
+
return navigateTo(loginTarget(to, loginPath));
|
|
38
41
|
}
|
|
39
42
|
});
|