ConusAI vendor 81941888f

This commit is contained in:
ConusAI vendor 81941888f
2026-10-07 08:47:51 +00:00
commit c3c6526952
135 changed files with 13010 additions and 0 deletions
@@ -0,0 +1,124 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
// The action runs against fakes: a Blob Storage client that records what it was
// given, and a database whose note and attachment rows are set per test.
const NOTE = '00000000-0000-4000-8000-0000000000aa'
const mocks = vi.hoisted(() => ({
put: vi.fn(async (pathname: string) => ({ url: `https://blob.example.com/${pathname}` })),
log: vi.fn(async () => {}),
recordUsage: vi.fn(async () => ({ accepted: 1, duplicates: 0, rejected: [] })),
consumeUploadQuota: vi.fn(async () => null as { allowed: boolean; remaining: number } | null),
revalidatePath: vi.fn(),
note: undefined as { id: string; authorId: string } | undefined,
inserted: [] as Record<string, unknown>[],
}))
const fakeDb = {
select: () => ({ from: () => ({ where: () => ({ limit: async () => (mocks.note ? [mocks.note] : []) }) }) }),
insert: () => ({
values: (row: Record<string, unknown>) => ({
returning: async () => {
mocks.inserted.push(row)
return [{ id: '00000000-0000-4000-8000-0000000000ff', ...row, createdAt: new Date() }]
},
}),
}),
}
vi.mock('next/cache', () => ({ revalidatePath: mocks.revalidatePath }))
vi.mock('@/shared/api', () => ({
db: () => fakeDb,
audit: () => ({ log: mocks.log }),
blob: () => ({ put: mocks.put }),
recordUsage: mocks.recordUsage,
serverErrors: () => ({ captureException: vi.fn() }),
}))
vi.mock('@/shared/config', () => ({
getEnv: () => ({ CONUSAI_API_URL: 'https://console.example.com', CONUSAI_API_TOKEN: 'dt_fixture' }),
}))
vi.mock('@/shared/lib/visitor-session', () => ({ ensureVisitor: async () => 'visitor-1' }))
vi.mock('@/shared/lib/optional', () => ({ consumeUploadQuota: mocks.consumeUploadQuota }))
import { uploadFile } from '@/features/upload-file/api/actions'
function attach(file: File): FormData {
const data = new FormData()
data.set('file', file)
return data
}
describe('uploadFile', () => {
beforeEach(() => {
mocks.put.mockClear()
mocks.log.mockClear()
mocks.revalidatePath.mockClear()
mocks.consumeUploadQuota.mockReset()
mocks.consumeUploadQuota.mockResolvedValue(null)
mocks.inserted.length = 0
mocks.note = { id: NOTE, authorId: 'visitor-1' }
})
it('refuses a file over the size limit before any upload', async () => {
const big = new File([new Uint8Array(5 * 1024 * 1024 + 1)], 'big.png', { type: 'image/png' })
await expect(uploadFile(NOTE, attach(big))).rejects.toThrow(/5 MiB/)
expect(mocks.put).not.toHaveBeenCalled()
expect(mocks.log).not.toHaveBeenCalled()
})
it('refuses a disallowed type before any upload', async () => {
const exe = new File(['MZ'], 'run.exe', { type: 'application/x-msdownload' })
await expect(uploadFile(NOTE, attach(exe))).rejects.toThrow(/not accepted/)
expect(mocks.put).not.toHaveBeenCalled()
})
it('refuses a note the visitor did not write, without uploading', async () => {
mocks.note = { id: NOTE, authorId: 'visitor-2' }
const png = new File(['png'], 'a.png', { type: 'image/png' })
await expect(uploadFile(NOTE, attach(png))).rejects.toThrow(/not yours/)
expect(mocks.put).not.toHaveBeenCalled()
expect(mocks.inserted).toHaveLength(0)
})
it('stores the bytes, records the attachment, and audits file.uploaded once', async () => {
const png = new File(['png'], 'a.png', { type: 'image/png' })
await uploadFile(NOTE, attach(png))
expect(mocks.put).toHaveBeenCalledTimes(1)
expect(mocks.put.mock.calls[0]?.[0]).toBe(`notes/${NOTE}/a.png`)
expect(mocks.inserted[0]).toMatchObject({
noteId: NOTE,
authorId: 'visitor-1',
name: 'a.png',
contentType: 'image/png',
size: 3,
url: `https://blob.example.com/notes/${NOTE}/a.png`,
})
expect(mocks.log).toHaveBeenCalledTimes(1)
expect(mocks.log).toHaveBeenCalledWith('file.uploaded', {
actor: { kind: 'human', id: 'visitor-1' },
target: { id: '00000000-0000-4000-8000-0000000000ff' },
})
})
it('sends exactly one usage event, keyed by the attachment, for one upload', async () => {
const png = new File(['png'], 'a.png', { type: 'image/png' })
await uploadFile(NOTE, attach(png))
expect(mocks.recordUsage).toHaveBeenCalledTimes(1)
const [config, events] = mocks.recordUsage.mock.calls[0] as unknown as [
{ baseUrl: string; token: string },
Array<{ idempotency_key: string; meter: string; quantity: string }>,
]
expect(config).toEqual({ baseUrl: 'https://console.example.com', token: 'dt_fixture' })
expect(events).toHaveLength(1)
expect(events[0]).toMatchObject({ idempotency_key: 'upload:00000000-0000-4000-8000-0000000000ff', meter: 'uploads', quantity: '1' })
})
it('refuses an upload over the minute allowance before any write', async () => {
mocks.consumeUploadQuota.mockResolvedValue({ allowed: false, remaining: 0 })
const png = new File(['png'], 'a.png', { type: 'image/png' })
await expect(uploadFile(NOTE, attach(png))).rejects.toThrow(/limit/)
expect(mocks.put).not.toHaveBeenCalled()
expect(mocks.inserted).toHaveLength(0)
})
})
+57
View File
@@ -0,0 +1,57 @@
'use server'
import { revalidatePath } from 'next/cache'
import { fileRepository, uploadLimits } from '@/entities/file'
import { noteId, noteRepository } from '@/entities/note'
import { getEnv } from '@/shared/config'
import { audit, blob, db, recordUsage, serverErrors } from '@/shared/api'
import { consumeUploadQuota } from '@/shared/lib/optional'
import { ensureVisitor } from '@/shared/lib/visitor-session'
/**
* Attach a file to a note the visitor wrote. The limits are checked before any
* upload, so a refused file never reaches Blob Storage.
*/
export async function uploadFile(note: string, form: FormData): Promise<void> {
const key = noteId.parse(note)
const upload = form.get('file')
if (!(upload instanceof File)) throw new Error('choose a file to upload')
const limits = uploadLimits.parse({
name: upload.name,
size: upload.size,
contentType: upload.type,
})
const actor = await ensureVisitor()
// With KV linked, each visitor has a per-minute upload allowance; without it, none.
const quota = await consumeUploadQuota(actor)
if (quota && !quota.allowed) throw new Error('the upload limit for this minute is reached')
const owner = await noteRepository(db()).get(key)
if (!owner || owner.authorId !== actor) throw new Error('that note is not yours to attach to')
const stored = await blob().put(`notes/${key}/${limits.name}`, Buffer.from(await upload.arrayBuffer()), {
contentType: limits.contentType,
})
const row = await fileRepository(db()).create({
noteId: key,
authorId: actor,
name: limits.name,
contentType: limits.contentType,
size: limits.size,
url: stored.url,
})
await audit().log('file.uploaded', { actor: { kind: 'human', id: actor }, target: { id: row.id } })
// One upload, one usage event. The key is the attachment's id, so a resend stores nothing twice.
// A failed send is reported, not raised: the upload itself succeeded.
const env = getEnv()
await recordUsage({ baseUrl: env.CONUSAI_API_URL, token: env.CONUSAI_API_TOKEN }, [
{
idempotency_key: `upload:${row.id}`,
customer: { external_id: 'showcase' },
meter: 'uploads',
quantity: '1',
properties: { bytes: limits.size, content_type: limits.contentType },
},
]).catch((error: unknown) => serverErrors().captureException(error))
revalidatePath('/')
}
+2
View File
@@ -0,0 +1,2 @@
export { uploadFile } from './api/actions'
export { UploadFileForm } from './ui/UploadFileForm'
@@ -0,0 +1,13 @@
import { uploadFile } from '@/features/upload-file/api/actions'
export function UploadFileForm({ noteId }: { noteId: string }) {
return (
<form action={uploadFile.bind(null, noteId)}>
<label>
Attachment
<input name="file" type="file" required />
</label>
<button type="submit">Attach</button>
</form>
)
}