scripts/local-presigned-put.ts
Rama main · réplica de lectura del repositorio original.
const encoder = new TextEncoder()
const DEFAULT_SERVICE_KEY = ''
function resolveCredentials() {
const serviceKey = Deno.env.get('SERVICE_KEY')
?? Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
?? DEFAULT_SERVICE_KEY
return { serviceKey }
}
function encodeObjectKey(objectKey: string) {
return objectKey.split('/').map(segment => encodeURIComponent(segment)).join('/')
}
async function requestSignedUploadUrl(
endpoint: string,
bucket: string,
objectKey: string,
serviceKey: string,
{ upsert }: { upsert: boolean },
) {
const sanitizedEndpoint = endpoint.endsWith('/') ? endpoint.slice(0, -1) : endpoint
const url = `${sanitizedEndpoint}/object/upload/sign/${bucket}/${encodeObjectKey(objectKey)}`
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': serviceKey,
'Authorization': `Bearer ${serviceKey}`,
'x-upsert': String(upsert),
},
body: '{}',
})
if (!response.ok) {
const errorBody = await response.text()
throw new Error(`Failed to create signed upload URL: ${response.status} ${errorBody}`)
}
const result = await response.json() as { url?: string }
if (!result.url) {
throw new Error('Signed upload URL response missing url field')
}
const relative = result.url.startsWith('/') ? result.url : `/${result.url}`
return `${sanitizedEndpoint}${relative}`
}
async function uploadWithSignedUrl(
signedUrl: string,
payload: Uint8Array,
contentType: string,
) {
const response = await fetch(signedUrl, {
method: 'PUT',
headers: {
'Content-Type': contentType,
},
body: payload,
})
const bodyText = await response.text()
console.log('Local storage response:', response.status)
if (bodyText) {
console.log('Response body:', bodyText)
}
if (!response.ok) {
throw new Error(`Signed upload failed: ${response.status}`)
}
}
async function main() {
const { serviceKey } = resolveCredentials()
if (!serviceKey) {
throw new Error('Missing storage service-role key')
}
const endpoint = Deno.env.get('STORAGE_API_URL') ?? 'http://127.0.0.1:54321/storage/v1'
const bucket = Deno.env.get('S3_BUCKET') ?? 'capgo'
const objectKey = Deno.env.get('S3_OBJECT_KEY') ?? 'orgs/demo-app/example3.txt'
const contentType = Deno.env.get('S3_UPLOAD_CONTENT_TYPE') ?? 'application/zip'
const payload = encoder.encode(Deno.env.get('S3_UPLOAD_PAYLOAD') ?? 'local presign repro')
console.log('Using Supabase signed upload URL flow (only Content-Type header used on upload).')
const signedUrl = await requestSignedUploadUrl(endpoint, bucket, objectKey, serviceKey, {
upsert: (Deno.env.get('S3_UPLOAD_UPSERT') ?? 'true') === 'true',
})
console.log('Signed upload URL:', signedUrl)
await uploadWithSignedUrl(signedUrl, payload, contentType)
}
main().catch((error) => {
console.error(error)
Deno.exit(1)
})