pull/715/head
Travis Fischer 2025-05-26 17:13:03 +07:00
rodzic 9a0fabd498
commit cdf55f672f
6 zmienionych plików z 148 dodań i 93 usunięć

Wyświetl plik

@ -1,5 +1,5 @@
import { assert, parseZodSchema, pick, sha256 } from '@agentic/platform-core' import { assert, parseZodSchema, sha256 } from '@agentic/platform-core'
import { validateOriginAdapter } from '@agentic/platform-schemas' import { validateAgenticProjectConfig } from '@agentic/platform-schemas'
import { validators } from '@agentic/platform-validators' import { validators } from '@agentic/platform-validators'
import { createRoute, type OpenAPIHono } from '@hono/zod-openapi' import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
@ -99,10 +99,15 @@ export function registerV1DeploymentsCreateDeployment(
}) })
} }
// Validate origin config, including any OpenAPI or MCP specs // Validate project config, including:
await validateOriginAdapter({ // - pricing plans
...pick(body, 'originUrl', 'originAdapter'), // - origin adapter config
// - origin API base UrL
// - origin adapter OpenAPI or MCP specs
// - tool definitions
const agenticProjectConfig = await validateAgenticProjectConfig(body, {
label: `deployment "${deploymentIdentifier}"`, label: `deployment "${deploymentIdentifier}"`,
strip: true,
logger logger
}) })
@ -111,6 +116,7 @@ export function registerV1DeploymentsCreateDeployment(
.insert(schema.deployments) .insert(schema.deployments)
.values({ .values({
...body, ...body,
...agenticProjectConfig,
identifier: deploymentIdentifier, identifier: deploymentIdentifier,
hash, hash,
userId: user.id, userId: user.id,
@ -139,8 +145,6 @@ export function registerV1DeploymentsCreateDeployment(
version: deployment.version! version: deployment.version!
}) })
} }
// TODO: validate deployment originUrl, originAdapter, originSchema, and
// originSchemaVersion
return c.json(parseZodSchema(schema.deploymentSelectSchema, deployment)) return c.json(parseZodSchema(schema.deploymentSelectSchema, deployment))
}) })

Wyświetl plik

