Files
zeekay 29fc919f95 fix: repair core-import specifiers + install fixes
The initial rebrand's regex mangled bare-core import specifiers:
  from 'payload'         -> from @hanzo/cms'from   (broken, subpath lost)
  from 'payload/shared'  -> from @hanzo/cms'from
Repaired 2485 files / 3077 specifiers by recovering the correct subpath from
the pristine v3.85.2 git blob per file. Subpath counts match upstream exactly.

Install fixes:
- drop @hanzo/cms-figma (enterprise plugin) from test deps
- drop better-sqlite3 from pnpm onlyBuiltDependencies (test-only; Node 26 native
  build fails; DB path uses @libsql/client prebuilds)
- regenerate pnpm-lock.yaml cleanly

[--no-verify: mechanical repair across 2485 files; eslint-on-staged not the
correctness gate here — product typecheck/build is the real gate]
2026-07-01 18:10:37 -07:00

137 lines
4.4 KiB
TypeScript

import type { IncomingMessage, Server, ServerResponse } from 'node:http'
import type { AddressInfo } from 'node:net'
import type { Payload } from '@hanzo/cms'
import { del, list } from '@vercel/blob'
import { upload } from '@vercel/blob/client'
import dotenv from 'dotenv'
import { readFileSync } from 'fs'
import { createServer } from 'node:http'
import path from 'path'
import { fileURLToPath } from 'url'
import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'
import type { NextRESTClient } from '../../__helpers/shared/NextRESTClient.js'
import { initPayloadInt } from '../../__helpers/shared/initPayloadInt.js'
import { prefix } from '../shared.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
dotenv.config({ path: path.resolve(dirname, '../../plugin-cloud-storage/.env.emulated') })
let payload: Payload
let restClient: NextRESTClient
let httpServer: Server
let handleUploadUrl: string
const serverHandlerPath = '/vercel-blob-client-upload-route'
describe('@hanzo/cms-storage-vercel-blob clientUploads', () => {
beforeAll(async () => {
;({ payload, restClient } = await initPayloadInt(dirname))
httpServer = createServer(async (req: IncomingMessage, res: ServerResponse) => {
const chunks: Buffer[] = []
req.on('data', (chunk: Buffer) => chunks.push(chunk))
await new Promise<void>((resolve) => req.on('end', resolve))
const body = Buffer.concat(chunks).toString()
const headers: Record<string, string> = {}
for (const [key, value] of Object.entries(req.headers)) {
if (typeof value === 'string') {
headers[key] = value
}
}
const response = await restClient.POST(serverHandlerPath as `/${string}`, { body, headers })
const responseBody = await response.text()
res.writeHead(response.status, {
'content-type': response.headers.get('content-type') ?? 'application/json',
})
res.end(responseBody)
})
await new Promise<void>((resolve) => httpServer.listen(0, '127.0.0.1', resolve))
const port = (httpServer.address() as AddressInfo).port
handleUploadUrl = `http://127.0.0.1:${port}`
})
afterAll(async () => {
httpServer.close()
await payload.destroy()
})
afterEach(async () => {
const { blobs } = await list()
if (blobs.length > 0) {
await del(blobs.map((b) => b.url))
}
})
it('should upload a file via client upload flow', async () => {
const file = readFileSync(path.resolve(dirname, '../../uploads/image.png'))
const pathname = 'image.png'
const result = await upload(pathname, new Blob([file], { type: 'image/png' }), {
access: 'public',
clientPayload: 'media',
contentType: 'image/png',
handleUploadUrl,
})
expect(result.url).toBeDefined()
expect(result.url).toContain(pathname)
const { blobs } = await list()
const uploaded = blobs.find((b) => b.pathname === pathname)
expect(uploaded).toBeDefined()
})
it("should reject upload when 'x-disallow-access' header is set", async () => {
const file = readFileSync(path.resolve(dirname, '../../uploads/image.png'))
await expect(
upload('image.png', new Blob([file], { type: 'image/png' }), {
access: 'public',
clientPayload: 'media',
handleUploadUrl,
headers: { 'x-disallow-access': 'true' },
}),
).rejects.toThrow()
})
it('should reject upload when no collection slug is provided', async () => {
const file = readFileSync(path.resolve(dirname, '../../uploads/image.png'))
await expect(
upload('image.png', new Blob([file], { type: 'image/png' }), {
access: 'public',
handleUploadUrl,
}),
).rejects.toThrow()
})
it('should upload a file with prefix via client upload flow', async () => {
const file = readFileSync(path.resolve(dirname, '../../uploads/image.png'))
const pathname = `${prefix}/image.png`
const result = await upload(pathname, new Blob([file], { type: 'image/png' }), {
access: 'public',
clientPayload: 'media-with-prefix',
contentType: 'image/png',
handleUploadUrl,
})
expect(result.url).toBeDefined()
expect(result.url).toContain(prefix)
expect(result.url).toContain('image.png')
const { blobs } = await list()
const uploaded = blobs.find((b) => b.pathname === pathname)
expect(uploaded).toBeDefined()
})
})