export declare const STARTER_UPLOAD_FEATURE = "import { Effect } from \"effect\";\nimport { Body, Controller, Inject, Injectable, Param, Post, DB_CLIENT, REQUEST_CONTEXT } from \"@supacloud/app\";\nimport { ApplicationError } from \"@supacloud/elysia\";\nimport { UploadBody, UploadLocation, UploadParams, UploadResult } from \"./contracts\";\n\nexport interface ReviewUploadInput { reviewId: string; artifactId: string; expectedVersion: number }\nexport interface ReviewUploadLocation { artifactId: string; bucketId: string; objectPath: string }\nexport interface ReviewUploadResult { artifactId: string; runId: string; objectPath: string; sha256: string; bytes: number }\ntype PreviewUploadError =\n | { readonly _tag: \"AUTHENTICATION_REQUIRED\" }\n | { readonly _tag: \"UPLOAD_INPUT_INVALID\" }\n | { readonly _tag: \"UPLOAD_DENIED\" }\n | { readonly _tag: \"UPLOADS_UNAVAILABLE\" };\ntype RegisterUploadError =\n | PreviewUploadError\n | { readonly _tag: \"UPLOAD_CONTENT_INVALID\" }\n | { readonly _tag: \"COMMAND_IDEMPOTENCY_CONFLICT\" }\n | { readonly _tag: \"COMMAND_REJECTED\" }\n | { readonly _tag: \"UPLOAD_OUTCOME_UNKNOWN\" };\nexport interface ReviewUploadPort {\n previewUpload(context: unknown, input: ReviewUploadInput): Promise;\n registerUpload(context: unknown, input: ReviewUploadInput): Promise;\n}\n@Injectable({ scope: \"request\" })\nexport class ReviewUploads {\n constructor(@Inject(DB_CLIENT) private readonly store: Partial,\n @Inject(REQUEST_CONTEXT) private readonly context: unknown) {}\n\n preview(input: ReviewUploadInput): Promise {\n if (!this.store.previewUpload) throw new ApplicationError(\"Attachment uploads are not configured\", { status: 501, code: \"UPLOADS_UNAVAILABLE\" });\n return this.store.previewUpload(this.context, input);\n }\n register(input: ReviewUploadInput): Promise {\n if (!this.store.registerUpload) throw new ApplicationError(\"Attachment uploads are not configured\", { status: 501, code: \"UPLOADS_UNAVAILABLE\" });\n return this.store.registerUpload(this.context, input);\n }\n}\n\n@Controller(\"/reviews\")\nexport class ReviewUploadsController {\n constructor(@Inject(ReviewUploads) private readonly uploads: ReviewUploads) {}\n\n @Post(\"/:id/attachment-upload\", {\n params: UploadParams,\n body: UploadBody,\n responses: { 200: UploadLocation },\n effect: {\n required: true,\n dependencies: [],\n errors: [\n { tag: \"AUTHENTICATION_REQUIRED\", status: 401, code: \"AUTHENTICATION_REQUIRED\" },\n { tag: \"UPLOAD_INPUT_INVALID\", status: 400, code: \"UPLOAD_INPUT_INVALID\" },\n { tag: \"UPLOAD_DENIED\", status: 403, code: \"UPLOAD_DENIED\" },\n { tag: \"UPLOADS_UNAVAILABLE\", status: 501, code: \"UPLOADS_UNAVAILABLE\" },\n ],\n retry: \"none\",\n },\n })\n preview(@Param(\"id\") id: string, @Body() body: { artifactId: string; expectedVersion: number }): Effect.Effect {\n return Effect.promise(() => this.uploads.preview({ reviewId: id, artifactId: body.artifactId, expectedVersion: body.expectedVersion }));\n }\n @Post(\"/:id/attachment-registration\", {\n params: UploadParams,\n body: UploadBody,\n responses: { 200: UploadResult },\n effect: {\n required: true,\n dependencies: [],\n errors: [\n { tag: \"AUTHENTICATION_REQUIRED\", status: 401, code: \"AUTHENTICATION_REQUIRED\" },\n { tag: \"UPLOAD_INPUT_INVALID\", status: 400, code: \"UPLOAD_INPUT_INVALID\" },\n { tag: \"UPLOAD_DENIED\", status: 403, code: \"UPLOAD_DENIED\" },\n { tag: \"UPLOAD_CONTENT_INVALID\", status: 400, code: \"UPLOAD_CONTENT_INVALID\" },\n { tag: \"COMMAND_IDEMPOTENCY_CONFLICT\", status: 409, code: \"COMMAND_IDEMPOTENCY_CONFLICT\" },\n { tag: \"COMMAND_REJECTED\", status: 403, code: \"COMMAND_REJECTED\" },\n { tag: \"UPLOADS_UNAVAILABLE\", status: 501, code: \"UPLOADS_UNAVAILABLE\" },\n { tag: \"UPLOAD_OUTCOME_UNKNOWN\", status: 503, code: \"UPLOAD_OUTCOME_UNKNOWN\" },\n ],\n retry: \"none\",\n },\n })\n register(@Param(\"id\") id: string, @Body() body: { artifactId: string; expectedVersion: number }): Effect.Effect {\n return Effect.promise(() => this.uploads.register({ reviewId: id, artifactId: body.artifactId, expectedVersion: body.expectedVersion }));\n }\n}\n"; export declare const STARTER_UPLOAD_SCHEMA = "-- Apply explicitly with the migration owner.\nALTER TABLE public.starter_members ADD COLUMN storage_subject uuid UNIQUE;\nGRANT SELECT (subject,enabled,can_approve,storage_subject) ON public.starter_members TO authenticated;\nDROP POLICY IF EXISTS starter_member_read ON public.starter_members;\nCREATE POLICY starter_member_read ON public.starter_members FOR SELECT TO authenticated\n USING (subject=COALESCE(NULLIF(auth.jwt()->>'external_sub',''),auth.jwt()->>'sub') AND storage_subject=auth.uid());\nGRANT SELECT ON public.starter_reviews TO authenticated;\nDROP POLICY IF EXISTS starter_review_read ON public.starter_reviews;\nCREATE POLICY starter_review_read ON public.starter_reviews FOR SELECT TO authenticated\n USING (owner_id=COALESCE(NULLIF(auth.jwt()->>'external_sub',''),auth.jwt()->>'sub') AND EXISTS (\n SELECT 1 FROM public.starter_members m WHERE m.subject=owner_id\n AND m.enabled AND m.can_approve AND m.storage_subject=auth.uid()\n ));\nINSERT INTO storage.buckets(id,name,public,file_size_limit,allowed_mime_types)\n VALUES ('review-attachments','review-attachments',false,1048576,ARRAY['text/plain']);\nDROP POLICY IF EXISTS starter_attachment_read ON storage.objects;\nCREATE POLICY starter_attachment_read ON storage.objects FOR SELECT TO authenticated\n USING (bucket_id='review-attachments');\nDROP POLICY IF EXISTS starter_attachment_insert ON storage.objects;\nCREATE POLICY starter_attachment_insert ON storage.objects FOR INSERT TO authenticated\n WITH CHECK (bucket_id='review-attachments');\n-- Restrictive fences also apply when the host already has permissive Storage policies.\nDROP POLICY IF EXISTS starter_attachment_owner_fence ON storage.objects;\nCREATE POLICY starter_attachment_owner_fence ON storage.objects AS RESTRICTIVE FOR ALL TO authenticated\n USING (bucket_id<>'review-attachments' OR (split_part(name,'/',1)=auth.uid()::text AND EXISTS (\n SELECT 1 FROM public.starter_reviews r JOIN public.starter_members m ON m.subject=r.owner_id\n WHERE r.id=split_part(name,'/',2) AND m.subject=COALESCE(NULLIF(auth.jwt()->>'external_sub',''),auth.jwt()->>'sub')\n AND m.storage_subject=auth.uid() AND m.enabled AND m.can_approve\n )))\n WITH CHECK (bucket_id<>'review-attachments' OR (split_part(name,'/',1)=auth.uid()::text\n AND name ~ '^[a-f0-9-]{36}/[a-f0-9-]{36}/[a-f0-9-]{36}[.]txt$' AND EXISTS (\n SELECT 1 FROM public.starter_reviews r JOIN public.starter_members m ON m.subject=r.owner_id\n WHERE r.id=split_part(name,'/',2) AND r.state='draft' AND m.subject=COALESCE(NULLIF(auth.jwt()->>'external_sub',''),auth.jwt()->>'sub')\n AND m.storage_subject=auth.uid() AND m.enabled AND m.can_approve\n )));\nDROP POLICY IF EXISTS starter_attachment_update_fence ON storage.objects;\nCREATE POLICY starter_attachment_update_fence ON storage.objects AS RESTRICTIVE FOR UPDATE TO authenticated\n USING (bucket_id<>'review-attachments') WITH CHECK (bucket_id<>'review-attachments');\nDROP POLICY IF EXISTS starter_attachment_delete_fence ON storage.objects;\nCREATE POLICY starter_attachment_delete_fence ON storage.objects AS RESTRICTIVE FOR DELETE TO authenticated\n USING (bucket_id<>'review-attachments');\n"; export declare const STARTER_UPLOAD_ADAPTER = "import { MIMEType } from \"node:util\";\nimport { SupaCloudArtifactsClient } from \"@supacloud/js\";\nimport { createTransactionalCommand, plaintextCommandInput } from \"@supacloud/commands\";\nimport { CommandError } from \"@supacloud/contracts\";\nimport { createPostgresCommandStore, type CommandTransaction } from \"@supacloud/db\";\nimport { ApplicationError, requireTrustedIdentity } from \"@supacloud/elysia\";\nimport type { ReviewAttachmentOptions } from \"./review-attachments\";\nimport type { ReviewUploadInput, ReviewUploadPort, ReviewUploadResult } from \"../review/uploads\";\n\nfunction isRecord(value: unknown): value is Record {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\nfunction record(value: unknown): Record {\n if (!isRecord(value)) throw new TypeError(\"Invalid upload record\");\n return value;\n}\nfunction rows(value: unknown): Record[] {\n if (!Array.isArray(value)) throw new TypeError(\"Invalid upload database result\");\n return value.map(record);\n}\nfunction capture(value: unknown): ReviewUploadInput {\n const item = record(value), uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n if (typeof item[\"reviewId\"] !== \"string\" || !uuid.test(item[\"reviewId\"])\n || typeof item[\"artifactId\"] !== \"string\" || !uuid.test(item[\"artifactId\"])\n || typeof item[\"expectedVersion\"] !== \"number\" || !Number.isSafeInteger(item[\"expectedVersion\"]) || item[\"expectedVersion\"] < 1) {\n throw new ApplicationError(\"Invalid upload input\", { status: 400, code: \"UPLOAD_INPUT_INVALID\" });\n }\n return { reviewId: item[\"reviewId\"].toLowerCase(), artifactId: item[\"artifactId\"].toLowerCase(), expectedVersion: item[\"expectedVersion\"] };\n}\nfunction result(value: unknown): ReviewUploadResult {\n const item = record(value);\n if (typeof item[\"artifactId\"] !== \"string\" || typeof item[\"runId\"] !== \"string\" || typeof item[\"objectPath\"] !== \"string\"\n || typeof item[\"sha256\"] !== \"string\" || typeof item[\"bytes\"] !== \"number\") throw new TypeError(\"Invalid upload receipt\");\n return { artifactId: item[\"artifactId\"], runId: item[\"runId\"], objectPath: item[\"objectPath\"], sha256: item[\"sha256\"], bytes: item[\"bytes\"] };\n}\n\nexport async function createReviewUploadAdapters(options: ReviewAttachmentOptions): Promise {\n const { database, service, projectId, tenantId } = options;\n const binding = rows(await database.transaction(tx => tx.query(\n \"SELECT project_id,tenant_id FROM public.starter_application WHERE singleton\",\n )));\n if (!projectId.trim() || !tenantId.trim() || binding.length !== 1\n || binding[0]?.[\"project_id\"] !== projectId || binding[0]?.[\"tenant_id\"] !== tenantId) {\n throw new Error(\"Upload database project/tenant binding mismatch\");\n }\n const artifacts = new SupaCloudArtifactsClient(service);\n function actor(context: unknown): string {\n const who = requireTrustedIdentity(context);\n const access = record(record(context)[\"access\"]);\n if (access[\"projectId\"] !== projectId || access[\"tenantId\"] !== tenantId\n || !Array.isArray(access[\"permissions\"]) || !access[\"permissions\"].includes(\"review.approve\")) {\n throw new ApplicationError(\"Upload permission denied\", { status: 403, code: \"UPLOAD_DENIED\" });\n }\n return who.subject;\n }\n async function authorize(tx: CommandTransaction, subject: string, input: ReviewUploadInput, replay = false) {\n const allowed = rows(await tx.query(\n \"SELECT m.storage_subject::text AS storage_subject FROM public.starter_reviews r \" +\n \"JOIN public.starter_members m ON m.subject=r.owner_id CROSS JOIN public.starter_application p \" +\n \"WHERE r.id=$1 AND r.owner_id=$2 AND ((r.state='draft' AND r.version=$3) OR \" +\n \"($6::boolean AND r.state='approved' AND r.version=$3+1 AND EXISTS (\" +\n \"SELECT 1 FROM public.starter_attachments b WHERE b.review_id=r.id AND b.artifact_id=$7::uuid AND b.owner_id=$2 \" +\n \"AND b.object_path=m.storage_subject::text || '/' || r.id || '/' || $7::text || '.txt'))) \" +\n \"AND m.enabled AND m.can_approve AND m.storage_subject IS NOT NULL \" +\n \"AND p.singleton AND p.project_id=$4 AND p.tenant_id=$5 FOR UPDATE OF r,m FOR SHARE OF p\",\n [input.reviewId, subject, input.expectedVersion, projectId, tenantId, replay, input.artifactId],\n ));\n if (allowed.length !== 1 || typeof allowed[0]?.[\"storage_subject\"] !== \"string\") {\n throw new ApplicationError(\"Upload ownership, permission or revision changed\", { status: 403, code: \"UPLOAD_DENIED\" });\n }\n return allowed[0][\"storage_subject\"] + \"/\" + input.reviewId + \"/\" + input.artifactId + \".txt\";\n }\n return {\n async previewUpload(context, value) {\n const input = capture(value), subject = actor(context);\n const objectPath = await database.transaction(tx => authorize(tx, subject, input));\n return { artifactId: input.artifactId, bucketId: \"review-attachments\", objectPath };\n },\n async registerUpload(context, value) {\n const input = capture(value), subject = actor(context);\n const objectPath = await database.transaction(tx => authorize(tx, subject, input, true));\n try {\n const downloaded = await service.storage.from(\"review-attachments\").download(objectPath);\n if (downloaded.error || !downloaded.data) throw new Error(\"Upload unavailable\");\n const blob = downloaded.data;\n if (blob.size < 1 || blob.size > 1048576 || new MIMEType(blob.type).essence !== \"text/plain\") {\n throw new ApplicationError(\"Unsupported upload\", { status: 400, code: \"UPLOAD_CONTENT_INVALID\" });\n }\n const sha256 = Array.from(new Uint8Array(await crypto.subtle.digest(\"SHA-256\", await blob.arrayBuffer())),\n byte => byte.toString(16).padStart(2, \"0\")).join(\"\");\n await artifacts.register({ artifactId: input.artifactId, bucketId: \"review-attachments\", objectPath,\n artifactType: \"review.attachment\", sha256, sizeBytes: blob.size, mimeType: \"text/plain\" });\n const command = createTransactionalCommand({\n name: \"review.attach\", store: createPostgresCommandStore(database), inputCodec: plaintextCommandInput,\n input: capture, result,\n async authorize(who, request, tx) {\n try {\n const currentPath = await authorize(tx, who.actorId, request, true);\n return currentPath === objectPath ? \"allow\" : \"deny\";\n } catch (error) {\n if (error instanceof ApplicationError && error.code === \"UPLOAD_DENIED\") return \"deny\";\n throw error;\n }\n },\n async execute(tx, request) {\n const existing = rows(await tx.query(\"SELECT artifact_id FROM public.starter_attachments WHERE review_id=$1\", [request.reviewId]));\n if (existing.length) throw new CommandError(\"COMMAND_IDEMPOTENCY_CONFLICT\");\n const bound: ReviewUploadResult = { artifactId: request.artifactId, runId: request.artifactId, objectPath, sha256, bytes: blob.size };\n await tx.query(\"INSERT INTO public.starter_attachments VALUES($1,$2,$3,$4,$5)\",\n [request.reviewId, bound.artifactId, subject, bound.runId, bound.objectPath]);\n return bound;\n },\n audit: { event: \"review.attachment-bound\", details: request => ({ reviewId: request.reviewId, artifactId: request.artifactId }) },\n });\n const receipt = await command.execute({ actorId: subject, tenantId }, input.artifactId, input);\n if (receipt.status !== \"confirmed\") throw new CommandError(\"COMMAND_OUTCOME_UNKNOWN\");\n return receipt.result;\n } catch (error) {\n if (error instanceof ApplicationError) throw error;\n if (error instanceof CommandError && error.code === \"COMMAND_IDEMPOTENCY_CONFLICT\") {\n throw new ApplicationError(\"Conflicting attachment binding\", { status: 409, code: error.code });\n }\n if (error instanceof CommandError && error.code === \"COMMAND_REJECTED\") {\n throw new ApplicationError(\"Upload permission denied\", { status: 403, code: error.code });\n }\n // Registration may have committed even when binding failed; never delete immutable evidence here.\n throw new ApplicationError(\"Upload registration could not be confirmed\", { status: 503, code: \"UPLOAD_OUTCOME_UNKNOWN\" });\n }\n },\n };\n}\n";