fix: document service hangs in API-key auth contexts (#85)
* fix: use caller's supabase client in ensureDocumentsBucket The bucket check was creating its own cookie-dependent service client via createServiceClient(), which calls `await cookies()`. This hangs in API-key auth contexts (MCP server) where no cookie store exists. Now uses the caller's supabase client instead — both uploadDocument() and createNewVersion() already receive a service-role client. Removes the unused createServiceClient import. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use cookieless service client in ensureDocumentsBucket ensureDocumentsBucket() needs a service-role client for storage admin operations (getBucket/createBucket). Previously it used createServiceClient() which calls `await cookies()` — this hangs in API-key auth contexts (e.g. MCP server) where no cookie store exists. Now uses createServiceClientNoCookies() internally, which provides a service-role client without cookie dependency. This is correct for all callers: both web API routes (which pass user-level clients) and the MCP server (which passes a cookieless service client) — bucket admin always requires service-role regardless of the caller's auth context. Also cleans up stale test mock that referenced the removed import. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,9 +43,8 @@ function makeClient(storageOverrides: Record<string, unknown> = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
// Keep createServiceClient mock since ensureDocumentsBucket still uses it
|
||||
vi.mock('@/lib/supabase/server', () => ({
|
||||
createServiceClient: vi.fn(async () => makeClient()),
|
||||
vi.mock('@/lib/auth/api-keys', () => ({
|
||||
createServiceClientNoCookies: vi.fn(() => makeClient()),
|
||||
}))
|
||||
|
||||
import { uploadDocument, createNewVersion, verifyIntegrity, _resetBucketVerified } from '../document-service'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { SupabaseClient } from '@supabase/supabase-js'
|
||||
import { createServiceClient } from '@/lib/supabase/server'
|
||||
import { createServiceClientNoCookies } from '@/lib/auth/api-keys'
|
||||
import { eventBus } from '@/lib/events'
|
||||
import type { DocumentAttachment, DocumentUploadSource } from '@/types'
|
||||
|
||||
@@ -21,15 +21,19 @@ export function _resetBucketVerified() {
|
||||
/**
|
||||
* Ensure the 'documents' storage bucket exists, creating it if missing.
|
||||
* Runs once per process lifetime (same pattern as ensureInitialized).
|
||||
*
|
||||
* Uses a cookieless service-role client for bucket admin operations
|
||||
* (getBucket/createBucket require service-role). This avoids the cookie
|
||||
* dependency that hangs in API-key auth contexts (e.g. MCP server).
|
||||
*/
|
||||
async function ensureDocumentsBucket(): Promise<void> {
|
||||
if (bucketVerified) return
|
||||
|
||||
const supabase = await createServiceClient()
|
||||
const { data: bucket } = await supabase.storage.getBucket('documents')
|
||||
const serviceClient = createServiceClientNoCookies()
|
||||
const { data: bucket } = await serviceClient.storage.getBucket('documents')
|
||||
|
||||
if (!bucket) {
|
||||
await supabase.storage.createBucket('documents', {
|
||||
await serviceClient.storage.createBucket('documents', {
|
||||
public: false,
|
||||
fileSizeLimit: 52428800, // 50 MB
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user