feat: initial release v0.3.0

This commit is contained in:
saturn
2026-03-08 03:15:27 +08:00
commit 881ed44996
1311 changed files with 225407 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
/**
* 图片 URL 流程测试
* 模拟图片生成后的存储和读取流程
* 运行: npx tsx scripts/test-image-url-flow.ts
*/
import { config } from 'dotenv'
config()
import { uploadObject, getSignedUrl, extractStorageKey, toFetchableUrl } from '../src/lib/storage'
import { keyToSignedUrl, addSignedUrlToLocation } from '../src/lib/storage'
import { encodeImageUrls, decodeImageUrlsFromDb } from '../src/lib/contracts/image-urls-contract'
import { randomUUID } from 'crypto'
async function testImageUrlFlow() {
console.log('🧪 测试图片 URL 全流程...\n')
// 1. 模拟上传图片到存储
console.log('1⃣ 模拟上传图片:')
const testKey = `images/location-${randomUUID()}.jpg`
const testImageContent = Buffer.from('fake-image-data')
let storedKey: string
try {
storedKey = await uploadObject(testImageContent, testKey)
console.log(` ✅ 上传成功,返回 key: ${storedKey}`)
} catch (error) {
console.log(` ❌ 上传失败:`, error)
process.exit(1)
}
// 2. 模拟存储到数据库encodeImageUrls
console.log('\n2⃣ 模拟数据库存储encodeImageUrls:')
const imageUrlsArray = [storedKey]
const dbValue = encodeImageUrls(imageUrlsArray)
console.log(` ✅ 数据库值: ${dbValue}`)
// 3. 模拟从数据库读取decodeImageUrlsFromDb
console.log('\n3⃣ 模拟数据库读取decodeImageUrlsFromDb:')
const decodedKeys = decodeImageUrlsFromDb(dbValue)
console.log(` ✅ 解析出的 keys: ${JSON.stringify(decodedKeys)}`)
// 4. 测试 keyToSignedUrl用于 API 返回给前端)
console.log('\n4⃣ 测试 keyToSignedUrlAPI 层转换):')
for (const key of decodedKeys) {
const signedUrl = keyToSignedUrl(key)
console.log(` Key: ${key}`)
console.log(` → Signed URL: ${signedUrl}`)
// 检查是否是 /api/storage/sign 格式
if (signedUrl?.startsWith('/api/storage/sign')) {
console.log(` ✅ 正确生成了签名 URL 路径`)
} else if (signedUrl?.startsWith('http')) {
console.log(` ⚠️ 返回了完整 HTTP URL可能无法直接访问`)
} else {
console.log(` ⚠️ URL 格式: ${signedUrl}`)
}
}
// 5. 测试 addSignedUrlToLocation完整对象转换
console.log('\n5⃣ 测试 addSignedUrlToLocation完整对象转换:')
const mockLocationFromDb = {
id: 'loc-123',
name: '测试场景',
images: [
{
id: 'img-1',
imageUrl: storedKey,
imageIndex: 0,
}
]
}
const locationWithSignedUrls = addSignedUrlToLocation(mockLocationFromDb)
console.log(` 转换后的 location.images:`)
for (const img of locationWithSignedUrls.images || []) {
console.log(` - imageIndex: ${img.imageIndex}`)
console.log(` - imageUrl: ${img.imageUrl}`)
if (img.imageUrl?.startsWith('/api/storage/sign')) {
console.log(` ✅ 正确: 是相对路径签名 URL`)
} else if (img.imageUrl?.startsWith('http://127.0.0.1:19000')) {
console.log(` ❌ 错误: 是 MinIO 直链,可能需要签名`)
} else if (img.imageUrl?.startsWith('http')) {
console.log(` ⚠️ 是外部 HTTP URL`)
} else {
console.log(` ⚠️ 其他格式: ${img.imageUrl}`)
}
}
// 6. 测试 getSignedUrl 直接调用
console.log('\n6⃣ 测试 getSignedUrl 直接调用:')
const directSignedUrl = getSignedUrl(storedKey)
console.log(` Key: ${storedKey}`)
console.log(` → URL: ${directSignedUrl}`)
// 7. 测试 extractStorageKey
console.log('\n7⃣ 测试 extractStorageKey从各种 URL 提取 key:')
const testUrls = [
storedKey,
`http://127.0.0.1:19000/waoowaoo/${storedKey}`,
directSignedUrl,
]
for (const url of testUrls) {
const extracted = extractStorageKey(url)
console.log(` ${url.substring(0, 60)}...`)
console.log(` → extracted: ${extracted}`)
}
// 8. 清理测试数据
console.log('\n8⃣ 清理测试数据:')
try {
const { deleteObject } = await import('../src/lib/storage')
await deleteObject(storedKey)
console.log(` ✅ 删除成功`)
} catch (error) {
console.log(` ⚠️ 删除失败(可忽略):`, error)
}
console.log('\n✨ 测试完成!')
console.log('\n📋 总结:')
console.log(' 如果第4、5步返回的是 /api/storage/sign?key=... 格式 → ✅ 正常')
console.log(' 如果第4、5步返回的是 http://127.0.0.1:19000/... 格式 → ❌ 需要修复')
}
testImageUrlFlow().catch(console.error)