next-supa-utils 0.1.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.
@@ -0,0 +1,127 @@
1
+ "use client";
2
+ "use client";
3
+
4
+ // src/client/hooks/useSupaUser.ts
5
+ import { useEffect, useState } from "react";
6
+ import { createBrowserClient } from "@supabase/ssr";
7
+
8
+ // src/shared/utils/error-handler.ts
9
+ function handleSupaError(error) {
10
+ if (error instanceof Error) {
11
+ const record = error;
12
+ return {
13
+ message: error.message,
14
+ code: typeof record.code === "string" ? record.code : void 0,
15
+ status: typeof record.status === "number" ? record.status : void 0
16
+ };
17
+ }
18
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
19
+ const err = error;
20
+ return {
21
+ message: err.message,
22
+ code: typeof err.code === "string" ? err.code : void 0,
23
+ status: typeof err.status === "number" ? err.status : void 0
24
+ };
25
+ }
26
+ if (typeof error === "string") {
27
+ return { message: error };
28
+ }
29
+ return { message: "An unknown error occurred" };
30
+ }
31
+
32
+ // src/client/hooks/useSupaUser.ts
33
+ function useSupaUser() {
34
+ const [state, setState] = useState({
35
+ user: null,
36
+ loading: true,
37
+ error: null
38
+ });
39
+ useEffect(() => {
40
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
41
+ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
42
+ if (!supabaseUrl || !supabaseAnonKey) {
43
+ setState({
44
+ user: null,
45
+ loading: false,
46
+ error: {
47
+ message: "Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.",
48
+ code: "CONFIG_ERROR"
49
+ }
50
+ });
51
+ return;
52
+ }
53
+ const supabase = createBrowserClient(supabaseUrl, supabaseAnonKey);
54
+ supabase.auth.getUser().then(({ data, error }) => {
55
+ setState({
56
+ user: data.user,
57
+ loading: false,
58
+ error: error ? handleSupaError(error) : null
59
+ });
60
+ });
61
+ const {
62
+ data: { subscription }
63
+ } = supabase.auth.onAuthStateChange((_event, session) => {
64
+ setState((prev) => ({
65
+ ...prev,
66
+ user: session?.user ?? null,
67
+ loading: false
68
+ }));
69
+ });
70
+ return () => {
71
+ subscription.unsubscribe();
72
+ };
73
+ }, []);
74
+ return state;
75
+ }
76
+
77
+ // src/client/hooks/useSupaSession.ts
78
+ import { useEffect as useEffect2, useState as useState2 } from "react";
79
+ import { createBrowserClient as createBrowserClient2 } from "@supabase/ssr";
80
+ function useSupaSession() {
81
+ const [state, setState] = useState2({
82
+ session: null,
83
+ loading: true,
84
+ error: null
85
+ });
86
+ useEffect2(() => {
87
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
88
+ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
89
+ if (!supabaseUrl || !supabaseAnonKey) {
90
+ setState({
91
+ session: null,
92
+ loading: false,
93
+ error: {
94
+ message: "Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.",
95
+ code: "CONFIG_ERROR"
96
+ }
97
+ });
98
+ return;
99
+ }
100
+ const supabase = createBrowserClient2(supabaseUrl, supabaseAnonKey);
101
+ supabase.auth.getSession().then(({ data, error }) => {
102
+ setState({
103
+ session: data.session,
104
+ loading: false,
105
+ error: error ? handleSupaError(error) : null
106
+ });
107
+ });
108
+ const {
109
+ data: { subscription }
110
+ } = supabase.auth.onAuthStateChange((_event, session) => {
111
+ setState((prev) => ({
112
+ ...prev,
113
+ session,
114
+ loading: false
115
+ }));
116
+ });
117
+ return () => {
118
+ subscription.unsubscribe();
119
+ };
120
+ }, []);
121
+ return state;
122
+ }
123
+ export {
124
+ useSupaSession,
125
+ useSupaUser
126
+ };
127
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/hooks/useSupaUser.ts","../../src/shared/utils/error-handler.ts","../../src/client/hooks/useSupaSession.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createBrowserClient } from \"@supabase/ssr\";\n\nimport type { UseSupaUserReturn } from \"../../types\";\nimport { handleSupaError } from \"../../shared/utils/error-handler\";\n\n/**\n * React hook that provides the current Supabase user and\n * subscribes to real-time auth state changes.\n *\n * Must be used inside a Client Component (`\"use client\"`).\n *\n * @example\n * ```tsx\n * \"use client\";\n * import { useSupaUser } from \"next-supa-utils/client\";\n *\n * export default function Avatar() {\n * const { user, loading, error } = useSupaUser();\n *\n * if (loading) return <p>Loading…</p>;\n * if (error) return <p>Error: {error.message}</p>;\n * if (!user) return <p>Not signed in</p>;\n *\n * return <p>Hello, {user.email}</p>;\n * }\n * ```\n */\nexport function useSupaUser(): UseSupaUserReturn {\n const [state, setState] = useState<UseSupaUserReturn>({\n user: null,\n loading: true,\n error: null,\n });\n\n useEffect(() => {\n const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;\n const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;\n\n if (!supabaseUrl || !supabaseAnonKey) {\n setState({\n user: null,\n loading: false,\n error: {\n message:\n \"Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.\",\n code: \"CONFIG_ERROR\",\n },\n });\n return;\n }\n\n const supabase = createBrowserClient(supabaseUrl, supabaseAnonKey);\n\n // ── Initial fetch ─────────────────────────────────────────────\n supabase.auth.getUser().then(({ data, error }) => {\n setState({\n user: data.user,\n loading: false,\n error: error ? handleSupaError(error) : null,\n });\n });\n\n // ── Subscribe to auth state changes ───────────────────────────\n const {\n data: { subscription },\n } = supabase.auth.onAuthStateChange((_event, session) => {\n setState((prev) => ({\n ...prev,\n user: session?.user ?? null,\n loading: false,\n }));\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, []);\n\n return state;\n}\n","import type { SupaError } from \"../../types\";\n\n/**\n * Normalize any thrown value into a consistent `SupaError` shape.\n *\n * Handles:\n * - Supabase `AuthError` / `PostgrestError` (has `.message` and optional `.code` / `.status`)\n * - Standard `Error` instances\n * - Plain strings\n * - Unknown values (fallback)\n */\nexport function handleSupaError(error: unknown): SupaError {\n // ── Supabase errors & standard Error instances ──────────────────\n if (error instanceof Error) {\n const record = error as unknown as Record<string, unknown>;\n return {\n message: error.message,\n code: typeof record.code === \"string\" ? record.code : undefined,\n status: typeof record.status === \"number\" ? record.status : undefined,\n };\n }\n\n // ── Plain object with a message property ────────────────────────\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof (error as Record<string, unknown>).message === \"string\"\n ) {\n const err = error as Record<string, unknown>;\n return {\n message: err.message as string,\n code: typeof err.code === \"string\" ? err.code : undefined,\n status: typeof err.status === \"number\" ? err.status : undefined,\n };\n }\n\n // ── String ──────────────────────────────────────────────────────\n if (typeof error === \"string\") {\n return { message: error };\n }\n\n // ── Fallback ────────────────────────────────────────────────────\n return { message: \"An unknown error occurred\" };\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createBrowserClient } from \"@supabase/ssr\";\nimport type { Session } from \"@supabase/supabase-js\";\n\nimport type { UseSupaSessionReturn } from \"../../types\";\nimport { handleSupaError } from \"../../shared/utils/error-handler\";\n\n/**\n * React hook that provides the current Supabase session and\n * subscribes to real-time auth state changes.\n *\n * Must be used inside a Client Component (`\"use client\"`).\n *\n * @example\n * ```tsx\n * \"use client\";\n * import { useSupaSession } from \"next-supa-utils/client\";\n *\n * export default function TokenDisplay() {\n * const { session, loading, error } = useSupaSession();\n *\n * if (loading) return <p>Loading…</p>;\n * if (error) return <p>Error: {error.message}</p>;\n * if (!session) return <p>No active session</p>;\n *\n * return <p>Token expires at: {session.expires_at}</p>;\n * }\n * ```\n */\nexport function useSupaSession(): UseSupaSessionReturn {\n const [state, setState] = useState<UseSupaSessionReturn>({\n session: null,\n loading: true,\n error: null,\n });\n\n useEffect(() => {\n const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;\n const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;\n\n if (!supabaseUrl || !supabaseAnonKey) {\n setState({\n session: null,\n loading: false,\n error: {\n message:\n \"Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.\",\n code: \"CONFIG_ERROR\",\n },\n });\n return;\n }\n\n const supabase = createBrowserClient(supabaseUrl, supabaseAnonKey);\n\n // ── Initial fetch ─────────────────────────────────────────────\n supabase.auth.getSession().then(({ data, error }) => {\n setState({\n session: data.session,\n loading: false,\n error: error ? handleSupaError(error) : null,\n });\n });\n\n // ── Subscribe to auth state changes ───────────────────────────\n const {\n data: { subscription },\n } = supabase.auth.onAuthStateChange((_event, session: Session | null) => {\n setState((prev) => ({\n ...prev,\n session,\n loading: false,\n }));\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, []);\n\n return state;\n}\n"],"mappings":"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","names":["useEffect","useState","createBrowserClient","useState","useEffect","createBrowserClient"]}
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/server/index.ts
21
+ var server_exports = {};
22
+ __export(server_exports, {
23
+ createAction: () => createAction,
24
+ withSupaAuth: () => withSupaAuth
25
+ });
26
+ module.exports = __toCommonJS(server_exports);
27
+
28
+ // src/server/middleware/withSupaAuth.ts
29
+ var import_ssr = require("@supabase/ssr");
30
+ var import_server = require("next/server");
31
+ function withSupaAuth(config) {
32
+ const {
33
+ protectedRoutes,
34
+ redirectTo = "/login",
35
+ publicRoutes = [],
36
+ onAuthSuccess
37
+ } = config;
38
+ return async function middleware(request) {
39
+ let response = import_server.NextResponse.next({
40
+ request: { headers: request.headers }
41
+ });
42
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
43
+ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
44
+ if (!supabaseUrl || !supabaseAnonKey) {
45
+ console.error(
46
+ "[next-supa-utils] Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables."
47
+ );
48
+ return response;
49
+ }
50
+ const supabase = (0, import_ssr.createServerClient)(supabaseUrl, supabaseAnonKey, {
51
+ cookies: {
52
+ getAll() {
53
+ return request.cookies.getAll();
54
+ },
55
+ setAll(cookiesToSet) {
56
+ cookiesToSet.forEach(({ name, value }) => {
57
+ request.cookies.set(name, value);
58
+ });
59
+ response = import_server.NextResponse.next({ request });
60
+ cookiesToSet.forEach(({ name, value, options }) => {
61
+ response.cookies.set(name, value, options);
62
+ });
63
+ }
64
+ }
65
+ });
66
+ const {
67
+ data: { user }
68
+ } = await supabase.auth.getUser();
69
+ const { pathname } = request.nextUrl;
70
+ const isPublicRoute = publicRoutes.some(
71
+ (route) => pathname.startsWith(route)
72
+ );
73
+ if (isPublicRoute) {
74
+ return response;
75
+ }
76
+ const isProtectedRoute = protectedRoutes.some(
77
+ (route) => pathname.startsWith(route)
78
+ );
79
+ if (isProtectedRoute && !user) {
80
+ const loginUrl = new URL(redirectTo, request.url);
81
+ loginUrl.searchParams.set("next", pathname);
82
+ return import_server.NextResponse.redirect(loginUrl);
83
+ }
84
+ if (user && onAuthSuccess) {
85
+ await onAuthSuccess({ id: user.id, email: user.email ?? void 0 });
86
+ }
87
+ return response;
88
+ };
89
+ }
90
+
91
+ // src/server/actions/actionWrapper.ts
92
+ var import_ssr2 = require("@supabase/ssr");
93
+ var import_headers = require("next/headers");
94
+
95
+ // src/shared/utils/error-handler.ts
96
+ function handleSupaError(error) {
97
+ if (error instanceof Error) {
98
+ const record = error;
99
+ return {
100
+ message: error.message,
101
+ code: typeof record.code === "string" ? record.code : void 0,
102
+ status: typeof record.status === "number" ? record.status : void 0
103
+ };
104
+ }
105
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
106
+ const err = error;
107
+ return {
108
+ message: err.message,
109
+ code: typeof err.code === "string" ? err.code : void 0,
110
+ status: typeof err.status === "number" ? err.status : void 0
111
+ };
112
+ }
113
+ if (typeof error === "string") {
114
+ return { message: error };
115
+ }
116
+ return { message: "An unknown error occurred" };
117
+ }
118
+
119
+ // src/server/actions/actionWrapper.ts
120
+ function createAction(fn) {
121
+ return async (...args) => {
122
+ try {
123
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
124
+ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
125
+ if (!supabaseUrl || !supabaseAnonKey) {
126
+ return {
127
+ data: null,
128
+ error: {
129
+ message: "Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.",
130
+ code: "CONFIG_ERROR"
131
+ }
132
+ };
133
+ }
134
+ const cookieStore = await (0, import_headers.cookies)();
135
+ const supabase = (0, import_ssr2.createServerClient)(supabaseUrl, supabaseAnonKey, {
136
+ cookies: {
137
+ getAll() {
138
+ return cookieStore.getAll();
139
+ },
140
+ setAll(cookiesToSet) {
141
+ try {
142
+ cookiesToSet.forEach(({ name, value, options }) => {
143
+ cookieStore.set(name, value, options);
144
+ });
145
+ } catch {
146
+ }
147
+ }
148
+ }
149
+ });
150
+ const data = await fn(supabase, ...args);
151
+ return { data, error: null };
152
+ } catch (caught) {
153
+ const error = handleSupaError(caught);
154
+ return { data: null, error };
155
+ }
156
+ };
157
+ }
158
+ // Annotate the CommonJS export names for ESM import in node:
159
+ 0 && (module.exports = {
160
+ createAction,
161
+ withSupaAuth
162
+ });
163
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/index.ts","../../src/server/middleware/withSupaAuth.ts","../../src/server/actions/actionWrapper.ts","../../src/shared/utils/error-handler.ts"],"sourcesContent":["// ── Server entry point ──────────────────────────────────────────────\n// This module should ONLY be imported in server-side contexts:\n// middleware.ts, Server Components, Server Actions, Route Handlers.\n\nexport { withSupaAuth } from \"./middleware/withSupaAuth\";\nexport { createAction } from \"./actions/actionWrapper\";\n\n// Re-export types consumers commonly need alongside server helpers.\nexport type { SupaAuthConfig, ActionResponse, SupaError } from \"../types\";\n","import { createServerClient, type CookieOptions } from \"@supabase/ssr\";\nimport { NextResponse, type NextRequest } from \"next/server\";\n\nimport type { SupaAuthConfig } from \"../../types\";\n\n/**\n * Create a Next.js middleware handler that protects routes based on\n * Supabase authentication state.\n *\n * @example\n * ```ts\n * // middleware.ts\n * import { withSupaAuth } from \"next-supa-utils/server\";\n *\n * export default withSupaAuth({\n * protectedRoutes: [\"/dashboard\", \"/admin\"],\n * redirectTo: \"/login\",\n * publicRoutes: [\"/admin/login\"],\n * });\n *\n * export const config = {\n * matcher: [\"/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)\"],\n * };\n * ```\n */\nexport function withSupaAuth(config: SupaAuthConfig) {\n const {\n protectedRoutes,\n redirectTo = \"/login\",\n publicRoutes = [],\n onAuthSuccess,\n } = config;\n\n return async function middleware(request: NextRequest): Promise<NextResponse> {\n // ── 1. Create a mutable response so Supabase can set cookies ──\n let response = NextResponse.next({\n request: { headers: request.headers },\n });\n\n const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;\n const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;\n\n if (!supabaseUrl || !supabaseAnonKey) {\n console.error(\n \"[next-supa-utils] Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.\",\n );\n return response;\n }\n\n // ── 2. Initialize server client with middleware cookie helpers ─\n const supabase = createServerClient(supabaseUrl, supabaseAnonKey, {\n cookies: {\n getAll() {\n return request.cookies.getAll();\n },\n setAll(cookiesToSet: { name: string; value: string; options?: CookieOptions }[]) {\n // Forward cookies to the request so downstream server\n // components can read the updated session.\n cookiesToSet.forEach(({ name, value }) => {\n request.cookies.set(name, value);\n });\n\n // Re-create the response so it carries the updated request.\n response = NextResponse.next({ request });\n\n // Set cookies on the outgoing response so the browser\n // stores the refreshed tokens.\n cookiesToSet.forEach(({ name, value, options }) => {\n response.cookies.set(name, value, options);\n });\n },\n },\n });\n\n // ── 3. Refresh session (required to keep tokens alive) ────────\n const {\n data: { user },\n } = await supabase.auth.getUser();\n\n const { pathname } = request.nextUrl;\n\n // ── 4. Check if current path matches a public override ────────\n const isPublicRoute = publicRoutes.some((route) =>\n pathname.startsWith(route),\n );\n\n if (isPublicRoute) {\n return response;\n }\n\n // ── 5. Check if current path requires authentication ──────────\n const isProtectedRoute = protectedRoutes.some((route) =>\n pathname.startsWith(route),\n );\n\n if (isProtectedRoute && !user) {\n const loginUrl = new URL(redirectTo, request.url);\n // Preserve the originally-requested URL so the app can redirect\n // back after login.\n loginUrl.searchParams.set(\"next\", pathname);\n return NextResponse.redirect(loginUrl);\n }\n\n // ── 6. Optional success callback ──────────────────────────────\n if (user && onAuthSuccess) {\n await onAuthSuccess({ id: user.id, email: user.email ?? undefined });\n }\n\n return response;\n };\n}\n","import { createServerClient, type CookieOptions } from \"@supabase/ssr\";\nimport { cookies } from \"next/headers\";\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\nimport type { ActionResponse, SupaError } from \"../../types\";\nimport { handleSupaError } from \"../../shared/utils/error-handler\";\n\n/**\n * Create a type-safe Server Action that automatically:\n * 1. Initialises a Supabase server client (with cookies)\n * 2. Wraps execution in try/catch\n * 3. Returns a standardised `{ data, error }` response\n *\n * @example\n * ```ts\n * // app/actions/profile.ts\n * \"use server\";\n * import { createAction } from \"next-supa-utils/server\";\n *\n * export const getProfile = createAction(async (supabase, userId: string) => {\n * const { data, error } = await supabase\n * .from(\"profiles\")\n * .select(\"*\")\n * .eq(\"id\", userId)\n * .single();\n *\n * if (error) throw error;\n * return data;\n * });\n *\n * // Usage in a Server Component or Client Component:\n * const result = await getProfile(\"user-uuid\");\n * if (result.error) { ... }\n * ```\n */\nexport function createAction<TArgs extends unknown[], TResult>(\n fn: (supabase: SupabaseClient, ...args: TArgs) => Promise<TResult>,\n): (...args: TArgs) => Promise<ActionResponse<TResult>> {\n return async (...args: TArgs): Promise<ActionResponse<TResult>> => {\n try {\n const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;\n const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;\n\n if (!supabaseUrl || !supabaseAnonKey) {\n return {\n data: null,\n error: {\n message:\n \"Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.\",\n code: \"CONFIG_ERROR\",\n },\n };\n }\n\n const cookieStore = await cookies();\n\n const supabase = createServerClient(supabaseUrl, supabaseAnonKey, {\n cookies: {\n getAll() {\n return cookieStore.getAll();\n },\n setAll(cookiesToSet: { name: string; value: string; options?: CookieOptions }[]) {\n try {\n cookiesToSet.forEach(({ name, value, options }) => {\n cookieStore.set(name, value, options);\n });\n } catch {\n // `cookies().set()` throws when called from a Server Component.\n // In that context we only need read access — the middleware\n // handles token refresh.\n }\n },\n },\n });\n\n const data = await fn(supabase, ...args);\n\n return { data, error: null };\n } catch (caught: unknown) {\n const error: SupaError = handleSupaError(caught);\n return { data: null, error };\n }\n };\n}\n","import type { SupaError } from \"../../types\";\n\n/**\n * Normalize any thrown value into a consistent `SupaError` shape.\n *\n * Handles:\n * - Supabase `AuthError` / `PostgrestError` (has `.message` and optional `.code` / `.status`)\n * - Standard `Error` instances\n * - Plain strings\n * - Unknown values (fallback)\n */\nexport function handleSupaError(error: unknown): SupaError {\n // ── Supabase errors & standard Error instances ──────────────────\n if (error instanceof Error) {\n const record = error as unknown as Record<string, unknown>;\n return {\n message: error.message,\n code: typeof record.code === \"string\" ? record.code : undefined,\n status: typeof record.status === \"number\" ? record.status : undefined,\n };\n }\n\n // ── Plain object with a message property ────────────────────────\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof (error as Record<string, unknown>).message === \"string\"\n ) {\n const err = error as Record<string, unknown>;\n return {\n message: err.message as string,\n code: typeof err.code === \"string\" ? err.code : undefined,\n status: typeof err.status === \"number\" ? err.status : undefined,\n };\n }\n\n // ── String ──────────────────────────────────────────────────────\n if (typeof error === \"string\") {\n return { message: error };\n }\n\n // ── Fallback ────────────────────────────────────────────────────\n return { message: \"An unknown error occurred\" };\n}\n"],"mappings":"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","names":["import_ssr"]}
@@ -0,0 +1,99 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { SupabaseClient } from '@supabase/supabase-js';
3
+
4
+ /** Standardized error shape returned by all next-supa-utils helpers. */
5
+ interface SupaError {
6
+ message: string;
7
+ code?: string;
8
+ status?: number;
9
+ }
10
+ /** Discriminated success/failure response returned by `createAction`. */
11
+ type ActionResponse<T> = {
12
+ data: T;
13
+ error: null;
14
+ } | {
15
+ data: null;
16
+ error: SupaError;
17
+ };
18
+ interface SupaAuthConfig {
19
+ /**
20
+ * Route prefixes that require an authenticated user.
21
+ * Supports simple prefix matching.
22
+ *
23
+ * @example ["/dashboard", "/admin", "/settings"]
24
+ */
25
+ protectedRoutes: string[];
26
+ /**
27
+ * Where to redirect unauthenticated users.
28
+ * @default "/login"
29
+ */
30
+ redirectTo?: string;
31
+ /**
32
+ * Routes that are always public, even if they match a protected prefix.
33
+ *
34
+ * @example ["/admin/login"]
35
+ */
36
+ publicRoutes?: string[];
37
+ /**
38
+ * Optional callback invoked after session refresh,
39
+ * before the redirect decision. Useful for custom logging or headers.
40
+ */
41
+ onAuthSuccess?: (user: {
42
+ id: string;
43
+ email?: string;
44
+ }) => void | Promise<void>;
45
+ }
46
+
47
+ /**
48
+ * Create a Next.js middleware handler that protects routes based on
49
+ * Supabase authentication state.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * // middleware.ts
54
+ * import { withSupaAuth } from "next-supa-utils/server";
55
+ *
56
+ * export default withSupaAuth({
57
+ * protectedRoutes: ["/dashboard", "/admin"],
58
+ * redirectTo: "/login",
59
+ * publicRoutes: ["/admin/login"],
60
+ * });
61
+ *
62
+ * export const config = {
63
+ * matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)"],
64
+ * };
65
+ * ```
66
+ */
67
+ declare function withSupaAuth(config: SupaAuthConfig): (request: NextRequest) => Promise<NextResponse>;
68
+
69
+ /**
70
+ * Create a type-safe Server Action that automatically:
71
+ * 1. Initialises a Supabase server client (with cookies)
72
+ * 2. Wraps execution in try/catch
73
+ * 3. Returns a standardised `{ data, error }` response
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * // app/actions/profile.ts
78
+ * "use server";
79
+ * import { createAction } from "next-supa-utils/server";
80
+ *
81
+ * export const getProfile = createAction(async (supabase, userId: string) => {
82
+ * const { data, error } = await supabase
83
+ * .from("profiles")
84
+ * .select("*")
85
+ * .eq("id", userId)
86
+ * .single();
87
+ *
88
+ * if (error) throw error;
89
+ * return data;
90
+ * });
91
+ *
92
+ * // Usage in a Server Component or Client Component:
93
+ * const result = await getProfile("user-uuid");
94
+ * if (result.error) { ... }
95
+ * ```
96
+ */
97
+ declare function createAction<TArgs extends unknown[], TResult>(fn: (supabase: SupabaseClient, ...args: TArgs) => Promise<TResult>): (...args: TArgs) => Promise<ActionResponse<TResult>>;
98
+
99
+ export { type ActionResponse, type SupaAuthConfig, type SupaError, createAction, withSupaAuth };
@@ -0,0 +1,99 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { SupabaseClient } from '@supabase/supabase-js';
3
+
4
+ /** Standardized error shape returned by all next-supa-utils helpers. */
5
+ interface SupaError {
6
+ message: string;
7
+ code?: string;
8
+ status?: number;
9
+ }
10
+ /** Discriminated success/failure response returned by `createAction`. */
11
+ type ActionResponse<T> = {
12
+ data: T;
13
+ error: null;
14
+ } | {
15
+ data: null;
16
+ error: SupaError;
17
+ };
18
+ interface SupaAuthConfig {
19
+ /**
20
+ * Route prefixes that require an authenticated user.
21
+ * Supports simple prefix matching.
22
+ *
23
+ * @example ["/dashboard", "/admin", "/settings"]
24
+ */
25
+ protectedRoutes: string[];
26
+ /**
27
+ * Where to redirect unauthenticated users.
28
+ * @default "/login"
29
+ */
30
+ redirectTo?: string;
31
+ /**
32
+ * Routes that are always public, even if they match a protected prefix.
33
+ *
34
+ * @example ["/admin/login"]
35
+ */
36
+ publicRoutes?: string[];
37
+ /**
38
+ * Optional callback invoked after session refresh,
39
+ * before the redirect decision. Useful for custom logging or headers.
40
+ */
41
+ onAuthSuccess?: (user: {
42
+ id: string;
43
+ email?: string;
44
+ }) => void | Promise<void>;
45
+ }
46
+
47
+ /**
48
+ * Create a Next.js middleware handler that protects routes based on
49
+ * Supabase authentication state.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * // middleware.ts
54
+ * import { withSupaAuth } from "next-supa-utils/server";
55
+ *
56
+ * export default withSupaAuth({
57
+ * protectedRoutes: ["/dashboard", "/admin"],
58
+ * redirectTo: "/login",
59
+ * publicRoutes: ["/admin/login"],
60
+ * });
61
+ *
62
+ * export const config = {
63
+ * matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)"],
64
+ * };
65
+ * ```
66
+ */
67
+ declare function withSupaAuth(config: SupaAuthConfig): (request: NextRequest) => Promise<NextResponse>;
68
+
69
+ /**
70
+ * Create a type-safe Server Action that automatically:
71
+ * 1. Initialises a Supabase server client (with cookies)
72
+ * 2. Wraps execution in try/catch
73
+ * 3. Returns a standardised `{ data, error }` response
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * // app/actions/profile.ts
78
+ * "use server";
79
+ * import { createAction } from "next-supa-utils/server";
80
+ *
81
+ * export const getProfile = createAction(async (supabase, userId: string) => {
82
+ * const { data, error } = await supabase
83
+ * .from("profiles")
84
+ * .select("*")
85
+ * .eq("id", userId)
86
+ * .single();
87
+ *
88
+ * if (error) throw error;
89
+ * return data;
90
+ * });
91
+ *
92
+ * // Usage in a Server Component or Client Component:
93
+ * const result = await getProfile("user-uuid");
94
+ * if (result.error) { ... }
95
+ * ```
96
+ */
97
+ declare function createAction<TArgs extends unknown[], TResult>(fn: (supabase: SupabaseClient, ...args: TArgs) => Promise<TResult>): (...args: TArgs) => Promise<ActionResponse<TResult>>;
98
+
99
+ export { type ActionResponse, type SupaAuthConfig, type SupaError, createAction, withSupaAuth };
@@ -0,0 +1,135 @@
1
+ // src/server/middleware/withSupaAuth.ts
2
+ import { createServerClient } from "@supabase/ssr";
3
+ import { NextResponse } from "next/server";
4
+ function withSupaAuth(config) {
5
+ const {
6
+ protectedRoutes,
7
+ redirectTo = "/login",
8
+ publicRoutes = [],
9
+ onAuthSuccess
10
+ } = config;
11
+ return async function middleware(request) {
12
+ let response = NextResponse.next({
13
+ request: { headers: request.headers }
14
+ });
15
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
16
+ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
17
+ if (!supabaseUrl || !supabaseAnonKey) {
18
+ console.error(
19
+ "[next-supa-utils] Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables."
20
+ );
21
+ return response;
22
+ }
23
+ const supabase = createServerClient(supabaseUrl, supabaseAnonKey, {
24
+ cookies: {
25
+ getAll() {
26
+ return request.cookies.getAll();
27
+ },
28
+ setAll(cookiesToSet) {
29
+ cookiesToSet.forEach(({ name, value }) => {
30
+ request.cookies.set(name, value);
31
+ });
32
+ response = NextResponse.next({ request });
33
+ cookiesToSet.forEach(({ name, value, options }) => {
34
+ response.cookies.set(name, value, options);
35
+ });
36
+ }
37
+ }
38
+ });
39
+ const {
40
+ data: { user }
41
+ } = await supabase.auth.getUser();
42
+ const { pathname } = request.nextUrl;
43
+ const isPublicRoute = publicRoutes.some(
44
+ (route) => pathname.startsWith(route)
45
+ );
46
+ if (isPublicRoute) {
47
+ return response;
48
+ }
49
+ const isProtectedRoute = protectedRoutes.some(
50
+ (route) => pathname.startsWith(route)
51
+ );
52
+ if (isProtectedRoute && !user) {
53
+ const loginUrl = new URL(redirectTo, request.url);
54
+ loginUrl.searchParams.set("next", pathname);
55
+ return NextResponse.redirect(loginUrl);
56
+ }
57
+ if (user && onAuthSuccess) {
58
+ await onAuthSuccess({ id: user.id, email: user.email ?? void 0 });
59
+ }
60
+ return response;
61
+ };
62
+ }
63
+
64
+ // src/server/actions/actionWrapper.ts
65
+ import { createServerClient as createServerClient2 } from "@supabase/ssr";
66
+ import { cookies } from "next/headers";
67
+
68
+ // src/shared/utils/error-handler.ts
69
+ function handleSupaError(error) {
70
+ if (error instanceof Error) {
71
+ const record = error;
72
+ return {
73
+ message: error.message,
74
+ code: typeof record.code === "string" ? record.code : void 0,
75
+ status: typeof record.status === "number" ? record.status : void 0
76
+ };
77
+ }
78
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
79
+ const err = error;
80
+ return {
81
+ message: err.message,
82
+ code: typeof err.code === "string" ? err.code : void 0,
83
+ status: typeof err.status === "number" ? err.status : void 0
84
+ };
85
+ }
86
+ if (typeof error === "string") {
87
+ return { message: error };
88
+ }
89
+ return { message: "An unknown error occurred" };
90
+ }
91
+
92
+ // src/server/actions/actionWrapper.ts
93
+ function createAction(fn) {
94
+ return async (...args) => {
95
+ try {
96
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
97
+ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
98
+ if (!supabaseUrl || !supabaseAnonKey) {
99
+ return {
100
+ data: null,
101
+ error: {
102
+ message: "Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY environment variables.",
103
+ code: "CONFIG_ERROR"
104
+ }
105
+ };
106
+ }
107
+ const cookieStore = await cookies();
108
+ const supabase = createServerClient2(supabaseUrl, supabaseAnonKey, {
109
+ cookies: {
110
+ getAll() {
111
+ return cookieStore.getAll();
112
+ },
113
+ setAll(cookiesToSet) {
114
+ try {
115
+ cookiesToSet.forEach(({ name, value, options }) => {
116
+ cookieStore.set(name, value, options);
117
+ });
118
+ } catch {
119
+ }
120
+ }
121
+ }
122
+ });
123
+ const data = await fn(supabase, ...args);
124
+ return { data, error: null };
125
+ } catch (caught) {
126
+ const error = handleSupaError(caught);
127
+ return { data: null, error };
128
+ }
129
+ };
130
+ }
131
+ export {
132
+ createAction,
133
+ withSupaAuth
134
+ };
135
+ //# sourceMappingURL=index.js.map