fix: set relative file paths in file editor

This commit is contained in:
Lakshan Perera committed 2025-03-27 23:16:33 +11:00
1 parent 3a95aec3ee
commit 01e6e21136
4 files changed
+49 -38

No files matched your search

@@ -7,6 +7,7 @@ import { edgeFunctionsKeys } from './keys'
export type EdgeFunctionBodyVariables = {
projectRef?: string
slug?: string
entrypoint?: string
}
export type EdgeFunctionFile = {
@@ -19,11 +20,12 @@ export type EdgeFunctionBodyResponse = {
}
export async function getEdgeFunctionBody(
{ projectRef, slug }: EdgeFunctionBodyVariables,
{ projectRef, slug, entrypoint }: EdgeFunctionBodyVariables,
signal?: AbortSignal
) {
if (!projectRef) throw new Error('projectRef is required')
if (!slug) throw new Error('slug is required')
if (!entrypoint) throw new Error('entrypoint is required')
try {
// Get authorization headers
@@ -34,7 +36,7 @@ export async function getEdgeFunctionBody(
// Send to our API for processing (the API will handle the fetch from v1 endpoint)
const parseResponse = await fetch(`${BASE_PATH}/api/edge-functions/body`, {
method: 'POST',
body: JSON.stringify({ projectRef, slug }),
body: JSON.stringify({ projectRef, slug, entrypoint }),
headers,
credentials: 'include',
signal,
@@ -59,7 +61,7 @@ export type EdgeFunctionBodyData = Awaited<ReturnType<typeof getEdgeFunctionBody
export type EdgeFunctionBodyError = ResponseError
export const useEdgeFunctionBodyQuery = <TData = EdgeFunctionBodyData>(
{ projectRef, slug }: EdgeFunctionBodyVariables,
{ projectRef, slug, entrypoint }: EdgeFunctionBodyVariables,
{
enabled = true,
...options
@@ -67,7 +69,7 @@ export const useEdgeFunctionBodyQuery = <TData = EdgeFunctionBodyData>(
) =>
useQuery<EdgeFunctionBodyData, EdgeFunctionBodyError, TData>(
edgeFunctionsKeys.body(projectRef, slug),
({ signal }) => getEdgeFunctionBody({ projectRef, slug }, signal),
({ signal }) => getEdgeFunctionBody({ projectRef, slug, entrypoint }, signal),
{
enabled:
IS_PLATFORM && enabled && typeof projectRef !== 'undefined' && typeof slug !== 'undefined',
+1 -22
View File
@@ -4,28 +4,7 @@ import path from 'path'
function url2path(url: string) {
try {
// Parse the URL
const parsedUrl = new URL(url)
// Get the pathname and split it
const pathParts = parsedUrl.pathname.split('/').filter(Boolean)
// For user function paths like "user_fn_ukekbxwcwofeosgskskm_66727868-6415-49d7-b518-2a057c8377cb_1/data.json"
// Just return the filename (data.json)
if (pathParts.length > 0) {
// Check if it's a user function path with UUID
if (pathParts[0].startsWith('user_fn_')) {
// Get just the filename (last part)
return pathParts[pathParts.length - 1]
}
// If it starts with 'tmp/' or similar, remove that prefix
if (pathParts[0] === 'tmp' || pathParts[0] === 'deno') {
// Get just the filename (last part)
return pathParts[pathParts.length - 1]
}
}
// Otherwise, return the full path without leading/trailing slashes
return pathParts.join('/')
return new URL(url).pathname
} catch (error) {
// If URL parsing fails, fallback to extracting just the filename
console.warn('Failed to parse URL:', url)
+36 -4
View File
@@ -1,6 +1,7 @@
import { API_URL } from 'lib/constants'
import { parseEszip } from 'lib/eszip-parser'
import { NextApiRequest, NextApiResponse } from 'next'
import path from 'path'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
@@ -10,7 +11,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return handlePost(req, res)
default:
return new Response(
JSON.stringify({ data: null, error: { message: `Method ${method} Not Allowed` } }),
JSON.stringify({
data: null,
error: { message: `Method ${method} Not Allowed` },
}),
{
status: 405,
headers: { 'Content-Type': 'application/json', Allow: 'POST' },
@@ -19,9 +23,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
function getBasePath(entrypoint: string | undefined): string {
if (!entrypoint) {
return '/'
}
try {
return path.dirname(new URL(entrypoint).pathname)
} catch (e) {
console.error('failed to parse entrypoint', entrypoint)
return '/'
}
}
async function handlePost(req: NextApiRequest, res: NextApiResponse) {
try {
const { projectRef, slug } = req.body || {}
const { projectRef, slug, entrypoint } = req.body || {}
if (!projectRef) {
return res.status(400).json({ error: 'projectRef is required' })
@@ -29,12 +46,17 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse) {
if (!slug) {
return res.status(400).json({ error: 'slug is required' })
}
if (!entrypoint) {
return res.status(400).json({ error: 'entrypoint is required' })
}
// Get authorization token from the request
const authToken = req.headers.authorization
if (!authToken) {
return res.status(401).json({ error: 'No authorization token was found' })
return res.status(401).json({
error: 'No authorization token was found',
})
}
// Fetch the eszip data
@@ -81,7 +103,17 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse) {
const uint8Array = new Uint8Array(arrayBuffer)
// Parse the eszip file using our utility
const files = await parseEszip(uint8Array)
let files = await parseEszip(uint8Array)
// ignnore empty files
files = files.filter((file: { name: string; content: string }) => !!file.content.length)
// set file paths relative to entrypoint
const base_path = getBasePath(entrypoint)
files = files.map((file: { name: string; content: string }) => {
file.name = path.relative(base_path, file.name)
return file
})
return res.status(200).json({
files,
@@ -34,7 +34,9 @@ const CodePage = () => {
} = useEdgeFunctionBodyQuery({
projectRef: ref,
slug: functionSlug,
entrypoint: selectedFunction?.entrypoint_path,
})
const [files, setFiles] = useState<
{ id: number; name: string; content: string; selected?: boolean }[]
>([])
@@ -49,12 +51,8 @@ const CodePage = () => {
if (isDeploying || !ref || !functionSlug || !selectedFunction || files.length === 0) return
try {
const parsedEntrypointPath =
selectedFunction.entrypoint_path?.replace(/\/tmp\/user_fn_[^/]+\//, '') || 'index.ts'
const existingFile = files.find((file) => file.name === parsedEntrypointPath) ||
files.find((file) => file.name.endsWith('.ts') || file.name.endsWith('.js')) || {
name: 'index.ts',
}
const newEntrypointPath = selectedFunction.entrypoint_path?.split('/').pop()
const newImportMapPath = selectedFunction.import_map_path?.split('/').pop()
await deployFunction({
projectRef: ref,
@@ -62,8 +60,8 @@ const CodePage = () => {
metadata: {
name: selectedFunction.name,
verify_jwt: selectedFunction.verify_jwt,
entrypoint_path: existingFile.name,
import_map_path: selectedFunction.import_map_path,
entrypoint_path: newEntrypointPath || 'index.ts',
import_map_path: newImportMapPath || '',
},
files: files.map(({ name, content }) => ({ name, content })),
})