From 35ff518ff79026f84ed061090543ec579f06622c Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Wed, 18 Jun 2025 07:39:02 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=98=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../get-public-project-by-identifier.ts | 9 +++----- .../src/api-v1/projects/get-public-project.ts | 9 +++----- apps/api/src/lib/acl-public-project.ts | 22 +++++++++++++++++++ .../upsert-consumer-stripe-checkout.ts | 18 +++++++++------ .../src/app/marketplace/marketplace-index.tsx | 3 ++- apps/web/src/lib/notifications.ts | 4 +++- packages/api-client/src/agentic-api-client.ts | 4 +++- 7 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 apps/api/src/lib/acl-public-project.ts diff --git a/apps/api/src/api-v1/projects/get-public-project-by-identifier.ts b/apps/api/src/api-v1/projects/get-public-project-by-identifier.ts index d5c73fc7..ec378277 100644 --- a/apps/api/src/api-v1/projects/get-public-project-by-identifier.ts +++ b/apps/api/src/api-v1/projects/get-public-project-by-identifier.ts @@ -1,8 +1,9 @@ import type { DefaultHonoEnv } from '@agentic/platform-hono' -import { assert, parseZodSchema } from '@agentic/platform-core' +import { parseZodSchema } from '@agentic/platform-core' import { createRoute, type OpenAPIHono } from '@hono/zod-openapi' import { db, eq, schema } from '@/db' +import { aclPublicProject } from '@/lib/acl-public-project' import { openapiAuthenticatedSecuritySchemas, openapiErrorResponse404, @@ -49,11 +50,7 @@ export function registerV1GetPublicProjectByIdentifier( ...Object.fromEntries(populate.map((field) => [field, true])) } }) - assert( - project && !project.private && project.lastPublishedDeploymentId, - 404, - `Public project not found "${projectIdentifier}"` - ) + await aclPublicProject(project, projectIdentifier) return c.json(parseZodSchema(schema.projectSelectSchema, project)) }) diff --git a/apps/api/src/api-v1/projects/get-public-project.ts b/apps/api/src/api-v1/projects/get-public-project.ts index ad708299..99700b71 100644 --- a/apps/api/src/api-v1/projects/get-public-project.ts +++ b/apps/api/src/api-v1/projects/get-public-project.ts @@ -1,8 +1,9 @@ import type { DefaultHonoEnv } from '@agentic/platform-hono' -import { assert, parseZodSchema } from '@agentic/platform-core' +import { parseZodSchema } from '@agentic/platform-core' import { createRoute, type OpenAPIHono } from '@hono/zod-openapi' import { db, eq, schema } from '@/db' +import { aclPublicProject } from '@/lib/acl-public-project' import { openapiAuthenticatedSecuritySchemas, openapiErrorResponse404, @@ -48,11 +49,7 @@ export function registerV1GetPublicProject(app: OpenAPIHono) { ...Object.fromEntries(populate.map((field) => [field, true])) } }) - assert( - project && !project.private && project.lastPublishedDeploymentId, - 404, - `Public project not found "${projectId}"` - ) + await aclPublicProject(project, projectId) return c.json(parseZodSchema(schema.projectSelectSchema, project)) }) diff --git a/apps/api/src/lib/acl-public-project.ts b/apps/api/src/lib/acl-public-project.ts new file mode 100644 index 00000000..6b55828a --- /dev/null +++ b/apps/api/src/lib/acl-public-project.ts @@ -0,0 +1,22 @@ +import { assert } from '@agentic/platform-core' + +import type { RawProject } from '@/db' + +export async function aclPublicProject( + project: RawProject | undefined, + projectId?: string +) { + assert( + project, + 404, + `Public project not found${projectId ? ` "${projectId}"` : ''}` + ) + + assert( + !project.private && project.lastPublishedDeploymentId, + 404, + `Public project not found "${project.id}"` + ) + + assert(!project.deletedAt, 410, `Project has been deleted "${project.id}"`) +} diff --git a/apps/api/src/lib/consumers/upsert-consumer-stripe-checkout.ts b/apps/api/src/lib/consumers/upsert-consumer-stripe-checkout.ts index 65c67633..66d828be 100644 --- a/apps/api/src/lib/consumers/upsert-consumer-stripe-checkout.ts +++ b/apps/api/src/lib/consumers/upsert-consumer-stripe-checkout.ts @@ -17,6 +17,7 @@ import { upsertStripeCustomer } from '@/lib/billing/upsert-stripe-customer' import { upsertStripePricing } from '@/lib/billing/upsert-stripe-pricing' import { createConsumerToken } from '@/lib/create-consumer-token' +import { aclPublicProject } from '../acl-public-project' import { createStripeCheckoutSession } from '../billing/create-stripe-checkout-session' export async function upsertConsumerStripeCheckout( @@ -65,12 +66,6 @@ export async function upsertConsumerStripeCheckout( } }) assert(deployment, 404, `Deployment not found "${deploymentId}"`) - assert( - !deployment.deletedAt, - 410, - `Deployment has been deleted by its owner "${deployment.id}"` - ) - await acl(c, deployment, { label: 'Deployment' }) project = deployment.project! assert( @@ -78,7 +73,16 @@ export async function upsertConsumerStripeCheckout( 404, `Project not found "${projectId}" for deployment "${deploymentId}"` ) - await acl(c, project, { label: 'Project' }) + await aclPublicProject(project) + + // Validate the deployment only after we're sure the project is publicly + // accessible. + assert( + !deployment.deletedAt, + 410, + `Deployment has been deleted by its owner "${deployment.id}"` + ) + projectId = project.id } diff --git a/apps/web/src/app/marketplace/marketplace-index.tsx b/apps/web/src/app/marketplace/marketplace-index.tsx index 61cf0378..7b27aeeb 100644 --- a/apps/web/src/app/marketplace/marketplace-index.tsx +++ b/apps/web/src/app/marketplace/marketplace-index.tsx @@ -70,7 +70,8 @@ export function MarketplaceIndex() {

Error fetching projects

) : !projects.length ? (

- No projects found. Create your first project to get started! + No projects found. This is likely an error on Agentic's side. + Please refresh or contact support.

) : (
diff --git a/apps/web/src/lib/notifications.ts b/apps/web/src/lib/notifications.ts index 06376271..172f5aae 100644 --- a/apps/web/src/lib/notifications.ts +++ b/apps/web/src/lib/notifications.ts @@ -33,7 +33,9 @@ export async function toastError( } console.error(...[ctx?.label, message, details].filter(Boolean)) - toastImpl.error(message) + toastImpl.error(message, { + duration: 10_000 + }) } export { toast } from 'sonner' diff --git a/packages/api-client/src/agentic-api-client.ts b/packages/api-client/src/agentic-api-client.ts index 425d4c3d..52251b27 100644 --- a/packages/api-client/src/agentic-api-client.ts +++ b/packages/api-client/src/agentic-api-client.ts @@ -347,7 +347,9 @@ export class AgenticApiClient { } = {} ): Promise>> { return this.ky - .get('v1/projects', { searchParams: sanitizeSearchParams(searchParams) }) + .get('v1/projects/public', { + searchParams: sanitizeSearchParams(searchParams) + }) .json() }