|
1 | 1 | import fsp from 'node:fs/promises' |
| 2 | +import { parse } from 'node:path' |
2 | 3 | import { join, resolve } from 'pathe' |
3 | 4 | import { imageMeta } from 'image-meta' |
4 | 5 | import { debounce } from 'perfect-debounce' |
5 | 6 | import fg from 'fast-glob' |
6 | 7 | import type { AssetEntry, AssetInfo, AssetType, ImageMeta, NuxtDevtoolsServerContext, ServerFunctions } from '../types' |
| 8 | +import { defaultAllowedExtensions } from '../constant' |
7 | 9 |
|
8 | | -export function setupAssetsRPC({ nuxt, ensureDevAuthToken, refresh }: NuxtDevtoolsServerContext) { |
| 10 | +export function setupAssetsRPC({ nuxt, ensureDevAuthToken, refresh, options }: NuxtDevtoolsServerContext) { |
9 | 11 | const _imageMetaCache = new Map<string, ImageMeta | undefined>() |
10 | 12 | let cache: AssetInfo[] | null = null |
11 | 13 |
|
| 14 | + const extensions = options.assets?.uploadExtensions || defaultAllowedExtensions |
| 15 | + |
12 | 16 | const publicDir = resolve(nuxt.options.srcDir, nuxt.options.dir.public) |
13 | 17 |
|
14 | 18 | const refreshDebounced = debounce(() => { |
@@ -96,25 +100,31 @@ export function setupAssetsRPC({ nuxt, ensureDevAuthToken, refresh }: NuxtDevtoo |
96 | 100 |
|
97 | 101 | return await Promise.all( |
98 | 102 | files.map(async ({ path, content, encoding, override }) => { |
99 | | - let dir = resolve(baseDir, path) |
| 103 | + let finalPath = resolve(baseDir, path) |
| 104 | + |
| 105 | + const { ext } = parse(finalPath) |
| 106 | + if (extensions !== '*') { |
| 107 | + if (!extensions.includes(ext.toLowerCase())) |
| 108 | + throw new Error(`File extension ${ext} is not allowed to upload, allowed extensions are: ${extensions.join(', ')}\nYou can configure it in Nuxt config at \`devtools.assets.uploadExtensions\`.`) |
| 109 | + } |
| 110 | + |
100 | 111 | if (!override) { |
101 | 112 | try { |
102 | | - await fsp.stat(dir) |
103 | | - const ext = dir.split('.').pop() as string |
104 | | - const base = dir.slice(0, dir.length - ext.length - 1) |
| 113 | + await fsp.stat(finalPath) |
| 114 | + const base = finalPath.slice(0, finalPath.length - ext.length - 1) |
105 | 115 | let i = 1 |
106 | 116 | while (await fsp.access(`${base}-${i}.${ext}`).then(() => true).catch(() => false)) |
107 | 117 | i++ |
108 | | - dir = `${base}-${i}.${ext}` |
| 118 | + finalPath = `${base}-${i}.${ext}` |
109 | 119 | } |
110 | 120 | catch (err) { |
111 | 121 | // Ignore error if file doesn't exist |
112 | 122 | } |
113 | 123 | } |
114 | | - await fsp.writeFile(dir, content, { |
| 124 | + await fsp.writeFile(finalPath, content, { |
115 | 125 | encoding: encoding ?? 'utf-8', |
116 | 126 | }) |
117 | | - return dir |
| 127 | + return finalPath |
118 | 128 | }), |
119 | 129 | ) |
120 | 130 | }, |
|
0 commit comments