@@ -2,11 +2,10 @@ import type { Context } from 'hono'
22import type { MiddlewareKeyVariables } from '../utils/hono.ts'
33import { getRuntimeKey } from 'hono/adapter'
44import { Hono } from 'hono/tiny'
5- import { DEFAULT_RETRY_PARAMS , RetryBucket } from '../tus/retry.ts'
65import { simpleError , useCors } from '../utils/hono.ts'
76import { cloudlog } from '../utils/logging.ts'
8- import { s3 } from '../utils/s3.ts'
97import { hasAppRight , supabaseAdmin } from '../utils/supabase.ts'
8+ import { DEFAULT_RETRY_PARAMS , RetryBucket } from './retry.ts'
109
1110// MIME type mapping for common file extensions
1211const MIME_TYPES : Record < string , string > = {
@@ -156,54 +155,36 @@ async function handlePreview(c: Context<MiddlewareKeyVariables>) {
156155 return simpleError ( 'file_not_found' , 'File not found in bundle' , { filePath } )
157156 }
158157
159- // Serve the file - use R2 bucket directly in Cloudflare Workers, or fetch via presigned URL in Supabase
160- try {
161- if ( getRuntimeKey ( ) === 'workerd' ) {
162- // Cloudflare Workers - use R2 bucket directly
163- const bucket = c . env . ATTACHMENT_BUCKET
164- if ( ! bucket ) {
165- cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'preview bucket is null' } )
166- return simpleError ( 'bucket_not_configured' , 'Storage bucket not configured' )
167- }
168-
169- const object = await new RetryBucket ( bucket , DEFAULT_RETRY_PARAMS ) . get ( manifestEntry . s3_path )
170- if ( ! object ) {
171- cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'file not found in R2' , s3_path : manifestEntry . s3_path } )
172- return simpleError ( 'file_not_found' , 'File not found in storage' , { filePath } )
173- }
158+ // Preview only works on Cloudflare Workers where the R2 bucket is available.
159+ // Supabase Edge Functions cannot serve HTML files properly due to platform limitations.
160+ if ( getRuntimeKey ( ) !== 'workerd' ) {
161+ cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'preview not supported on Supabase Edge Functions' } )
162+ return simpleError ( 'preview_not_supported' , 'Preview is not supported on Supabase Edge Functions. This feature requires Cloudflare Workers with R2 bucket access.' )
163+ }
174164
175- // Use our own MIME type detection - R2 rewrites text/html to text/plain without custom domains
176- const contentType = getContentType ( filePath )
177- const headers = new Headers ( )
178- headers . set ( 'Content-Type' , contentType )
179- headers . set ( 'etag' , object . httpEtag )
180- headers . set ( 'Cache-Control' , 'private, max-age=3600' )
181- headers . set ( 'X-Content-Type-Options' , 'nosniff' )
165+ const bucket = c . env . ATTACHMENT_BUCKET
166+ if ( ! bucket ) {
167+ cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'preview bucket is null' } )
168+ return simpleError ( 'bucket_not_configured' , 'Storage bucket not configured' )
169+ }
182170
183- cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'serving preview file from R2' , filePath, contentType } )
184- return new Response ( object . body , { headers } )
171+ try {
172+ const object = await new RetryBucket ( bucket , DEFAULT_RETRY_PARAMS ) . get ( manifestEntry . s3_path )
173+ if ( ! object ) {
174+ cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'file not found in R2' , s3_path : manifestEntry . s3_path } )
175+ return simpleError ( 'file_not_found' , 'File not found in storage' , { filePath } )
185176 }
186- else {
187- // Supabase Edge Functions - fetch via presigned URL
188- const response = await s3 . getObject ( c , manifestEntry . s3_path )
189- if ( ! response ) {
190- cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'failed to fetch file from S3' , s3_path : manifestEntry . s3_path } )
191- return simpleError ( 'file_fetch_failed' , 'Failed to fetch file' )
192- }
193177
194- // Use our MIME type detection based on file extension
195- const contentType = getContentType ( filePath )
196- cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'serving preview file via S3' , filePath, contentType } )
197-
198- return new Response ( response . body , {
199- status : 200 ,
200- headers : {
201- 'Content-Type' : contentType ,
202- 'Cache-Control' : 'private, max-age=3600' ,
203- 'X-Content-Type-Options' : 'nosniff' ,
204- } ,
205- } )
206- }
178+ // Use our own MIME type detection - R2 rewrites text/html to text/plain without custom domains
179+ const contentType = getContentType ( filePath )
180+ const headers = new Headers ( )
181+ headers . set ( 'Content-Type' , contentType )
182+ headers . set ( 'etag' , object . httpEtag )
183+ headers . set ( 'Cache-Control' , 'private, max-age=3600' )
184+ headers . set ( 'X-Content-Type-Options' , 'nosniff' )
185+
186+ cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'serving preview file from R2' , filePath, contentType } )
187+ return new Response ( object . body , { headers } )
207188 }
208189 catch ( error ) {
209190 cloudlog ( { requestId : c . get ( 'requestId' ) , message : 'failed to serve preview file' , error, s3_path : manifestEntry . s3_path } )
0 commit comments