feat: add name/slug to project config

pull/715/head
Travis Fischer 2025-06-25 23:01:38 -05:00
rodzic e223d60946
commit a4b6827f34
62 zmienionych plików z 1197 dodań i 284 usunięć

Wyświetl plik

@ -34,6 +34,8 @@
"@agentic/platform-hono": "workspace:*",
"@agentic/platform-types": "workspace:*",
"@agentic/platform-validators": "workspace:*",
"@dicebear/collection": "^9.2.3",
"@dicebear/core": "^9.2.3",
"@fisch0920/drizzle-orm": "catalog:",
"@fisch0920/drizzle-zod": "catalog:",
"@hono/node-server": "catalog:",

Wyświetl plik

@ -1,5 +1,5 @@
import { resolveAgenticProjectConfig } from '@agentic/platform'
import { assert, parseZodSchema, sha256 } from '@agentic/platform-core'
import { assert, parseZodSchema, sha256, slugify } from '@agentic/platform-core'
import {
isValidDeploymentIdentifier,
parseProjectIdentifier
@ -66,8 +66,9 @@ export function registerV1CreateDeployment(
const logger = c.get('logger')
const inputNamespace = teamMember ? teamMember.teamSlug : user.username
const inputProjectIdentifier = `@${inputNamespace}/${body.name}`
const { projectIdentifier, projectNamespace, projectName } =
const slug = body.slug ?? slugify(body.name) // TODO: don't duplicate this logic here
const inputProjectIdentifier = `@${inputNamespace}/${slug}`
const { projectIdentifier, projectNamespace, projectSlug } =
parseProjectIdentifier(inputProjectIdentifier)
let project = await db.query.projects.findFirst({
@ -99,9 +100,10 @@ export function registerV1CreateDeployment(
await db
.insert(schema.projects)
.values({
name: body.name,
identifier: projectIdentifier,
namespace: projectNamespace,
name: projectName,
slug: projectSlug,
userId: user.id,
teamId: teamMember?.teamId,
private: isPrivate,

Wyświetl plik

@ -15,7 +15,7 @@ import { deploymentIdentifierAndPopulateSchema } from './schemas'
const route = createRoute({
description:
'Gets a deployment by its identifier (eg, "@username/project-name@latest").',
'Gets a deployment by its identifier (eg, "@username/project-slug@latest").',
tags: ['deployments'],
operationId: 'getDeploymentByIdentifier',
method: 'get',

Wyświetl plik

@ -15,7 +15,7 @@ import { deploymentIdentifierAndPopulateSchema } from './schemas'
const route = createRoute({
description:
'Gets a public deployment by its identifier (eg, "@username/project-name@latest").',
'Gets a public deployment by its identifier (eg, "@username/project-slug@latest").',
tags: ['deployments'],
operationId: 'getPublicDeploymentByIdentifier',
method: 'get',

Wyświetl plik

@ -54,8 +54,8 @@ export function registerV1CreateProject(
const teamMember = c.get('teamMember')
const namespace = teamMember ? teamMember.teamSlug : user.username
const identifier = `@${namespace}/${body.name}`
const { projectIdentifier, projectNamespace, projectName } =
const identifier = `@${namespace}/${body.slug}`
const { projectIdentifier, projectNamespace, projectSlug } =
parseProjectIdentifier(identifier)
// Used for testing e2e fixtures in the development marketplace
@ -77,7 +77,7 @@ export function registerV1CreateProject(
...body,
identifier: projectIdentifier,
namespace: projectNamespace,
name: projectName,
slug: projectSlug,
teamId: teamMember?.teamId,
userId: user.id,
private: isPrivate,

Wyświetl plik

@ -14,7 +14,7 @@ import { projectIdentifierAndPopulateSchema } from './schemas'
const route = createRoute({
description:
'Gets a project by its public identifier (eg, "@username/project-name").',
'Gets a project by its public identifier (eg, "@username/project-slug").',
tags: ['projects'],
operationId: 'getProjectByIdentifier',
method: 'get',

Wyświetl plik

@ -14,7 +14,7 @@ import { projectIdentifierAndPopulateSchema } from './schemas'
const route = createRoute({
description:
'Gets a public project by its public identifier (eg, "@username/project-name").',
'Gets a public project by its public identifier (eg, "@username/project-slug").',
tags: ['projects'],
operationId: 'getPublicProjectByIdentifier',
method: 'get',

Wyświetl plik

@ -15,6 +15,8 @@ import { z } from '@hono/zod-openapi'
import { createId as createCuid2 } from '@paralleldrive/cuid2'
export const namespaceMaxLength = 256 as const
export const projectSlugMaxLength = 256 as const
export const projectNameMaxLength = 1024 as const
// prefix is max 5 characters
// separator is 1 character
@ -87,7 +89,7 @@ export function stripeId<U extends string, T extends Readonly<[U, ...U[]]>>(
}
/**
* `namespace/project-name`
* `namespace/project-slug`
*/
export function projectIdentifier<
U extends string,
@ -99,7 +101,7 @@ export function projectIdentifier<
}
/**
* `namespace/project-name@hash`
* `namespace/project-slug@hash`
*/
export function deploymentIdentifier<
U extends string,
@ -122,6 +124,27 @@ export function teamSlug<U extends string, T extends Readonly<[U, ...U[]]>>(
return varchar({ length: namespaceMaxLength, ...config })
}
export function projectNamespace<
U extends string,
T extends Readonly<[U, ...U[]]>
>(
config?: PgVarcharConfig<T | Writable<T>, never>
): PgVarcharBuilderInitial<'', Writable<T>, typeof namespaceMaxLength> {
return varchar({ length: namespaceMaxLength, ...config })
}
export function projectSlug<U extends string, T extends Readonly<[U, ...U[]]>>(
config?: PgVarcharConfig<T | Writable<T>, never>
): PgVarcharBuilderInitial<'', Writable<T>, typeof projectSlugMaxLength> {
return varchar({ length: projectSlugMaxLength, ...config })
}
export function projectName<U extends string, T extends Readonly<[U, ...U[]]>>(
config?: PgVarcharConfig<T | Writable<T>, never>
): PgVarcharBuilderInitial<'', Writable<T>, typeof projectNameMaxLength> {
return varchar({ length: projectNameMaxLength, ...config })
}
/**
* Timestamp with mode `string`
*/

Wyświetl plik

@ -1,4 +1,5 @@
import {
agenticProjectConfigSchema,
pricingIntervalSchema,
type StripeMeterIdMap,
stripeMeterIdMapSchema,
@ -7,7 +8,6 @@ import {
type StripeProductIdMap,
stripeProductIdMapSchema
} from '@agentic/platform-types'
import { isValidProjectName } from '@agentic/platform-validators'
import { relations } from '@fisch0920/drizzle-orm'
import {
boolean,
@ -35,7 +35,10 @@ import {
pricingCurrencyEnum,
pricingIntervalEnum,
projectIdentifier,
projectName,
projectNamespace,
projectPrimaryId,
projectSlug,
stripeId,
teamId,
timestamps,
@ -63,9 +66,17 @@ export const projects = pgTable(
...projectPrimaryId,
...timestamps,
// display name
name: projectName().notNull(),
// identifier is `@namespace/slug`
identifier: projectIdentifier().unique().notNull(),
namespace: text().notNull(),
name: text().notNull(),
// namespace is either a username or team slug
namespace: projectNamespace().notNull(),
// slug is a unique identifier for the project within its namespace
slug: projectSlug().notNull(),
// Defaulting to `true` for now to hide all projects from the marketplace
// by default. Will need to manually set to `true` to allow projects to be
@ -200,6 +211,8 @@ export const projectSelectSchema = createSelectSchema(projects, {
userId: userIdSchema,
teamId: teamIdSchema.optional(),
identifier: projectIdentifierSchema,
name: agenticProjectConfigSchema.shape.name,
slug: agenticProjectConfigSchema.shape.slug,
lastPublishedDeploymentId: deploymentIdSchema.optional(),
lastDeploymentId: deploymentIdSchema.optional(),
@ -299,13 +312,12 @@ Internally, Projects manage all of the Stripe billing resources across Deploymen
export const projectInsertSchema = createInsertSchema(projects, {
identifier: projectIdentifierSchema,
name: (schema) =>
schema.refine((name) => isValidProjectName(name), {
message: 'Invalid project name'
})
name: agenticProjectConfigSchema.shape.name,
slug: agenticProjectConfigSchema.shape.slug
})
.pick({
name: true
name: true,
slug: true
})
.strict()

Wyświetl plik

@ -60,7 +60,7 @@ export const projectIdentifierSchema = z
message: 'Invalid project identifier'
}
)
.describe('Public project identifier (e.g. "@namespace/project-name")')
.describe('Public project identifier (e.g. "@namespace/project-slug")')
.openapi('ProjectIdentifier')
export const deploymentIdentifierSchema = z
@ -74,7 +74,7 @@ export const deploymentIdentifierSchema = z
}
)
.describe(
'Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}")'
'Public deployment identifier (e.g. "@namespace/project-slug@{hash|version|latest}")'
)
.openapi('DeploymentIdentifier')

Wyświetl plik

@ -3,6 +3,7 @@ import { assert } from '@agentic/platform-core'
import { and, db, eq, type RawAccount, type RawUser, schema } from '@/db'
import { createAvatar } from '../create-avatar'
import { getUniqueNamespace } from '../ensure-unique-namespace'
/**
@ -50,6 +51,9 @@ export async function upsertOrLinkUserAccount({
}): Promise<RawUser> {
const { provider, accountId } = partialAccount
// Set a default profile image if one isn't provided
partialUser.image ??= createAvatar(partialUser.email)
const [existingAccount, existingUser] = await Promise.all([
db.query.accounts.findFirst({
where: and(

Wyświetl plik

@ -0,0 +1,6 @@
import { identicon } from '@dicebear/collection'
import { createAvatar as createAvatarImpl } from '@dicebear/core'
export function createAvatar(seed: string): string {
return createAvatarImpl(identicon, { seed }).toDataUri()
}

Wyświetl plik

@ -716,24 +716,25 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
}
]
},
{
title: 'HTTP => Production MCP origin "search" tool',
// NOTE: this one actually hits a production service and costs a small
// amount of $ per request.
fixtures: [
{
path: '@agentic/search/search',
request: {
method: 'POST',
json: {
query: 'latest ai news'
}
},
response: {
snapshot: false
}
}
]
}
// TODO
// {
// title: 'HTTP => Production MCP origin "search" tool',
// // NOTE: this one actually hits a production service and costs a small
// // amount of $ per request.
// fixtures: [
// {
// path: '@agentic/search/search',
// request: {
// method: 'POST',
// json: {
// query: 'latest ai news'
// }
// },
// response: {
// snapshot: false
// }
// }
// ]
// }
]

Wyświetl plik

@ -40,7 +40,7 @@ export function AppProjectIndex({
className='text-center text-balance leading-snug md:leading-none
text-4xl font-extrabold'
>
Project {project.name}
{project.name}
</h1>
<div className='mt-8'>

Wyświetl plik

@ -10,18 +10,18 @@ export default async function AppProjectIndexPage({
}: {
params: Promise<{
namespace: string
'project-name': string
'project-slug': string
}>
}) {
const { namespace: rawNamespace, 'project-name': rawProjectName } =
const { namespace: rawNamespace, 'project-slug': rawProjectSlug } =
await params
try {
const namespace = decodeURIComponent(rawNamespace)
const projectName = decodeURIComponent(rawProjectName)
const projectSlug = decodeURIComponent(rawProjectSlug)
const { projectIdentifier } = parseProjectIdentifier(
`${namespace}/${projectName}`,
`${namespace}/${projectSlug}`,
{ strict: true }
)

Wyświetl plik

@ -10,18 +10,18 @@ export default async function MarketplaceProjectIndexPage({
}: {
params: Promise<{
namespace: string
'project-name': string
'project-slug': string
}>
}) {
const { namespace: rawNamespace, 'project-name': rawProjectName } =
const { namespace: rawNamespace, 'project-slug': rawProjectSlug } =
await params
try {
const namespace = decodeURIComponent(rawNamespace)
const projectName = decodeURIComponent(rawProjectName)
const projectSlug = decodeURIComponent(rawProjectSlug)
const { projectIdentifier } = parseProjectIdentifier(
`${namespace}/${projectName}`,
`${namespace}/${projectSlug}`,
{ strict: true }
)

Wyświetl plik

@ -3,7 +3,8 @@ import 'dotenv/config'
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'search',
name: 'Search',
slug: 'search',
description:
'Google Search tool. Useful for finding up-to-date news and information about any topic.',
origin: {
@ -13,8 +14,63 @@ export default defineConfig({
toolConfigs: [
{
name: 'search',
// Allow results to be cached publicly for ~1 minute
cacheControl: 'public, max-age=60, s-maxage=60 stale-while-revalidate=10'
}
],
pricingPlans: [
{
name: 'Free',
slug: 'free',
lineItems: [
{
slug: 'requests',
usageType: 'metered',
billingScheme: 'per_unit',
unitAmount: 0
}
],
rateLimit: {
interval: '1d',
limit: 10
}
},
{
name: 'Standard',
slug: 'standard',
lineItems: [
{
slug: 'requests',
usageType: 'metered',
billingScheme: 'tiered',
tiersMode: 'volume',
tiers: [
{
upTo: 1000,
unitAmount: 0
},
{
upTo: 50_000,
unitAmount: 0.01
},
{
upTo: 500_000,
unitAmount: 0.008
},
{
upTo: 2_500_000,
unitAmount: 0.006
},
{
upTo: 'inf',
unitAmount: 0.005
}
]
}
],
rateLimit: {
interval: '1s',
limit: 100
}
}
]
})

Wyświetl plik

@ -54,7 +54,7 @@ export function registerDeployCommand({
publish: opts.publish ? 'true' : 'false'
}),
{
text: `Creating deployment for project "${config.name}"`,
text: `Creating deployment for project "${config.slug}"`,
successText: `Deployment created successfully`,
failText: 'Failed to create deployment'
}

Wyświetl plik

@ -24,10 +24,10 @@ export async function resolveDeployment({
const auth = AuthStore.getAuth()
const namespace = auth.user.username
// TODO: resolve deploymentIdentifier; config name may include namespace?
// TODO: resolve deploymentIdentifier; config identifier may include namespace?
// TODO: this needs work...
deploymentIdentifier = `@${namespace}/${config.name}${fuzzyDeploymentIdentifierVersion ? `@${fuzzyDeploymentIdentifierVersion}` : ''}`
deploymentIdentifier = `@${namespace}/${config.slug}${fuzzyDeploymentIdentifierVersion ? `@${fuzzyDeploymentIdentifierVersion}` : ''}`
}
const deployment = await client.getDeploymentByIdentifier({

Wyświetl plik

@ -27,6 +27,7 @@
"test:unit": "vitest run"
},
"dependencies": {
"@sindresorhus/slugify": "^2.2.1",
"decircular": "catalog:",
"is-obj": "catalog:",
"parse-json": "catalog:",

Wyświetl plik

@ -1,6 +1,13 @@
import { expect, test } from 'vitest'
import { omit, pick, pruneEmpty, pruneEmptyDeep, sha256 } from './utils'
import {
omit,
pick,
pruneEmpty,
pruneEmptyDeep,
sha256,
slugify
} from './utils'
test('pick', () => {
expect(pick({ a: 1, b: 2, c: 3 }, 'a', 'c')).toEqual({ a: 1, c: 3 })
@ -101,3 +108,22 @@ test('pruneEmptyDeep', () => {
})
).toEqual(undefined)
})
test('slugify', () => {
expect(slugify('Foo Bar')).toBe('foo-bar')
expect(slugify('FooBar')).toBe('foo-bar')
expect(slugify('FooBarBaz')).toBe('foo-bar-baz')
expect(slugify('FooBarBazQux')).toBe('foo-bar-baz-qux')
expect(slugify('FooBarBazQuxQuux')).toBe('foo-bar-baz-qux-quux')
expect(slugify('foo-bar')).toBe('foo-bar')
expect(slugify('--foo BAR --')).toBe('foo-bar')
expect(slugify('я люблю единорогов')).toBe('ya-lyublyu-edinorogov')
expect(slugify('fooBar 123 $#%')).toBe('foo-bar-123')
expect(slugify(' Déjà Vu! ')).toBe('deja-vu')
expect(slugify('I ♥ Dogs')).toBe('i-love-dogs')
expect(slugify('')).toBe('')
expect(slugify(' ')).toBe('')
expect(slugify('-')).toBe('')
expect(slugify('--')).toBe('')
expect(slugify('- -')).toBe('')
})

Wyświetl plik

@ -1,4 +1,5 @@
import type { z, ZodType } from 'zod'
import slugifyImpl from '@sindresorhus/slugify'
import { HttpError, ZodValidationError } from './errors'
@ -280,3 +281,21 @@ export function pruneEmptyDeep<T>(
return value as any
}
/**
* Slugifies a string.
*
* - converts to lowercase
* - decamelizes (fooBar -> foo-bar)
* - replaces non-latin characters with latin equivalents (transliteration)
* - replaces spaces with hyphens
* - removes trailing hyphens
* - removes leading hyphens
* - removes multiple consecutive hyphens
* - removes multiple consecutive spaces
*
* @see https://github.com/sindresorhus/slugify
*/
export function slugify(input: string): string {
return slugifyImpl(input)
}

Wyświetl plik

@ -1,9 +1,9 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'Test Invalid Name 0',
slug: 'test-invalid-name-0',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'
}
})
} as any) // invalid; missing name

Wyświetl plik

@ -1,7 +1,8 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'Test-Invalid-Name-1',
name: 'a'.repeat(1025), // invalid; too long
slug: 'test-invalid-name-2',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'

Wyświetl plik

@ -1,7 +1,8 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'test_invalid_name_2',
name: '', // invalid; must not be empty
slug: 'test-invalid-name-1',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'

Wyświetl plik

@ -1,7 +1,8 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: '@foo/bar', // invalid; name contains invalid characters
name: 'Test Invalid Slug 0',
slug: 'Test Invalid Slug 0',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'

Wyświetl plik

@ -0,0 +1,10 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'Test Invalid Slug 1',
slug: 'Test-Invalid-Slug-1',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'
}
})

Wyświetl plik

@ -0,0 +1,10 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'Test Invalid Slug 2',
slug: 'test_invalid_slug_2',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'
}
})

Wyświetl plik

@ -1,8 +1,9 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: ' ',
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'
}
} as any) // invalid; missing name
} as any) // invalid; missing slug

Wyświetl plik

@ -0,0 +1,10 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'Test Invalid Name 4',
slug: '@foo/bar', // invalid; slug contains invalid characters
origin: {
type: 'raw',
url: 'https://jsonplaceholder.typicode.com'
}
})