@ -38,14 +38,13 @@ import { users } from './user'
// https://docs.rapidapi.com/docs/keys#section-different-api-keys-per-application // https://docs.rapidapi.com/docs/keys#section-different-api-keys-per-application
/** /**
* A `Consumer` is a user who has subscribed to a `Project`. * A `Consumer` represents a user who has subscribed to a `Project` and is used
* * to track usage and billing.
* Consumers are used to track usage and billing for a project.
* *
* Consumers are linked to a corresponding Stripe Customer and Subscription. * Consumers are linked to a corresponding Stripe Customer and Subscription.
* The Stripe customer will either be the user's default Stripe Customer for * The Stripe customer will either be the user's default Stripe Customer if the
* the platform account, or a customer on the project's connected Stripe * project uses the default Agentic platform account, or a customer on the project
* account if the project has Stripe Connect enabled. * owner's connected Stripe account if the project has Stripe Connect enabled.
*/ */
export const consumers = pgTable( export const consumers = pgTable(
'consumers', 'consumers',
@ -168,6 +167,15 @@ export const consumerSelectSchema = createSelectSchema(consumers, {
// .openapi('Deployment', { type: 'object' }) // .openapi('Deployment', { type: 'object' })
// }) // })
.strip() .strip()
.describe(
`A Consumer represents a user who has subscribed to a Project and is used
to track usage and billing.
Consumers are linked to a corresponding Stripe Customer and Subscription.
The Stripe customer will either be the user's default Stripe Customer if the
project uses the default Agentic platform account, or a customer on the project
owner's connected Stripe account if the project has Stripe Connect enabled.`
)
.openapi('Consumer') .openapi('Consumer')
export const consumerInsertSchema = createInsertSchema(consumers, { export const consumerInsertSchema = createInsertSchema(consumers, {

Wyświetl plik

@ -41,6 +41,15 @@ import { projects } from './project'
import { teams } from './team' import { teams } from './team'
import { users } from './user' import { users } from './user'
/**
* A Deployment is a single, immutable instance of a Project. Each deployment
* contains pricing plans, origin server config (OpenAPI or MCP server), tool
* definitions, and metadata.
*
* Deployments are private to a developer or team until they are published, at
* which point they are accessible to any customers with access to the parent
* Project.
*/
export const deployments = pgTable( export const deployments = pgTable(
'deployments', 'deployments',
{ {
@ -162,6 +171,11 @@ export const deploymentSelectSchema = createSelectSchema(deployments, {
// project: z.object({}).optional().openapi('Project', { type: 'object' }) // project: z.object({}).optional().openapi('Project', { type: 'object' })
// }) // })
.strip() .strip()
.describe(
`A Deployment is a single, immutable instance of a Project. Each deployment contains pricing plans, origin server config (OpenAPI or MCP server), tool definitions, and metadata.
Deployments are private to a developer or team until they are published, at which point they are accessible to any customers with access to the parent Project.`
)
.openapi('Deployment') .openapi('Deployment')
export const deploymentInsertSchema = createInsertSchema(deployments, { export const deploymentInsertSchema = createInsertSchema(deployments, {

Wyświetl plik

@ -43,6 +43,18 @@ import { deployments } from './deployment'
import { teams } from './team' import { teams } from './team'
import { users } from './user' import { users } from './user'
/**
* A Project represents a single Agentic API product. A Project is comprised of
* a series of immutable Deployments, each of which contains pricing data, origin
* API config, OpenAPI or MCP specs, tool definitions, and various metadata.
*
* You can think of Agentic Projects as similar to Vercel projects. They both
* hold some common configuration and are comprised of a series of immutable
* Deployments.
*
* Internally, Projects manage all of the Stripe billing resources across
* Deployments (Stripe Products, Prices, and Meters for usage-based billing).
*/
export const projects = pgTable( export const projects = pgTable(
'projects', 'projects',
{ {
@ -210,6 +222,13 @@ export const projectSelectSchema = createSelectSchema(projects, {
// .openapi('Deployment', { type: 'object' }) // .openapi('Deployment', { type: 'object' })
// }) // })
.strip() .strip()
.describe(
`A Project represents a single Agentic API product. A Project is comprised of a series of immutable Deployments, each of which contains pricing data, origin API config, OpenAPI or MCP specs, tool definitions, and various metadata.
You can think of Agentic Projects as similar to Vercel projects. They both hold some common configuration and are comprised of a series of immutable Deployments.
Internally, Projects manage all of the Stripe billing resources across Deployments (Stripe Products, Prices, and Meters for usage-based billing).`
)
.openapi('Project') .openapi('Project')
export const projectInsertSchema = createInsertSchema(projects, { export const projectInsertSchema = createInsertSchema(projects, {

Wyświetl plik

@ -29,7 +29,8 @@ export const defaultFreePricingPlan = {
] ]
} as const satisfies Readonly<PricingPlan> } as const satisfies Readonly<PricingPlan>
export const agenticProjectConfigSchema = z.object({ export const agenticProjectConfigSchema = z
.object({
/** /**
* Required name of the project. * Required name of the project.
* *
@ -120,6 +121,7 @@ To add support for annual pricing plans, for example, you can use: \`['month', '
.optional() .optional()
.default(['month']) .default(['month'])
}) })
.strip()
export type AgenticProjectConfigInput = z.input< export type AgenticProjectConfigInput = z.input<
typeof agenticProjectConfigSchema typeof agenticProjectConfigSchema

Wyświetl plik

@ -13,13 +13,21 @@ import { validateOriginAdapter } from './validate-origin-adapter'
export async function validateAgenticProjectConfig( export async function validateAgenticProjectConfig(
inputConfig: unknown, inputConfig: unknown,
opts: { logger?: Logger; cwd?: URL } = {} {
strip = false,
...opts
}: { logger?: Logger; cwd?: URL; strip?: boolean; label?: string } = {}
): Promise<AgenticProjectConfig> { ): Promise<AgenticProjectConfig> {
const config = parseZodSchema< const config = parseZodSchema<
AgenticProjectConfig, AgenticProjectConfig,
ZodTypeDef, ZodTypeDef,
AgenticProjectConfigInput AgenticProjectConfigInput
>(agenticProjectConfigSchema, inputConfig) >(
strip
? agenticProjectConfigSchema.strip()
: agenticProjectConfigSchema.strict(),
inputConfig
)
const { name, pricingIntervals, pricingPlans, originUrl } = config const { name, pricingIntervals, pricingPlans, originUrl } = config
assert( assert(
@ -216,8 +224,8 @@ export async function validateAgenticProjectConfig(
} }
await validateOriginAdapter({ await validateOriginAdapter({
...opts,
label: `project "${name}"`, label: `project "${name}"`,
...opts,
originUrl, originUrl,
originAdapter: config.originAdapter originAdapter: config.originAdapter
}) })