feat: move db schemas to separate package to share types

pull/715/head
Travis Fischer 2025-05-20 00:31:26 +07:00
rodzic d0539ecaff
commit 4ec31b176c
44 zmienionych plików z 398 dodań i 296 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ import { defineConfig } from 'drizzle-kit'
export default defineConfig({
out: './drizzle',
schema: './src/db/schema/index.ts',
schema: './src/db/schema.ts',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!

Wyświetl plik

@ -10,7 +10,10 @@ export default [
drizzle
},
rules: {
...drizzle.configs.recommended.rules
...drizzle.configs.recommended.rules,
'no-console': 'error',
'unicorn/no-array-reduce': 'off',
'no-restricted-imports': ['error', '@agentic/platform-db']
}
}
]

Wyświetl plik

@ -23,29 +23,23 @@
"clean": "del dist",
"test": "run-s test:*",
"test:lint": "eslint .",
"test:typecheck": "tsc --noEmit",
"test:unit": "vitest run"
"test:typecheck": "tsc --noEmit"
},
"dependencies": {
"@agentic/platform-core": "workspace:*",
"@agentic/validators": "workspace:*",
"@fisch0920/drizzle-orm": "^0.43.7",
"@fisch0920/drizzle-zod": "^0.7.9",
"@agentic/platform-db": "workspace:*",
"@agentic/platform-validators": "workspace:*",
"@hono/node-server": "^1.14.1",
"@hono/sentry": "^1.2.1",
"@hono/zod-openapi": "^0.19.6",
"@hono/zod-validator": "^0.5.0",
"@paralleldrive/cuid2": "^2.2.2",
"@redocly/openapi-core": "^1.34.3",
"@sentry/node": "^9.19.0",
"bcryptjs": "^3.0.2",
"eventid": "^2.0.1",
"exit-hook": "catalog:",
"hono": "^4.7.9",
"jsonwebtoken": "^9.0.2",
"p-all": "^5.0.0",
"parse-json": "^8.3.0",
"postgres": "^3.4.5",
"restore-cursor": "catalog:",
"semver": "^7.7.2",
"stripe": "^18.1.0",

Wyświetl plik

@ -1,7 +1,10 @@
import { z } from '@hono/zod-openapi'
import { consumerIdSchema, paginationSchema } from '@/db'
import { consumerRelationsSchema } from '@/db/schema'
import {
consumerIdSchema,
consumerRelationsSchema,
paginationSchema
} from '@/db'
export const consumerIdParamsSchema = z.object({
consumerId: consumerIdSchema.openapi({

Wyświetl plik

@ -1,5 +1,5 @@
import { assert, parseZodSchema, pick, sha256 } from '@agentic/platform-core'
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
import type { AuthenticatedEnv } from '@/lib/types'

Wyświetl plik

@ -1,7 +1,11 @@
import { z } from '@hono/zod-openapi'
import { deploymentIdSchema, paginationSchema, projectIdSchema } from '@/db'
import { deploymentRelationsSchema } from '@/db/schema'
import {
deploymentIdSchema,
deploymentRelationsSchema,
paginationSchema,
projectIdSchema
} from '@/db'
export const deploymentIdParamsSchema = z.object({
deploymentId: deploymentIdSchema.openapi({

Wyświetl plik

@ -110,35 +110,36 @@ apiV1.route('/', privateRouter)
// API route types to be used by Hono's RPC client.
// Should include all routes except for internal and admin routes.
export type ApiRoutes =
| ReturnType<typeof registerHealthCheck>
// Users
| ReturnType<typeof registerV1UsersGetUser>
| ReturnType<typeof registerV1UsersUpdateUser>
// Teams
| ReturnType<typeof registerV1TeamsCreateTeam>
| ReturnType<typeof registerV1TeamsListTeams>
| ReturnType<typeof registerV1TeamsGetTeam>
| ReturnType<typeof registerV1TeamsDeleteTeam>
| ReturnType<typeof registerV1TeamsUpdateTeam>
// Team members
| ReturnType<typeof registerV1TeamsMembersCreateTeamMember>
| ReturnType<typeof registerV1TeamsMembersUpdateTeamMember>
| ReturnType<typeof registerV1TeamsMembersDeleteTeamMember>
// Projects
| ReturnType<typeof registerV1ProjectsCreateProject>
| ReturnType<typeof registerV1ProjectsListProjects>
| ReturnType<typeof registerV1ProjectsGetProject>
| ReturnType<typeof registerV1ProjectsUpdateProject>
// Consumers
| ReturnType<typeof registerV1ConsumersGetConsumer>
| ReturnType<typeof registerV1ConsumersCreateConsumer>
| ReturnType<typeof registerV1ConsumersUpdateConsumer>
| ReturnType<typeof registerV1ConsumersRefreshConsumerToken>
| ReturnType<typeof registerV1ProjectsListConsumers>
// Deployments
| ReturnType<typeof registerV1DeploymentsGetDeployment>
| ReturnType<typeof registerV1DeploymentsCreateDeployment>
| ReturnType<typeof registerV1DeploymentsUpdateDeployment>
| ReturnType<typeof registerV1DeploymentsListDeployments>
| ReturnType<typeof registerV1DeploymentsPublishDeployment>
// NOTE: Removing for now because Hono's RPC client / types are clunky and slow.
// export type ApiRoutes =
// | ReturnType<typeof registerHealthCheck>
// // Users
// | ReturnType<typeof registerV1UsersGetUser>
// | ReturnType<typeof registerV1UsersUpdateUser>
// // Teams
// | ReturnType<typeof registerV1TeamsCreateTeam>
// | ReturnType<typeof registerV1TeamsListTeams>
// | ReturnType<typeof registerV1TeamsGetTeam>
// | ReturnType<typeof registerV1TeamsDeleteTeam>
// | ReturnType<typeof registerV1TeamsUpdateTeam>
// // Team members
// | ReturnType<typeof registerV1TeamsMembersCreateTeamMember>
// | ReturnType<typeof registerV1TeamsMembersUpdateTeamMember>
// | ReturnType<typeof registerV1TeamsMembersDeleteTeamMember>
// // Projects
// | ReturnType<typeof registerV1ProjectsCreateProject>
// | ReturnType<typeof registerV1ProjectsListProjects>
// | ReturnType<typeof registerV1ProjectsGetProject>
// | ReturnType<typeof registerV1ProjectsUpdateProject>
// // Consumers
// | ReturnType<typeof registerV1ConsumersGetConsumer>
// | ReturnType<typeof registerV1ConsumersCreateConsumer>
// | ReturnType<typeof registerV1ConsumersUpdateConsumer>
// | ReturnType<typeof registerV1ConsumersRefreshConsumerToken>
// | ReturnType<typeof registerV1ProjectsListConsumers>
// // Deployments
// | ReturnType<typeof registerV1DeploymentsGetDeployment>
// | ReturnType<typeof registerV1DeploymentsCreateDeployment>
// | ReturnType<typeof registerV1DeploymentsUpdateDeployment>
// | ReturnType<typeof registerV1DeploymentsListDeployments>
// | ReturnType<typeof registerV1DeploymentsPublishDeployment>

Wyświetl plik

@ -1,7 +1,6 @@
import { z } from '@hono/zod-openapi'
import { paginationSchema, projectIdSchema } from '@/db'
import { projectRelationsSchema } from '@/db/schema'
import { paginationSchema, projectIdSchema, projectRelationsSchema } from '@/db'
export const projectIdParamsSchema = z.object({
projectId: projectIdSchema.openapi({

Wyświetl plik

@ -1,6 +1,6 @@
import type { OpenAPIHono } from '@hono/zod-openapi'
import type Stripe from 'stripe'
import { assert,HttpError } from '@agentic/platform-core'
import { assert, HttpError } from '@agentic/platform-core'
import { and, db, eq, schema } from '@/db'
import { env, isStripeLive } from '@/lib/env'

Wyświetl plik

@ -1,44 +1,20 @@
import { drizzle } from '@fisch0920/drizzle-orm/postgres-js'
import postgres from 'postgres'
// The only place we allow `@agentic/platform-db` imports is in this directory.
import {
drizzle,
postgres,
type PostgresClient,
schema
} from '@agentic/platform-db'
import { env } from '@/lib/env'
import * as schema from './schema'
let _postgresClient: ReturnType<typeof postgres> | undefined
let _postgresClient: PostgresClient | undefined
const postgresClient =
_postgresClient ?? (_postgresClient = postgres(env.DATABASE_URL))
export const db = drizzle({ client: postgresClient, schema })
export * as schema from './schema'
export * from './schemas'
export type * from './types'
export {
and,
arrayContained,
arrayContains,
arrayOverlaps,
asc,
between,
desc,
eq,
exists,
gt,
gte,
ilike,
inArray,
isNotNull,
isNull,
like,
lt,
lte,
ne,
not,
notBetween,
notExists,
notIlike,
notInArray,
notLike,
or
} from '@fisch0920/drizzle-orm'
export * from '@agentic/platform-db'

Wyświetl plik

@ -0,0 +1,4 @@
// The only place we allow `@agentic/platform-db` imports is in this directory.
export * from '@agentic/platform-db'

Wyświetl plik

@ -1,5 +1,5 @@
import { assert } from '@agentic/platform-core'
import { parseFaasIdentifier } from '@agentic/validators'
import { parseFaasIdentifier } from '@agentic/platform-validators'
import type { AuthenticatedContext } from '@/lib/types'
import { and, db, eq, schema } from '@/db'

Wyświetl plik

@ -2,14 +2,18 @@ import type Stripe from 'stripe'
import { assert } from '@agentic/platform-core'
import pAll from 'p-all'
import { db, eq, type RawDeployment, type RawProject, schema } from '@/db'
import {
db,
eq,
getLabelForPricingInterval,
getPricingPlanLineItemHashForStripePrice,
getPricingPlansByInterval,
type PricingPlan,
type PricingPlanLineItem
} from '@/db/schema'
type PricingPlanLineItem,
type RawDeployment,
type RawProject,
schema
} from '@/db'
import { stripe } from '@/lib/stripe'
/**

Wyświetl plik

@ -6,13 +6,13 @@ import {
type ConsumerUpdate,
db,
eq,
getStripePriceIdForPricingPlanLineItem,
type RawConsumer,
type RawDeployment,
type RawProject,
type RawUser,
schema
} from '@/db'
import { getStripePriceIdForPricingPlanLineItem } from '@/db/schema'
import { stripe } from '@/lib/stripe'
export async function upsertStripeSubscription(

Wyświetl plik

@ -1,7 +1,7 @@
import { assert } from '@agentic/platform-core'
import semver from 'semver'
import type { RawProject } from '@/db/types'
import type { RawProject } from '@/db'
export function normalizeDeploymentVersion({
deploymentId,

Wyświetl plik

@ -1,5 +1,5 @@
import { assert } from '@agentic/platform-core'
import { parseFaasIdentifier } from '@agentic/validators'
import { parseFaasIdentifier } from '@agentic/platform-validators'
import type { AuthenticatedContext } from '@/lib/types'
import { db, eq, type RawDeployment, schema } from '@/db'

Wyświetl plik

@ -1,6 +1,6 @@
import { assert } from '@agentic/platform-core'
import type { DeploymentOriginAdapter } from '@/db/schema'
import type { DeploymentOriginAdapter } from '@/db'
import type { Logger } from '@/lib/logger'
import { validateOpenAPISpec } from '@/lib/validate-openapi-spec'

Wyświetl plik

@ -1,9 +1,8 @@
import { assert } from '@agentic/platform-core'
import { and, eq } from '@fisch0920/drizzle-orm'
import { createMiddleware } from 'hono/factory'
import type { AuthenticatedEnv } from '@/lib/types'
import { db, schema } from '@/db'
import { and, db, eq, schema } from '@/db'
import { aclTeamMember } from '@/lib/acl-team-member'
export const team = createMiddleware<AuthenticatedEnv>(

Wyświetl plik

@ -38,5 +38,3 @@ initExitHooks({ server })
// eslint-disable-next-line no-console
console.log(`Server running on port ${env.PORT}`)
export { type ApiRoutes } from '@/api-v1'

Wyświetl plik

@ -22,8 +22,7 @@
"scripts": {
"test": "run-s test:*",
"test:lint": "eslint .",
"test:typecheck": "tsc --noEmit",
"test:unit": "vitest run"
"test:typecheck": "tsc --noEmit"
},
"dependencies": {
"@agentic/platform-core": "workspace:*",
@ -35,6 +34,7 @@
},
"devDependencies": {
"@agentic/platform-api": "workspace:*",
"@agentic/platform-db": "workspace:*",
"@commander-js/extra-typings": "^14.0.0"
},
"publishConfig": {

Wyświetl plik

@ -8,6 +8,8 @@ export const signin = new Command('login')
.option('-u, --username <username>', 'account username')
.option('-e, --email <email>', 'account email')
.option('-p, --password <password>', 'account password')
.action(async (opts) => {
.action(async (_opts) => {
// TODO
// eslint-disable-next-line no-console
console.log('TODO: signin')
})

Wyświetl plik

@ -1,11 +1,14 @@
import { Command } from 'commander'
import { getAuth, requireAuth } from '../store'
import { getAuth } from '../store'
export const whoami = new Command('whoami')
.description('Displays info about the current user')
.action(async (opts) => {
.action(async () => {
const auth = getAuth()
// TODO
// eslint-disable-next-line no-console
console.log(
JSON.stringify({ user: auth.user, team: auth.teamSlug }, null, 2)
)

Wyświetl plik

@ -1,3 +1,4 @@
import type { User } from '@agentic/platform-db'
import { assert } from '@agentic/platform-core'
import Conf from 'conf'
@ -5,7 +6,7 @@ export const store = new Conf({ projectName: 'agentic' })
export type Auth = {
token: string
user: string
user: User
teamId?: string
teamSlug?: string
}

Wyświetl plik

@ -0,0 +1,43 @@
{
"name": "@agentic/platform-db",
"version": "0.0.1",
"description": "Postgres database schemas and types for the Agentic platform using Drizzle as the ORM.",
"author": "Travis Fischer <travis@transitivebullsh.it>",
"license": "UNLICENSED",
"repository": {
"type": "git",
"url": "git+https://github.com/transitive-bullshit/agentic-platform.git",
"directory": "packages/db"
},
"type": "module",
"main": "./src/index.ts",
"source": "./src/index.ts",
"types": "./src/index.ts",
"sideEffects": false,
"exports": {
".": "./src/index.ts"
},
"scripts": {
"test": "run-s test:*",
"test:lint": "eslint .",
"test:typecheck": "tsc --noEmit",
"test:unit": "vitest run"
},
"dependencies": {
"@agentic/platform-core": "workspace:*",
"@agentic/platform-validators": "workspace:*",
"@fisch0920/drizzle-orm": "^0.43.7",
"@fisch0920/drizzle-zod": "^0.7.9",
"@hono/zod-openapi": "^0.19.6",
"@paralleldrive/cuid2": "^2.2.2",
"bcryptjs": "^3.0.2",
"hono": "^4.7.9",
"parse-json": "^8.3.0",
"postgres": "^3.4.5",
"type-fest": "catalog:",
"zod": "catalog:"
},
"publishConfig": {
"access": "public"
}
}

Wyświetl plik

@ -0,0 +1,40 @@
import type postgres from 'postgres'
export { drizzle } from '@fisch0920/drizzle-orm/postgres-js'
export type PostgresClient = ReturnType<typeof postgres>
export * as schema from './schema'
export * from './schema/schemas'
export * from './schemas'
export type * from './types'
export * from './utils'
export {
and,
arrayContained,
arrayContains,
arrayOverlaps,
asc,
between,
desc,
eq,
exists,
gt,
gte,
ilike,
inArray,
isNotNull,
isNull,
like,
lt,
lte,
ne,
not,
notBetween,
notExists,
notIlike,
notInArray,
notLike,
or
} from '@fisch0920/drizzle-orm'
export { default as postgres } from 'postgres'

Wyświetl plik

@ -1,4 +1,3 @@
import { hashObject } from '@agentic/platform-core'
import { type Equal, sql, type Writable } from '@fisch0920/drizzle-orm'
import {
pgEnum,
@ -14,14 +13,6 @@ import { createSchemaFactory } from '@fisch0920/drizzle-zod'
import { z } from '@hono/zod-openapi'
import { createId } from '@paralleldrive/cuid2'
import type { RawProject } from '../types'
import type {
PricingInterval,
PricingPlan,
PricingPlanLineItem,
PricingPlanList
} from './schemas'
const usernameAndTeamSlugLength = 64 as const
/**
@ -125,85 +116,3 @@ export const { createInsertSchema, createSelectSchema, createUpdateSchema } =
date: true
}
})
/**
* Gets the hash used to uniquely map a PricingPlanLineItem to its
* corresponding Stripe Price in a stable way across deployments within a
* project.
*
* This hash is used as the key for the `Project._stripePriceIdMap`.
*/
export function getPricingPlanLineItemHashForStripePrice({
pricingPlan,
pricingPlanLineItem,
project
}: {
pricingPlan: PricingPlan
pricingPlanLineItem: PricingPlanLineItem
project: RawProject
}) {
// TODO: use pricingPlan.slug as well here?
// TODO: not sure if this is needed or not...
// With pricing plan slug:
// - 'price:free:base:<hash>'
// - 'price:basic-monthly:base:<hash>'
// - 'price:basic-monthly:requests:<hash>'
// Without pricing plan slug:
// - 'price:base:<hash>'
// - 'price:base:<hash>'
// - 'price:requests:<hash>'
const hash = hashObject({
...pricingPlanLineItem,
projectId: project.id,
stripeAccountId: project._stripeAccountId,
currency: project.pricingCurrency
})
return `price:${pricingPlan.slug}:${pricingPlanLineItem.slug}:${hash}`
}
export function getStripePriceIdForPricingPlanLineItem({
pricingPlan,
pricingPlanLineItem,
project
}: {
pricingPlan: PricingPlan
pricingPlanLineItem: PricingPlanLineItem
project: RawProject
}): string | undefined {
const pricingPlanLineItemHash = getPricingPlanLineItemHashForStripePrice({
pricingPlan,
pricingPlanLineItem,
project
})
return project._stripePriceIdMap[pricingPlanLineItemHash]
}
export function getPricingPlansByInterval({
pricingInterval,
pricingPlans
}: {
pricingInterval: PricingInterval
pricingPlans: PricingPlanList
}): PricingPlan[] {
return pricingPlans.filter(
(pricingPlan) =>
pricingPlan.interval === undefined ||
pricingPlan.interval === pricingInterval
)
}
const pricingIntervalToLabelMap: Record<PricingInterval, string> = {
day: 'daily',
week: 'weekly',
month: 'monthly',
year: 'yearly'
}
export function getLabelForPricingInterval(
pricingInterval: PricingInterval
): string {
return pricingIntervalToLabelMap[pricingInterval]
}

Wyświetl plik

@ -1,4 +1,4 @@
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { relations } from '@fisch0920/drizzle-orm'
import {
boolean,
@ -9,13 +9,6 @@ import {
} from '@fisch0920/drizzle-orm/pg-core'
import { z } from '@hono/zod-openapi'
import { deployments, deploymentSelectSchema } from './deployment'
import { projects, projectSelectSchema } from './project'
import {
type StripeSubscriptionItemIdMap,
stripeSubscriptionItemIdMapSchema
} from './schemas'
import { users, userSelectSchema } from './user'
import {
createInsertSchema,
createSelectSchema,
@ -26,7 +19,14 @@ import {
projectId,
stripeId,
timestamps
} from './utils'
} from './common'
import { deployments, deploymentSelectSchema } from './deployment'
import { projects, projectSelectSchema } from './project'
import {
type StripeSubscriptionItemIdMap,
stripeSubscriptionItemIdMapSchema
} from './schemas'
import { users, userSelectSchema } from './user'
// TODO: Consumers should be valid for any enabled project like in RapidAPI and GCP.
// This may require a separate model to aggregate User Applications.
@ -128,13 +128,6 @@ export const consumersRelations = relations(consumers, ({ one }) => ({
})
}))
export type ConsumerRelationFields = keyof ReturnType<
(typeof consumersRelations)['config']
>
export const consumerRelationsSchema: z.ZodType<ConsumerRelationFields> =
z.enum(['user', 'project', 'deployment'])
export const consumerSelectSchema = createSelectSchema(consumers, {
_stripeSubscriptionItemIdMap: stripeSubscriptionItemIdMapSchema,

Wyświetl plik

@ -1,4 +1,4 @@
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { relations } from '@fisch0920/drizzle-orm'
import {
boolean,
@ -9,6 +9,15 @@ import {
} from '@fisch0920/drizzle-orm/pg-core'
import { z } from '@hono/zod-openapi'
import {
createInsertSchema,
createSelectSchema,
createUpdateSchema,
cuid,
deploymentId,
projectId,
timestamps
} from './common'
import { projects } from './project'
import {
type DeploymentOriginAdapter,
@ -18,15 +27,6 @@ import {
} from './schemas'
import { teams, teamSelectSchema } from './team'
import { users, userSelectSchema } from './user'
import {
createInsertSchema,
createSelectSchema,
createUpdateSchema,
cuid,
deploymentId,
projectId,
timestamps
} from './utils'
export const deployments = pgTable(
'deployments',
@ -105,13 +105,6 @@ export const deploymentsRelations = relations(deployments, ({ one }) => ({
})
}))
export type DeploymentRelationFields = keyof ReturnType<
(typeof deploymentsRelations)['config']
>
export const deploymentRelationsSchema: z.ZodType<DeploymentRelationFields> =
z.enum(['user', 'team', 'project'])
// TODO: virtual hasFreeTier
// TODO: virtual url
// TODO: virtual openApiUrl

Wyświetl plik

@ -1,9 +1,8 @@
export * from './common'
export * from './consumer'
export * from './deployment'
export * from './log-entry'
export * from './project'
export * from './schemas'
export * from './team'
export * from './team-member'
export * from './user'
export * from './utils'

Wyświetl plik

@ -2,10 +2,6 @@ import { relations } from '@fisch0920/drizzle-orm'
import { index, jsonb, pgTable, text } from '@fisch0920/drizzle-orm/pg-core'
import { z } from '@hono/zod-openapi'
import { consumers, consumerSelectSchema } from './consumer'
import { deployments, deploymentSelectSchema } from './deployment'
import { projects, projectSelectSchema } from './project'
import { users, userSelectSchema } from './user'
import {
createInsertSchema,
createSelectSchema,
@ -16,7 +12,11 @@ import {
logEntryTypeEnum,
projectId,
timestamps
} from './utils'
} from './common'
import { consumers, consumerSelectSchema } from './consumer'
import { deployments, deploymentSelectSchema } from './deployment'
import { projects, projectSelectSchema } from './project'
import { users, userSelectSchema } from './user'
/**
* A `LogEntry` is an internal audit log entry.

Wyświetl plik

@ -1,4 +1,4 @@
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { relations } from '@fisch0920/drizzle-orm'
import {
boolean,
@ -10,6 +10,18 @@ import {
} from '@fisch0920/drizzle-orm/pg-core'
import { z } from '@hono/zod-openapi'
import {
createInsertSchema,
createSelectSchema,
createUpdateSchema,
cuid,
deploymentId,
pricingCurrencyEnum,
pricingIntervalEnum,
projectId,
stripeId,
timestamps
} from './common'
import { deployments, deploymentSelectSchema } from './deployment'
import {
pricingIntervalSchema,
@ -22,18 +34,6 @@ import {
} from './schemas'
import { teams, teamSelectSchema } from './team'
import { users, userSelectSchema } from './user'
import {
createInsertSchema,
createSelectSchema,
createUpdateSchema,
cuid,
deploymentId,
pricingCurrencyEnum,
pricingIntervalEnum,
projectId,
stripeId,
timestamps
} from './utils'
export const projects = pgTable(
'projects',
@ -157,17 +157,6 @@ export const projectsRelations = relations(projects, ({ one }) => ({
// })
}))
export type ProjectRelationFields = keyof ReturnType<
(typeof projectsRelations)['config']
>
export const projectRelationsSchema: z.ZodType<ProjectRelationFields> = z.enum([
'user',
'team',
'lastPublishedDeployment',
'lastDeployment'
])
export const projectSelectSchema = createSelectSchema(projects, {
applicationFeePercent: (schema) => schema.nonnegative(),

Wyświetl plik

@ -7,8 +7,6 @@ import {
} from '@fisch0920/drizzle-orm/pg-core'
import { z } from '@hono/zod-openapi'
import { teams, teamSelectSchema } from './team'
import { users, userSelectSchema } from './user'
import {
createInsertSchema,
createSelectSchema,
@ -18,7 +16,9 @@ import {
teamSlug,
timestamp,
timestamps
} from './utils'
} from './common'
import { teams, teamSelectSchema } from './team'
import { users, userSelectSchema } from './user'
export const teamMembers = pgTable(
'team_members',

Wyświetl plik

@ -1,4 +1,4 @@
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { relations } from '@fisch0920/drizzle-orm'
import {
index,
@ -8,8 +8,6 @@ import {
} from '@fisch0920/drizzle-orm/pg-core'
import { z } from '@hono/zod-openapi'
import { teamMembers } from './team-member'
import { users, userSelectSchema } from './user'
import {
createInsertSchema,
createSelectSchema,
@ -18,7 +16,9 @@ import {
id,
teamSlug,
timestamps
} from './utils'
} from './common'
import { teamMembers } from './team-member'
import { users, userSelectSchema } from './user'
export const teams = pgTable(
'teams',

Wyświetl plik

@ -1,5 +1,5 @@
import { sha256 } from '@agentic/platform-core'
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { relations } from '@fisch0920/drizzle-orm'
import {
boolean,
@ -11,8 +11,6 @@ import {
} from '@fisch0920/drizzle-orm/pg-core'
import { hashSync } from 'bcryptjs'
import { type AuthProviders, publicAuthProvidersSchema } from './schemas'
import { teams } from './team'
import {
createInsertSchema,
createSelectSchema,
@ -23,7 +21,9 @@ import {
timestamps,
username,
userRoleEnum
} from './utils'
} from './common'
import { type AuthProviders, publicAuthProvidersSchema } from './schemas'
import { teams } from './team'
export const users = pgTable(
'users',

Wyświetl plik

@ -1,6 +1,10 @@
import { validators } from '@agentic/validators'
import { validators } from '@agentic/platform-validators'
import { z } from '@hono/zod-openapi'
import type { consumersRelations } from './schema/consumer'
import type { deploymentsRelations } from './schema/deployment'
import type { projectsRelations } from './schema/project'
function getCuidSchema(idLabel: string) {
return z.string().refine((id) => validators.cuid(id), {
message: `Invalid ${idLabel}`
@ -57,3 +61,25 @@ export const paginationSchema = z.object({
// )
// })
// }
export type ProjectRelationFields = keyof ReturnType<
(typeof projectsRelations)['config']
>
export const projectRelationsSchema: z.ZodType<ProjectRelationFields> = z.enum([
'user',
'team',
'lastPublishedDeployment',
'lastDeployment'
])
export type DeploymentRelationFields = keyof ReturnType<
(typeof deploymentsRelations)['config']
>
export const deploymentRelationsSchema: z.ZodType<DeploymentRelationFields> =
z.enum(['user', 'team', 'project'])
export type ConsumerRelationFields = keyof ReturnType<
(typeof consumersRelations)['config']
>
export const consumerRelationsSchema: z.ZodType<ConsumerRelationFields> =
z.enum(['user', 'project', 'deployment'])

Wyświetl plik

@ -1,7 +1,5 @@
import { expectTypeOf, test } from 'vitest'
import type { LogLevel } from '@/lib/logger'
import type { LogEntry, RawLogEntry, RawUser, User } from './types'
type UserKeys = Exclude<keyof User & keyof RawUser, 'authProviders'>
@ -19,6 +17,4 @@ test('LogEntry types are compatible', () => {
expectTypeOf<LogEntry[LogEntryKeys]>().toEqualTypeOf<
RawLogEntry[LogEntryKeys]
>()
expectTypeOf<LogEntry['level']>().toEqualTypeOf<LogLevel>()
})

Wyświetl plik

@ -0,0 +1,91 @@
import { hashObject } from '@agentic/platform-core'
import type {
PricingInterval,
PricingPlan,
PricingPlanLineItem,
PricingPlanList
} from './schema/schemas'
import type { RawProject } from './types'
/**
* Gets the hash used to uniquely map a PricingPlanLineItem to its
* corresponding Stripe Price in a stable way across deployments within a
* project.
*
* This hash is used as the key for the `Project._stripePriceIdMap`.
*/
export function getPricingPlanLineItemHashForStripePrice({
pricingPlan,
pricingPlanLineItem,
project
}: {
pricingPlan: PricingPlan
pricingPlanLineItem: PricingPlanLineItem
project: RawProject
}) {
// TODO: use pricingPlan.slug as well here?
// TODO: not sure if this is needed or not...
// With pricing plan slug:
// - 'price:free:base:<hash>'
// - 'price:basic-monthly:base:<hash>'
// - 'price:basic-monthly:requests:<hash>'
// Without pricing plan slug:
// - 'price:base:<hash>'
// - 'price:base:<hash>'
// - 'price:requests:<hash>'
const hash = hashObject({
...pricingPlanLineItem,
projectId: project.id,
stripeAccountId: project._stripeAccountId,
currency: project.pricingCurrency
})
return `price:${pricingPlan.slug}:${pricingPlanLineItem.slug}:${hash}`
}
export function getStripePriceIdForPricingPlanLineItem({
pricingPlan,
pricingPlanLineItem,
project
}: {
pricingPlan: PricingPlan
pricingPlanLineItem: PricingPlanLineItem
project: RawProject
}): string | undefined {
const pricingPlanLineItemHash = getPricingPlanLineItemHashForStripePrice({
pricingPlan,
pricingPlanLineItem,
project
})
return project._stripePriceIdMap[pricingPlanLineItemHash]
}
export function getPricingPlansByInterval({
pricingInterval,
pricingPlans
}: {
pricingInterval: PricingInterval
pricingPlans: PricingPlanList
}): PricingPlan[] {
return pricingPlans.filter(
(pricingPlan) =>
pricingPlan.interval === undefined ||
pricingPlan.interval === pricingInterval
)
}
const pricingIntervalToLabelMap: Record<PricingInterval, string> = {
day: 'daily',
week: 'weekly',
month: 'monthly',
year: 'yearly'
}
export function getLabelForPricingInterval(
pricingInterval: PricingInterval
): string {
return pricingIntervalToLabelMap[pricingInterval]
}

Wyświetl plik

@ -0,0 +1,5 @@
{
"extends": "@fisch0920/config/tsconfig-node",
"include": ["src", "*.config.ts"],
"exclude": ["node_modules"]
}

Wyświetl plik

@ -1,5 +1,5 @@
{
"name": "@agentic/validators",
"name": "@agentic/platform-validators",
"private": true,
"version": "0.1.0",
"description": "Validation utils for the Agentic platform.",

Wyświetl plik

@ -128,15 +128,12 @@ importers:
'@agentic/platform-core':
specifier: workspace:*
version: link:../../packages/core
'@agentic/validators':
'@agentic/platform-db':
specifier: workspace:*
version: link:../../packages/db
'@agentic/platform-validators':
specifier: workspace:*
version: link:../../packages/validators
'@fisch0920/drizzle-orm':
specifier: ^0.43.7
version: 0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5)
'@fisch0920/drizzle-zod':
specifier: ^0.7.9
version: 0.7.9(@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5))(zod@3.24.4)
'@hono/node-server':
specifier: ^1.14.1
version: 1.14.1(hono@4.7.9)
@ -146,21 +143,12 @@ importers:
'@hono/zod-openapi':
specifier: ^0.19.6
version: 0.19.6(hono@4.7.9)(zod@3.24.4)
'@hono/zod-validator':
specifier: ^0.5.0
version: 0.5.0(hono@4.7.9)(zod@3.24.4)
'@paralleldrive/cuid2':
specifier: ^2.2.2
version: 2.2.2
'@redocly/openapi-core':
specifier: ^1.34.3
version: 1.34.3(supports-color@10.0.0)
'@sentry/node':
specifier: ^9.19.0
version: 9.19.0
bcryptjs:
specifier: ^3.0.2
version: 3.0.2
eventid:
specifier: ^2.0.1
version: 2.0.1
@ -179,9 +167,6 @@ importers:
parse-json:
specifier: ^8.3.0
version: 8.3.0
postgres:
specifier: ^3.4.5
version: 3.4.5
restore-cursor:
specifier: 'catalog:'
version: 5.1.0
@ -238,6 +223,9 @@ importers:
'@agentic/platform-api':
specifier: workspace:*
version: link:../../apps/api
'@agentic/platform-db':
specifier: workspace:*
version: link:../db
'@commander-js/extra-typings':
specifier: ^14.0.0
version: 14.0.0(commander@14.0.0)
@ -258,6 +246,45 @@ importers:
specifier: ^4.7.9
version: 4.7.9
packages/db:
dependencies:
'@agentic/platform-core':
specifier: workspace:*
version: link:../core
'@agentic/platform-validators':
specifier: workspace:*
version: link:../validators
'@fisch0920/drizzle-orm':
specifier: ^0.43.7
version: 0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5)
'@fisch0920/drizzle-zod':
specifier: ^0.7.9
version: 0.7.9(@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5))(zod@3.24.4)
'@hono/zod-openapi':
specifier: ^0.19.6
version: 0.19.6(hono@4.7.9)(zod@3.24.4)
'@paralleldrive/cuid2':
specifier: ^2.2.2
version: 2.2.2
bcryptjs:
specifier: ^3.0.2
version: 3.0.2
hono:
specifier: ^4.7.9
version: 4.7.9
parse-json:
specifier: ^8.3.0
version: 8.3.0
postgres:
specifier: ^3.4.5
version: 3.4.5
type-fest:
specifier: 'catalog:'
version: 4.41.0
zod:
specifier: 'catalog:'
version: 3.24.4
packages/validators:
dependencies:
'@paralleldrive/cuid2':