@supacloud/cli 0.101.3 → 0.103.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1619 -76
- package/dist/shared/tools/app-evidence.test.d.ts +1 -0
- package/dist/shared/tools/app-starter-attachment-worker.d.ts +2 -2
- package/dist/shared/tools/app-starter-client.d.ts +4 -0
- package/dist/shared/tools/app-starter-client.test.d.ts +1 -0
- package/dist/shared/tools/app-starter-database.d.ts +3 -3
- package/dist/shared/tools/app-starter-execution-observability.d.ts +2 -0
- package/dist/shared/tools/app-starter-postgres.d.ts +2 -2
- package/dist/shared/tools/app-starter-receipts.d.ts +1 -0
- package/dist/shared/tools/app-starter-recovery.test.d.ts +1 -0
- package/dist/shared/tools/app-starter-task-provisioning.d.ts +2 -0
- package/dist/shared/tools/app-starter-task-provisioning.test.d.ts +1 -0
- package/dist/shared/tools/app-starter-tasks.d.ts +4 -0
- package/dist/shared/tools/app-starter-upload.d.ts +2 -2
- package/dist/shared/tools/app-starter-worker-observability.test.d.ts +1 -0
- package/dist/shared/tools/app-task-context.test.d.ts +1 -0
- package/dist/shared/tools/app-tools.d.ts +1 -0
- package/dist/shared/tools/app-verification-plan.d.ts +6 -0
- package/package.json +8 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const STARTER_ATTACHMENT_WORKER = "import { createWorker, type CompiledModule } from \"@supacloud/elysia\";\nimport {\n createSupaCloudWorkflowTransport,\n type SupaCloudWorkflowClaim,\n type SupaCloudWorkflowsClient,\n} from \"@supacloud/js\";\nimport { createReviewAttachmentAdapters, type ReviewAttachmentOptions } from \"./review-attachments\";\n\nexport interface ReviewAttachmentWorkerOptions extends ReviewAttachmentOptions {\n modules: readonly CompiledModule[];\n workflows: Pick<SupaCloudWorkflowsClient, \"claim\" | \"complete\" | \"retry\" | \"fail\">;\n workerId: string;\n queueOwnership: \"exclusive-review-attachments\";\n pollIntervalMs?: number;\n}\n\nexport async function createReviewAttachmentWorker(options: ReviewAttachmentWorkerOptions) {\n if (options.queueOwnership !== \"exclusive-review-attachments\") {\n throw new Error(\"Attachment worker requires an exclusively owned Workflow queue\");\n }\n const { store } = await createReviewAttachmentAdapters(options);\n const { workflows, workerId } = options;\n const failure = Promise.withResolvers<never>();\n // The executable attaches its fatal listener after this async factory returns.\n void failure.promise.catch(() => {});\n let halted: boolean = false;\n const fatal = () => {\n halted = true;\n failure.reject(new Error(\"Attachment worker requires recovery\"));\n };\n async function ownedClaim(claim: SupaCloudWorkflowClaim) {\n if (claim.workflowName !== \"review.verify-attachment\" || claim.workflowVersion !== \"1\"\n || claim.stepKey !== \"verify\" || claim.maxAttempts !== 3 || claim.workerId !== workerId) {\n throw new Error(\"Unsupported attachment workflow\");\n }\n const { reviewId, artifactId } = claim.input;\n if (typeof reviewId !== \"string\" || typeof artifactId !== \"string\") {\n throw new Error(\"Invalid attachment workflow input\");\n }\n const bound = await options.database.transaction(tx => tx.query(\n \"SELECT run_id FROM public.starter_attachments WHERE review_id=$1 AND artifact_id=$2 AND run_id=$3\",\n [reviewId, artifactId, claim.runId],\n ));\n if (!Array.isArray(bound) || bound.length !== 1) throw new Error(\"Attachment workflow ownership mismatch\");\n }\n const workflowTransport = createSupaCloudWorkflowTransport({\n workflows, workerId, visibilityTimeoutSeconds: 120, retryDelaySeconds: 5, acceptClaim: ownedClaim,\n });\n const worker = createWorker({\n modules: options.modules, deps: { dbClient: store }, workerId, concurrency: 1,\n pollIntervalMs: options.pollIntervalMs ?? 1000,\n onError: fatal,\n transport: {\n async claim(signal): Promise<SupaCloudWorkflowClaim | null> {\n if (halted || signal.aborted) return null;\n try {\n return await workflowTransport.claim(signal);\n } catch {\n if (!signal.aborted) fatal();\n throw new Error(\"Attachment workflow claim failed\");\n }\n },\n async ack(claim, output) {\n try {\n await workflowTransport.ack(claim, output);\n } catch {\n fatal();\n throw new Error(\"Attachment workflow completion is unconfirmed\");\n }\n },\n async fail(claim) {\n try {\n await workflowTransport.fail(claim, \"Attachment verification failed\");\n } catch {\n fatal();\n throw new Error(\"Attachment workflow failure receipt is unconfirmed\");\n }\n },\n },\n mapClaim: (claim: SupaCloudWorkflowClaim) => ({\n id: claim.stepId, jobName: claim.workflowName, input: claim.input, attempt: claim.attempt,\n requestContext: { workerId, jobId: claim.stepId, requestId: claim.runId },\n }),\n });\n if (worker.jobNames.length !== 1 || worker.jobNames[0] !== \"review.verify-attachment\") {\n throw new Error(\"Attachment worker requires its compiled reference Job\");\n }\n let closing: Promise<void> | undefined;\n return {\n failure: failure.promise,\n async start() {\n if (halted) throw new Error(\"Attachment worker is not startable\");\n await worker.start();\n },\n close() {\n halted = true;\n return closing ??= worker.stop();\n },\n };\n}\n";
|
|
2
|
-
export declare const STARTER_ATTACHMENT_DELIVERY_WORKER = "import { SQL } from \"bun\";\nimport { createClient } from \"@supabase/supabase-js\";\nimport { SupaCloudWorkflowsClient } from \"@supacloud/js\";\nimport { createBunCommandDatabase } from \"@supacloud/db/bun\";\nimport type { CompiledModule } from \"@supacloud/elysia\";\nimport { createReviewAttachmentWorker } from \"./host/review-attachment-worker\";\n\nfunction required(name: string): string {\n const value = process.env[name];\n if (!value?.trim()) throw new Error(\"Missing required worker setting: \" + name);\n return value;\n}\n\nfunction databaseConnection(): SQL.Options {\n const socket = process.env[\"DATABASE_SOCKET_PATH\"];\n if (socket && process.env[\"DATABASE_URL\"]) throw new Error(\"Conflicting database connection settings\");\n if (socket) {\n return { adapter: \"postgres\", path: socket, database: required(\"DATABASE_NAME\"), username: required(\"DATABASE_USER\") };\n }\n const url = new URL(required(\"DATABASE_URL\"));\n if (url.protocol !== \"postgres:\" && url.protocol !== \"postgresql:\") throw new Error(\"Invalid database URL\");\n return {\n adapter: \"postgres\", url: url.href, hostname: url.hostname.replace(/^\\[|\\]$/g, \"\"), port: Number(url.port || 5432),\n username: decodeURIComponent(url.username), password: decodeURIComponent(url.password),\n database: decodeURIComponent(url.pathname.slice(1)),\n };\n}\n\nexport async function createDeliveryWorker(modules: CompiledModule[], lifecycle: { signal: AbortSignal }) {\n lifecycle.signal.throwIfAborted();\n if (required(\"REVIEW_QUEUE_OWNERSHIP\") !== \"exclusive-review-attachments\") {\n throw new Error(\"Attachment worker requires an exclusively owned Workflow queue\");\n }\n const connection = databaseConnection();\n const settings = {\n projectId: required(\"SUPACLOUD_PROJECT_ID\"), tenantId: required(\"APP_TENANT_ID\"),\n workerId: required(\"REVIEW_WORKER_ID\"), url: required(\"SUPACLOUD_URL\"), key: required(\"SUPACLOUD_SERVICE_ROLE_KEY\"),\n };\n const service = createClient(settings.url, settings.key, {\n auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },\n });\n const pool = new SQL({ ...connection, max: 4, connectionTimeout: 5 });\n let closing: Promise<void> | undefined;\n const closePool = () => closing ??= pool.close({ timeout: 5 });\n try {\n const worker = await createReviewAttachmentWorker({\n database: createBunCommandDatabase(pool), service, projectId: settings.projectId,\n tenantId: settings.tenantId, modules, workerId: settings.workerId,\n workflows: new SupaCloudWorkflowsClient(service), queueOwnership: \"exclusive-review-attachments\",\n });\n lifecycle.signal.throwIfAborted();\n return {\n start: () => worker.start(), failure: worker.failure,\n async close() { try { await worker.close(); } finally { await closePool(); } },\n };\n } catch (error) {\n await closePool();\n const code = error !== null && typeof error === \"object\" && \"code\" in error\n && typeof error.code === \"string\" && /^[A-Z0-9_]{1,64}$/.test(error.code) ? error.code : \"UNKNOWN\";\n console.error(JSON.stringify({ event: \"review-worker-initialization-failed\", code }));\n throw new Error(\"Attachment worker initialization failed\");\n }\n}\n";
|
|
1
|
+
export declare const STARTER_ATTACHMENT_WORKER = "import { createWorker, type CompiledModule, type ExecutionObserver } from \"@supacloud/elysia\";\nimport {\n createSupaCloudWorkflowTransport,\n type SupaCloudWorkflowClaim,\n type SupaCloudWorkflowsClient,\n} from \"@supacloud/js\";\nimport { createReviewAttachmentAdapters, type ReviewAttachmentOptions } from \"./review-attachments\";\n\nexport interface ReviewAttachmentWorkerOptions extends ReviewAttachmentOptions {\n modules: readonly CompiledModule[];\n workflows: Pick<SupaCloudWorkflowsClient, \"claim\" | \"complete\" | \"retry\" | \"fail\">;\n workerId: string;\n queueOwnership: \"exclusive-review-attachments\";\n pollIntervalMs?: number;\n onExecution?: ExecutionObserver;\n}\n\nexport async function createReviewAttachmentWorker(options: ReviewAttachmentWorkerOptions) {\n if (options.queueOwnership !== \"exclusive-review-attachments\") {\n throw new Error(\"Attachment worker requires an exclusively owned Workflow queue\");\n }\n const { store } = await createReviewAttachmentAdapters(options);\n const { workflows, workerId } = options;\n const failure = Promise.withResolvers<never>();\n // The executable attaches its fatal listener after this async factory returns.\n void failure.promise.catch(() => {});\n let halted: boolean = false;\n const fatal = () => {\n halted = true;\n failure.reject(new Error(\"Attachment worker requires recovery\"));\n };\n async function ownedClaim(claim: SupaCloudWorkflowClaim) {\n if (claim.workflowName !== \"review.verify-attachment\" || claim.workflowVersion !== \"1\"\n || claim.stepKey !== \"verify\" || claim.maxAttempts !== 3 || claim.workerId !== workerId) {\n throw new Error(\"Unsupported attachment workflow\");\n }\n const { reviewId, artifactId } = claim.input;\n if (typeof reviewId !== \"string\" || typeof artifactId !== \"string\") {\n throw new Error(\"Invalid attachment workflow input\");\n }\n const bound = await options.database.transaction(tx => tx.query(\n \"SELECT a.run_id FROM public.starter_attachments a WHERE a.review_id=$1 AND a.artifact_id=$2 \" +\n \"AND COALESCE((SELECT r.run_id FROM public.starter_attachment_retries r \" +\n \"WHERE r.review_id=a.review_id ORDER BY r.generation DESC LIMIT 1),a.run_id)=$3\",\n [reviewId, artifactId, claim.runId],\n ));\n if (!Array.isArray(bound) || bound.length !== 1) throw new Error(\"Attachment workflow ownership mismatch\");\n }\n const workflowTransport = createSupaCloudWorkflowTransport({\n workflows, workerId, visibilityTimeoutSeconds: 120, retryDelaySeconds: 5, acceptClaim: ownedClaim,\n });\n const worker = createWorker({\n modules: options.modules, deps: { dbClient: store }, workerId, concurrency: 1,\n pollIntervalMs: options.pollIntervalMs ?? 1000,\n onError: fatal,\n ...(options.onExecution === undefined ? {} : { onExecution: options.onExecution }),\n transport: {\n async claim(signal): Promise<SupaCloudWorkflowClaim | null> {\n if (halted || signal.aborted) return null;\n try {\n return await workflowTransport.claim(signal);\n } catch {\n if (!signal.aborted) fatal();\n throw new Error(\"Attachment workflow claim failed\");\n }\n },\n async ack(claim, output) {\n try {\n await workflowTransport.ack(claim, output);\n } catch {\n fatal();\n throw new Error(\"Attachment workflow completion is unconfirmed\");\n }\n },\n async fail(claim) {\n try {\n await workflowTransport.fail(claim, \"Attachment verification failed\");\n } catch {\n fatal();\n throw new Error(\"Attachment workflow failure receipt is unconfirmed\");\n }\n },\n },\n mapClaim: (claim: SupaCloudWorkflowClaim) => ({\n id: claim.stepId, jobName: claim.workflowName, input: claim.input, attempt: claim.attempt,\n requestContext: { workerId, jobId: claim.stepId, requestId: claim.runId },\n }),\n });\n if (worker.jobNames.length !== 1 || worker.jobNames[0] !== \"review.verify-attachment\") {\n throw new Error(\"Attachment worker requires its compiled reference Job\");\n }\n let closing: Promise<void> | undefined;\n return {\n failure: failure.promise,\n async start() {\n if (halted) throw new Error(\"Attachment worker is not startable\");\n await worker.start();\n },\n close() {\n halted = true;\n return closing ??= worker.stop();\n },\n };\n}\n";
|
|
2
|
+
export declare const STARTER_ATTACHMENT_DELIVERY_WORKER = "import { SQL } from \"bun\";\nimport { createClient } from \"@supabase/supabase-js\";\nimport { SupaCloudWorkflowsClient } from \"@supacloud/js\";\nimport { createBunCommandDatabase } from \"@supacloud/db/bun\";\nimport type { CompiledModule } from \"@supacloud/elysia\";\nimport { createReviewAttachmentWorker } from \"./host/review-attachment-worker\";\nimport { createReviewWorkerObserver } from \"./host/review-worker-observability\";\n\nfunction required(name: string): string {\n const value = process.env[name];\n if (!value?.trim()) throw new Error(\"Missing required worker setting: \" + name);\n return value;\n}\n\nfunction databaseConnection(): SQL.Options {\n const socket = process.env[\"DATABASE_SOCKET_PATH\"];\n if (socket && process.env[\"DATABASE_URL\"]) throw new Error(\"Conflicting database connection settings\");\n if (socket) {\n return { adapter: \"postgres\", path: socket, database: required(\"DATABASE_NAME\"), username: required(\"DATABASE_USER\") };\n }\n const url = new URL(required(\"DATABASE_URL\"));\n if (url.protocol !== \"postgres:\" && url.protocol !== \"postgresql:\") throw new Error(\"Invalid database URL\");\n return {\n adapter: \"postgres\", url: url.href, hostname: url.hostname.replace(/^\\[|\\]$/g, \"\"), port: Number(url.port || 5432),\n username: decodeURIComponent(url.username), password: decodeURIComponent(url.password),\n database: decodeURIComponent(url.pathname.slice(1)),\n };\n}\n\nexport async function createDeliveryWorker(modules: CompiledModule[], lifecycle: { signal: AbortSignal }) {\n lifecycle.signal.throwIfAborted();\n if (required(\"REVIEW_QUEUE_OWNERSHIP\") !== \"exclusive-review-attachments\") {\n throw new Error(\"Attachment worker requires an exclusively owned Workflow queue\");\n }\n const connection = databaseConnection();\n const settings = {\n projectId: required(\"SUPACLOUD_PROJECT_ID\"), tenantId: required(\"APP_TENANT_ID\"),\n workerId: required(\"REVIEW_WORKER_ID\"), url: required(\"SUPACLOUD_URL\"), key: required(\"SUPACLOUD_SERVICE_ROLE_KEY\"),\n };\n const service = createClient(settings.url, settings.key, {\n auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },\n });\n const pool = new SQL({ ...connection, max: 4, connectionTimeout: 5 });\n let closing: Promise<void> | undefined;\n const closePool = () => closing ??= pool.close({ timeout: 5 });\n try {\n const worker = await createReviewAttachmentWorker({\n database: createBunCommandDatabase(pool), service, projectId: settings.projectId,\n tenantId: settings.tenantId, modules, workerId: settings.workerId,\n workflows: new SupaCloudWorkflowsClient(service), queueOwnership: \"exclusive-review-attachments\",\n onExecution: createReviewWorkerObserver(settings.workerId),\n });\n lifecycle.signal.throwIfAborted();\n return {\n start: () => worker.start(), failure: worker.failure,\n async close() { try { await worker.close(); } finally { await closePool(); } },\n };\n } catch (error) {\n await closePool();\n const code = error !== null && typeof error === \"object\" && \"code\" in error\n && typeof error.code === \"string\" && /^[A-Z0-9_]{1,64}$/.test(error.code) ? error.code : \"UNKNOWN\";\n console.error(JSON.stringify({ event: \"review-worker-initialization-failed\", code }));\n throw new Error(\"Attachment worker initialization failed\");\n }\n}\n";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -9,8 +9,8 @@ export declare const STARTER_DATABASE_CONFIG: {
|
|
|
9
9
|
auditConsumers: never[];
|
|
10
10
|
role: string;
|
|
11
11
|
};
|
|
12
|
-
export declare const STARTER_DATABASE_SCHEMA = "import { sql } from \"drizzle-orm\";\nimport { boolean, check, integer, jsonb, pgTable, primaryKey, text, uuid } from \"drizzle-orm/pg-core\";\n\n// Structure for the reviewed starter migrations. Grants/policies stay in those migrations.\nexport const application = pgTable.withRLS(\"starter_application\", {\n singleton: boolean().default(true).primaryKey(),\n projectId: text(\"project_id\").notNull(),\n tenantId: text(\"tenant_id\").notNull(),\n}, table => [\n check(\"starter_application_singleton_check\", sql`${table.singleton}`),\n check(\"starter_application_project_id_check\", sql`length(${table.projectId}) > 0`),\n check(\"starter_application_tenant_id_check\", sql`length(${table.tenantId}) > 0`),\n]);\n\nexport const reviews = pgTable.withRLS(\"starter_reviews\", {\n id: text().primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n state: text({ enum: [\"draft\", \"approved\"] }).notNull(),\n version: integer().notNull(),\n}, table => [\n check(\"starter_reviews_state_check\", sql`${table.state} IN ('draft', 'approved')`),\n check(\"starter_reviews_version_check\", sql`${table.version} > 0`),\n]);\n\nexport const members = pgTable.withRLS(\"starter_members\", {\n subject: text().primaryKey(),\n enabled: boolean().default(true).notNull(),\n canApprove: boolean(\"can_approve\").default(false).notNull(),\n storageSubject: uuid(\"storage_subject\").unique(),\n});\n\nexport const attachments = pgTable.withRLS(\"starter_attachments\", {\n reviewId: text(\"review_id\").primaryKey().references(() => reviews.id),\n artifactId: uuid(\"artifact_id\").notNull().unique(),\n ownerId: text(\"owner_id\").notNull(),\n runId: uuid(\"run_id\").notNull().unique(),\n objectPath: text(\"object_path\").notNull().unique(),\n});\n\nexport const attachmentResults = pgTable.withRLS(\"starter_attachment_results\", {\n reviewId: text(\"review_id\").notNull().references(() => reviews.id),\n version: integer().notNull(),\n artifactId: uuid(\"artifact_id\").notNull(),\n result: jsonb().$type<unknown>().notNull(),\n}, table => [\n primaryKey({ columns: [table.reviewId, table.version, table.artifactId] }),\n check(\"starter_attachment_results_version_check\", sql`${table.version} >= 2`),\n]);\n\nexport type ReviewRow = typeof reviews.$inferSelect;\nexport type NewReview = typeof reviews.$inferInsert;\n";
|
|
13
|
-
export declare const STARTER_DATABASE_MODULES = "import { defineDatabaseModule } from \"@supacloud/db\";\nimport { getTableConfig } from \"drizzle-orm/pg-core\";\nimport { application, reviews, members, attachments, attachmentResults } from \"./schema\";\n\nconst backendPolicies = [\n [\"starter_backend_binding_read\", \"public.starter_application\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_binding_lock\", \"public.starter_application\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_binding_immutable\", \"public.starter_application\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_member_read\", \"public.starter_members\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_member_lock\", \"public.starter_members\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_member_immutable\", \"public.starter_members\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_review_read\", \"public.starter_reviews\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_review_update\", \"public.starter_reviews\", \"update\", [\"starter_review_http\"]],\n [\"starter_worker_review_immutable\", \"public.starter_reviews\", \"update\", [\"starter_review_worker\"]],\n [\"starter_backend_attachment_read\", \"public.starter_attachments\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_attachment_lock\", \"public.starter_attachments\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_attachment_immutable\", \"public.starter_attachments\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_http_attachment_insert\", \"public.starter_attachments\", \"insert\", [\"starter_review_http\"]],\n [\"starter_worker_result_read\", \"public.starter_attachment_results\", \"select\", [\"starter_review_worker\"]],\n [\"starter_worker_result_insert\", \"public.starter_attachment_results\", \"insert\", [\"starter_review_worker\"]],\n] as const;\n\n// The module is the single live-Catalog ownership contract for starter tables.\nexport default defineDatabaseModule({\n name: \"starter\",\n tables: [application, reviews, members, attachments, attachmentResults].map(table => {\n const config = getTableConfig(table);\n return (config.schema ?? \"public\") + \".\" + config.name;\n }),\n policies: [\n ...backendPolicies.map(([name, table, operation, roles]) => ({\n name, table, operation, roles: [...roles], source: \"migrations/004-review-runtime-roles.sql\",\n tests: [\"tests/database-governance.sql\"],\n })),\n {\n name: \"starter_member_read\", table: \"public.starter_members\", operation: \"select\",\n roles: [\"authenticated\"], source: \"migrations/003-review-uploads.sql\",\n tests: [\"tests/database-governance.sql\"],\n },\n {\n name: \"starter_review_read\", table: \"public.starter_reviews\", operation: \"select\",\n roles: [\"authenticated\"], source: \"migrations/003-review-uploads.sql\",\n tests: [\"tests/database-governance.sql\"],\n },\n ],\n});\n";
|
|
14
|
-
export declare const STARTER_DATABASE_TEST = "-- Read-only catalog assertions; behavioral authorization tests remain separate.\nBEGIN READ ONLY;\nDO $test$\nDECLARE\n owned text[] := ARRAY['starter_application','starter_reviews','starter_members',\n 'starter_attachments','starter_attachment_results'];\nBEGIN\n IF (SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace\n WHERE n.nspname='public' AND c.relname=ANY(owned) AND c.relrowsecurity) <>
|
|
12
|
+
export declare const STARTER_DATABASE_SCHEMA = "import { sql } from \"drizzle-orm\";\nimport { boolean, check, integer, jsonb, pgTable, primaryKey, text, unique, uuid } from \"drizzle-orm/pg-core\";\n\n// Structure for the reviewed starter migrations. Grants/policies stay in those migrations.\nexport const application = pgTable.withRLS(\"starter_application\", {\n singleton: boolean().default(true).primaryKey(),\n projectId: text(\"project_id\").notNull(),\n tenantId: text(\"tenant_id\").notNull(),\n}, table => [\n check(\"starter_application_singleton_check\", sql`${table.singleton}`),\n check(\"starter_application_project_id_check\", sql`length(${table.projectId}) > 0`),\n check(\"starter_application_tenant_id_check\", sql`length(${table.tenantId}) > 0`),\n]);\n\nexport const reviews = pgTable.withRLS(\"starter_reviews\", {\n id: text().primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n state: text({ enum: [\"draft\", \"approved\"] }).notNull(),\n version: integer().notNull(),\n}, table => [\n check(\"starter_reviews_state_check\", sql`${table.state} IN ('draft', 'approved')`),\n check(\"starter_reviews_version_check\", sql`${table.version} > 0`),\n]);\n\nexport const members = pgTable.withRLS(\"starter_members\", {\n subject: text().primaryKey(),\n enabled: boolean().default(true).notNull(),\n canApprove: boolean(\"can_approve\").default(false).notNull(),\n storageSubject: uuid(\"storage_subject\").unique(),\n});\n\nexport const attachments = pgTable.withRLS(\"starter_attachments\", {\n reviewId: text(\"review_id\").primaryKey().references(() => reviews.id),\n artifactId: uuid(\"artifact_id\").notNull().unique(),\n ownerId: text(\"owner_id\").notNull(),\n runId: uuid(\"run_id\").notNull().unique(),\n objectPath: text(\"object_path\").notNull().unique(),\n});\n\nexport const attachmentResults = pgTable.withRLS(\"starter_attachment_results\", {\n reviewId: text(\"review_id\").notNull().references(() => reviews.id),\n version: integer().notNull(),\n artifactId: uuid(\"artifact_id\").notNull(),\n result: jsonb().$type<unknown>().notNull(),\n}, table => [\n primaryKey({ columns: [table.reviewId, table.version, table.artifactId] }),\n check(\"starter_attachment_results_version_check\", sql`${table.version} >= 2`),\n]);\n\nexport const attachmentRetries = pgTable.withRLS(\"starter_attachment_retries\", {\n runId: uuid(\"run_id\").primaryKey(),\n reviewId: text(\"review_id\").notNull().references(() => attachments.reviewId),\n previousRunId: uuid(\"previous_run_id\").notNull().unique(),\n generation: integer().notNull(),\n}, table => [\n unique(\"starter_attachment_retries_review_id_generation_key\").on(table.reviewId, table.generation),\n check(\"starter_attachment_retries_generation_check\", sql`${table.generation} > 0`),\n check(\"starter_attachment_retries_check\", sql`${table.runId} <> ${table.previousRunId}`),\n]);\n\nexport type ReviewRow = typeof reviews.$inferSelect;\nexport type NewReview = typeof reviews.$inferInsert;\n";
|
|
13
|
+
export declare const STARTER_DATABASE_MODULES = "import { defineDatabaseModule } from \"@supacloud/db\";\nimport { getTableConfig } from \"drizzle-orm/pg-core\";\nimport { application, reviews, members, attachments, attachmentResults, attachmentRetries } from \"./schema\";\n\nconst backendPolicies = [\n [\"starter_backend_binding_read\", \"public.starter_application\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_binding_lock\", \"public.starter_application\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_binding_immutable\", \"public.starter_application\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_member_read\", \"public.starter_members\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_member_lock\", \"public.starter_members\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_member_immutable\", \"public.starter_members\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_review_read\", \"public.starter_reviews\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_review_update\", \"public.starter_reviews\", \"update\", [\"starter_review_http\"]],\n [\"starter_worker_review_immutable\", \"public.starter_reviews\", \"update\", [\"starter_review_worker\"]],\n [\"starter_backend_attachment_read\", \"public.starter_attachments\", \"select\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_attachment_lock\", \"public.starter_attachments\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_backend_attachment_immutable\", \"public.starter_attachments\", \"update\", [\"starter_review_http\", \"starter_review_worker\"]],\n [\"starter_http_attachment_insert\", \"public.starter_attachments\", \"insert\", [\"starter_review_http\"]],\n [\"starter_worker_result_read\", \"public.starter_attachment_results\", \"select\", [\"starter_review_worker\"]],\n [\"starter_worker_result_insert\", \"public.starter_attachment_results\", \"insert\", [\"starter_review_worker\"]],\n] as const;\n\n// The module is the single live-Catalog ownership contract for starter tables.\nexport default defineDatabaseModule({\n name: \"starter\",\n tables: [application, reviews, members, attachments, attachmentResults, attachmentRetries].map(table => {\n const config = getTableConfig(table);\n return (config.schema ?? \"public\") + \".\" + config.name;\n }),\n policies: [\n ...([\n [\"starter_http_retry_read\", \"select\", \"starter_review_http\"],\n [\"starter_http_retry_insert\", \"insert\", \"starter_review_http\"],\n [\"starter_worker_retry_read\", \"select\", \"starter_review_worker\"],\n ] as const).map(([name, operation, role]) => ({\n name, table: \"public.starter_attachment_retries\", operation, roles: [role],\n source: \"migrations/005-review-task-recovery.sql\", tests: [\"tests/database-governance.sql\"],\n })),\n ...backendPolicies.map(([name, table, operation, roles]) => ({\n name, table, operation, roles: [...roles], source: \"migrations/004-review-runtime-roles.sql\",\n tests: [\"tests/database-governance.sql\"],\n })),\n {\n name: \"starter_member_read\", table: \"public.starter_members\", operation: \"select\",\n roles: [\"authenticated\"], source: \"migrations/003-review-uploads.sql\",\n tests: [\"tests/database-governance.sql\"],\n },\n {\n name: \"starter_review_read\", table: \"public.starter_reviews\", operation: \"select\",\n roles: [\"authenticated\"], source: \"migrations/003-review-uploads.sql\",\n tests: [\"tests/database-governance.sql\"],\n },\n ],\n});\n";
|
|
14
|
+
export declare const STARTER_DATABASE_TEST = "-- Read-only catalog assertions; behavioral authorization tests remain separate.\nBEGIN READ ONLY;\nDO $test$\nDECLARE\n owned text[] := ARRAY['starter_application','starter_reviews','starter_members',\n 'starter_attachments','starter_attachment_results','starter_attachment_retries'];\nBEGIN\n IF (SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace\n WHERE n.nspname='public' AND c.relname=ANY(owned) AND c.relrowsecurity) <> 6 THEN\n RAISE EXCEPTION 'All starter tables must exist with RLS enabled';\n END IF;\n IF (SELECT count(*) FROM pg_policy p JOIN pg_class c ON c.oid=p.polrelid\n JOIN pg_namespace n ON n.oid=c.relnamespace\n WHERE n.nspname='public' AND c.relname=ANY(owned)) <> 20 THEN\n RAISE EXCEPTION 'Starter policy inventory changed; reconcile db/modules.ts';\n END IF;\n IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname IN ('starter_review_http','starter_review_worker')\n AND (rolsuper OR rolbypassrls)) THEN\n RAISE EXCEPTION 'Starter roles must not bypass row security';\n END IF;\n IF (SELECT count(*) FROM pg_roles WHERE rolname IN ('starter_review_http','starter_review_worker')) <> 2 THEN\n RAISE EXCEPTION 'Starter runtime roles are missing';\n END IF;\nEND\n$test$;\nROLLBACK;\n";
|
|
15
15
|
export declare const STARTER_DATABASE_GUIDE = "\n## Database Source Workflow\n\nDrizzle owns table declarations and inferred row types in db/schema.ts.\nUse the existing @supacloud/db/drizzle-bun adapters for typed queries and governed\ntransactions; never replace permission, idempotency or audit checks with plain CRUD.\nOpaque JSON still needs runtime decoding.\n\nAfter installing dependencies, run `bun run db:generate` once and commit db/contracts/.\nThe default `bun run check` and build fail on stale database contracts before any\ncompiler regeneration. After an intentional source change, run db:generate again,\nreview the diff, then run check.\nThe command starter registers databaseGovernance.moduleFile = \"db/modules.ts\" and\nkeeps the default `databaseGovernance.mode = \"check\"`: compile/check/build run\nthe offline source-contract gate without a database. Use `bun run dev:integration`\nwith the CLI's explicit loopback database URL, or set databaseGovernance.mode to\n\"enforce\" with an explicitly supplied `DATABASE_URL`, to run SQL lint and live\nCatalog reconciliation. Missing connections, stale source contracts and Catalog\ndrift fail closed; no contracts or migrations are silently regenerated.\n\n- Maintain one schema-qualified function with explicit grants per db/functions/*.sql.\n- Preserve migrations/ and its existing executor/ledger. Add forward migrations only.\n- `bun run db:diff` generates Drizzle drafts under db/migration-candidates/, never\n into the deployment directory. The starter has existing SQL history, so establish\n and review a matching Drizzle baseline before promoting any draft; the first\n draft is not automatically an incremental production migration.\n- `bun run db:pull` requires an explicitly selected DATABASE_URL and writes only\n output/database-audit/drizzle-candidate/. Review candidates; never overwrite source blindly.\n- Full SQL dumps belong under the ignored output/database-audit/ directory. They are\n audit/recovery artifacts, never ordinary type, application or test inputs.\n- `bun run db:assess` explains adoption/findings without writing or connecting.\n- GraphQL/PostgREST exports remain legitimate protocol contracts. This check is not\n proof of deployed schema, effective role permissions or complete RLS equivalence.\n\nDo not introduce any/@ts-ignore to bypass a contract. Use Drizzle-inferred types,\npreserve bigint/numeric precision and decode unknown results at the boundary.\n";
|
|
16
16
|
export declare function starterDatabaseFiles(): Record<string, string>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const STARTER_EXECUTION_OBSERVABILITY = "import type { ExecutionObserver } from \"@supacloud/elysia\";\n\nfunction correlationId(value: string | undefined): string | undefined {\n return typeof value === \"string\" && /^[A-Za-z0-9._:-]{1,256}$/.test(value) ? value : undefined;\n}\n\nfunction createObserver(source: \"http\" | \"worker\", workerId?: string): ExecutionObserver {\n return metadata => {\n // Select fields explicitly: future observer extensions must not leak payloads.\n console.info(JSON.stringify({\n event: source === \"http\" ? \"review-http-execution\" : \"review-worker-execution\",\n component: source === \"http\" ? \"review-http\" : \"review-attachment-worker\",\n timestamp: new Date().toISOString(),\n workerId: correlationId(workerId),\n kind: metadata.kind,\n operation: metadata.operation,\n stage: metadata.stage,\n phase: metadata.phase,\n requestId: correlationId(metadata.requestId),\n durationMs: typeof metadata.durationMs === \"number\" && Number.isFinite(metadata.durationMs)\n && metadata.durationMs >= 0 ? metadata.durationMs : undefined,\n }));\n };\n}\n\nexport function createReviewHttpObserver(): ExecutionObserver {\n return createObserver(\"http\");\n}\n\nexport function createReviewWorkerObserver(workerId: string): ExecutionObserver {\n return createObserver(\"worker\", workerId);\n}\n";
|
|
2
|
+
export declare const STARTER_WORKER_OBSERVABILITY = "export { createReviewWorkerObserver } from \"./review-execution-observability\";\n";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const STARTER_REVIEW_SCHEMA = "-- Apply with the platform migration owner, never from the HTTP process.\n-- One application database belongs to one explicitly provisioned project/tenant.\nCREATE TABLE public.starter_application (\n singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),\n project_id text NOT NULL CHECK (length(project_id) > 0),\n tenant_id text NOT NULL CHECK (length(tenant_id) > 0)\n);\nCREATE TABLE public.starter_reviews (\n id text PRIMARY KEY, owner_id text NOT NULL,\n state text NOT NULL CHECK (state IN ('draft','approved')),\n version integer NOT NULL CHECK (version > 0)\n);\nCREATE TABLE public.starter_members (\n subject text PRIMARY KEY, enabled boolean NOT NULL DEFAULT true,\n can_approve boolean NOT NULL DEFAULT false\n);\nALTER TABLE public.starter_application ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.starter_reviews ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.starter_members ENABLE ROW LEVEL SECURITY;\n";
|
|
2
|
-
export declare const STARTER_REVIEW_POSTGRES = "import { plaintextCommandInput } from \"@supacloud/commands\";\nimport { CommandError } from \"@supacloud/contracts\";\nimport { createPostgresCommandStore, type CommandDatabase, type CommandTransaction } from \"@supacloud/db\";\nimport {\n ApplicationError, createSchemaDecoder, createSupAuthRequestContext, requireTrustedIdentity,\n createTransactionalCommandGovernance,\n type
|
|
2
|
+
export declare const STARTER_REVIEW_POSTGRES = "import { createTransactionalCommand, plaintextCommandInput } from \"@supacloud/commands\";\nimport { CommandError } from \"@supacloud/contracts\";\nimport { createPostgresCommandStore, type CommandDatabase, type CommandTransaction } from \"@supacloud/db\";\nimport {\n ApplicationError, createSchemaDecoder, createSupAuthRequestContext, requireTrustedIdentity,\n createTransactionalCommandGovernance,\n type SupAuthContextOptions,\n} from \"@supacloud/elysia\";\nimport type { AppAdapters } from \"../application\";\nimport type { ReviewStore } from \"../review/review\";\nimport type { ReviewUploadPort } from \"../review/uploads\";\nimport type { ReviewTaskPort } from \"../review/tasks\";\nimport { ApprovalInput, ReviewResult } from \"../review/contracts\";\nimport type { ReviewRow } from \"../../db/schema\";\n\nconst input = createSchemaDecoder(ApprovalInput, { normalize: false });\nconst result: (value: unknown) => Pick<ReviewRow, \"state\" | \"version\"> =\n createSchemaDecoder(ReviewResult, { normalize: false });\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\nfunction record(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new TypeError(\"Invalid review record\");\n return value;\n}\nfunction rows(value: unknown): Record<string, unknown>[] {\n if (!Array.isArray(value)) throw new TypeError(\"Invalid database result\");\n return value.map(record);\n}\nfunction isPublicConflict(value: unknown): boolean {\n return value instanceof ApplicationError && value.status === 409\n || isRecord(value) && value[\"expose\"] === true && value[\"status\"] === 409 && typeof value[\"code\"] === \"string\";\n}\nexport interface ReviewPostgresOptions {\n database: CommandDatabase;\n tenantId: string;\n identity: Omit<SupAuthContextOptions, \"resolveAccess\">;\n uploads?: ReviewUploadPort;\n tasks?: ReviewTaskPort;\n // Only database effects here: they commit/rollback with the approval and receipt.\n afterApproved?(tx: CommandTransaction, id: string, version: number): Promise<void>;\n}\n\nexport async function createReviewPostgresAdapters(options: ReviewPostgresOptions): Promise<\n AppAdapters & { requestContext: ReturnType<typeof createSupAuthRequestContext> }\n> {\n const { database, tenantId, identity } = options;\n const projectId = identity.projectId;\n const afterApproved = options.afterApproved;\n if (!tenantId.trim()) throw new TypeError(\"Review tenantId is required\");\n const query = (text: string, parameters: readonly string[] = []) =>\n database.transaction(tx => tx.query(text, parameters));\n const binding = rows(await query(\n \"SELECT project_id,tenant_id FROM public.starter_application WHERE singleton\",\n ));\n if (binding.length !== 1 || binding[0]?.[\"project_id\"] !== projectId || binding[0]?.[\"tenant_id\"] !== tenantId) {\n throw new Error(\"Review database project/tenant binding mismatch\");\n }\n const requestContext = createSupAuthRequestContext({\n ...identity,\n async resolveAccess(who) {\n const found = rows(await query(\n \"SELECT m.can_approve FROM public.starter_members m,public.starter_application a \" +\n \"WHERE m.subject=$1 AND m.enabled AND a.singleton AND a.project_id=$2 AND a.tenant_id=$3\",\n [who.subject, projectId, tenantId],\n ));\n return found.length === 1 ? { projectId, tenantId,\n permissions: found[0]?.[\"can_approve\"] === true ? [\"review.approve\"] : [],\n } : null;\n },\n });\n const transaction = () => commandBinding.transaction();\n const store: ReviewStore = {\n ...options.uploads,\n ...options.tasks,\n async lookupOperation(context, operation) {\n const subject = actor(context);\n try {\n let confirmed: boolean = false;\n if (operation.kind === \"upload\") {\n if (!options.uploads?.lookupUpload) {\n throw new ApplicationError(\"Upload receipt lookup unavailable\", { status: 503, code: \"RECEIPTS_UNAVAILABLE\" });\n }\n confirmed = await options.uploads.lookupUpload(context, {\n reviewId: operation.reviewId, artifactId: operation.operationId, expectedVersion: operation.expectedVersion,\n });\n } else {\n const command = createTransactionalCommand({\n name: \"review.approve\", store: commandStore, inputCodec: plaintextCommandInput, input, result,\n authorize: authorizeApproval,\n execute: async () => { throw new Error(\"Receipt lookup cannot execute a command\"); },\n audit: { event: \"review.approved\", details: request => ({ reviewId: request.id }) },\n });\n const receipt = await command.lookup({ actorId: subject, tenantId }, operation.operationId,\n { id: operation.reviewId, expectedVersion: operation.expectedVersion });\n confirmed = receipt?.status === \"confirmed\";\n }\n return { status: confirmed ? \"confirmed\" : \"unknown\", operationId: operation.operationId, reviewId: operation.reviewId };\n } catch (error) {\n if (error instanceof ApplicationError) throw error;\n if (error instanceof CommandError && [\"COMMAND_REJECTED\", \"COMMAND_IDEMPOTENCY_CONFLICT\"].includes(error.code)) {\n throw new ApplicationError(error.code, { code: error.code, status: error.code === \"COMMAND_REJECTED\" ? 403 : 409 });\n }\n throw new ApplicationError(\"Receipt lookup unavailable\", { status: 503, code: \"RECEIPTS_UNAVAILABLE\" });\n }\n },\n async get(table, id) {\n if (table !== \"reviews\") throw new Error(\"Unsupported review table\");\n return rows(await transaction().query(\n \"SELECT state,version FROM public.starter_reviews WHERE id=$1 FOR UPDATE\", [id],\n ))[0];\n },\n async set(table, id, value) {\n if (table !== \"reviews\") throw new Error(\"Unsupported review table\");\n const review = result(value);\n const updated = rows(await transaction().query(\n \"UPDATE public.starter_reviews SET state=$2,version=$3 WHERE id=$1 RETURNING id\",\n [id, review.state, review.version],\n ));\n if (updated.length !== 1) throw new Error(\"Review write did not update one record\");\n await afterApproved?.(transaction(), id, review.version);\n },\n };\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(\"Command permission denied\", { status: 403, code: \"REVIEW_PERMISSION_DENIED\" });\n }\n return who.subject;\n }\n const commandStore = createPostgresCommandStore(database);\n async function authorizeApproval(who: { actorId: string; tenantId: string }, request: ReturnType<typeof input>, tx: CommandTransaction): Promise<\"allow\" | \"deny\"> {\n const found = rows(await tx.query(\n \"SELECT r.id FROM public.starter_reviews r JOIN public.starter_members m ON m.subject=r.owner_id \" +\n \"CROSS JOIN public.starter_application a \" +\n \"WHERE r.id=$1 AND r.owner_id=$2 AND m.enabled AND m.can_approve \" +\n \"AND a.singleton AND a.project_id=$3 AND a.tenant_id=$4 FOR UPDATE OF r,m FOR SHARE OF a\",\n [request.id, who.actorId, projectId, who.tenantId],\n ));\n return found.length === 1 ? \"allow\" : \"deny\";\n }\n const commandBinding = createTransactionalCommandGovernance({\n permission: \"review.approve\",\n identity: invocation => ({ actorId: actor(invocation.requestContext), tenantId }),\n input: invocation => ({\n ...record(invocation.input.body), id: invocation.input.params[\"id\"],\n }),\n rejection: error => isPublicConflict(error) ? new CommandError(\"COMMAND_IDEMPOTENCY_CONFLICT\") : undefined,\n definition: {\n name: \"review.approve\", store: commandStore,\n inputCodec: plaintextCommandInput, input, result,\n authorize: authorizeApproval,\n audit: { event: \"review.approved\", details: request => ({ reviewId: request.id }) },\n },\n });\n return { deps: { dbClient: store }, requestContext, commandGovernance: commandBinding.governance };\n}\n";
|
|
3
3
|
export declare const STARTER_REVIEW_POSTGRES_TEST = "import { expect, test } from \"bun:test\";\nimport { createReviewPostgresAdapters } from \"../src/host/review-postgres\";\nimport type { ReviewStore } from \"../src/review/review\";\n\nconst identity = {\n issuer: \"https://identity.example.test\", audience: \"review-test\", clientId: \"review-client\",\n projectId: \"review-test\", jwksUrl: \"https://identity.example.test/jwks\",\n};\nfunction database(binding: unknown) {\n const queries: string[] = [];\n return {\n queries,\n async transaction<T>(run: (tx: { query(text: string): Promise<unknown> }) => Promise<T>): Promise<T> {\n return run({ async query(text) { queries.push(text); return binding; } });\n },\n };\n}\n\ntest(\"PostgreSQL host rejects missing or mismatched application ownership without creating data\", async () => {\n for (const binding of [[], [{ project_id: \"other\", tenant_id: \"review-test\" }],\n [{ project_id: \"review-test\", tenant_id: \"other\" }]]) {\n const db = database(binding);\n await expect(createReviewPostgresAdapters({ database: db, identity, tenantId: \"review-test\" }))\n .rejects.toThrow(\"binding mismatch\");\n expect(db.queries).toEqual([\"SELECT project_id,tenant_id FROM public.starter_application WHERE singleton\"]);\n }\n});\n\ntest(\"PostgreSQL host never falls back to demo identity or unbound business storage\", async () => {\n const db = database([{ project_id: \"review-test\", tenant_id: \"review-test\" }]);\n const adapters = await createReviewPostgresAdapters({ database: db, identity, tenantId: \"review-test\" });\n await expect(adapters.requestContext(new Request(\"http://localhost/reviews/health\")))\n .rejects.toMatchObject({ code: \"AUTHENTICATION_REQUIRED\" });\n const store = adapters.deps[\"dbClient\"] as ReviewStore;\n await expect(store.get(\"reviews\", \"example\")).rejects.toThrow(\"not active\");\n await expect(store.set(\"reviews\", \"example\", { state: \"approved\", version: 2 }))\n .rejects.toThrow(\"not active\");\n expect(db.queries).toHaveLength(1);\n});\n";
|
|
4
|
-
export declare const STARTER_REVIEW_DELIVERY_HOST = "import { SQL } from \"bun\";\nimport { createClient } from \"@supabase/supabase-js\";\nimport { createBunCommandDatabase } from \"@supacloud/db/bun\";\nimport { createApplication, type CompiledModule } from \"@supacloud/elysia\";\nimport { createReviewPostgresAdapters } from \"./host/review-postgres\";\nimport { createReviewAttachmentAdapters } from \"./host/review-attachments\";\nimport { createReviewUploadAdapters } from \"./host/review-uploads\";\n\nfunction required(name: string): string {\n const value = process.env[name];\n if (!value?.trim()) throw new Error(\"Missing required host setting: \" + name);\n return value;\n}\n\nfunction databaseConnection(): SQL.Options {\n const socket = process.env[\"DATABASE_SOCKET_PATH\"];\n if (socket && process.env[\"DATABASE_URL\"]) throw new Error(\"Conflicting database connection settings\");\n if (socket) {\n return { adapter: \"postgres\", path: socket, database: required(\"DATABASE_NAME\"), username: required(\"DATABASE_USER\") };\n }\n const url = new URL(required(\"DATABASE_URL\"));\n if (url.protocol !== \"postgres:\" && url.protocol !== \"postgresql:\") throw new Error(\"Invalid database URL\");\n return {\n adapter: \"postgres\", url: url.href, hostname: url.hostname.replace(/^\\[|\\]$/g, \"\"), port: Number(url.port || 5432),\n username: decodeURIComponent(url.username), password: decodeURIComponent(url.password),\n database: decodeURIComponent(url.pathname.slice(1)),\n };\n}\n\nexport async function createDeliveryApplication(modules: CompiledModule[], lifecycle: { signal: AbortSignal }) {\n lifecycle.signal.throwIfAborted();\n const connection = databaseConnection();\n const attachments = process.env[\"REVIEW_ATTACHMENTS\"];\n if (attachments !== undefined && attachments !== \"enabled\") throw new Error(\"Invalid attachment configuration\");\n const settings = {\n tenantId: required(\"APP_TENANT_ID\"),\n identity: {\n issuer: required(\"SUPAUTH_ISSUER\"), audience: required(\"SUPAUTH_AUDIENCE\"),\n clientId: required(\"SUPAUTH_CLIENT_ID\"), projectId: required(\"SUPACLOUD_PROJECT_ID\"),\n jwksUrl: required(\"SUPAUTH_JWKS_URL\"),\n },\n };\n const pool = new SQL({ ...connection, max: 12, connectionTimeout: 5 });\n let closing: Promise<void> | undefined;\n const close = () => closing ??= pool.close({ timeout: 5 });\n let stage: \"attachments\" | \"uploads\" | \"postgres\" | \"application\" = \"attachments\";\n try {\n const database = createBunCommandDatabase(pool);\n const attachmentOptions = attachments === \"enabled\" ? {\n database, tenantId: settings.tenantId, projectId: settings.identity.projectId,\n service: createClient(required(\"SUPACLOUD_URL\"), required(\"SUPACLOUD_SERVICE_ROLE_KEY\"), {\n auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },\n }),\n } : undefined;\n const durable = attachmentOptions ? await createReviewAttachmentAdapters(attachmentOptions) : undefined;\n stage = \"uploads\";\n const uploads = attachmentOptions ? await createReviewUploadAdapters(attachmentOptions) : undefined;\n stage = \"postgres\";\n const adapters = await createReviewPostgresAdapters({\n database, tenantId: settings.tenantId, identity: settings.identity,\n ...(uploads ? { uploads } : {}),\n ...(durable ? { afterApproved: durable.enqueue } : {}),\n });\n lifecycle.signal.throwIfAborted();\n stage = \"application\";\n const app = createApplication({ name: \"review\", modules, ...adapters });\n return { fetch: (request: Request) => app.handle(request), close };\n } catch (error) {\n await close();\n const code = error !== null && typeof error === \"object\" && \"code\" in error\n && typeof error.code === \"string\" && /^[A-Z0-9_]{1,64}$/.test(error.code) ? error.code : \"UNKNOWN\";\n console.error(JSON.stringify({ event: \"review-host-initialization-failed\", stage, code }));\n // Database/identity errors can contain connection details; never echo the underlying cause.\n throw new Error(\"Review host initialization failed\");\n }\n}\n";
|
|
4
|
+
export declare const STARTER_REVIEW_DELIVERY_HOST = "import { SQL } from \"bun\";\nimport { createClient } from \"@supabase/supabase-js\";\nimport { createBunCommandDatabase } from \"@supacloud/db/bun\";\nimport { createApplication, type CompiledModule } from \"@supacloud/elysia\";\nimport { createReviewPostgresAdapters } from \"./host/review-postgres\";\nimport { createReviewAttachmentAdapters } from \"./host/review-attachments\";\nimport { createReviewUploadAdapters } from \"./host/review-uploads\";\nimport { createReviewTaskAdapters } from \"./host/review-tasks\";\nimport { createReviewHttpObserver } from \"./host/review-execution-observability\";\n\nfunction required(name: string): string {\n const value = process.env[name];\n if (!value?.trim()) throw new Error(\"Missing required host setting: \" + name);\n return value;\n}\n\nfunction databaseConnection(): SQL.Options {\n const socket = process.env[\"DATABASE_SOCKET_PATH\"];\n if (socket && process.env[\"DATABASE_URL\"]) throw new Error(\"Conflicting database connection settings\");\n if (socket) {\n return { adapter: \"postgres\", path: socket, database: required(\"DATABASE_NAME\"), username: required(\"DATABASE_USER\") };\n }\n const url = new URL(required(\"DATABASE_URL\"));\n if (url.protocol !== \"postgres:\" && url.protocol !== \"postgresql:\") throw new Error(\"Invalid database URL\");\n return {\n adapter: \"postgres\", url: url.href, hostname: url.hostname.replace(/^\\[|\\]$/g, \"\"), port: Number(url.port || 5432),\n username: decodeURIComponent(url.username), password: decodeURIComponent(url.password),\n database: decodeURIComponent(url.pathname.slice(1)),\n };\n}\n\nexport async function createDeliveryApplication(modules: CompiledModule[], lifecycle: { signal: AbortSignal }) {\n lifecycle.signal.throwIfAborted();\n const connection = databaseConnection();\n const attachments = process.env[\"REVIEW_ATTACHMENTS\"];\n if (attachments !== undefined && attachments !== \"enabled\") throw new Error(\"Invalid attachment configuration\");\n const settings = {\n tenantId: required(\"APP_TENANT_ID\"),\n identity: {\n issuer: required(\"SUPAUTH_ISSUER\"), audience: required(\"SUPAUTH_AUDIENCE\"),\n clientId: required(\"SUPAUTH_CLIENT_ID\"), projectId: required(\"SUPACLOUD_PROJECT_ID\"),\n jwksUrl: required(\"SUPAUTH_JWKS_URL\"),\n },\n };\n const pool = new SQL({ ...connection, max: 12, connectionTimeout: 5 });\n let closing: Promise<void> | undefined;\n const close = () => closing ??= pool.close({ timeout: 5 });\n let stage: \"attachments\" | \"uploads\" | \"postgres\" | \"application\" = \"attachments\";\n try {\n const database = createBunCommandDatabase(pool);\n const attachmentOptions = attachments === \"enabled\" ? {\n database, tenantId: settings.tenantId, projectId: settings.identity.projectId,\n service: createClient(required(\"SUPACLOUD_URL\"), required(\"SUPACLOUD_SERVICE_ROLE_KEY\"), {\n auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },\n }),\n } : undefined;\n const durable = attachmentOptions ? await createReviewAttachmentAdapters(attachmentOptions) : undefined;\n stage = \"uploads\";\n const uploads = attachmentOptions ? await createReviewUploadAdapters(attachmentOptions) : undefined;\n const tasks = attachmentOptions ? await createReviewTaskAdapters(attachmentOptions) : undefined;\n stage = \"postgres\";\n const adapters = await createReviewPostgresAdapters({\n database, tenantId: settings.tenantId, identity: settings.identity,\n ...(uploads ? { uploads } : {}),\n ...(tasks ? { tasks } : {}),\n ...(durable ? { afterApproved: durable.enqueue } : {}),\n });\n lifecycle.signal.throwIfAborted();\n stage = \"application\";\n const app = createApplication({ name: \"review\", modules, ...adapters, onExecution: createReviewHttpObserver() });\n return { fetch: (request: Request) => app.handle(request), close };\n } catch (error) {\n await close();\n const code = error !== null && typeof error === \"object\" && \"code\" in error\n && typeof error.code === \"string\" && /^[A-Z0-9_]{1,64}$/.test(error.code) ? error.code : \"UNKNOWN\";\n console.error(JSON.stringify({ event: \"review-host-initialization-failed\", stage, code }));\n // Database/identity errors can contain connection details; never echo the underlying cause.\n throw new Error(\"Review host initialization failed\");\n }\n}\n";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const STARTER_REVIEW_RECEIPTS = "import { Effect } from \"effect\";\nimport { Controller, DB_CLIENT, Get, Inject, Injectable, Param, Query, REQUEST_CONTEXT } from \"@supacloud/app\";\nimport { ApplicationError, createSchemaDecoder } from \"@supacloud/elysia\";\nimport { ReceiptOperation, ReceiptParams, ReceiptQuery, ReceiptResult,\n type ReviewOperation, type ReviewReceipt } from \"./contracts\";\nexport type { ReviewOperation, ReviewReceipt } from \"./contracts\";\n\nconst decodeOperation = createSchemaDecoder(ReceiptOperation, { normalize: false });\nexport interface ReviewReceiptPort {\n lookupOperation(context: unknown, operation: ReviewOperation): Promise<ReviewReceipt>;\n}\ntype ReceiptError =\n | { readonly _tag: \"AUTHENTICATION_REQUIRED\" }\n | { readonly _tag: \"REVIEW_PERMISSION_DENIED\" }\n | { readonly _tag: \"UPLOAD_DENIED\" }\n | { readonly _tag: \"COMMAND_REJECTED\" }\n | { readonly _tag: \"COMMAND_IDEMPOTENCY_CONFLICT\" }\n | { readonly _tag: \"RECEIPT_INPUT_INVALID\" }\n | { readonly _tag: \"RECEIPTS_UNAVAILABLE\" };\n\n@Injectable({ scope: \"request\" })\nexport class ReviewReceipts {\n constructor(@Inject(DB_CLIENT) private readonly store: Partial<ReviewReceiptPort>,\n @Inject(REQUEST_CONTEXT) private readonly context: unknown) {}\n lookup(operation: ReviewOperation): Promise<ReviewReceipt> {\n let input: ReviewOperation;\n try { input = decodeOperation(operation); }\n catch {\n throw new ApplicationError(\"Invalid receipt input\", { status: 400, code: \"RECEIPT_INPUT_INVALID\" });\n }\n if (!this.store.lookupOperation) {\n throw new ApplicationError(\"Receipt lookup is unavailable\", { status: 503, code: \"RECEIPTS_UNAVAILABLE\" });\n }\n return this.store.lookupOperation(this.context, input);\n }\n}\n\n@Controller(\"/reviews\")\nexport class ReviewReceiptsController {\n constructor(@Inject(ReviewReceipts) private readonly receipts: ReviewReceipts) {}\n @Get(\"/:id/operations/:operationId\", {\n params: ReceiptParams, query: ReceiptQuery, responses: { 200: ReceiptResult },\n effect: {\n required: true, dependencies: [], retry: \"none\",\n errors: [\n { tag: \"AUTHENTICATION_REQUIRED\", status: 401, code: \"AUTHENTICATION_REQUIRED\" },\n { tag: \"REVIEW_PERMISSION_DENIED\", status: 403, code: \"REVIEW_PERMISSION_DENIED\" },\n { tag: \"UPLOAD_DENIED\", status: 403, code: \"UPLOAD_DENIED\" },\n { tag: \"COMMAND_REJECTED\", status: 403, code: \"COMMAND_REJECTED\" },\n { tag: \"COMMAND_IDEMPOTENCY_CONFLICT\", status: 409, code: \"COMMAND_IDEMPOTENCY_CONFLICT\" },\n { tag: \"RECEIPT_INPUT_INVALID\", status: 400, code: \"RECEIPT_INPUT_INVALID\" },\n { tag: \"RECEIPTS_UNAVAILABLE\", status: 503, code: \"RECEIPTS_UNAVAILABLE\" },\n ],\n },\n })\n lookup(@Param(\"id\") reviewId: string, @Param(\"operationId\") operationId: string,\n @Query(\"kind\") kind: ReviewOperation[\"kind\"], @Query(\"expectedVersion\") expectedVersion: string): Effect.Effect<ReviewReceipt, ReceiptError, never> {\n return Effect.promise(() => this.receipts.lookup({ reviewId, operationId, kind, expectedVersion: Number(expectedVersion) }));\n }\n}\n";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const STARTER_TASK_CONTRACTS = "import { t, type UnwrapSchema } from \"elysia\";\nimport { AttachmentResult } from \"./attachment\";\nimport { REVIEW_VERSION_MAX } from \"./limits\";\nimport { ReviewVersion } from \"./contracts\";\n\nexport const TaskParams = t.Object({ id: t.String({ minLength: 1, maxLength: 100 }) }, { additionalProperties: false });\nexport const RetryBody = t.Object({\n expectedVersion: t.Integer({ minimum: 2, maximum: REVIEW_VERSION_MAX }),\n expectedRunId: t.String({ format: \"uuid\" }),\n recoveryId: t.String({ format: \"uuid\" }),\n}, { additionalProperties: false });\nexport const RetryInput = t.Object({\n reviewId: TaskParams.properties.id, ...RetryBody.properties,\n}, { additionalProperties: false });\nexport const TaskStatus = t.Object({\n reviewId: TaskParams.properties.id,\n version: ReviewVersion,\n artifactId: t.Nullable(t.String({ format: \"uuid\" })),\n runId: t.Nullable(t.String({ format: \"uuid\" })),\n state: t.Union([t.Literal(\"not_submitted\"), t.Literal(\"queued\"), t.Literal(\"running\"),\n t.Literal(\"completed\"), t.Literal(\"failed\"), t.Literal(\"cancelled\")]),\n attempts: t.Integer({ minimum: 0 }),\n maxAttempts: t.Literal(3),\n canRetry: t.Boolean(),\n result: t.Nullable(AttachmentResult),\n}, { additionalProperties: false });\nexport const RetryResult = t.Object({\n reviewId: TaskParams.properties.id,\n previousRunId: t.String({ format: \"uuid\" }),\n runId: t.String({ format: \"uuid\" }),\n state: t.Literal(\"queued\"),\n}, { additionalProperties: false });\nexport type ReviewTaskStatus = UnwrapSchema<typeof TaskStatus>;\nexport type ReviewRetryBody = UnwrapSchema<typeof RetryBody>;\nexport type ReviewRetryInput = UnwrapSchema<typeof RetryInput>;\nexport type ReviewRetryResult = UnwrapSchema<typeof RetryResult>;\n";
|
|
2
|
+
export declare const STARTER_TASK_FEATURE = "import { Effect } from \"effect\";\nimport { Body, Controller, DB_CLIENT, Get, Inject, Injectable, Param, Post, REQUEST_CONTEXT } from \"@supacloud/app\";\nimport { ApplicationError } from \"@supacloud/elysia\";\nimport { RetryBody, RetryResult, TaskParams, TaskStatus,\n type ReviewRetryBody, type ReviewRetryInput, type ReviewRetryResult, type ReviewTaskStatus } from \"./task-contracts\";\n\nexport interface ReviewTaskPort {\n attachmentTask(context: unknown, reviewId: string): Promise<ReviewTaskStatus>;\n retryAttachmentTask(context: unknown, input: ReviewRetryInput): Promise<ReviewRetryResult>;\n}\ntype TaskError =\n | { readonly _tag: \"AUTHENTICATION_REQUIRED\" }\n | { readonly _tag: \"TASK_INPUT_INVALID\" }\n | { readonly _tag: \"TASK_DENIED\" }\n | { readonly _tag: \"TASK_CONFLICT\" }\n | { readonly _tag: \"TASK_UNAVAILABLE\" }\n | { readonly _tag: \"TASK_OUTCOME_UNKNOWN\" };\n\n@Injectable({ scope: \"request\" })\nexport class ReviewTasks {\n constructor(@Inject(DB_CLIENT) private readonly store: Partial<ReviewTaskPort>,\n @Inject(REQUEST_CONTEXT) private readonly context: unknown) {}\n\n status(id: string): Promise<ReviewTaskStatus> {\n if (!this.store.attachmentTask) throw new ApplicationError(\"Attachment tasks are not configured\", { status: 501, code: \"TASK_UNAVAILABLE\" });\n return this.store.attachmentTask(this.context, id);\n }\n retry(input: ReviewRetryInput): Promise<ReviewRetryResult> {\n if (!this.store.retryAttachmentTask) throw new ApplicationError(\"Attachment tasks are not configured\", { status: 501, code: \"TASK_UNAVAILABLE\" });\n return this.store.retryAttachmentTask(this.context, input);\n }\n}\n\n@Controller(\"/reviews\")\nexport class ReviewTasksController {\n constructor(@Inject(ReviewTasks) private readonly tasks: ReviewTasks) {}\n\n @Get(\"/:id/attachment-task\", {\n params: TaskParams, responses: { 200: TaskStatus },\n effect: { required: true, dependencies: [], retry: \"none\", errors: [\n { tag: \"AUTHENTICATION_REQUIRED\", status: 401, code: \"AUTHENTICATION_REQUIRED\" },\n { tag: \"TASK_INPUT_INVALID\", status: 400, code: \"TASK_INPUT_INVALID\" },\n { tag: \"TASK_DENIED\", status: 403, code: \"TASK_DENIED\" },\n { tag: \"TASK_CONFLICT\", status: 409, code: \"TASK_CONFLICT\" },\n { tag: \"TASK_UNAVAILABLE\", status: 501, code: \"TASK_UNAVAILABLE\" },\n { tag: \"TASK_OUTCOME_UNKNOWN\", status: 503, code: \"TASK_OUTCOME_UNKNOWN\" },\n ] },\n })\n status(@Param(\"id\") id: string): Effect.Effect<ReviewTaskStatus, TaskError, never> {\n return Effect.promise(() => this.tasks.status(id));\n }\n\n @Post(\"/:id/attachment-task/retry\", {\n params: TaskParams, body: RetryBody, responses: { 200: RetryResult },\n effect: { required: true, dependencies: [], retry: \"none\", errors: [\n { tag: \"AUTHENTICATION_REQUIRED\", status: 401, code: \"AUTHENTICATION_REQUIRED\" },\n { tag: \"TASK_INPUT_INVALID\", status: 400, code: \"TASK_INPUT_INVALID\" },\n { tag: \"TASK_DENIED\", status: 403, code: \"TASK_DENIED\" },\n { tag: \"TASK_CONFLICT\", status: 409, code: \"TASK_CONFLICT\" },\n { tag: \"TASK_UNAVAILABLE\", status: 501, code: \"TASK_UNAVAILABLE\" },\n { tag: \"TASK_OUTCOME_UNKNOWN\", status: 503, code: \"TASK_OUTCOME_UNKNOWN\" },\n ] },\n })\n retry(@Param(\"id\") id: string, @Body() body: ReviewRetryBody): Effect.Effect<ReviewRetryResult, TaskError, never> {\n return Effect.promise(() => this.tasks.retry({ ...body, reviewId: id }));\n }\n}\n";
|
|
3
|
+
export declare const STARTER_TASK_SCHEMA = "-- Forward-only operator provisioning after 004 and the platform Workflow runtime.\nCREATE TABLE public.starter_attachment_retries (\n run_id uuid PRIMARY KEY,\n review_id text NOT NULL REFERENCES public.starter_attachments(review_id),\n previous_run_id uuid NOT NULL UNIQUE,\n generation integer NOT NULL CHECK (generation > 0),\n UNIQUE(review_id,generation),\n CHECK (run_id <> previous_run_id)\n);\nALTER TABLE public.starter_attachment_retries ENABLE ROW LEVEL SECURITY;\nREVOKE ALL ON public.starter_attachment_retries FROM PUBLIC, anon, authenticated;\nGRANT SELECT,INSERT ON public.starter_attachment_retries TO starter_review_http;\nGRANT SELECT ON public.starter_attachment_retries TO starter_review_worker;\nDROP POLICY IF EXISTS starter_http_retry_read ON public.starter_attachment_retries;\nCREATE POLICY starter_http_retry_read ON public.starter_attachment_retries\n FOR SELECT TO starter_review_http USING (true);\nDROP POLICY IF EXISTS starter_http_retry_insert ON public.starter_attachment_retries;\nCREATE POLICY starter_http_retry_insert ON public.starter_attachment_retries\n FOR INSERT TO starter_review_http WITH CHECK (true);\nDROP POLICY IF EXISTS starter_worker_retry_read ON public.starter_attachment_retries;\nCREATE POLICY starter_worker_retry_read ON public.starter_attachment_retries\n FOR SELECT TO starter_review_worker USING (true);\n-- Trusted HTTP adapters authorize the review before inspecting its bound run.\nGRANT EXECUTE ON FUNCTION supacloud_workflows.snapshot(uuid,boolean) TO starter_review_http;\n";
|
|
4
|
+
export declare const STARTER_TASK_HOST = "import { t } from \"elysia\";\nimport { createTransactionalCommand, plaintextCommandInput } from \"@supacloud/commands\";\nimport { CommandError } from \"@supacloud/contracts\";\nimport { createPostgresCommandStore, type CommandDatabase, type CommandTransaction } from \"@supacloud/db\";\nimport { ApplicationError, createSchemaDecoder, requireTrustedIdentity } from \"@supacloud/elysia\";\nimport { AttachmentInput, AttachmentResult } from \"../review/attachment\";\nimport { ReviewResult } from \"../review/contracts\";\nimport { RetryInput, RetryResult, TaskParams, TaskStatus, type ReviewRetryInput } from \"../review/task-contracts\";\nimport type { ReviewTaskPort } from \"../review/tasks\";\nimport type { attachments, attachmentRetries, ReviewRow } from \"../../db/schema\";\n\nexport interface ReviewTaskOptions { database: CommandDatabase; projectId: string; tenantId: string }\ntype Binding = Pick<typeof attachments.$inferSelect, \"artifactId\" | \"runId\">\n & Pick<typeof attachmentRetries.$inferSelect, \"generation\" | \"runId\">;\nconst decodeInput = createSchemaDecoder(RetryInput, { normalize: false });\nconst decodeRetry = createSchemaDecoder(RetryResult, { normalize: false });\nconst decodeStatus = createSchemaDecoder(TaskStatus, { normalize: false });\nconst decodeParams = createSchemaDecoder(TaskParams, { normalize: false });\nconst decodeReview: (value: unknown) => Pick<ReviewRow, \"state\" | \"version\"> =\n createSchemaDecoder(ReviewResult, { normalize: false });\nconst decodeResult = createSchemaDecoder(AttachmentResult, { normalize: false });\nconst decodeBinding: (value: unknown) => Binding = createSchemaDecoder(t.Object({\n artifactId: t.String({ format: \"uuid\" }), runId: t.String({ format: \"uuid\" }),\n generation: t.Integer({ minimum: 0 }),\n}), { normalize: false });\nconst decodeRun = createSchemaDecoder(t.Object({\n runId: t.String({ format: \"uuid\" }), workflowName: t.Literal(\"review.verify-attachment\"),\n workflowVersion: t.Literal(\"1\"),\n status: t.Union([t.Literal(\"queued\"), t.Literal(\"running\"), t.Literal(\"completed\"), t.Literal(\"failed\"), t.Literal(\"cancelled\")]),\n input: AttachmentInput, output: t.Unknown(), idempotent: t.Boolean(),\n steps: t.Array(t.Object({\n stepKey: t.Literal(\"verify\"), attempts: t.Integer({ minimum: 0 }),\n maxAttempts: t.Literal(3),\n status: t.Union([t.Literal(\"queued\"), t.Literal(\"running\"), t.Literal(\"completed\"), t.Literal(\"failed\"), t.Literal(\"dead_lettered\"), t.Literal(\"cancelled\")]),\n }, { additionalProperties: true }), { minItems: 1, maxItems: 1 }),\n}, { additionalProperties: true }), { normalize: false });\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\nfunction record(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(\"Invalid task record\");\n return value;\n}\nfunction rows(value: unknown): Record<string, unknown>[] {\n if (!Array.isArray(value)) throw new Error(\"Invalid task rows\");\n return value.map(record);\n}\nfunction capture(value: unknown): ReviewRetryInput {\n try {\n const input = decodeInput(value);\n return { ...input, recoveryId: input.recoveryId.toLowerCase(), expectedRunId: input.expectedRunId.toLowerCase() };\n } catch { throw new ApplicationError(\"Invalid task request\", { status: 400, code: \"TASK_INPUT_INVALID\" }); }\n}\nfunction failure(error: unknown): never {\n if (error instanceof ApplicationError) throw error;\n if (error instanceof CommandError && error.code === \"COMMAND_REJECTED\") {\n throw new ApplicationError(\"Task access denied\", { status: 403, code: \"TASK_DENIED\" });\n }\n if (error instanceof CommandError && error.code === \"COMMAND_IDEMPOTENCY_CONFLICT\") {\n throw new ApplicationError(\"Task changed or is not retryable\", { status: 409, code: \"TASK_CONFLICT\" });\n }\n throw new ApplicationError(\"Task outcome could not be confirmed\", { status: 503, code: \"TASK_OUTCOME_UNKNOWN\" });\n}\nconst conflict = () => { throw new CommandError(\"COMMAND_IDEMPOTENCY_CONFLICT\"); };\n\nexport async function createReviewTaskAdapters(options: ReviewTaskOptions): Promise<ReviewTaskPort> {\n const { database, projectId, tenantId } = options;\n const configured = 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() || configured.length !== 1\n || configured[0]?.[\"project_id\"] !== projectId || configured[0]?.[\"tenant_id\"] !== tenantId) {\n throw new Error(\"Task database project/tenant binding mismatch\");\n }\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(\"Task access denied\", { status: 403, code: \"TASK_DENIED\" });\n }\n return who.subject;\n }\n async function authorize(tx: CommandTransaction, subject: string, reviewId: string) {\n const found = rows(await tx.query(\n \"SELECT r.state,r.version 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 m.enabled AND m.can_approve \" +\n \"AND p.singleton AND p.project_id=$3 AND p.tenant_id=$4 FOR UPDATE OF r,m FOR SHARE OF p\",\n [reviewId, subject, projectId, tenantId],\n ));\n if (found.length !== 1) throw new ApplicationError(\"Task access denied\", { status: 403, code: \"TASK_DENIED\" });\n return decodeReview(found[0]);\n }\n async function binding(tx: CommandTransaction, reviewId: string) {\n const found = rows(await tx.query(\n 'SELECT a.artifact_id AS \"artifactId\",COALESCE(retry.run_id,a.run_id) AS \"runId\",COALESCE(retry.generation,0) AS generation ' +\n \"FROM public.starter_attachments a LEFT JOIN LATERAL (\" +\n \"SELECT run_id,generation FROM public.starter_attachment_retries WHERE review_id=a.review_id ORDER BY generation DESC LIMIT 1\" +\n \") retry ON true WHERE a.review_id=$1\", [reviewId],\n ));\n return found.length === 0 ? null : decodeBinding(found[0]);\n }\n async function snapshot(tx: CommandTransaction, runId: string) {\n return rows(await tx.query(\"SELECT supacloud_workflows.snapshot($1::uuid,false) AS run\", [runId]))[0]?.[\"run\"];\n }\n function boundRun(value: unknown, reviewId: string, version: number, bound: NonNullable<Awaited<ReturnType<typeof binding>>>) {\n const run = decodeRun(value);\n if (run.runId !== bound.runId || run.input.reviewId !== reviewId\n || run.input.version !== version || run.input.artifactId !== bound.artifactId) {\n throw new Error(\"Task Workflow binding mismatch\");\n }\n const step = run.steps[0];\n if (!step || (run.status === \"queued\" && step.status !== \"queued\")\n || (run.status === \"running\" && step.status !== \"queued\" && step.status !== \"running\")\n || (run.status === \"completed\" && step.status !== \"completed\")\n || (run.status === \"failed\" && step.status !== \"failed\" && step.status !== \"dead_lettered\")\n || (run.status === \"cancelled\" && step.status !== \"cancelled\")) {\n throw new Error(\"Task Workflow state mismatch\");\n }\n return run;\n }\n const retry = createTransactionalCommand({\n name: \"review.retry-attachment\", store: createPostgresCommandStore(database),\n inputCodec: plaintextCommandInput, input: capture, result: decodeRetry,\n async authorize(who, input, tx) {\n try {\n const review = await authorize(tx, who.actorId, input.reviewId);\n return review.state === \"approved\" && review.version === input.expectedVersion ? \"allow\" : \"deny\";\n } catch (error) {\n if (error instanceof ApplicationError && error.code === \"TASK_DENIED\") return \"deny\";\n throw error;\n }\n },\n async execute(tx, input) {\n const bound = await binding(tx, input.reviewId);\n if (!bound || bound.runId !== input.expectedRunId || input.recoveryId === bound.runId) return conflict();\n const previous = boundRun(await snapshot(tx, bound.runId), input.reviewId, input.expectedVersion, bound);\n if (previous.status !== \"failed\") return conflict();\n if (await snapshot(tx, input.recoveryId) !== null) return conflict();\n const started = rows(await tx.query(\n \"SELECT supacloud_workflows.start_run($1::uuid,'review.verify-attachment','1','verify',$2::text::jsonb,3) AS run\",\n [input.recoveryId, JSON.stringify(previous.input)],\n ))[0]?.[\"run\"];\n const next = boundRun(started, input.reviewId, input.expectedVersion, { ...bound, runId: input.recoveryId });\n if (next.idempotent || next.status !== \"queued\") return conflict();\n await tx.query(\"INSERT INTO public.starter_attachment_retries(run_id,review_id,previous_run_id,generation) VALUES($1,$2,$3,$4)\",\n [input.recoveryId, input.reviewId, bound.runId, bound.generation + 1]);\n return { reviewId: input.reviewId, previousRunId: bound.runId, runId: input.recoveryId, state: \"queued\" as const };\n },\n audit: { event: \"review.attachment-retried\", details: input => ({\n reviewId: input.reviewId, previousRunId: input.expectedRunId, runId: input.recoveryId,\n }) },\n });\n return {\n async attachmentTask(context, reviewId) {\n try {\n const subject = actor(context);\n try { decodeParams({ id: reviewId }); }\n catch { throw new ApplicationError(\"Invalid task request\", { status: 400, code: \"TASK_INPUT_INVALID\" }); }\n return await database.transaction(async tx => {\n const review = await authorize(tx, subject, reviewId);\n const bound = await binding(tx, reviewId);\n const empty = { reviewId, version: review.version, artifactId: bound?.artifactId ?? null,\n runId: null, state: \"not_submitted\", attempts: 0, maxAttempts: 3, canRetry: false, result: null } as const;\n if (!bound) return decodeStatus(empty);\n const value = await snapshot(tx, bound.runId);\n if (value === null && review.state === \"draft\" && bound.generation === 0) return decodeStatus(empty);\n const run = boundRun(value, reviewId, review.version, bound);\n const step = run.steps[0];\n if (!step) throw new Error(\"Missing task step\");\n const result = run.status === \"completed\" ? decodeResult(run.output) : null;\n if (result && (result.reviewId !== reviewId || result.version !== review.version || result.artifactId !== bound.artifactId)) {\n throw new Error(\"Task result binding mismatch\");\n }\n return decodeStatus({ ...empty, runId: run.runId,\n state: run.status === \"running\" && step.status === \"queued\" ? \"queued\" : run.status,\n attempts: step.attempts, canRetry: run.status === \"failed\", result });\n });\n } catch (error) { return failure(error); }\n },\n async retryAttachmentTask(context, value) {\n try {\n const subject = actor(context), input = capture(value);\n const receipt = await retry.execute({ actorId: subject, tenantId }, input.recoveryId, input);\n if (receipt.status !== \"confirmed\") throw new CommandError(\"COMMAND_OUTCOME_UNKNOWN\");\n return receipt.result;\n } catch (error) { return failure(error); }\n },\n };\n}\n";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
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\";\
|
|
1
|
+
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,\n type ReviewUploadBody, type ReviewUploadInput, type ReviewUploadLocation, type ReviewUploadResult } from \"./contracts\";\nexport type { ReviewUploadInput, ReviewUploadLocation, ReviewUploadResult } from \"./contracts\";\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<ReviewUploadLocation>;\n registerUpload(context: unknown, input: ReviewUploadInput): Promise<ReviewUploadResult>;\n lookupUpload?(context: unknown, input: ReviewUploadInput): Promise<boolean>;\n}\n@Injectable({ scope: \"request\" })\nexport class ReviewUploads {\n constructor(@Inject(DB_CLIENT) private readonly store: Partial<ReviewUploadPort>,\n @Inject(REQUEST_CONTEXT) private readonly context: unknown) {}\n\n preview(input: ReviewUploadInput): Promise<ReviewUploadLocation> {\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<ReviewUploadResult> {\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: ReviewUploadBody): Effect.Effect<ReviewUploadLocation, PreviewUploadError, never> {\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: ReviewUploadBody): Effect.Effect<ReviewUploadResult, RegisterUploadError, never> {\n return Effect.promise(() => this.uploads.register({ reviewId: id, artifactId: body.artifactId, expectedVersion: body.expectedVersion }));\n }\n}\n";
|
|
2
2
|
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";
|
|
3
|
-
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<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\nfunction record(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new TypeError(\"Invalid upload record\");\n return value;\n}\nfunction rows(value: unknown): Record<string, unknown>[] {\n if (!Array.isArray(value)) throw new TypeError(\"Invalid upload database result\");\n return value.map(record);\n}\
|
|
3
|
+
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, createSchemaDecoder, requireTrustedIdentity } from \"@supacloud/elysia\";\nimport { UploadInput, UploadResult } from \"../review/contracts\";\nimport type { ReviewAttachmentOptions } from \"./review-attachments\";\nimport type { ReviewUploadInput, ReviewUploadPort, ReviewUploadResult } from \"../review/uploads\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\nfunction record(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new TypeError(\"Invalid upload record\");\n return value;\n}\nfunction rows(value: unknown): Record<string, unknown>[] {\n if (!Array.isArray(value)) throw new TypeError(\"Invalid upload database result\");\n return value.map(record);\n}\nconst decodeInput = createSchemaDecoder(UploadInput, { normalize: false });\nconst result = createSchemaDecoder(UploadResult, { normalize: false });\nfunction capture(value: unknown): ReviewUploadInput {\n try {\n const input = decodeInput(value);\n return { ...input, reviewId: input.reviewId.toLowerCase(), artifactId: input.artifactId.toLowerCase() };\n } catch {\n throw new ApplicationError(\"Invalid upload input\", { status: 400, code: \"UPLOAD_INPUT_INVALID\" });\n }\n}\n\nexport async function createReviewUploadAdapters(options: ReviewAttachmentOptions): Promise<ReviewUploadPort> {\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::bigint+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 const receiptLookup = createTransactionalCommand({\n name: \"review.attach\", store: createPostgresCommandStore(database), inputCodec: plaintextCommandInput,\n input: capture, result,\n async authorize(who, request, tx) {\n try { await authorize(tx, who.actorId, request, true); return \"allow\"; }\n catch (error) {\n if (error instanceof ApplicationError && error.code === \"UPLOAD_DENIED\") return \"deny\";\n throw error;\n }\n },\n execute: async () => { throw new Error(\"Receipt lookup cannot register an upload\"); },\n audit: { event: \"review.attachment-bound\", details: request => ({ reviewId: request.reviewId, artifactId: request.artifactId }) },\n });\n return {\n async lookupUpload(context, value) {\n const input = capture(value), subject = actor(context);\n return (await receiptLookup.lookup({ actorId: subject, tenantId }, input.artifactId, input))?.status === \"confirmed\";\n },\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 try {\n // Only an authorized, validated receipt can bypass external registration.\n const saved = await receiptLookup.lookup({ actorId: subject, tenantId }, input.artifactId, input);\n if (saved !== null) {\n if (saved.status !== \"confirmed\") throw new CommandError(\"COMMAND_RECEIPT_INVALID\");\n return saved.result;\n }\n const objectPath = await database.transaction(tx => authorize(tx, subject, input, true));\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";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -18,6 +18,7 @@ declare const REMOTE_APP_ACTIONS: {
|
|
|
18
18
|
readonly "deploy-plan": "get_deploy_plan";
|
|
19
19
|
readonly diff: "get_deploy_plan";
|
|
20
20
|
readonly status: "get_runtime";
|
|
21
|
+
readonly evidence: "get_deployment_evidence";
|
|
21
22
|
readonly rollback: "rollback_release";
|
|
22
23
|
readonly "rollback-plan": "get_rollback_snapshot";
|
|
23
24
|
readonly history: "get_history";
|
|
@@ -9,6 +9,12 @@ export declare function createVerificationPlan(root: string, graph: ApplicationG
|
|
|
9
9
|
tests: string[];
|
|
10
10
|
commands: string[][];
|
|
11
11
|
manual: string[];
|
|
12
|
+
coverage: {
|
|
13
|
+
directory: string;
|
|
14
|
+
tests: string[];
|
|
15
|
+
basis: "colocated-not-proven";
|
|
16
|
+
}[];
|
|
17
|
+
limitations: string[];
|
|
12
18
|
releaseOnly: string[];
|
|
13
19
|
executed: boolean;
|
|
14
20
|
}>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supacloud/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.103.1",
|
|
4
4
|
"description": "Project-scoped CLI for SupaCloud users",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,18 +52,19 @@
|
|
|
52
52
|
"directory": "packages/cli"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@supacloud/compiler": "^0.46.
|
|
56
|
-
"@supacloud/delivery": "0.
|
|
57
|
-
"@supacloud/db": "0.
|
|
55
|
+
"@supacloud/compiler": "^0.46.5",
|
|
56
|
+
"@supacloud/delivery": "0.19.0",
|
|
57
|
+
"@supacloud/db": "0.18.0",
|
|
58
58
|
"typebox": "1.3.37"
|
|
59
59
|
},
|
|
60
60
|
"overrides": {
|
|
61
|
-
"@supacloud/contracts": "0.
|
|
62
|
-
"@supacloud/delivery": "0.
|
|
61
|
+
"@supacloud/contracts": "0.11.1",
|
|
62
|
+
"@supacloud/delivery": "0.19.0",
|
|
63
63
|
"@graphql-tools/utils": "^12.0.4"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@
|
|
66
|
+
"@supabase/supabase-js": "2.117.3",
|
|
67
|
+
"@supacloud/elysia": "0.33.1",
|
|
67
68
|
"@types/bun": "^1.4.3",
|
|
68
69
|
"effect": "4.0.5",
|
|
69
70
|
"elysia": "2.0.0-beta.32",
|