@floatingpixels/supabase-nuxt 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -11
- package/dist/module.json +2 -2
- package/dist/module.mjs +27 -16
- package/dist/runtime/plugins/supabase.server.js +3 -2
- package/dist/runtime/server/services/supabaseServerClient.js +4 -3
- package/dist/runtime/server/services/supabaseServiceRole.js +4 -3
- package/package.json +29 -38
package/README.md
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
[@floatingpixels/supabase-nuxt](https://github.com/
|
|
10
|
+
[@floatingpixels/supabase-nuxt](https://github.com/floatingpixels/supabase-nuxt) is a Nuxt module for first-class integration with Supabase. It makes it easy to use Supabase authentication, database and realtime features in your Nuxt 3 or Nuxt 4 application. Especially when using server-side rendering (SSR), using Supabase can be tricky, this module takes care of the intricacies and lets you simply use the power of Supabase!
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Check out the [Nuxt](https://nuxt.com/docs) documentation and [Supabase](https://supabase.com/docs) to learn more.
|
|
13
13
|
|
|
14
14
|
## Testing
|
|
15
15
|
|
|
@@ -37,14 +37,14 @@ export default defineNuxtConfig({
|
|
|
37
37
|
})
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
Add `
|
|
40
|
+
Add `NUXT_PUBLIC_SUPABASE_URL` and `NUXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` to `.env`:
|
|
41
41
|
|
|
42
42
|
```zsh
|
|
43
43
|
NUXT_PUBLIC_SUPABASE_URL="https://example.supabase.co"
|
|
44
44
|
NUXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=""
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
When dynamically setting the variables
|
|
47
|
+
When dynamically setting the variables in an environment, make sure to prefix the public environment variables with `NUXT_PUBLIC_` in order to use `runtimeConfig`.
|
|
48
48
|
|
|
49
49
|
The public keys are required to be set in the environment for the module to work. If the service role is needed, you should also set `NUXT_SUPABASE_SERVICE_ROLE_KEY` in the environment, which will be only available on the server side as a private runtime variable.
|
|
50
50
|
|
|
@@ -61,6 +61,8 @@ export default defineNuxtConfig({
|
|
|
61
61
|
}
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
The module extends existing `runtimeConfig.public.supabase` and `runtimeConfig.supabase` values instead of replacing them. This lets explicit runtime config and `NUXT_*` environment overrides take precedence over module defaults.
|
|
65
|
+
|
|
64
66
|
### `url`
|
|
65
67
|
|
|
66
68
|
Default: `process.env.NUXT_PUBLIC_SUPABASE_URL` (e.g.: `https://example.supabase.co`)
|
|
@@ -83,7 +85,7 @@ Supabase 'service role key', has super admin rights and can bypass your Row Leve
|
|
|
83
85
|
|
|
84
86
|
Default: `false`
|
|
85
87
|
|
|
86
|
-
Re-direct automatically to the configured login page if a non authenticated user is navigating to a page. When set to `true` a global middleware is used to check for a logged-in Supabase
|
|
88
|
+
Re-direct automatically to the configured login page if a non authenticated user is navigating to a page. When set to `true` a global middleware is used to check for a logged-in Supabase user on all non-excluded routes.
|
|
87
89
|
|
|
88
90
|
### `redirectOptions`
|
|
89
91
|
|
|
@@ -169,9 +171,9 @@ When using e-mail authentication, a confirmation e-mail is sent to new users, an
|
|
|
169
171
|
|
|
170
172
|
The confirmation route on your server is provided by this module, so you don't need to implement it yourself. It's available at `/auth/confirm`. It will automatically confirm the user and re-direct to the `redirect_to` route.
|
|
171
173
|
|
|
172
|
-
If you want to customize the confirmation route, you can do so by creating a server route to handle the request, and point to it in your Supabase e-mail template. Your custom route will receive the `token_hash` and `type` URL parameters, and the `redirect_to` URL parameter if provided. You can use the `
|
|
174
|
+
If you want to customize the confirmation route, you can do so by creating a server route to handle the request, and point to it in your Supabase e-mail template. Your custom route will receive the `token_hash` and `type` URL parameters, and the `redirect_to` URL parameter if provided. You can use the `supabaseServerClient` server helper to confirm the user and re-direct to the next route:
|
|
173
175
|
|
|
174
|
-
> ⚠️ You can use the provided confirm route at `/
|
|
176
|
+
> ⚠️ You can use the provided confirm route at `/auth/confirm`, the implementation of a custom route is optional!
|
|
175
177
|
|
|
176
178
|
```ts [server/api/confirm.ts]
|
|
177
179
|
import { EmailOtpType } from '@supabase/supabase-js'
|
|
@@ -278,7 +280,7 @@ This composable can be used to make requests to the Supabase API. It's auto-impo
|
|
|
278
280
|
|
|
279
281
|
Please check [Supabase](https://supabase.com/docs/reference/javascript/select) documentation on how to fully use the Supabase client.
|
|
280
282
|
|
|
281
|
-
Here is an example of fetching from the database using the Supabase client's `select` method with Nuxt
|
|
283
|
+
Here is an example of fetching from the database using the Supabase client's `select` method with Nuxt's [useAsyncData](https://nuxt.com/docs/getting-started/data-fetching#useasyncdata).
|
|
282
284
|
|
|
283
285
|
```vue
|
|
284
286
|
<script setup lang="ts">
|
|
@@ -356,7 +358,7 @@ const signInWithOAuth = async () => {
|
|
|
356
358
|
const { error } = await supabase.auth.signInWithOAuth({
|
|
357
359
|
provider: 'github',
|
|
358
360
|
options: {
|
|
359
|
-
redirectTo: 'http://localhost:3000/
|
|
361
|
+
redirectTo: 'http://localhost:3000/auth/callback',
|
|
360
362
|
},
|
|
361
363
|
})
|
|
362
364
|
if (error) console.log(error)
|
|
@@ -395,7 +397,7 @@ Make requests with super admin rights to the Supabase API with the `supabaseServ
|
|
|
395
397
|
|
|
396
398
|
It provides similar functionality as the `supabaseServerClient` but it provides a client with super admin rights that can bypass your [Row Level Security](https://supabase.com/docs/guides/auth/row-level-security).
|
|
397
399
|
|
|
398
|
-
The client is initialized with the `
|
|
400
|
+
The client is initialized with the `NUXT_SUPABASE_SERVICE_ROLE_KEY` you must have in your environment. Check out the doc if you want to know more about [Supabase keys](https://supabase.com/docs/learn/auth-deep-dive/auth-deep-dive-jwts#jwts-in-supabase).
|
|
399
401
|
|
|
400
402
|
> ⚠️ The service key gives admin access to your database, be careful to not expose it in your client side code or in your git repository.
|
|
401
403
|
|
|
@@ -405,7 +407,7 @@ In your server route use the `supabaseServiceRole` from `#supabase/server`.
|
|
|
405
407
|
import { supabaseServiceRole } from '#supabase/server'
|
|
406
408
|
|
|
407
409
|
export default eventHandler(async event => {
|
|
408
|
-
const client = supabaseServiceRole(event)
|
|
410
|
+
const client = await supabaseServiceRole(event)
|
|
409
411
|
|
|
410
412
|
const { data } = await client.from('rls-protected-table').select()
|
|
411
413
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, addServerHandler, addPlugin, addTypeTemplate, extendViteConfig } from '@nuxt/kit';
|
|
1
|
+
import { defineNuxtModule, createResolver, addServerHandler, addPlugin, addImportsDir, addTypeTemplate, extendViteConfig } from '@nuxt/kit';
|
|
2
|
+
import { defu } from 'defu';
|
|
2
3
|
|
|
3
4
|
const module$1 = defineNuxtModule({
|
|
4
5
|
meta: {
|
|
@@ -28,24 +29,36 @@ const module$1 = defineNuxtModule({
|
|
|
28
29
|
},
|
|
29
30
|
setup(options, nuxt) {
|
|
30
31
|
const { resolve } = createResolver(import.meta.url);
|
|
31
|
-
|
|
32
|
+
const publicSupabaseConfig = nuxt.options.runtimeConfig.public.supabase;
|
|
33
|
+
const supabaseConfig = nuxt.options.runtimeConfig.supabase;
|
|
34
|
+
if (!process.env.NUXT_PUBLIC_SUPABASE_URL && !options.url && !publicSupabaseConfig?.url) {
|
|
32
35
|
console.warn("Missing `NUXT_PUBLIC_SUPABASE_URL` in environment or `url` in module options");
|
|
33
36
|
}
|
|
34
|
-
if (!process.env.NUXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY && !options.publishableKey) {
|
|
37
|
+
if (!process.env.NUXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY && !options.publishableKey && !publicSupabaseConfig?.publishableKey) {
|
|
35
38
|
console.warn(
|
|
36
39
|
"Missing `NUXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` in environment or `publishableKey` in module options"
|
|
37
40
|
);
|
|
38
41
|
}
|
|
39
|
-
nuxt.options.runtimeConfig.public.supabase = {
|
|
40
|
-
url: options.url,
|
|
41
|
-
publishableKey: options.publishableKey,
|
|
42
|
-
redirect: options.redirect,
|
|
43
|
-
redirectOptions: options.redirectOptions
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
nuxt.options.runtimeConfig.public.supabase = defu(publicSupabaseConfig, {
|
|
43
|
+
url: options.url ?? "",
|
|
44
|
+
publishableKey: options.publishableKey ?? "",
|
|
45
|
+
redirect: options.redirect ?? false,
|
|
46
|
+
redirectOptions: options.redirectOptions ?? {
|
|
47
|
+
login: "/login",
|
|
48
|
+
exclude: []
|
|
49
|
+
},
|
|
50
|
+
clientOptions: options.clientOptions ?? {
|
|
51
|
+
auth: {
|
|
52
|
+
flowType: "pkce",
|
|
53
|
+
detectSessionInUrl: true,
|
|
54
|
+
persistSession: true,
|
|
55
|
+
autoRefreshToken: true
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
nuxt.options.runtimeConfig.supabase = defu(supabaseConfig, {
|
|
60
|
+
serviceRoleKey: options.secretKey ?? ""
|
|
61
|
+
});
|
|
49
62
|
nuxt.options.alias = {
|
|
50
63
|
...nuxt.options.alias,
|
|
51
64
|
"#supabase/server": resolve("./runtime/server/services")
|
|
@@ -62,9 +75,7 @@ const module$1 = defineNuxtModule({
|
|
|
62
75
|
});
|
|
63
76
|
addPlugin(resolve("./runtime/plugins/supabase.server"));
|
|
64
77
|
addPlugin(resolve("./runtime/plugins/supabase.client"));
|
|
65
|
-
|
|
66
|
-
dirs.push(resolve("./runtime/composables"));
|
|
67
|
-
});
|
|
78
|
+
addImportsDir(resolve("./runtime/composables"));
|
|
68
79
|
if (options.redirect) {
|
|
69
80
|
addPlugin(resolve("./runtime/plugins/middleware-auth-redirect"));
|
|
70
81
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineNuxtPlugin, useRuntimeConfig, useRequestEvent } from "nuxt/app";
|
|
2
2
|
import { createServerClient } from "@supabase/ssr";
|
|
3
|
-
import { setCookie, parseCookies } from "h3";
|
|
3
|
+
import { setCookie, parseCookies, setResponseHeaders } from "h3";
|
|
4
4
|
export default defineNuxtPlugin({
|
|
5
5
|
name: "supabase",
|
|
6
6
|
enforce: "pre",
|
|
@@ -20,11 +20,12 @@ export default defineNuxtPlugin({
|
|
|
20
20
|
value
|
|
21
21
|
}));
|
|
22
22
|
},
|
|
23
|
-
setAll(cookiesToSet) {
|
|
23
|
+
setAll(cookiesToSet, headers = {}) {
|
|
24
24
|
try {
|
|
25
25
|
cookiesToSet.forEach(({ name, value, options }) => {
|
|
26
26
|
setCookie(event, name, value, options);
|
|
27
27
|
});
|
|
28
|
+
setResponseHeaders(event, headers);
|
|
28
29
|
} catch {
|
|
29
30
|
console.error("Error setting cookies", cookiesToSet);
|
|
30
31
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createServerClient } from "@supabase/ssr";
|
|
2
|
-
import { setCookie, parseCookies } from "h3";
|
|
2
|
+
import { setCookie, parseCookies, setResponseHeaders } from "h3";
|
|
3
3
|
import { useRuntimeConfig } from "#imports";
|
|
4
4
|
export const supabaseServerClient = async (event) => {
|
|
5
5
|
const {
|
|
6
6
|
supabase: { url, publishableKey, clientOptions }
|
|
7
|
-
} = useRuntimeConfig().public;
|
|
7
|
+
} = useRuntimeConfig(event).public;
|
|
8
8
|
let supabaseClient = event.context._supabaseClient;
|
|
9
9
|
const createTypedServerClient = createServerClient;
|
|
10
10
|
if (!supabaseClient) {
|
|
@@ -18,11 +18,12 @@ export const supabaseServerClient = async (event) => {
|
|
|
18
18
|
value
|
|
19
19
|
}));
|
|
20
20
|
},
|
|
21
|
-
setAll(cookiesToSet) {
|
|
21
|
+
setAll(cookiesToSet, headers = {}) {
|
|
22
22
|
try {
|
|
23
23
|
cookiesToSet.forEach(({ name, value, options }) => {
|
|
24
24
|
setCookie(event, name, value, options);
|
|
25
25
|
});
|
|
26
|
+
setResponseHeaders(event, headers);
|
|
26
27
|
} catch {
|
|
27
28
|
console.error("Error setting cookies", cookiesToSet);
|
|
28
29
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createServerClient } from "@supabase/ssr";
|
|
2
|
-
import { setCookie, parseCookies } from "h3";
|
|
2
|
+
import { setCookie, parseCookies, setResponseHeaders } from "h3";
|
|
3
3
|
import { useRuntimeConfig } from "#imports";
|
|
4
4
|
export const supabaseServiceRole = async (event) => {
|
|
5
5
|
const {
|
|
@@ -7,7 +7,7 @@ export const supabaseServiceRole = async (event) => {
|
|
|
7
7
|
public: {
|
|
8
8
|
supabase: { url, clientOptions }
|
|
9
9
|
}
|
|
10
|
-
} = useRuntimeConfig();
|
|
10
|
+
} = useRuntimeConfig(event);
|
|
11
11
|
if (!serviceRoleKey) {
|
|
12
12
|
throw new Error("Missing `SUPABASE_SERVICE_ROLE_KEY` in `.env`");
|
|
13
13
|
}
|
|
@@ -24,11 +24,12 @@ export const supabaseServiceRole = async (event) => {
|
|
|
24
24
|
value
|
|
25
25
|
}));
|
|
26
26
|
},
|
|
27
|
-
setAll(cookiesToSet) {
|
|
27
|
+
setAll(cookiesToSet, headers = {}) {
|
|
28
28
|
try {
|
|
29
29
|
cookiesToSet.forEach(({ name, value, options }) => {
|
|
30
30
|
setCookie(event, name, value, options);
|
|
31
31
|
});
|
|
32
|
+
setResponseHeaders(event, headers);
|
|
32
33
|
} catch {
|
|
33
34
|
console.error("Error setting cookies", cookiesToSet);
|
|
34
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floatingpixels/supabase-nuxt",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Supabase module for Nuxt",
|
|
5
5
|
"repository": "floatingpixels/supabase-nuxt",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,14 +43,13 @@
|
|
|
43
43
|
"test:pw": "playwright test test/playwright/",
|
|
44
44
|
"test:e2e": "pnpm run --silent db:start && pnpm run --silent db:reset && pnpm run --silent test:pw && pnpm run --silent db:stop",
|
|
45
45
|
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
46
|
-
"supa": "./node_modules/supabase/bin/supabase",
|
|
47
46
|
"db:fullreset": "pnpm run --silent db:reset && pnpm run --silent db:types && pnpm run --silent db:sync && pnpm run --silent db:seed",
|
|
48
|
-
"db:start": "
|
|
49
|
-
"db:stop": "
|
|
50
|
-
"db:types": "
|
|
47
|
+
"db:start": "supabase start",
|
|
48
|
+
"db:stop": "supabase stop",
|
|
49
|
+
"db:types": "supabase gen types --lang=typescript --local > ./playground/types/supabase.d.ts",
|
|
51
50
|
"db:lint": "sqlfluff lint --dialect postgres ./supabase/migrations/*.sql",
|
|
52
51
|
"db:format": "sqlfluff format --dialect postgres ./supabase/migrations/*.sql",
|
|
53
|
-
"db:reset": "
|
|
52
|
+
"db:reset": "supabase db reset",
|
|
54
53
|
"db:seed": "npx tsx seed.ts",
|
|
55
54
|
"db:sync": "npx @snaplet/seed sync",
|
|
56
55
|
"db:fullseed": "(npx @snaplet/seed sync) -and (npx tsx seed.ts)",
|
|
@@ -58,46 +57,38 @@
|
|
|
58
57
|
"cleanup": "pnpm nuxi cleanup && rm -rf node_modules pnpm-lock.yaml && pnpm i"
|
|
59
58
|
},
|
|
60
59
|
"dependencies": {
|
|
61
|
-
"@supabase/ssr": "^0.
|
|
62
|
-
"@supabase/supabase-js": "^2.
|
|
63
|
-
"cookie": "^1.1.1"
|
|
60
|
+
"@supabase/ssr": "^0.10.3",
|
|
61
|
+
"@supabase/supabase-js": "^2.106.2",
|
|
62
|
+
"cookie": "^1.1.1",
|
|
63
|
+
"defu": "^6.1.7"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@nuxt/devtools": "
|
|
66
|
+
"@nuxt/devtools": "4.0.0-alpha.6",
|
|
67
67
|
"@nuxt/eslint-config": "^1.15.2",
|
|
68
|
-
"@nuxt/kit": "^4.4.
|
|
68
|
+
"@nuxt/kit": "^4.4.6",
|
|
69
69
|
"@nuxt/module-builder": "^1.0.2",
|
|
70
|
-
"@nuxt/schema": "^4.4.
|
|
71
|
-
"@nuxt/test-utils": "4.0.
|
|
72
|
-
"@playwright/test": "^1.
|
|
70
|
+
"@nuxt/schema": "^4.4.6",
|
|
71
|
+
"@nuxt/test-utils": "4.0.3",
|
|
72
|
+
"@playwright/test": "^1.60.0",
|
|
73
73
|
"@snaplet/copycat": "^6.0.0",
|
|
74
74
|
"@snaplet/seed": "^0.98.0",
|
|
75
75
|
"@types/eslint-config-prettier": "^6.11.3",
|
|
76
|
-
"@types/node": "^25.
|
|
77
|
-
"@vitest/coverage-v8": "4.1.
|
|
78
|
-
"@vue/test-utils": "^2.4.
|
|
76
|
+
"@types/node": "^25.9.1",
|
|
77
|
+
"@vitest/coverage-v8": "4.1.7",
|
|
78
|
+
"@vue/test-utils": "^2.4.10",
|
|
79
79
|
"changelogen": "^0.6.2",
|
|
80
|
-
"eslint": "^10.
|
|
80
|
+
"eslint": "^10.4.1",
|
|
81
81
|
"eslint-config-prettier": "^10.1.8",
|
|
82
|
-
"happy-dom": "^20.
|
|
83
|
-
"nuxt": "^4.4.
|
|
84
|
-
"playwright-core": "^1.
|
|
85
|
-
"postgres": "^3.4.
|
|
86
|
-
"prettier": "^3.8.
|
|
87
|
-
"release-it": "^
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
"pnpm": {
|
|
94
|
-
"onlyBuiltDependencies": [
|
|
95
|
-
"@parcel/watcher",
|
|
96
|
-
"@prisma/engines",
|
|
97
|
-
"@snaplet/seed",
|
|
98
|
-
"esbuild",
|
|
99
|
-
"supabase",
|
|
100
|
-
"unrs-resolver"
|
|
101
|
-
]
|
|
82
|
+
"happy-dom": "^20.9.0",
|
|
83
|
+
"nuxt": "^4.4.6",
|
|
84
|
+
"playwright-core": "^1.60.0",
|
|
85
|
+
"postgres": "^3.4.9",
|
|
86
|
+
"prettier": "^3.8.3",
|
|
87
|
+
"release-it": "^20.2.0",
|
|
88
|
+
"std-env": "^4.1.0",
|
|
89
|
+
"supabase": "^2.102.0",
|
|
90
|
+
"typescript": "6.0.3",
|
|
91
|
+
"vitest": "^4.1.7",
|
|
92
|
+
"vue-tsc": "^3.3.3"
|
|
102
93
|
}
|
|
103
94
|
}
|