Ctrl K
ComunidadGuías…

scripts/local-presigned-put.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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)
})