Supabase storage

createSupabaseStorage() returns a user-bound StorageAdapterFactory.

code
import { createSupabaseStorage }
  from '@mordn/chat-widget/server/supabase';
code
NEXT_PUBLIC_SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_SERVICE_ROLE_KEY="..."

Keep the bucket and key private

Create a private bucket named chat-attachments. Never prefix the service-role key with NEXT_PUBLIC_; it must not enter the client bundle.

code
createChatHandler({
  getUserId: getChatUserId,
  model,
  store,
  storage: createSupabaseStorage(),
});
supabaseUrlstringdefault: NEXT_PUBLIC_SUPABASE_URL
Project URL.
serviceRoleKeystringdefault: SUPABASE_SERVICE_ROLE_KEY
Server-only service key.
bucketstringdefault: chat-attachments
Private bucket name.
signedUrlTtlSecondsnumberdefault: 3600
Signed URL lifetime.

Objects use a bound-user namespace and random path segment. The adapter never calls getPublicUrl; history reload creates fresh signed URLs.

Omitting storage disables uploads and the upload route returns 503. The widget's features.fileUpload flag should therefore be enabled only when a storage adapter is mounted.