Wyświetl plik

@ -1,7 +1,8 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'test-basic-mcp',
name: 'Test Basic MCP',
slug: 'test-basic-mcp',
origin: {
type: 'mcp',
url: 'https://agentic-basic-mcp-test.onrender.com/mcp'

Wyświetl plik

@ -1,7 +1,8 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'test-basic-openapi',
name: 'Test Basic OpenAPI',
slug: 'test-basic-openapi',
origin: {
type: 'openapi',
url: 'https://jsonplaceholder.typicode.com',

Wyświetl plik

@ -1,7 +1,8 @@
import { defineConfig } from '@agentic/platform'
export default defineConfig({
name: 'test-everything-openapi',
name: 'Test Everything OpenAPI',
slug: 'test-everything-openapi',
origin: {
type: 'openapi',
url: 'https://agentic-platform-fixtures-everything.onrender.com',

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -33,8 +33,11 @@ const invalidFixtures = [
'invalid-name-0',
'invalid-name-1',
'invalid-name-2',
'invalid-name-3',
'invalid-name-4'
'invalid-slug-0',
'invalid-slug-1',
'invalid-slug-2',
'invalid-slug-3',
'invalid-slug-4'
]
const fixturesDir = path.join(

Wyświetl plik

@ -20,27 +20,27 @@ export async function resolveAgenticProjectConfig(
): Promise<ResolvedAgenticProjectConfig> {
const config = parseAgenticProjectConfig(inputConfig)
const { name, version } = resolveMetadata(config)
const { slug, version } = resolveMetadata(config)
validatePricing(config)
const { origin, tools } = await resolveOriginAdapter({
name,
slug,
version,
label: `project "${name}"`,
label: `project "${slug}"`,
...opts,
origin: config.origin
})
const resolvedConfig = parseResolvedAgenticProjectConfig({
...config,
name,
slug,
version,
origin,
tools
})
validateTools({
label: `project "${name}"`,
label: `project "${slug}"`,
...opts,
origin: resolvedConfig.origin,
tools: resolvedConfig.tools,

Wyświetl plik

@ -1,27 +1,33 @@
import type { AgenticProjectConfig } from '@agentic/platform-types'
import { assert } from '@agentic/platform-core'
import { isValidProjectName } from '@agentic/platform-validators'
import type {
AgenticProjectConfig,
ResolvedAgenticProjectConfig
} from '@agentic/platform-types'
import { assert, slugify } from '@agentic/platform-core'
import { isValidProjectSlug } from '@agentic/platform-validators'
import { clean as cleanSemver, valid as isValidSemver } from 'semver'
export function resolveMetadata({
name,
slug,
version
}: Pick<AgenticProjectConfig, 'name' | 'version'>): Pick<
AgenticProjectConfig,
'name' | 'version'
}: Pick<AgenticProjectConfig, 'name' | 'slug' | 'version'>): Pick<
ResolvedAgenticProjectConfig,
'slug' | 'version'
> {
slug ??= slugify(name)
assert(
isValidProjectName(name),
`Invalid project name "${name}". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"`
isValidProjectSlug(slug),
`Invalid project slug "${slug}" for project name "${name}". Must be ascii-only, lower-case, and kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"`
)
if (version) {
const normalizedVersion = cleanSemver(version)!
assert(version, `Invalid semver version "${version}" for project "${name}"`)
assert(version, `Invalid semver version "${version}" for project "${slug}"`)
assert(
isValidSemver(version),
`Invalid semver version "${version}" for project "${name}"`
`Invalid semver version "${version}" for project "${slug}"`
)
// Update the config with the normalized semver version
@ -29,7 +35,7 @@ export function resolveMetadata({
}
return {
name,
slug,
version
}
}

Wyświetl plik

@ -13,14 +13,14 @@ import { validateOriginUrl } from './validate-origin-url'
* Validates, normalizes, and resolves the origin adapter config for a project.
*/
export async function resolveOriginAdapter({
name,
slug,
version = '0.0.0',
origin,
label,
cwd,
logger
}: {
name: string
slug: string
origin: OriginAdapterConfig
label: string
version?: string
@ -41,7 +41,7 @@ export async function resolveOriginAdapter({
})
} else if (origin.type === 'mcp') {
return resolveMCPOriginAdapter({
name,
name: slug,
version,
origin,
label

Wyświetl plik

@ -18,13 +18,13 @@ export async function validateAgenticProjectConfig(
strict: !strip
})
const { name, version } = resolveMetadata(config)
const { slug, version } = resolveMetadata(config)
validatePricing(config)
const origin = await validateOriginAdapter({
name,
slug,
version,
label: `project "${name}"`,
label: `project "${slug}"`,
...opts,
origin: config.origin
})
@ -32,7 +32,7 @@ export async function validateAgenticProjectConfig(
return parseAgenticProjectConfig(
{
...config,
name,
slug,
version,
origin
},

Wyświetl plik

@ -9,14 +9,14 @@ import { validateOriginUrl } from './validate-origin-url'
* Validates and normalizes the origin adapter for a project.
*/
export async function validateOriginAdapter({
name,
slug,
version = '0.0.0',
origin,
label,
cwd,
logger
}: {
name: string
slug: string
origin: Readonly<OriginAdapterConfig>
label: string
version?: string
@ -47,7 +47,7 @@ export async function validateOriginAdapter({
// We intentionally ignore the resolved version and tools here because the
// server will need to re-validate the MCP server info and tools anyway.
await resolveMCPOriginAdapter({
name,
name: slug,
version,
origin,
label

Wyświetl plik

@ -1,6 +1,6 @@
## Project Identifier
`@namespace/project-name`
`@namespace/project-slug`
## Deployment Identifier

Wyświetl plik

@ -28,6 +28,7 @@
"test:unit": "vitest run"
},
"dependencies": {
"@agentic/platform-core": "workspace:*",
"@agentic/platform-validators": "workspace:*",
"@hono/zod-openapi": "catalog:",
"ms": "catalog:",

Wyświetl plik

@ -1,4 +1,5 @@
import type { Simplify } from 'type-fest'
import { isValidProjectSlug } from '@agentic/platform-validators'
import { z } from '@hono/zod-openapi'
import {
@ -35,17 +36,49 @@ import {
export const agenticProjectConfigSchema = z
.object({
/**
* Required name of the project.
* Display name for the project.
*
* Must be lower kebab-case with no spaces and between 2 and 64 characters.
* Max length 1024 characters.
*
* @required
* @example "My Project"
* @example "LinkedIn Resolver"
*/
name: z
.string()
.max(1024)
.nonempty()
.describe('Display name for the project. Max length 1024 characters.'),
/**
* Slug for the project.
*
* Must be ascii-only, lower-case, and kebab-case with no spaces between 1
* and 256 characters.
*
* The project's fully qualified identifier will be `@namespace/slug`, where
* the `namespace` is determined by the author's `username` or team slug.
*
* If not provided, the project `slug` will be derived by slugifying `name`.
*
* @example "my-project"
* @example "linkedin-resolver-23"
*/
name: z.string().nonempty().describe('Name of the project.'),
slug: z
.string()
.nonempty()
.describe(
'Unique project slug. Must be ascii-only, lower-case, and kebab-case with no spaces between 1 and 256 characters. If not provided, it will be derived by slugifying `name`.'
)
.optional()
.refine((slug) => (slug ? isValidProjectSlug(slug) : true), {
message: 'Invalid project slug'
}),
/**
* Optional semantic version of the project as a semver string.
*
* @example "1.0.0"
*/
version: z
.string()
@ -55,13 +88,19 @@ export const agenticProjectConfigSchema = z
)
.optional(),
/** Optional short description of the project. */
/**
* Optional short description of the project.
*
* Should be no longer than a few lines.
*/
description: z
.string()
.describe('A short description of the project.')
.optional(),
/** Optional readme documenting the project (supports GitHub-flavored markdown). */
/**
* Optional embedded markdown readme documenting the project (supports GitHub-flavored markdown).
*/
readme: z
.string()
.describe(
@ -70,7 +109,10 @@ export const agenticProjectConfigSchema = z
.optional(),
/**
* Optional logo image URL to use for the project. Logos should have a square aspect ratio.
* Optional logo image URL to use for the project. Logos should have a
* square aspect ratio.
*
* @example "https://example.com/logo.png"
*/
iconUrl: z
.string()
@ -80,7 +122,11 @@ export const agenticProjectConfigSchema = z
'Optional logo image URL to use for the project. Logos should have a square aspect ratio.'
),
/** Optional URL to the source code of the project. */
/**
* Optional URL to the source code of the project (eg, GitHub repo).
*
* @example "https://github.com/my-org/my-project"
*/
sourceUrl: z
.string()
.url()
@ -102,6 +148,8 @@ export const agenticProjectConfigSchema = z
* @note Currently, only external origin servers are supported. If you'd like
* to host your API or MCP server on Agentic's infrastructure, please reach
* out to support@agentic.so.
*
* @required
*/
origin: originAdapterConfigSchema,
@ -195,14 +243,18 @@ export type AgenticProjectConfigRaw = z.output<
>
export type AgenticProjectConfig = Simplify<
Omit<AgenticProjectConfigRaw, 'pricingPlans' | 'toolConfigs'> & {
slug: string
pricingPlans: PricingPlanList
toolConfigs: ToolConfig[]
defaultRateLimit: RateLimit
}
>
export const resolvedAgenticProjectConfigSchema =
agenticProjectConfigSchema.extend({
export const resolvedAgenticProjectConfigSchema = agenticProjectConfigSchema
.required({
slug: true
})
.extend({
origin: originAdapterSchema,
tools: z.array(toolSchema).default([])
})
@ -211,6 +263,7 @@ export type ResolvedAgenticProjectConfig = Simplify<
z.output<typeof resolvedAgenticProjectConfigSchema>,
'pricingPlans' | 'toolConfigs'
> & {
slug: string
pricingPlans: PricingPlanList
toolConfigs: ToolConfig[]
defaultRateLimit: RateLimit

Wyświetl plik

@ -113,7 +113,7 @@ export interface paths {
path?: never;
cookie?: never;
};
/** @description Gets a public project by its public identifier (eg, "@username/project-name"). */
/** @description Gets a public project by its public identifier (eg, "@username/project-slug"). */
get: operations["getPublicProjectByIdentifier"];
put?: never;
post?: never;
@ -147,7 +147,7 @@ export interface paths {
path?: never;
cookie?: never;
};
/** @description Gets a public deployment by its identifier (eg, "@username/project-name@latest"). */
/** @description Gets a public deployment by its identifier (eg, "@username/project-slug@latest"). */
get: operations["getPublicDeploymentByIdentifier"];
put?: never;
post?: never;
@ -272,7 +272,7 @@ export interface paths {
path?: never;
cookie?: never;
};
/** @description Gets a project by its public identifier (eg, "@username/project-name"). */
/** @description Gets a project by its public identifier (eg, "@username/project-slug"). */
get: operations["getProjectByIdentifier"];
put?: never;
post?: never;
@ -445,7 +445,7 @@ export interface paths {
path?: never;
cookie?: never;
};
/** @description Gets a deployment by its identifier (eg, "@username/project-name@latest"). */
/** @description Gets a deployment by its identifier (eg, "@username/project-slug@latest"). */
get: operations["getDeploymentByIdentifier"];
put?: never;
post?: never;
@ -582,7 +582,7 @@ export interface components {
token: string;
user: components["schemas"]["User"];
};
/** @description Public project identifier (e.g. "@namespace/project-name") */
/** @description Public project identifier (e.g. "@namespace/project-slug") */
ProjectIdentifier: string;
/** @description The frequency at which a subscription is billed. */
PricingInterval: "day" | "week" | "month" | "year";
@ -598,9 +598,12 @@ export interface components {
createdAt: string;
updatedAt: string;
deletedAt?: string;
/** @description Display name for the project. Max length 1024 characters. */
name: string;
identifier: components["schemas"]["ProjectIdentifier"];
namespace: string;
name: string;
/** @description Unique project slug. Must be ascii-only, lower-case, and kebab-case with no spaces between 1 and 256 characters. If not provided, it will be derived by slugifying `name`. */
slug?: string;
private: boolean;
/** @description User id (e.g. "user_tz4a98xxat96iws9zmbrgj3a") */
userId: string;
@ -620,7 +623,7 @@ export interface components {
lastDeployment?: unknown;
deployment?: unknown;
};
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
/** @description Public deployment identifier (e.g. "@namespace/project-slug@{hash|version|latest}") */
DeploymentIdentifier: string;
JsonSchemaObject: {
/** @enum {string} */
@ -1264,7 +1267,7 @@ export interface operations {
parameters: {
query: {
populate?: ("user" | "team" | "lastPublishedDeployment" | "lastDeployment") | ("user" | "team" | "lastPublishedDeployment" | "lastDeployment")[];
/** @description Public project identifier (e.g. "@namespace/project-name") */
/** @description Public project identifier (e.g. "@namespace/project-slug") */
projectIdentifier: components["schemas"]["ProjectIdentifier"];
};
header?: never;
@ -1321,7 +1324,7 @@ export interface operations {
parameters: {
query: {
populate?: ("user" | "team" | "project") | ("user" | "team" | "project")[];
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
/** @description Public deployment identifier (e.g. "@namespace/project-slug@{hash|version|latest}") */
deploymentIdentifier: components["schemas"]["DeploymentIdentifier"];
};
header?: never;
@ -1736,7 +1739,10 @@ export interface operations {
requestBody: {
content: {
"application/json": {
/** @description Display name for the project. Max length 1024 characters. */
name: string;
/** @description Unique project slug. Must be ascii-only, lower-case, and kebab-case with no spaces between 1 and 256 characters. If not provided, it will be derived by slugifying `name`. */
slug?: string;
};
};
};
@ -1759,7 +1765,7 @@ export interface operations {
parameters: {
query: {
populate?: ("user" | "team" | "lastPublishedDeployment" | "lastDeployment") | ("user" | "team" | "lastPublishedDeployment" | "lastDeployment")[];
/** @description Public project identifier (e.g. "@namespace/project-name") */
/** @description Public project identifier (e.g. "@namespace/project-slug") */
projectIdentifier: components["schemas"]["ProjectIdentifier"];
};
header?: never;
@ -1848,7 +1854,7 @@ export interface operations {
getConsumerByProjectIdentifier: {
parameters: {
query: {
/** @description Public project identifier (e.g. "@namespace/project-name") */
/** @description Public project identifier (e.g. "@namespace/project-slug") */
projectIdentifier: components["schemas"]["ProjectIdentifier"];
populate?: ("user" | "project" | "deployment") | ("user" | "project" | "deployment")[];
};
@ -2171,7 +2177,7 @@ export interface operations {
parameters: {
query: {
populate?: ("user" | "team" | "project") | ("user" | "team" | "project")[];
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
/** @description Public deployment identifier (e.g. "@namespace/project-slug@{hash|version|latest}") */
deploymentIdentifier: components["schemas"]["DeploymentIdentifier"];
};
header?: never;
@ -2266,9 +2272,9 @@ export interface operations {
sort?: "asc" | "desc";
sortBy?: "createdAt" | "updatedAt";
populate?: ("user" | "team" | "project") | ("user" | "team" | "project")[];
/** @description Public project identifier (e.g. "@namespace/project-name") */
/** @description Public project identifier (e.g. "@namespace/project-slug") */
projectIdentifier?: components["schemas"]["ProjectIdentifier"];
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
/** @description Public deployment identifier (e.g. "@namespace/project-slug@{hash|version|latest}") */
deploymentIdentifier?: components["schemas"]["DeploymentIdentifier"];
};
header?: never;
@ -2303,8 +2309,10 @@ export interface operations {
requestBody: {
content: {
"application/json": {
/** @description Name of the project. */
/** @description Display name for the project. Max length 1024 characters. */
name: string;
/** @description Unique project slug. Must be ascii-only, lower-case, and kebab-case with no spaces between 1 and 256 characters. If not provided, it will be derived by slugifying `name`. */
slug?: string;
/** @description Optional semantic version of the project as a semver string. Ex: 1.0.0, 0.0.1, 5.0.1, etc. */
version?: string;
/** @description A short description of the project. */
@ -2474,7 +2482,7 @@ export interface operations {
parameters: {
query: {
populate?: ("user" | "team" | "project") | ("user" | "team" | "project")[];
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
/** @description Public deployment identifier (e.g. "@namespace/project-slug@{hash|version|latest}") */
deploymentIdentifier: components["schemas"]["DeploymentIdentifier"];
};
header?: never;

Wyświetl plik

@ -202,9 +202,12 @@ export const pricingPlanMeteredLineItemSchema =
/**
* Defines if the tiering price should be `graduated` or `volume` based.
*
* In `volume`-based tiering, the maximum quantity within a period
* determines the per unit price, in `graduated` tiering pricing can
* successively change as the quantity grows.
* determines the per unit price.
*
* In `graduated`-based tiering, the per-unit price changes successively
* as the quantity grows.
*
* This field requires `billingScheme` to be set to `tiered`.
*/
@ -466,10 +469,11 @@ export type PricingPlanLineItem =
export const pricingPlanSchema = z
.object({
/**
* Human-readable name for the pricing plan.
* Display name for the pricing plan.
*
* Used in UI and billing invoices.
*
* @required
* @example "Free"
* @example "Starter Monthly"
* @example "Pro Annual"
@ -493,6 +497,7 @@ export const pricingPlanSchema = z
* as a suffix so pricing plans can be uniquely differentiated from each
* other across billing intervals.
*
* @required
* @example "free"
* @example "starter-monthly"
* @example "pro-annual"
@ -503,6 +508,7 @@ export const pricingPlanSchema = z
.describe(
'PricingPlan slug (eg, "free", "starter-monthly", "pro-annual", etc). Should be lower-cased and kebab-cased. Should be stable across deployments.'
)
// TODO: Make `slug` optional and derive it from `name` if not provided.
.openapi('slug', { example: 'starter-monthly' }),
/**

Wyświetl plik

@ -1,6 +1,6 @@
## Project Identifier
`@namespace/project-name`
`@namespace/project-slug`
## Deployment Identifier

Wyświetl plik

@ -5,8 +5,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 1`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -15,8 +15,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 2`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -25,8 +25,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 3`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -35,8 +35,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 4`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -45,8 +45,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 5`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -55,8 +55,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 6`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -65,8 +65,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 7`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -75,8 +75,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 8`] = `
"deploymentIdentifier": "@username/foo-bar@dev",
"deploymentVersion": "dev",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -85,8 +85,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 9`] = `
"deploymentIdentifier": "@username/foo-bar@1.0.0",
"deploymentVersion": "1.0.0",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -95,8 +95,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 10`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -105,8 +105,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 11`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -116,8 +116,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 12`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -126,8 +126,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 13`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -136,8 +136,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 14`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -147,8 +147,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 15`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -158,8 +158,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 16`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -169,8 +169,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 17`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -180,8 +180,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 18`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -191,8 +191,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 19`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -202,8 +202,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 20`] = `
"deploymentIdentifier": "@username/foo-bar@dev",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -213,8 +213,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 21`] = `
"deploymentIdentifier": "@username/foo-bar@1.0.0",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -224,8 +224,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 22`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -235,8 +235,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 23`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -246,8 +246,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 24`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -257,8 +257,8 @@ exports[`parseDeploymentIdentifier > non-strict mode valid 25`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -268,8 +268,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 1`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -278,8 +278,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 2`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -288,8 +288,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 3`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -298,8 +298,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 4`] = `
"deploymentIdentifier": "@username/foo-bar@dev",
"deploymentVersion": "dev",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -308,8 +308,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 5`] = `
"deploymentIdentifier": "@username/foo-bar@1.0.0",
"deploymentVersion": "1.0.0",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -318,8 +318,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 6`] = `
"deploymentHash": "abc123lz",
"deploymentIdentifier": "@username/foo-bar@abc123lz",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -328,8 +328,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 7`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foobar123-yo@01234567",
"projectIdentifier": "@username/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "username",
"projectSlug": "foobar123-yo",
}
`;
@ -338,8 +338,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 8`] = `
"deploymentIdentifier": "@u/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@u/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "u",
"projectSlug": "foo-bar",
}
`;
@ -348,8 +348,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 9`] = `
"deploymentIdentifier": "@a/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@a/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "a",
"projectSlug": "foo-bar",
}
`;
@ -358,8 +358,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 10`] = `
"deploymentIdentifier": "@foo/foobar123-yo@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@foo/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "foo",
"projectSlug": "foobar123-yo",
}
`;
@ -368,8 +368,8 @@ exports[`parseDeploymentIdentifier > strict mode valid 11`] = `
"deploymentIdentifier": "@foo/foobar123-yo@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@foo/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "foo",
"projectSlug": "foobar123-yo",
}
`;
@ -378,7 +378,7 @@ exports[`parseDeploymentIdentifier > strict mode valid 12`] = `
"deploymentIdentifier": "@foo/bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@foo/bar",
"projectName": "bar",
"projectNamespace": "foo",
"projectSlug": "bar",
}
`;

Wyświetl plik

@ -5,8 +5,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 1`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -15,8 +15,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 2`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -25,8 +25,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 3`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -35,8 +35,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 4`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -45,8 +45,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 5`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -55,8 +55,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 6`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -65,8 +65,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 7`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -75,8 +75,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 8`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -85,8 +85,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 9`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -95,8 +95,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 10`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
@ -105,8 +105,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 11`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -116,8 +116,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 12`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -127,8 +127,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 13`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -138,8 +138,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 14`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -149,8 +149,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 15`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -160,8 +160,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 16`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -171,8 +171,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 17`] = `
"deploymentIdentifier": "@username/foo-bar@dev",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -182,8 +182,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 18`] = `
"deploymentIdentifier": "@username/foo-bar@1.0.0",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -193,8 +193,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 19`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -204,8 +204,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 20`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -215,8 +215,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 21`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -226,8 +226,8 @@ exports[`parseProjectIdentifier > non-strict mode valid 22`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -235,55 +235,55 @@ exports[`parseProjectIdentifier > non-strict mode valid 22`] = `
exports[`parseProjectIdentifier > strict mode valid 1`] = `
{
"projectIdentifier": "@username/foo",
"projectName": "foo",
"projectNamespace": "username",
"projectSlug": "foo",
}
`;
exports[`parseProjectIdentifier > strict mode valid 2`] = `
{
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
}
`;
exports[`parseProjectIdentifier > strict mode valid 3`] = `
{
"projectIdentifier": "@username/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "username",
"projectSlug": "foobar123-yo",
}
`;
exports[`parseProjectIdentifier > strict mode valid 4`] = `
{
"projectIdentifier": "@u/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "u",
"projectSlug": "foo-bar",
}
`;
exports[`parseProjectIdentifier > strict mode valid 5`] = `
{
"projectIdentifier": "@a/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "a",
"projectSlug": "foo-bar",
}
`;
exports[`parseProjectIdentifier > strict mode valid 6`] = `
{
"projectIdentifier": "@foo/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "foo",
"projectSlug": "foobar123-yo",
}
`;
exports[`parseProjectIdentifier > strict mode valid 7`] = `
{
"projectIdentifier": "@foo/bar",
"projectName": "bar",
"projectNamespace": "foo",
"projectSlug": "bar",
}
`;

Wyświetl plik

@ -5,8 +5,8 @@ exports[`parseToolIdentifier > non-strict mode valid 1`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -16,8 +16,8 @@ exports[`parseToolIdentifier > non-strict mode valid 2`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -27,8 +27,8 @@ exports[`parseToolIdentifier > non-strict mode valid 3`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -38,8 +38,8 @@ exports[`parseToolIdentifier > non-strict mode valid 4`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -49,8 +49,8 @@ exports[`parseToolIdentifier > non-strict mode valid 5`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -60,8 +60,8 @@ exports[`parseToolIdentifier > non-strict mode valid 6`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -71,8 +71,8 @@ exports[`parseToolIdentifier > non-strict mode valid 7`] = `
"deploymentIdentifier": "@username/foo-bar@dev",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -82,8 +82,8 @@ exports[`parseToolIdentifier > non-strict mode valid 8`] = `
"deploymentIdentifier": "@username/foo-bar@1.0.0",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -93,8 +93,8 @@ exports[`parseToolIdentifier > non-strict mode valid 9`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -104,8 +104,8 @@ exports[`parseToolIdentifier > non-strict mode valid 10`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -115,8 +115,8 @@ exports[`parseToolIdentifier > non-strict mode valid 11`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -126,8 +126,8 @@ exports[`parseToolIdentifier > non-strict mode valid 12`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -137,8 +137,8 @@ exports[`parseToolIdentifier > strict mode valid 1`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -148,8 +148,8 @@ exports[`parseToolIdentifier > strict mode valid 2`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foo-bar@01234567",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -159,8 +159,8 @@ exports[`parseToolIdentifier > strict mode valid 3`] = `
"deploymentHash": "abc123lz",
"deploymentIdentifier": "@username/foo-bar@abc123lz",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -170,8 +170,8 @@ exports[`parseToolIdentifier > strict mode valid 4`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -181,8 +181,8 @@ exports[`parseToolIdentifier > strict mode valid 5`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foobar123-yo@01234567",
"projectIdentifier": "@username/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "username",
"projectSlug": "foobar123-yo",
"toolName": "foo_bar_BAR_901",
}
`;
@ -192,8 +192,8 @@ exports[`parseToolIdentifier > strict mode valid 6`] = `
"deploymentHash": "01234567",
"deploymentIdentifier": "@username/foobar@01234567",
"projectIdentifier": "@username/foobar",
"projectName": "foobar",
"projectNamespace": "username",
"projectSlug": "foobar",
"toolName": "get_weather01",
}
`;
@ -203,8 +203,8 @@ exports[`parseToolIdentifier > strict mode valid 7`] = `
"deploymentIdentifier": "@username/foobar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foobar",
"projectName": "foobar",
"projectNamespace": "username",
"projectSlug": "foobar",
"toolName": "foo",
}
`;
@ -214,8 +214,8 @@ exports[`parseToolIdentifier > strict mode valid 8`] = `
"deploymentIdentifier": "@username/foobar@dev",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foobar",
"projectName": "foobar",
"projectNamespace": "username",
"projectSlug": "foobar",
"toolName": "foo",
}
`;
@ -225,8 +225,8 @@ exports[`parseToolIdentifier > strict mode valid 9`] = `
"deploymentIdentifier": "@username/foobar@1.0.0",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foobar",
"projectName": "foobar",
"projectNamespace": "username",
"projectSlug": "foobar",
"toolName": "foo",
}
`;
@ -236,8 +236,8 @@ exports[`parseToolIdentifier > strict mode valid 10`] = `
"deploymentIdentifier": "@username/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -247,8 +247,8 @@ exports[`parseToolIdentifier > strict mode valid 11`] = `
"deploymentIdentifier": "@username/foo-bar@dev",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -258,8 +258,8 @@ exports[`parseToolIdentifier > strict mode valid 12`] = `
"deploymentIdentifier": "@username/foo-bar@1.0.0",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "username",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -269,8 +269,8 @@ exports[`parseToolIdentifier > strict mode valid 13`] = `
"deploymentIdentifier": "@username/foobar123-yo@0.0.1",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "username",
"projectSlug": "foobar123-yo",
"toolName": "foo_bar_BAR_901",
}
`;
@ -280,8 +280,8 @@ exports[`parseToolIdentifier > strict mode valid 14`] = `
"deploymentIdentifier": "@username/foobar123-yo@0.0.1",
"deploymentVersion": "latest",
"projectIdentifier": "@username/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "username",
"projectSlug": "foobar123-yo",
"toolName": "foo",
}
`;
@ -291,8 +291,8 @@ exports[`parseToolIdentifier > strict mode valid 15`] = `
"deploymentIdentifier": "@u/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@u/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "u",
"projectSlug": "foo-bar",
"toolName": "foo",
}
`;
@ -302,8 +302,8 @@ exports[`parseToolIdentifier > strict mode valid 16`] = `
"deploymentIdentifier": "@a/foo-bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@a/foo-bar",
"projectName": "foo-bar",
"projectNamespace": "a",
"projectSlug": "foo-bar",
"toolName": "foo_123",
}
`;
@ -313,8 +313,8 @@ exports[`parseToolIdentifier > strict mode valid 17`] = `
"deploymentIdentifier": "@foo/foobar123-yo@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@foo/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "foo",
"projectSlug": "foobar123-yo",
"toolName": "foo_bar_BAR_901",
}
`;
@ -324,8 +324,8 @@ exports[`parseToolIdentifier > strict mode valid 18`] = `
"deploymentIdentifier": "@foo/foobar123-yo@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@foo/foobar123-yo",
"projectName": "foobar123-yo",
"projectNamespace": "foo",
"projectSlug": "foobar123-yo",
"toolName": "foo",
}
`;
@ -335,8 +335,8 @@ exports[`parseToolIdentifier > strict mode valid 19`] = `
"deploymentIdentifier": "@foo/bar@latest",
"deploymentVersion": "latest",
"projectIdentifier": "@foo/bar",
"projectName": "bar",
"projectNamespace": "foo",
"projectSlug": "bar",
"toolName": "baz",
}
`;

Wyświetl plik

@ -35,7 +35,7 @@ export const namespaceBlacklist = new Set([
'public',
'private',
'404',
'500',
'429',
'403',
'401',
'400',
@ -43,6 +43,7 @@ export const namespaceBlacklist = new Set([
'408',
'407',
'406',
'500',
// bad words
'fuck',

Wyświetl plik

@ -6,7 +6,7 @@ import {
isValidDeploymentIdentifier,
isValidNamespace,
isValidProjectIdentifier,
isValidProjectName
isValidProjectSlug
} from './validators'
function success(...args: Parameters<typeof parseDeploymentIdentifier>) {
@ -14,11 +14,11 @@ function success(...args: Parameters<typeof parseDeploymentIdentifier>) {
expect(result).toBeTruthy()
expect(result!.projectIdentifier).toBeTruthy()
expect(result!.projectNamespace).toBeTruthy()
expect(result!.projectName).toBeTruthy()
expect(result!.projectSlug).toBeTruthy()
expect(result!.deploymentIdentifier).toBeTruthy()
expect(result!.deploymentVersion || result!.deploymentHash).toBeTruthy()
expect(isValidProjectIdentifier(result!.projectIdentifier)).toBe(true)
expect(isValidProjectName(result!.projectName)).toBe(true)
expect(isValidProjectSlug(result!.projectSlug)).toBe(true)
expect(isValidNamespace(result!.projectNamespace)).toBe(true)
expect(isValidDeploymentIdentifier(result!.deploymentIdentifier)).toBe(true)

Wyświetl plik

@ -50,7 +50,7 @@ export function parseDeploymentIdentifier(
return {
projectIdentifier: `@${iMatch[1]!}/${iMatch[2]!}`,
projectNamespace: iMatch[1]!,
projectName: iMatch[2]!,
projectSlug: iMatch[2]!,
deploymentIdentifier: `@${iMatch[1]!}/${iMatch[2]!}@latest`,
deploymentVersion: 'latest'
}
@ -62,7 +62,7 @@ export function parseDeploymentIdentifier(
return {
projectIdentifier: `@${hMatch[1]!}/${hMatch[2]!}`,
projectNamespace: hMatch[1]!,
projectName: hMatch[2]!,
projectSlug: hMatch[2]!,
deploymentIdentifier: `@${hMatch[1]!}/${hMatch[2]!}@${hMatch[3]!}`,
deploymentHash: hMatch[3]!
}
@ -74,7 +74,7 @@ export function parseDeploymentIdentifier(
return {
projectIdentifier: `@${vMatch[1]!}/${vMatch[2]!}`,
projectNamespace: vMatch[1]!,
projectName: vMatch[2]!,
projectSlug: vMatch[2]!,
deploymentIdentifier: `@${vMatch[1]!}/${vMatch[2]!}@${vMatch[3]!}`,
deploymentVersion: vMatch[3]!
}

Wyświetl plik

@ -4,7 +4,7 @@ import { parseProjectIdentifier } from './parse-project-identifier'
import {
isValidNamespace,
isValidProjectIdentifier,
isValidProjectName
isValidProjectSlug
} from './validators'
function success(...args: Parameters<typeof parseProjectIdentifier>) {
@ -12,9 +12,9 @@ function success(...args: Parameters<typeof parseProjectIdentifier>) {
expect(result).toBeTruthy()
expect(result!.projectIdentifier).toBeTruthy()
expect(result!.projectNamespace).toBeTruthy()
expect(result!.projectName).toBeTruthy()
expect(result!.projectSlug).toBeTruthy()
expect(isValidProjectIdentifier(result!.projectIdentifier)).toBe(true)
expect(isValidProjectName(result!.projectName)).toBe(true)
expect(isValidProjectSlug(result!.projectSlug)).toBe(true)
expect(isValidNamespace(result!.projectNamespace)).toBe(true)
expect(result).toMatchSnapshot()
}

Wyświetl plik

@ -40,7 +40,7 @@ export function parseProjectIdentifier(
return {
projectIdentifier: `@${match[1]!}/${match[2]!}`,
projectNamespace: match[1]!,
projectName: match[2]!
projectSlug: match[2]!
}
}

Wyświetl plik

@ -6,7 +6,7 @@ import {
isValidDeploymentIdentifier,
isValidNamespace,
isValidProjectIdentifier,
isValidProjectName,
isValidProjectSlug,
isValidToolName
} from './validators'
@ -15,11 +15,11 @@ function success(...args: Parameters<typeof parseToolIdentifier>) {
expect(result).toBeTruthy()
expect(result!.projectIdentifier).toBeTruthy()
expect(result!.projectNamespace).toBeTruthy()
expect(result!.projectName).toBeTruthy()
expect(result!.projectSlug).toBeTruthy()
expect(result!.deploymentIdentifier).toBeTruthy()
expect(result!.deploymentVersion || result!.deploymentHash).toBeTruthy()
expect(isValidProjectIdentifier(result!.projectIdentifier)).toBe(true)
expect(isValidProjectName(result!.projectName)).toBe(true)
expect(isValidProjectSlug(result!.projectSlug)).toBe(true)
expect(isValidNamespace(result!.projectNamespace)).toBe(true)
expect(isValidDeploymentIdentifier(result!.deploymentIdentifier)).toBe(true)
expect(isValidToolName(result!.toolName)).toBe(true)

Wyświetl plik

@ -35,7 +35,7 @@ export function parseToolIdentifier(
return {
projectIdentifier: `@${iMatch[1]!}/${iMatch[2]!}`,
projectNamespace: iMatch[1]!,
projectName: iMatch[2]!,
projectSlug: iMatch[2]!,
deploymentIdentifier: `@${iMatch[1]!}/${iMatch[2]!}@latest`,
deploymentVersion: 'latest',
toolName: iMatch[3]!
@ -48,7 +48,7 @@ export function parseToolIdentifier(
return {
projectIdentifier: `@${hMatch[1]!}/${hMatch[2]!}`,
projectNamespace: hMatch[1]!,
projectName: hMatch[2]!,
projectSlug: hMatch[2]!,
deploymentIdentifier: `@${hMatch[1]!}/${hMatch[2]!}@${hMatch[3]!}`,
deploymentHash: hMatch[3]!,
toolName: hMatch[4]!
@ -61,7 +61,7 @@ export function parseToolIdentifier(
return {
projectIdentifier: `@${vMatch[1]!}/${vMatch[2]!}`,
projectNamespace: vMatch[1]!,
projectName: vMatch[2]!,
projectSlug: vMatch[2]!,
deploymentIdentifier: `@${vMatch[1]!}/${vMatch[2]!}@${vMatch[3]!}`,
deploymentVersion: 'latest',
toolName: vMatch[4]!

Wyświetl plik

@ -8,7 +8,7 @@ export type ParseIdentifierOptions = {
export type ParsedProjectIdentifier = {
projectIdentifier: string
projectNamespace: string
projectName: string
projectSlug: string
}
export type ParsedDeploymentIdentifier = Simplify<

Wyświetl plik

@ -8,7 +8,7 @@ import {
isValidEmail,
isValidPassword,
isValidProjectIdentifier,
isValidProjectName,
isValidProjectSlug,
isValidToolName,
isValidUsername
} from './validators'
@ -63,23 +63,23 @@ test('isValidPassword failure', () => {
expect(isValidPassword('a'.repeat(1025))).toBe(false)
})
test('isValidProjectName success', () => {
expect(isValidProjectName('a')).toBe(true)
expect(isValidProjectName('ai')).toBe(true)
expect(isValidProjectName('aaa')).toBe(true)
expect(isValidProjectName('hello-world')).toBe(true)
expect(isValidProjectName('123-abc')).toBe(true)
expect(isValidProjectName('f'.repeat(256))).toBe(true)
test('isValidProjectSlug success', () => {
expect(isValidProjectSlug('a')).toBe(true)
expect(isValidProjectSlug('ai')).toBe(true)
expect(isValidProjectSlug('aaa')).toBe(true)
expect(isValidProjectSlug('hello-world')).toBe(true)
expect(isValidProjectSlug('123-abc')).toBe(true)
expect(isValidProjectSlug('f'.repeat(256))).toBe(true)
})
test('isValidProjectName failure', () => {
expect(isValidProjectName('hello_world')).toBe(false)
expect(isValidProjectName('a_bc')).toBe(false)
expect(isValidProjectName('abc.')).toBe(false)
expect(isValidProjectName('abc_123')).toBe(false)
expect(isValidProjectName('ah^23')).toBe(false)
expect(isValidProjectName('Hello-World')).toBe(false)
expect(isValidProjectName('f'.repeat(257))).toBe(false)
test('isValidProjectSlug failure', () => {
expect(isValidProjectSlug('hello_world')).toBe(false)
expect(isValidProjectSlug('a_bc')).toBe(false)
expect(isValidProjectSlug('abc.')).toBe(false)
expect(isValidProjectSlug('abc_123')).toBe(false)
expect(isValidProjectSlug('ah^23')).toBe(false)
expect(isValidProjectSlug('Hello-World')).toBe(false)
expect(isValidProjectSlug('f'.repeat(257))).toBe(false)
})
test('isValidDeploymentHash success', () => {
@ -96,7 +96,7 @@ test('isValidDeploymentHash failure', () => {
})
test('isValidProjectIdentifier success', () => {
expect(isValidProjectIdentifier('@username/project-name')).toBe(true)
expect(isValidProjectIdentifier('@username/project-slug')).toBe(true)
expect(isValidProjectIdentifier('@a/123')).toBe(true)
})
@ -114,20 +114,20 @@ test('isValidProjectIdentifier failure', () => {
expect(isValidProjectIdentifier('@abc/1.23')).toBe(false)
expect(isValidProjectIdentifier('@012345678/123@latest')).toBe(false)
expect(isValidProjectIdentifier('@foo@dev')).toBe(false)
expect(isValidProjectIdentifier('@username/Project-Name')).toBe(false)
expect(isValidProjectIdentifier('@username/Project-Slug')).toBe(false)
expect(isValidProjectIdentifier('@_/___')).toBe(false)
})
test('isValidDeploymentIdentifier success', () => {
expect(isValidDeploymentIdentifier('@username/project-name@01234567')).toBe(
expect(isValidDeploymentIdentifier('@username/project-slug@01234567')).toBe(
true
)
expect(isValidDeploymentIdentifier('@username/project-name@latest')).toBe(
expect(isValidDeploymentIdentifier('@username/project-slug@latest')).toBe(
true
)
expect(isValidDeploymentIdentifier('@username/project-name@dev')).toBe(true)
expect(isValidDeploymentIdentifier('@username/project-name@0.0.1')).toBe(true)
expect(isValidDeploymentIdentifier('@username/project-name')).toBe(true)
expect(isValidDeploymentIdentifier('@username/project-slug@dev')).toBe(true)
expect(isValidDeploymentIdentifier('@username/project-slug@0.0.1')).toBe(true)
expect(isValidDeploymentIdentifier('@username/project-slug')).toBe(true)
expect(isValidDeploymentIdentifier('@a/123@01234567')).toBe(true)
expect(isValidDeploymentIdentifier('@a/123@0.1.0')).toBe(true)
expect(isValidDeploymentIdentifier('@a/123@latest')).toBe(true)

Wyświetl plik

@ -10,7 +10,7 @@ import { toolNameBlacklist } from './tool-name-blacklist'
export const namespaceRe = /^[a-z0-9-]{1,256}$/
export const passwordRe = /^.{3,1024}$/
export const projectNameRe = /^[a-z0-9-]{1,256}$/
export const projectSlugRe = /^[a-z0-9-]{1,256}$/
export const deploymentHashRe = /^[a-z0-9]{8}$/
export const toolNameRe = /^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/
@ -39,8 +39,8 @@ export function isValidPassword(value?: string): boolean {
return !!value && passwordRe.test(value)
}
export function isValidProjectName(value?: string): boolean {
return !!value && projectNameRe.test(value)
export function isValidProjectSlug(value?: string): boolean {
return !!value && projectSlugRe.test(value)
}
export function isValidDeploymentHash(value?: string): boolean {

Wyświetl plik

@ -6,9 +6,63 @@ settings:
catalogs:
default:
'@agentic/core':
specifier: ^7.6.7
version: 7.6.7
'@agentic/serper':
specifier: ^7.6.7
version: 7.6.7
'@apideck/better-ajv-errors':
specifier: ^0.3.6
version: 0.3.6
'@clack/prompts':
specifier: 0.11.0
version: 0.11.0
'@cloudflare/workers-types':
specifier: ^4.20250620.0
version: 4.20250620.0
'@commander-js/extra-typings':
specifier: ^14.0.0
version: 14.0.0
'@dotenvx/dotenvx':
specifier: ^1.45.1
version: 1.45.1
'@edge-runtime/vm':
specifier: ^5.0.0
version: 5.0.0
'@fisch0920/config':
specifier: ^1.1.3
version: 1.1.4
'@fisch0920/drizzle-orm':
specifier: ^0.43.7
version: 0.43.7
'@fisch0920/drizzle-zod':
specifier: ^0.7.9
version: 0.7.9
'@hono/mcp':
specifier: ^0.1.0
version: 0.1.0
'@hono/node-server':
specifier: 1.14.4
version: 1.14.4
'@hono/sentry':
specifier: ^1.2.2
version: 1.2.2
'@hono/zod-openapi':
specifier: ^0.19.8
version: 0.19.8
'@hono/zod-validator':
specifier: ^0.7.0
version: 0.7.0
'@modelcontextprotocol/sdk':
specifier: ^1.13.0
version: 1.13.0
'@number-flow/react':
specifier: ^0.5.10
version: 0.5.10
'@paralleldrive/cuid2':
specifier: ^2.2.2
version: 2.2.2
'@pmndrs/assets':
specifier: ^1.7.0
version: 1.7.0
@ -27,6 +81,9 @@ catalogs:
'@radix-ui/react-tooltip':
specifier: ^1.2.7
version: 1.2.7
'@react-email/components':
specifier: ^0.1.0
version: 0.1.0
'@react-three/cannon':
specifier: ^6.6.0
version: 6.6.0
@ -42,6 +99,24 @@ catalogs:
'@react-three/rapier':
specifier: ^2.1.0
version: 2.1.0
'@redocly/openapi-core':
specifier: ^1.34.3
version: 1.34.3
'@sentry/cli':
specifier: ^2.46.0
version: 2.46.0
'@sentry/cloudflare':
specifier: ^9.30.0
version: 9.30.0
'@sentry/core':
specifier: ^9.30.0
version: 9.30.0
'@sentry/node':
specifier: ^9.30.0
version: 9.30.0
'@standard-schema/spec':
specifier: ^1.0.0
version: 1.0.0
'@tailwindcss/postcss':
specifier: ^4.1.10
version: 4.1.10
@ -60,18 +135,45 @@ catalogs:
'@types/canvas-confetti':
specifier: ^1.9.0
version: 1.9.0
'@types/ms':
specifier: ^2.1.0
version: 2.1.0
'@types/node':
specifier: ^24.0.4
version: 24.0.4
'@types/react':
specifier: ^19.1.8
version: 19.1.8
'@types/react-dom':
specifier: ^19.1.6
version: 19.1.6
'@types/semver':
specifier: ^7.7.0
version: 7.7.0
'@types/three':
specifier: ^0.177.0
version: 0.177.0
agents:
specifier: ^0.0.95
version: 0.0.95
ajv:
specifier: ^8.17.1
version: 8.17.1
ajv-formats:
specifier: ^3.0.1
version: 3.0.1
autoprefixer:
specifier: ^10.4.21
version: 10.4.21
bcryptjs:
specifier: ^3.0.2
version: 3.0.2
bumpp:
specifier: ^10.2.0
version: 10.2.0
camelcase:
specifier: ^8.0.0
version: 8.0.0
canvas-confetti:
specifier: ^1.9.3
version: 1.9.3
@ -81,36 +183,144 @@ catalogs:
clsx:
specifier: ^2.1.1
version: 2.1.1
commander:
specifier: ^14.0.0
version: 14.0.0
conf:
specifier: ^14.0.0
version: 14.0.0
decamelize:
specifier: ^6.0.0
version: 6.0.0
decircular:
specifier: ^1.0.0
version: 1.0.0
del-cli:
specifier: ^6.0.0
version: 6.0.0
dotenv:
specifier: ^16.5.0
version: 16.5.0
drizzle-kit:
specifier: ^0.31.1
version: 0.31.1
drizzle-orm:
specifier: ^0.44.2
version: 0.44.2
email-validator:
specifier: ^2.0.4
version: 2.0.4
eslint:
specifier: ^9.29.0
version: 9.29.0
eslint-plugin-drizzle:
specifier: ^0.2.3
version: 0.2.3
eventid:
specifier: ^2.0.1
version: 2.0.1
exit-hook:
specifier: 4.0.0
version: 4.0.0
fast-content-type-parse:
specifier: ^3.0.0
version: 3.0.0
fast-uri:
specifier: ^3.0.6
version: 3.0.6
fastmcp:
specifier: ^3.4.0
version: 3.4.0
get-port:
specifier: ^7.1.0
version: 7.1.0
hast-util-to-jsx-runtime:
specifier: ^2.3.6
version: 2.3.6
hono:
specifier: 4.8.1
version: 4.8.1
is-obj:
specifier: ^3.0.0
version: 3.0.0
knip:
specifier: ^5.61.2
version: 5.61.2
ky:
specifier: 1.8.1
version: 1.8.1
lint-staged:
specifier: ^16.1.2
version: 16.1.2
lucide-react:
specifier: ^0.518.0
version: 0.518.0
motion:
specifier: ^12.18.1
version: 12.18.1
ms:
specifier: ^2.1.3
version: 2.1.3
next:
specifier: ^15.3.4
version: 15.3.4
next-themes:
specifier: ^0.4.6
version: 0.4.6
npm-run-all2:
specifier: ^8.0.4
version: 8.0.4
octokit:
specifier: ^5.0.3
version: 5.0.3
only-allow:
specifier: ^1.2.1
version: 1.2.1
open:
specifier: ^10.1.2
version: 10.1.2
openapi-typescript:
specifier: ^7.8.0
version: 7.8.0
ora:
specifier: ^8.2.0
version: 8.2.0
p-all:
specifier: ^5.0.0
version: 5.0.0
p-map:
specifier: 7.0.3
version: 7.0.3
p-times:
specifier: ^4.0.0
version: 4.0.0
parse-json:
specifier: ^8.3.0
version: 8.3.0
plur:
specifier: ^5.1.0
version: 5.1.0
postcss:
specifier: ^8.5.6
version: 8.5.6
postgres:
specifier: ^3.4.7
version: 3.4.7
posthog-js:
specifier: ^1.255.0
version: 1.255.0
prettier:
specifier: ^3.6.0
version: 3.6.0
react:
specifier: ^19.1.0
version: 19.1.0
react-dom:
specifier: ^19.1.0
version: 19.1.0
react-email:
specifier: ^4.0.16
version: 4.0.16
react-infinite-scroll-hook:
specifier: ^6.0.1
version: 6.0.1
@ -120,15 +330,30 @@ catalogs:
react-use:
specifier: ^17.6.0
version: 17.6.0
resend:
specifier: ^4.6.0
version: 4.6.0
restore-cursor:
specifier: ^5.1.0
version: 5.1.0
semver:
specifier: ^7.7.2
version: 7.7.2
server-only:
specifier: ^0.0.1
version: 0.0.1
shiki:
specifier: ^3.7.0
version: 3.7.0
simple-git-hooks:
specifier: ^2.13.0
version: 2.13.0
sonner:
specifier: ^2.0.5
version: 2.0.5
sort-keys:
specifier: ^5.1.0
version: 5.1.0
stripe:
specifier: ^18.2.1
version: 18.2.1
@ -144,12 +369,45 @@ catalogs:
three:
specifier: ^0.177.0
version: 0.177.0
tsup:
specifier: ^8.5.0
version: 8.5.0
tsx:
specifier: ^4.20.3
version: 4.20.3
turbo:
specifier: ^2.5.4
version: 2.5.4
tw-animate-css:
specifier: ^1.3.4
version: 1.3.4
type-fest:
specifier: ^4.41.0
version: 4.41.0
typescript:
specifier: ^5.8.3
version: 5.8.3
unconfig:
specifier: ^7.3.2
version: 7.3.2
vite-tsconfig-paths:
specifier: ^5.1.4
version: 5.1.4
vitest:
specifier: ^3.2.4
version: 3.2.4
wrangler:
specifier: ^4.21.0
version: 4.21.0
zod:
specifier: ^3.25.67
version: 3.25.67
zod-to-json-schema:
specifier: ^3.24.5
version: 3.24.5
zod-validation-error:
specifier: ^3.5.2
version: 3.5.2
importers:
@ -236,6 +494,12 @@ importers:
'@agentic/platform-validators':
specifier: workspace:*
version: link:../../packages/validators
'@dicebear/collection':
specifier: ^9.2.3
version: 9.2.3(@dicebear/core@9.2.3)
'@dicebear/core':
specifier: ^9.2.3
version: 9.2.3
'@fisch0920/drizzle-orm':
specifier: 'catalog:'
version: 0.43.7(@cloudflare/workers-types@4.20250620.0)(@neondatabase/serverless@1.0.1)(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(kysely@0.28.2)(postgres@3.4.7)
@ -692,6 +956,9 @@ importers:
packages/core:
dependencies:
'@sindresorhus/slugify':
specifier: ^2.2.1
version: 2.2.1
decircular:
specifier: 'catalog:'
version: 1.0.0
@ -925,6 +1192,9 @@ importers:
packages/types:
dependencies:
'@agentic/platform-core':
specifier: workspace:*
version: link:../core
'@agentic/platform-validators':
specifier: workspace:*
version: link:../validators
@ -1127,6 +1397,196 @@ packages:
'@date-fns/utc@2.1.0':
resolution: {integrity: sha512-176grgAgU2U303rD2/vcOmNg0kGPbhzckuH1TEP2al7n0AQipZIy9P15usd2TKQCG1g+E1jX/ZVQSzs4sUDwgA==}
'@dicebear/adventurer-neutral@9.2.3':
resolution: {integrity: sha512-yjsflrlGIZolEJDcIhdh5l8R6QoyZ0Fc5ZaRS95Na15GeCA0bcq92fDpyb/87F8QRYR4hcn8wYim+MZKyDnm3A==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/adventurer@9.2.3':
resolution: {integrity: sha512-kF97966JCLbLFkavLKLplhubC4k8G19e1V3vtq+XWKKSBNNLMc0yhiEXnFjS6eVI4rnQ6dUpTff4gUmpREmEnQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/avataaars-neutral@9.2.3':
resolution: {integrity: sha512-v9Ga01GVKGchqNBc4Z2Gk5Y4P0c/jzNg6l/r4kX0xCMDXNd/vchi6QI464pHnJpDC/I8BzL1wYbpZrUEmTWJmA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/avataaars@9.2.3':
resolution: {integrity: sha512-Jh6mGKMA99KCF+S5rnS+QIlrApCy7NJI6SwmCzixJQmlX0GbWrgBuRxPEy2XJo4FWKGI9eFKOQ4QtNFEwGKjWQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/big-ears-neutral@9.2.3':
resolution: {integrity: sha512-y4T8ukm+A/ZXBnwyx3CFZxxJlzoTGJ1xmJL2j4/6zXxjlzl3wkc2mZX36t16i6NKiBs9LJwOUNx6IezbmYjDjg==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/big-ears@9.2.3':
resolution: {integrity: sha512-YTZ3QIWlG6HlkDyASAaQoetxYtQgOwq4GTJxDpzzawFbhhtMJabqAU7dzWkPY6IgJfI/MAKVxdeqXK0Aiw4E6w==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/big-smile@9.2.3':
resolution: {integrity: sha512-/QvZlUmNIjnA6GN5VPUiD5g1MYr+qTOun3CfBSrPAav+tFo8RQGszM6ggvkmn4Q1aHwJ0XQNRiIvTJtQisuqKg==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/bottts-neutral@9.2.3':
resolution: {integrity: sha512-6wFfWwXHE3kJKP0DqgN/SmSBDPs/s8o46APst8RfHnmcDLEsQExg0WquGwXfP+3XqGjPhsm/LGaA/yXKlE/84w==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/bottts@9.2.3':
resolution: {integrity: sha512-udHSuK7uDYMFiCPZsHkaqCyo0hoJFMehsTSBtvOUOQqlQGYA2E7+gLgLmfvBQlYuk61lBM4yLyQdbGj0W7Nl1Q==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/collection@9.2.3':
resolution: {integrity: sha512-PWW1x6EnDKw66dtpy3+1/W/UTrxq9jOGaWgRj+PV6Y0Pvc2a7ZMi6tBzfGWpy0r+XdhREUQ3vyFqim+R/iE2Rg==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/core@9.2.3':
resolution: {integrity: sha512-rsWmQO/TxBtnYbQSOrOESmf/XD5TC30cwKw9LBT2+7Q9HwIf5qJKBJT25bmwvn3RPHVe4A6DkTVMtmsoSaErFg==}
engines: {node: '>=18.0.0'}
'@dicebear/croodles-neutral@9.2.3':
resolution: {integrity: sha512-peurufAge4ZbzqGVAyFxhZ64qKv+MLBuQK2XvXsXX0uHgtEeAgSjFl6+O0wgJ7KVKtHL56qY68Acdhy3U91BYw==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/croodles@9.2.3':
resolution: {integrity: sha512-dzFhchlmhst+PBMkNbLNVcOyNFWAhaFnxQOMwWluHPzg8ryiFt/LEKWB7bPKMue1jBwta6LfoUv7vDG4LpdXIw==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/dylan@9.2.3':
resolution: {integrity: sha512-gtRhE1jxKwgUE4d2N7KHJ/rSdAg8zxgViALygs8/kcs2y4uinNx5NW3OvJwNPMBAwHRqeM6GbLKycbfiYMKdwA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/fun-emoji@9.2.3':
resolution: {integrity: sha512-zR+SmA7hWT8FDkJsdvg5uI7fOabilZfheM8RnMkEXXA0NmKgNKuWX9yFjLxeWESbJwBZFJ/SKasKcZSJP88eyw==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/glass@9.2.3':
resolution: {integrity: sha512-ucaM6TrTt/JsDa26ZQbtxevN0JLu2S06Q2+M/kAT2f0OdR6hSNdPnj/hDIVWg/u4XgW9HXrJ4Lt2KG2nZGq1MA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/icons@9.2.3':
resolution: {integrity: sha512-2IaSmvgxzEvbtXHxhuxaCrBCtTG7HouxbInzPOetWz/YroTe5qj2k81uhl6ctbviO1PgGgkhIJ12nCIey6O/Tw==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/identicon@9.2.3':
resolution: {integrity: sha512-WCMYjOV19ocaJQDgD3E1z2FRgY4Zbnjieb2FSXPwW6zi04l52rhGaywk8YlCbaHilE43Iybyu1v6iDf4I71qKg==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/initials@9.2.3':
resolution: {integrity: sha512-Qz668xB/XHRNsxW3vpZ0q9xq/M6tscbv1FaFvAGbnFO2hzfqiCWSK1cfNrrqlPJbz7Pz5LIlL5xObLZ0UYhFRA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/lorelei-neutral@9.2.3':
resolution: {integrity: sha512-C0XcfvB1Td9y1jeaBSkuMrQTAv/RiupQ62cE25f18Mw9UuTC3TwnHR6Ms/4SAEhCZxE2xYHZccs3Lvgkn/b3dA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/lorelei@9.2.3':
resolution: {integrity: sha512-ribIq7I669JyUSZ0s8jDx5N2NqQUhGSoFGK5d82JqI2HYIAury/0WDsMh0fKeuYUJb9KuDEv+e9nO3OJVa8Hog==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/micah@9.2.3':
resolution: {integrity: sha512-CcA/vVqrFEu5oDNAwJRRmLAE1gGJseP6BJTHMOdROkIOMpt1sy7OBqOFmajGnpOxOhvqBmvTZy0bw0G2TnnKSQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/miniavs@9.2.3':
resolution: {integrity: sha512-l111IVYtbUXypFQz1U4hTFM5DxGThDmluG7mNi1Uu92I5/3mH7Eltm2mX3T6g1HFW8MDaTeSBKee1xGVaHmmaA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/notionists-neutral@9.2.3':
resolution: {integrity: sha512-4WXCE9e9xIe1QdxiGXONxWhAzDVT4nMjoZA0rtgX8Sl0lqSIeBrO4RTnyaqFbGG1V1MiPj9CbE5OB8YbwexFBg==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/notionists@9.2.3':
resolution: {integrity: sha512-0bqS1pwAR8aAm6BDShgD5eI+u0f2CtgeFIDsOER6Je3WwFGyIBUTwwVSL7gmiA5qcvQAB9Slohj7vbN0pifTyA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/open-peeps@9.2.3':
resolution: {integrity: sha512-QcqKF3geA2Aqw1aJo8PO7+mKXz2I882D61I19vm94V1ojWnyw+8ihFmCLPReVcxQatxNjraTXCoKyT37TbgKBg==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/personas@9.2.3':
resolution: {integrity: sha512-YUXyoOwgt9CGhEuWl+dChDLmcVyuoU5UB7GY8PLWyHoy+1K3MzHJI7XFeDXyOYFpfuBiVY2++YjUZg26loqCNw==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/pixel-art-neutral@9.2.3':
resolution: {integrity: sha512-Eblj/m8x0VSsJfN++GRMPdqOXCcTh0TIIf2waLbNlaOEU1xdhkYC9wSdYfjNv3gUIdbButiYWHwPgRZETcx1qQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/pixel-art@9.2.3':
resolution: {integrity: sha512-4JZS/zbZZXg99P10sza0yxC2v+ugEWcoNy+c4I98ylWOjs2BrKcupSsU/2R11egT4u7hEknlVqR1zxKBGjuIDA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/rings@9.2.3':
resolution: {integrity: sha512-L4gZAzMsf9TNS99Um1ElG7Ncs9VSpQugLL0fCfDkMEkGxvwM+Aqu1UfX7iV3qNsEiu/zaR+3qCMBOEfNGUE1vA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/shapes@9.2.3':
resolution: {integrity: sha512-4MlhZED2ZDfHymNiPtj67UwW79ECoK1gDjRsUS5BPQUBFIQ22cYrKrRhDcs1CxMZCStnVsH26tt3atIkFeIo9Q==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dicebear/thumbs@9.2.3':
resolution: {integrity: sha512-C9vFXjYpLWa98tc4n+FcWkpJAWaGSJOqPUeaom+KVU/ibXLkr21RlcDCRc63YJfiULlE8bQhDWw7FaUAFV3gew==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@dicebear/core': ^9.0.0
'@dimforge/rapier3d-compat@0.12.0':
resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==}
@ -3310,6 +3770,14 @@ packages:
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
engines: {node: '>=18'}
'@sindresorhus/slugify@2.2.1':
resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==}
engines: {node: '>=12'}
'@sindresorhus/transliterate@1.6.0':
resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==}
engines: {node: '>=12'}
'@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
@ -7944,6 +8412,164 @@ snapshots:
'@date-fns/utc@2.1.0': {}
'@dicebear/adventurer-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/adventurer@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/avataaars-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/avataaars@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/big-ears-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/big-ears@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/big-smile@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/bottts-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/bottts@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/collection@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/adventurer': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/adventurer-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/avataaars': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/avataaars-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/big-ears': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/big-ears-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/big-smile': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/bottts': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/bottts-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/core': 9.2.3
'@dicebear/croodles': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/croodles-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/dylan': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/fun-emoji': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/glass': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/icons': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/identicon': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/initials': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/lorelei': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/lorelei-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/micah': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/miniavs': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/notionists': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/notionists-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/open-peeps': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/personas': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/pixel-art': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/pixel-art-neutral': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/rings': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/shapes': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/thumbs': 9.2.3(@dicebear/core@9.2.3)
'@dicebear/core@9.2.3':
dependencies:
'@types/json-schema': 7.0.15
'@dicebear/croodles-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/croodles@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/dylan@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/fun-emoji@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/glass@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/icons@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/identicon@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/initials@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/lorelei-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/lorelei@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/micah@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/miniavs@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/notionists-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/notionists@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/open-peeps@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/personas@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/pixel-art-neutral@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/pixel-art@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/rings@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/shapes@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dicebear/thumbs@9.2.3(@dicebear/core@9.2.3)':
dependencies:
'@dicebear/core': 9.2.3
'@dimforge/rapier3d-compat@0.12.0': {}
'@dimforge/rapier3d-compat@0.15.0': {}
@ -9850,6 +10476,15 @@ snapshots:
'@sindresorhus/merge-streams@4.0.0': {}
'@sindresorhus/slugify@2.2.1':
dependencies:
'@sindresorhus/transliterate': 1.6.0
escape-string-regexp: 5.0.0
'@sindresorhus/transliterate@1.6.0':
dependencies:
escape-string-regexp: 5.0.0
'@socket.io/component-emitter@3.1.2': {}
'@standard-schema/spec@1.0.0': {}
@ -10846,10 +11481,6 @@ snapshots:
dependencies:
ms: 2.1.3
debug@4.4.1:
dependencies:
ms: 2.1.3
debug@4.4.1(supports-color@10.0.0):
dependencies:
ms: 2.1.3
@ -12672,7 +13303,7 @@ snapshots:
micromark@4.0.2:
dependencies:
'@types/debug': 4.1.12
debug: 4.4.1
debug: 4.4.1(supports-color@10.0.0)
decode-named-character-reference: 1.2.0
devlop: 1.1.0
micromark-core-commonmark: 2.0.3

Wyświetl plik

@ -7,8 +7,8 @@
## API Gateway
- **MCP**: `https://gateway.agentic.so/@{username}/{project-name}/mcp`
- **HTTP**: `GET/POST` `https://gateway.agentic.so/@{username}/{project-name}/{tool-name}`
- **MCP**: `https://gateway.agentic.so/@{username}/{project-slug}/mcp`
- **HTTP**: `GET/POST` `https://gateway.agentic.so/@{username}/{project-slug}/{tool-name}`
## TODO: MVP
@ -41,6 +41,7 @@
- social images
- simplify `AgenticToolClient` and only require one package per TS LLM SDK
- `createAISDKToolsFromIdentifier(projectIdentifier)`
- add really strict free rate-limits to `@agentic/search`
## TODO: Post-MVP
@ -96,9 +97,7 @@
- prompts
- other MCP features?
- additional transactional emails
- consider `projectName` and `projectSlug` or `projectIdentifier`?
- handle or validate against dynamic MCP origin tools
- allow config name to be `project-name` or `@namespace/project-name`?
- upgrade to zod v4
- decide whether deployment fields like `defaultRateLimit` and others should be generated and stored in the db, or should be inferred based on `undefined` values
- support multiple rate-limits by slug