feat(release): prepare 1.1.0 candidate
This commit is contained in:
parent
5a34f66981
commit
5205dcdfa9
736 changed files with 115667 additions and 12203 deletions
94
server/supabase/functions/content-report/index.ts
Normal file
94
server/supabase/functions/content-report/index.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import { corsHeaders, handleCorsPreflightRequest } from '../_shared/cors.ts'
|
||||
import { requireUser, type AuthError } from '../_shared/auth.ts'
|
||||
import { createServiceRoleClient } from '../_shared/quota.ts'
|
||||
import {
|
||||
ContentReportRequestError,
|
||||
mapContentReportRpcError,
|
||||
parseContentReportReceipt,
|
||||
parseContentReportRequest,
|
||||
parseIdempotencyKey,
|
||||
} from '../_shared/content-report-contract.ts'
|
||||
|
||||
const MAX_REQUEST_BYTES = 25_000
|
||||
|
||||
function jsonResponse(body: unknown, status: number): Response {
|
||||
return new Response(JSON.stringify(body), {
|
||||
status,
|
||||
headers: {
|
||||
...corsHeaders,
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-store',
|
||||
Pragma: 'no-cache',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function readRequestJson(req: Request): Promise<unknown> {
|
||||
const contentType = req.headers.get('content-type')?.toLowerCase() ?? ''
|
||||
if (contentType.split(';', 1)[0].trim() !== 'application/json') {
|
||||
throw new ContentReportRequestError('content_type_must_be_json', 415)
|
||||
}
|
||||
const declaredLength = Number(req.headers.get('content-length'))
|
||||
if (Number.isFinite(declaredLength) && declaredLength > MAX_REQUEST_BYTES) {
|
||||
throw new ContentReportRequestError('request_too_large', 413)
|
||||
}
|
||||
const rawBody = await req.text()
|
||||
if (new TextEncoder().encode(rawBody).byteLength > MAX_REQUEST_BYTES) {
|
||||
throw new ContentReportRequestError('request_too_large', 413)
|
||||
}
|
||||
try {
|
||||
return JSON.parse(rawBody) as unknown
|
||||
} catch {
|
||||
throw new ContentReportRequestError('invalid_json')
|
||||
}
|
||||
}
|
||||
|
||||
Deno.serve(async (req: Request) => {
|
||||
const preflight = handleCorsPreflightRequest(req)
|
||||
if (preflight) {
|
||||
const headers = new Headers(preflight.headers)
|
||||
headers.set('Cache-Control', 'no-store')
|
||||
return new Response(preflight.body, { status: preflight.status, headers })
|
||||
}
|
||||
|
||||
if (req.method !== 'POST') return jsonResponse({ error: 'method_not_allowed' }, 405)
|
||||
|
||||
try {
|
||||
const user = await requireUser(req)
|
||||
const idempotencyKey = parseIdempotencyKey(req.headers.get('Idempotency-Key'))
|
||||
const body = parseContentReportRequest(await readRequestJson(req))
|
||||
const serviceClient = createServiceRoleClient()
|
||||
|
||||
const { data, error } = await serviceClient.rpc('submit_content_report_v1', {
|
||||
p_actor_id: user.id,
|
||||
p_idempotency_key: idempotencyKey,
|
||||
p_kind: body.kind,
|
||||
p_source_type: body.source.type,
|
||||
p_source_id: body.source.generationId,
|
||||
p_reason: body.reason,
|
||||
p_comment: body.comment ?? null,
|
||||
p_snapshot: body.snapshot,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
const mapped = mapContentReportRpcError(error)
|
||||
if (mapped.status === 500) {
|
||||
console.error('content-report RPC failed', { code: error.code ?? 'unknown' })
|
||||
}
|
||||
return jsonResponse({ error: mapped.code }, mapped.status)
|
||||
}
|
||||
|
||||
const receipt = parseContentReportReceipt(data)
|
||||
return jsonResponse(receipt, receipt.idempotent ? 200 : 201)
|
||||
} catch (error) {
|
||||
if (error instanceof ContentReportRequestError) {
|
||||
return jsonResponse({ error: error.code }, error.status)
|
||||
}
|
||||
if (error && typeof error === 'object' && 'status' in error && 'message' in error) {
|
||||
const authError = error as AuthError
|
||||
return jsonResponse({ error: authError.message }, authError.status)
|
||||
}
|
||||
console.error('content-report failed', { code: 'internal_error' })
|
||||
return jsonResponse({ error: 'internal_error' }, 500)
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue