Add some actions to make stuff easy
This commit is contained in:
parent
0cf1049ec6
commit
c5eed77822
@ -34,7 +34,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@tailwindcss/postcss": "^4.1.6",
|
"@tailwindcss/postcss": "^4.1.6",
|
||||||
"@types/node": "^20.17.46",
|
"@types/node": "^20.17.47",
|
||||||
"@types/react": "^19.1.4",
|
"@types/react": "^19.1.4",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"eslint": "^9.26.0",
|
"eslint": "^9.26.0",
|
||||||
|
42
pnpm-lock.yaml
generated
42
pnpm-lock.yaml
generated
@ -58,8 +58,8 @@ importers:
|
|||||||
specifier: ^4.1.6
|
specifier: ^4.1.6
|
||||||
version: 4.1.6
|
version: 4.1.6
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.17.46
|
specifier: ^20.17.47
|
||||||
version: 20.17.46
|
version: 20.17.47
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^19.1.4
|
specifier: ^19.1.4
|
||||||
version: 19.1.4
|
version: 19.1.4
|
||||||
@ -680,8 +680,8 @@ packages:
|
|||||||
'@types/json5@0.0.29':
|
'@types/json5@0.0.29':
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
|
|
||||||
'@types/node@20.17.46':
|
'@types/node@20.17.47':
|
||||||
resolution: {integrity: sha512-0PQHLhZPWOxGW4auogW0eOQAuNIlCYvibIpG67ja0TOJ6/sehu+1en7sfceUn+QQtx4Rk3GxbLNwPh0Cav7TWw==}
|
resolution: {integrity: sha512-3dLX0Upo1v7RvUimvxLeXqwrfyKxUINk0EAM83swP2mlSUcwV73sZy8XhNz8bcZ3VbsfQyC/y6jRdL5tgCNpDQ==}
|
||||||
|
|
||||||
'@types/phoenix@1.6.6':
|
'@types/phoenix@1.6.6':
|
||||||
resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==}
|
resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==}
|
||||||
@ -1041,8 +1041,8 @@ packages:
|
|||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
debug@4.4.0:
|
debug@4.4.1:
|
||||||
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
|
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
supports-color: '*'
|
supports-color: '*'
|
||||||
@ -2378,7 +2378,7 @@ snapshots:
|
|||||||
'@eslint/config-array@0.20.0':
|
'@eslint/config-array@0.20.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint/object-schema': 2.1.6
|
'@eslint/object-schema': 2.1.6
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -2392,7 +2392,7 @@ snapshots:
|
|||||||
'@eslint/eslintrc@3.3.1':
|
'@eslint/eslintrc@3.3.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
espree: 10.3.0
|
espree: 10.3.0
|
||||||
globals: 14.0.0
|
globals: 14.0.0
|
||||||
ignore: 5.3.2
|
ignore: 5.3.2
|
||||||
@ -2841,7 +2841,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/json5@0.0.29': {}
|
'@types/json5@0.0.29': {}
|
||||||
|
|
||||||
'@types/node@20.17.46':
|
'@types/node@20.17.47':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
|
|
||||||
@ -2857,7 +2857,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.17.46
|
'@types/node': 20.17.47
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
|
'@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2882,7 +2882,7 @@ snapshots:
|
|||||||
'@typescript-eslint/types': 8.32.1
|
'@typescript-eslint/types': 8.32.1
|
||||||
'@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
|
'@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
|
||||||
'@typescript-eslint/visitor-keys': 8.32.1
|
'@typescript-eslint/visitor-keys': 8.32.1
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
eslint: 9.26.0(jiti@2.4.2)
|
eslint: 9.26.0(jiti@2.4.2)
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -2897,7 +2897,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
|
'@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
|
||||||
'@typescript-eslint/utils': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
|
'@typescript-eslint/utils': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
eslint: 9.26.0(jiti@2.4.2)
|
eslint: 9.26.0(jiti@2.4.2)
|
||||||
ts-api-utils: 2.1.0(typescript@5.8.3)
|
ts-api-utils: 2.1.0(typescript@5.8.3)
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
@ -2910,7 +2910,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.32.1
|
'@typescript-eslint/types': 8.32.1
|
||||||
'@typescript-eslint/visitor-keys': 8.32.1
|
'@typescript-eslint/visitor-keys': 8.32.1
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
fast-glob: 3.3.3
|
fast-glob: 3.3.3
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
minimatch: 9.0.5
|
minimatch: 9.0.5
|
||||||
@ -3098,7 +3098,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.1.2
|
bytes: 3.1.2
|
||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
http-errors: 2.0.0
|
http-errors: 2.0.0
|
||||||
iconv-lite: 0.6.3
|
iconv-lite: 0.6.3
|
||||||
on-finished: 2.4.1
|
on-finished: 2.4.1
|
||||||
@ -3232,7 +3232,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
debug@4.4.0:
|
debug@4.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
@ -3408,7 +3408,7 @@ snapshots:
|
|||||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0(jiti@2.4.2)):
|
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0(jiti@2.4.2)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nolyfill/is-core-module': 1.0.39
|
'@nolyfill/is-core-module': 1.0.39
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
eslint: 9.26.0(jiti@2.4.2)
|
eslint: 9.26.0(jiti@2.4.2)
|
||||||
get-tsconfig: 4.10.0
|
get-tsconfig: 4.10.0
|
||||||
is-bun-module: 2.0.0
|
is-bun-module: 2.0.0
|
||||||
@ -3533,7 +3533,7 @@ snapshots:
|
|||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 8.3.0
|
eslint-scope: 8.3.0
|
||||||
eslint-visitor-keys: 4.2.0
|
eslint-visitor-keys: 4.2.0
|
||||||
@ -3596,7 +3596,7 @@ snapshots:
|
|||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
cookie: 0.7.2
|
cookie: 0.7.2
|
||||||
cookie-signature: 1.2.2
|
cookie-signature: 1.2.2
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
@ -3660,7 +3660,7 @@ snapshots:
|
|||||||
|
|
||||||
finalhandler@2.1.0:
|
finalhandler@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
on-finished: 2.4.1
|
on-finished: 2.4.1
|
||||||
@ -4307,7 +4307,7 @@ snapshots:
|
|||||||
|
|
||||||
router@2.2.0:
|
router@2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
is-promise: 4.0.0
|
is-promise: 4.0.0
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
@ -4350,7 +4350,7 @@ snapshots:
|
|||||||
|
|
||||||
send@1.2.0:
|
send@1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.0
|
debug: 4.4.1
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
'use server';
|
|
||||||
|
|
||||||
import 'server-only';
|
|
||||||
import { createServerClient } from '@/utils/supabase';
|
|
@ -1,5 +1,5 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { forgotPassword } from '@/actions/auth';
|
import { forgotPassword } from '@/lib/actions';
|
||||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||||
import { Input, Label } from '@/components/ui';
|
import { Input, Label } from '@/components/ui';
|
||||||
import { SmtpMessage } from '@/app/(auth-pages)/smtp-message';
|
import { SmtpMessage } from '@/app/(auth-pages)/smtp-message';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { signIn } from '@/actions/auth';
|
import { signIn } from '@/lib/actions';
|
||||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||||
import { Input, Label } from '@/components/ui';
|
import { Input, Label } from '@/components/ui';
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { signUp } from '@/actions/auth';
|
import { signUp } from '@/lib/actions';
|
||||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||||
import { Input, Label } from '@/components/ui';
|
import { Input, Label } from '@/components/ui';
|
||||||
import { SmtpMessage } from '@/app/(auth-pages)/smtp-message';
|
import { SmtpMessage } from '@/app/(auth-pages)/smtp-message';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { resetPassword } from '@/actions/auth';
|
import { resetPassword } from '@/lib/actions';
|
||||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||||
import { Input, Label } from '@/components/ui';
|
import { Input, Label } from '@/components/ui';
|
||||||
|
|
||||||
|
@ -1,54 +1,21 @@
|
|||||||
'use server';
|
'use server';
|
||||||
|
import { getSignedUrl, getProfile } from '@/lib/actions';
|
||||||
import { createServerClient } from '@/utils/supabase';
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
|
||||||
export default async function Page() {
|
const Page = async () => {
|
||||||
const supabase = await createServerClient();
|
const user = await getProfile();
|
||||||
|
if (!user.success) throw new Error(user.error);
|
||||||
|
|
||||||
// Get authenticated user
|
const imageUrl = await getSignedUrl({
|
||||||
const {
|
bucket: 'avatars',
|
||||||
data: { user: authUser },
|
url: user.data.avatar_url ?? '',
|
||||||
error: userError,
|
});
|
||||||
} = await supabase.auth.getUser();
|
if (!imageUrl.success) throw new Error(imageUrl.error);
|
||||||
|
|
||||||
if (userError || !authUser) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Error loading user: {userError?.message ?? 'User not authenticated'}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get user profile
|
|
||||||
const { data: user, error: profileError } = await supabase
|
|
||||||
.from('profiles')
|
|
||||||
.select('*')
|
|
||||||
.eq('id', authUser.id)
|
|
||||||
.single();
|
|
||||||
|
|
||||||
if (profileError || !user) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Error loading profile: {profileError?.message ?? 'Profile not found'}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if avatar URL exists
|
|
||||||
if (!user.avatar_url) {
|
|
||||||
return <div>No avatar image available</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get public URL for the avatar
|
|
||||||
const { data: imageData } = await supabase.storage
|
|
||||||
.from('avatars')
|
|
||||||
.createSignedUrl(user.avatar_url, 3600);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-center items-center p-8'>
|
<div className='flex justify-center items-center p-8'>
|
||||||
<Image
|
<Image
|
||||||
src={imageData?.signedUrl ?? '/images/default_pfp.png'}
|
src={imageUrl.data ?? '/favicon.ico'}
|
||||||
alt='User avatar'
|
alt='User avatar'
|
||||||
width={150}
|
width={150}
|
||||||
height={150}
|
height={150}
|
||||||
@ -57,4 +24,5 @@ export default async function Page() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
export default Page;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Button } from '@/components/ui';
|
import { Button } from '@/components/ui';
|
||||||
import { createServerClient } from '@/utils/supabase';
|
import { createServerClient } from '@/utils/supabase';
|
||||||
import { signOut } from '@/actions/auth';
|
import { signOut } from '@/lib/actions';
|
||||||
|
|
||||||
const NavigationAuth = async () => {
|
const NavigationAuth = async () => {
|
||||||
const supabase = await createServerClient();
|
const supabase = await createServerClient();
|
||||||
|
@ -136,3 +136,14 @@ export const signOut = async () => {
|
|||||||
await supabase.auth.signOut();
|
await supabase.auth.signOut();
|
||||||
return redirect('/sign-in');
|
return redirect('/sign-in');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getUser = async () => {
|
||||||
|
try {
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { data, error } = await supabase.auth.getUser();
|
||||||
|
if (error) throw error;
|
||||||
|
return data.user;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not get user!', error);
|
||||||
|
}
|
||||||
|
};
|
7
src/lib/actions/index.ts
Normal file
7
src/lib/actions/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export * from './auth';
|
||||||
|
export * from './storage';
|
||||||
|
export * from './public';
|
||||||
|
|
||||||
|
export type Result<T> =
|
||||||
|
| { success: true; data: T }
|
||||||
|
| { success: false; error: string };
|
30
src/lib/actions/public.ts
Normal file
30
src/lib/actions/public.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
import 'server-only';
|
||||||
|
import { createServerClient, type Profile } from '@/utils/supabase';
|
||||||
|
import { getUser } from '@/lib/actions';
|
||||||
|
import type { Result } from './index';
|
||||||
|
|
||||||
|
export const getProfile = async (): Promise<Result<Profile>> => {
|
||||||
|
try {
|
||||||
|
const user = await getUser();
|
||||||
|
if (!user) throw new Error('User not found');
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('*')
|
||||||
|
.eq('id', user.id)
|
||||||
|
.single();
|
||||||
|
if (error) throw error;
|
||||||
|
return { success: true, data: data as Profile };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not get profile!', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error getting profile',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
184
src/lib/actions/storage.ts
Normal file
184
src/lib/actions/storage.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
'use server';
|
||||||
|
import 'server-only';
|
||||||
|
import { createServerClient } from '@/utils/supabase';
|
||||||
|
import type { Result } from './index';
|
||||||
|
|
||||||
|
export type GetStorageProps = {
|
||||||
|
bucket: string;
|
||||||
|
url: string;
|
||||||
|
seconds?: number;
|
||||||
|
transform?: {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
quality?: number;
|
||||||
|
format?: 'origin';
|
||||||
|
resize?: 'cover' | 'contain' | 'fill';
|
||||||
|
};
|
||||||
|
download?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UploadStorageProps = {
|
||||||
|
bucket: string;
|
||||||
|
path: string;
|
||||||
|
file: File;
|
||||||
|
options?: {
|
||||||
|
cacheControl?: string;
|
||||||
|
upsert?: boolean;
|
||||||
|
contentType?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getSignedUrl({
|
||||||
|
bucket,
|
||||||
|
url,
|
||||||
|
seconds = 3600,
|
||||||
|
transform,
|
||||||
|
download = false,
|
||||||
|
}: GetStorageProps): Promise<Result<string>> {
|
||||||
|
try {
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { data, error } = await supabase.storage
|
||||||
|
.from(bucket)
|
||||||
|
.createSignedUrl(url, seconds, { transform });
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
if (!data?.signedUrl) throw new Error('No signed URL returned');
|
||||||
|
|
||||||
|
// Safely add download parameter if needed
|
||||||
|
if (download) {
|
||||||
|
const urlObj = new URL(data.signedUrl);
|
||||||
|
urlObj.searchParams.append('download', '');
|
||||||
|
return { success: true, data: urlObj.toString() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true, data: data.signedUrl };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not get signed URL for asset!', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error getting signed URL',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPublicUrl({
|
||||||
|
bucket,
|
||||||
|
url,
|
||||||
|
transform = {},
|
||||||
|
download = false,
|
||||||
|
}: GetStorageProps): Promise<Result<string>> {
|
||||||
|
try {
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { data } = supabase.storage
|
||||||
|
.from(bucket)
|
||||||
|
.getPublicUrl(url, { transform });
|
||||||
|
|
||||||
|
if (!data?.publicUrl) throw new Error('No public URL returned');
|
||||||
|
|
||||||
|
// Safely add download parameter if needed
|
||||||
|
if (download) {
|
||||||
|
const urlObj = new URL(data.publicUrl);
|
||||||
|
urlObj.searchParams.append('download', '');
|
||||||
|
return { success: true, data: urlObj.toString() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true, data: data.publicUrl };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not get public URL for asset!', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error getting public URL',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function uploadFile({
|
||||||
|
bucket,
|
||||||
|
path,
|
||||||
|
file,
|
||||||
|
options = {},
|
||||||
|
}: UploadStorageProps): Promise<Result<string>> {
|
||||||
|
try {
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { data, error } = await supabase.storage
|
||||||
|
.from(bucket)
|
||||||
|
.upload(path, file, options);
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
if (!data?.path) throw new Error('No path returned from upload');
|
||||||
|
|
||||||
|
return { success: true, data: data.path };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not upload file!', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
error instanceof Error ? error.message : 'Unknown error uploading file',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a helper to delete files
|
||||||
|
export async function deleteFile({
|
||||||
|
bucket,
|
||||||
|
path,
|
||||||
|
}: {
|
||||||
|
bucket: string;
|
||||||
|
path: string[];
|
||||||
|
}): Promise<Result<null>> {
|
||||||
|
try {
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { error } = await supabase.storage.from(bucket).remove(path);
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
return { success: true, data: null };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not delete file!', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
error instanceof Error ? error.message : 'Unknown error deleting file',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a helper to list files in a bucket
|
||||||
|
export async function listFiles({
|
||||||
|
bucket,
|
||||||
|
path = '',
|
||||||
|
options = {},
|
||||||
|
}: {
|
||||||
|
bucket: string;
|
||||||
|
path?: string;
|
||||||
|
options?: {
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
sortBy?: { column: string; order: 'asc' | 'desc' };
|
||||||
|
};
|
||||||
|
}): Promise<Result<Array<{ name: string; id: string; metadata: any }>>> {
|
||||||
|
try {
|
||||||
|
const supabase = await createServerClient();
|
||||||
|
const { data, error } = await supabase.storage
|
||||||
|
.from(bucket)
|
||||||
|
.list(path, options);
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
if (!data) throw new Error('No data returned from list operation');
|
||||||
|
|
||||||
|
return { success: true, data };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Could not list files!', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
error instanceof Error ? error.message : 'Unknown error listing files',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user