feat: drizzle-zod and hono openapi improvements

pull/715/head
Travis Fischer 2025-04-26 06:11:33 +07:00
rodzic f1437a47d1
commit 05d6b25781
30 zmienionych plików z 461 dodań i 190 usunięć

Wyświetl plik

@ -36,16 +36,17 @@
"test:unit": "vitest run"
},
"dependencies": {
"@agentic/faas-utils": "workspace:*",
"@agentic/validators": "workspace:*",
"@fisch0920/drizzle-zod": "^0.7.2",
"@google-cloud/logging": "^11.2.0",
"@hono/node-server": "^1.14.1",
"@hono/sentry": "^1.2.1",
"@hono/zod-openapi": "^0.19.5",
"@hono/zod-validator": "^0.4.3",
"@paralleldrive/cuid2": "^2.2.2",
"@sentry/node": "^9.14.0",
"@workos-inc/node": "^7.47.0",
"drizzle-orm": "^0.43.0",
"drizzle-zod": "^0.7.1",
"eventid": "^2.0.1",
"exit-hook": "catalog:",
"hono": "^4.7.7",

Wyświetl plik

@ -1,5 +1,24 @@
import type { Context } from 'hono'
import { createRoute, type OpenAPIHono, z } from '@hono/zod-openapi'
export async function healthCheck(c: Context) {
return c.json({ status: 'ok' })
const route = createRoute({
method: 'get',
path: 'health',
responses: {
200: {
description: 'OK',
content: {
'application/json': {
schema: z.object({
status: z.string()
})
}
}
}
}
})
export function registerHealthCheck(app: OpenAPIHono) {
return app.openapi(route, async (c) => {
return c.json({ status: 'ok' })
})
}

Wyświetl plik

@ -1,19 +1,23 @@
import { Hono } from 'hono'
import { OpenAPIHono } from '@hono/zod-openapi'
import type { AuthenticatedEnv } from '@/lib/types'
import * as middleware from '@/lib/middleware'
import { healthCheck } from './health-check'
import { registerHealthCheck } from './health-check'
import { registerV1UsersGetUser } from './users/get-user'
export const apiV1 = new Hono()
export const apiV1 = new OpenAPIHono()
const pub = new Hono()
const pri = new Hono<AuthenticatedEnv>()
const pub = new OpenAPIHono()
const pri = new OpenAPIHono<AuthenticatedEnv>()
pub.get('/health', healthCheck)
registerHealthCheck(pub)
apiV1.route('', pub)
// users
registerV1UsersGetUser(pri)
apiV1.route('/', pub)
apiV1.use(middleware.authenticate)
apiV1.use(middleware.team)
apiV1.use(middleware.me)
apiV1.route('', pri)
apiV1.route('/', pri)

Wyświetl plik

@ -0,0 +1,55 @@
import { createRoute, type OpenAPIHono, z } from '@hono/zod-openapi'
import type { AuthenticatedEnv } from '@/lib/types'
import { db, eq, schema, userIdSchema } from '@/db'
import { assert, parseZodSchema } from '@/lib/utils'
const ParamsSchema = z.object({
userId: userIdSchema.openapi({
param: {
name: 'userId',
in: 'path'
},
example: 'pfh0haxfpzowht3oi213cqos'
})
})
const route = createRoute({
tags: ['users'],
operationId: 'getUser',
method: 'get',
path: 'users/{userId}',
security: [{ bearerAuth: [] }],
request: {
params: ParamsSchema
},
responses: {
200: {
description: 'A user object',
content: {
'application/json': {
schema: schema.userSelectSchema
}
}
}
// TODO
// ...openApiErrorResponses
}
})
export type Route = typeof route
export type V1UsersGetUserResponse = z.infer<
(typeof route.responses)[200]['content']['application/json']['schema']
>
export const registerV1UsersGetUser = (app: OpenAPIHono<AuthenticatedEnv>) =>
app.openapi(route, async (c) => {
const { userId } = c.req.valid('param')
const user = await db.query.users.findFirst({
where: eq(schema.users.id, userId)
})
assert(user, 404, `User not found: ${userId}`)
return c.json(parseZodSchema(schema.userSelectSchema, user))
})

Wyświetl plik

@ -12,4 +12,30 @@ const postgresClient =
export const db = drizzle({ client: postgresClient, schema })
export * as schema from './schema'
export * from './schemas'
export type * from './types'
export {
and,
arrayContained,
arrayContains,
between,
eq,
exists,
gt,
gte,
ilike,
inArray,
isNotNull,
isNull,
like,
lt,
lte,
ne,
not,
notBetween,
notExists,
notIlike,
notInArray,
notLike,
or
} from 'drizzle-orm'

Wyświetl plik

@ -1,10 +1,16 @@
import { validators } from '@agentic/faas-utils'
import { validators } from '@agentic/validators'
import { z } from '@hono/zod-openapi'
import { relations } from 'drizzle-orm'
import { boolean, index, jsonb, pgTable, text } from 'drizzle-orm/pg-core'
import type { Coupon, PricingPlan } from './types'
import { projects } from './project'
import { teams } from './team'
import {
type Coupon,
couponSchema,
type PricingPlan,
pricingPlanSchema
} from './types'
import { users } from './user'
import {
createInsertSchema,
@ -105,12 +111,24 @@ export const deploymentInsertSchema = createInsertSchema(deployments, {
message: 'Invalid deployment hash'
}),
_url: (schema) => schema.url()
_url: (schema) => schema.url(),
build: z.object({}),
env: z.object({}),
pricingPlans: z.array(pricingPlanSchema),
coupons: z.array(couponSchema).optional()
})
export const deploymentSelectSchema = createSelectSchema(deployments).omit({
_url: true
export const deploymentSelectSchema = createSelectSchema(deployments, {
build: z.object({}),
env: z.object({}),
pricingPlans: z.array(pricingPlanSchema),
coupons: z.array(couponSchema)
})
.omit({
_url: true
})
.openapi('Deployment')
export const deploymentUpdateSchema = createUpdateSchema(deployments).pick({
enabled: true,

Wyświetl plik

@ -4,4 +4,3 @@ export * from './team'
export * from './team-member'
export type * from './types'
export * from './user'
export * from './utils'

Wyświetl plik

@ -1,4 +1,5 @@
import { validators } from '@agentic/faas-utils'
import { validators } from '@agentic/validators'
import { z } from '@hono/zod-openapi'
import { relations } from 'drizzle-orm'
import {
boolean,
@ -11,9 +12,9 @@ import {
import { getProviderToken } from '@/lib/auth/get-provider-token'
import type { Webhook } from './types'
import { deployments } from './deployment'
import { teams } from './team'
import { type Webhook, webhookSchema } from './types'
import { users } from './user'
import {
createInsertSchema,
@ -149,15 +150,30 @@ export const projectInsertSchema = createInsertSchema(projects, {
}
})
export const projectSelectSchema = createSelectSchema(projects).omit({
_secret: true,
_providerToken: true,
_text: true,
_webhooks: true,
_stripeCouponIds: true,
_stripePlanIds: true,
_stripeAccountId: true
export const projectSelectSchema = createSelectSchema(projects, {
_webhooks: z.array(webhookSchema),
stripeMetricProductIds: z.record(z.string(), z.string()).optional(),
_stripeCouponIds: z.record(z.string(), z.string()).optional(),
_stripePlanIds: z
.record(
z.string(),
z.object({
basePlanId: z.string(),
requestPlanId: z.string()
})
)
.optional()
})
.omit({
_secret: true,
_providerToken: true,
_text: true,
_webhooks: true,
_stripeCouponIds: true,
_stripePlanIds: true,
_stripeAccountId: true
})
.openapi('Project')
// TODO: narrow update schema
export const projectUpdateSchema = createUpdateSchema(projects)

Wyświetl plik

@ -9,7 +9,12 @@ import {
import { teams } from './team'
import { users } from './user'
import { cuid, teamMemberRoleEnum, timestamps } from './utils'
import {
createSelectSchema,
cuid,
teamMemberRoleEnum,
timestamps
} from './utils'
export const teamMembers = pgTable(
'team_members',
@ -25,7 +30,7 @@ export const teamMembers = pgTable(
role: teamMemberRoleEnum().default('user').notNull(),
confirmed: boolean().default(false),
confirmedAt: timestamp()
confirmedAt: timestamp({ mode: 'string' })
},
(table) => [
primaryKey({ columns: [table.userId, table.teamId] }),
@ -46,3 +51,6 @@ export const teamMembersRelations = relations(teamMembers, ({ one }) => ({
references: [teams.id]
})
}))
export const teamMemberSelectSchema =
createSelectSchema(teamMembers).openapi('TeamMember')

Wyświetl plik

@ -41,5 +41,5 @@ export const teamsRelations = relations(teams, ({ one, many }) => ({
export const teamInsertSchema = createInsertSchema(teams, {
slug: (schema) => schema.min(3).max(20) // TODO
})
export const teamSelectSchema = createSelectSchema(teams)
export const teamSelectSchema = createSelectSchema(teams).openapi('Team')
export const teamUpdateSchema = createUpdateSchema(teams).omit({ slug: true })

Wyświetl plik

@ -1,146 +1,161 @@
export type AuthProviderType =
| 'github'
| 'google'
| 'spotify'
| 'twitter'
| 'linkedin'
| 'stripe'
import { z } from '@hono/zod-openapi'
export type AuthProvider = {
provider: AuthProviderType
export const authProviderTypeSchema = z
.enum(['github', 'google', 'spotify', 'twitter', 'linkedin', 'stripe'])
.openapi('AuthProviderType')
export type AuthProviderType = z.infer<typeof authProviderTypeSchema>
/** Provider-specific user id */
id: string
export const authProviderSchema = z
.object({
provider: authProviderTypeSchema,
/** Provider-specific username */
username?: string
/** Provider-specific user id */
id: z.string(),
/** Standard oauth2 access token */
accessToken?: string
/** Provider-specific username */
username: z.string().optional(),
/** Standard oauth2 refresh token */
refreshToken?: string
/** Standard oauth2 access token */
accessToken: z.string().optional(),
/** Stripe public key */
publicKey?: string
/** Standard oauth2 refresh token */
refreshToken: z.string().optional(),
/** OAuth scope(s) */
scope?: string
}
/** Stripe public key */
publicKey: z.string().optional(),
export type AuthProviders = {
github?: AuthProvider
google?: AuthProvider
spotify?: AuthProvider
twitter?: AuthProvider
linkedin?: AuthProvider
stripeTest?: AuthProvider
stripeLive?: AuthProvider
}
/** OAuth scope(s) */
scope: z.string().optional()
})
.openapi('AuthProvider')
export type AuthProvider = z.infer<typeof authProviderSchema>
export type Webhook = {
url: string
events: string[]
}
export const authProvidersSchema = z
.record(authProviderTypeSchema, authProviderSchema)
.openapi('AuthProviders')
export type AuthProviders = z.infer<typeof authProvidersSchema>
export type RateLimit = {
enabled: boolean
export const webhookSchema = z
.object({
url: z.string(),
events: z.array(z.string())
})
.openapi('Webhook')
export type Webhook = z.infer<typeof webhookSchema>
// informal description that overrides any other properties
desc?: string
export const rateLimitSchema = z
.object({
enabled: z.boolean(),
interval: number // seconds
maxPerInterval: number // unitless
}
// informal description that overrides any other properties
desc: z.string().optional(),
export type PricingPlanTier = {
unitAmount?: number
flatAmount?: number
upTo: string
} & (
| {
unitAmount: number
interval: z.number(), // seconds
maxPerInterval: z.number() // unitless
})
.openapi('RateLimit')
export type RateLimit = z.infer<typeof rateLimitSchema>
export const pricingPlanTierSchema = z
.object({
unitAmount: z.number().optional(),
flatAmount: z.number().optional(),
upTo: z.string()
})
.refine(
(data) =>
(data.unitAmount !== undefined) !== (data.flatAmount !== undefined),
{
message: 'Either unitAmount or flatAmount must be provided, but not both'
}
| {
flatAmount: number
}
)
)
.openapi('PricingPlanTier')
export type PricingPlanTier = z.infer<typeof pricingPlanTierSchema>
export type PricingPlanMetric = {
// slug acts as a primary key for metrics
slug: string
export const pricingPlanMetricSchema = z
.object({
// slug acts as a primary key for metrics
slug: z.string(),
amount: number
amount: z.number(),
label: string
unitLabel: string
label: z.string(),
unitLabel: z.string(),
// TODO: should this default be 'licensed' or 'metered'?
// methinks licensed for "sites", "jobs", etc...
// TODO: this should probably be explicit since its easy to confuse
usageType: 'licensed' | 'metered'
// TODO: should this default be 'licensed' or 'metered'?
// methinks licensed for "sites", "jobs", etc...
// TODO: this should probably be explicit since its easy to confuse
usageType: z.enum(['licensed', 'metered']),
billingScheme: 'per_unit' | 'tiered'
billingScheme: z.enum(['per_unit', 'tiered']),
tiersMode: 'graduated' | 'volume'
tiers: PricingPlanTier[]
tiersMode: z.enum(['graduated', 'volume']),
tiers: z.array(pricingPlanTierSchema),
// TODO (low priority): add aggregateUsage
// TODO (low priority): add aggregateUsage
rateLimit?: RateLimit
}
rateLimit: rateLimitSchema.optional()
})
.openapi('PricingPlanMetric')
export type PricingPlanMetric = z.infer<typeof pricingPlanMetricSchema>
export type PricingPlan = {
name: string
slug: string
export const pricingPlanSchema = z
.object({
name: z.string(),
slug: z.string(),
desc?: string
features: string[]
desc: z.string().optional(),
features: z.array(z.string()),
auth: boolean
amount: number
trialPeriodDays?: number
auth: z.boolean(),
amount: z.number(),
trialPeriodDays: z.number().optional(),
requests: PricingPlanMetric
metrics: PricingPlanMetric[]
requests: pricingPlanMetricSchema,
metrics: z.array(pricingPlanMetricSchema),
rateLimit?: RateLimit
rateLimit: rateLimitSchema.optional(),
// used to uniquely identify this plan across deployments
baseId: string
// used to uniquely identify this plan across deployments
baseId: z.string(),
// used to uniquely identify this plan across deployments
requestsId: string
// used to uniquely identify this plan across deployments
requestsId: z.string(),
// [metricSlug: string]: string
metricIds: Record<string, string>
// [metricSlug: string]: string
metricIds: z.record(z.string()),
// NOTE: the stripe billing plan id(s) for this PricingPlan are referenced
// in the Project._stripePlans mapping via the plan's hash.
// NOTE: all metered billing usage is stored in stripe
stripeBasePlan: string
stripeRequestPlan: string
// NOTE: the stripe billing plan id(s) for this PricingPlan are referenced
// in the Project._stripePlans mapping via the plan's hash.
// NOTE: all metered billing usage is stored in stripe
stripeBasePlan: z.string(),
stripeRequestPlan: z.string(),
// [metricSlug: string]: string
stripeMetricPlans: Record<string, string>
}
// [metricSlug: string]: string
stripeMetricPlans: z.record(z.string())
})
.openapi('PricingPlan')
export type PricingPlan = z.infer<typeof pricingPlanSchema>
export type Coupon = {
// used to uniquely identify this coupon across deployments
id: string
export const couponSchema = z
.object({
// used to uniquely identify this coupon across deployments
id: z.string(),
valid: boolean
stripeCoupon: string
valid: z.boolean(),
stripeCoupon: z.string(),
name?: string
name: z.string().optional(),
currency?: string
amount_off?: number
percent_off?: number
currency: z.string().optional(),
amount_off: z.number().optional(),
percent_off: z.number().optional(),
duration: string
duration_in_months?: number
duration: z.string(),
duration_in_months: z.number().optional(),
redeem_by?: Date
max_redemptions?: number
}
redeem_by: z.date().optional(),
max_redemptions: z.number().optional()
})
.openapi('Coupon')
export type Coupon = z.infer<typeof couponSchema>

Wyświetl plik

@ -1,4 +1,4 @@
import { validators } from '@agentic/faas-utils'
import { validators } from '@agentic/validators'
import { relations } from 'drizzle-orm'
import {
boolean,
@ -12,8 +12,8 @@ import {
import { sha256 } from '@/lib/utils'
import type { AuthProviders } from './types'
import { teams } from './team'
import { type AuthProviders, authProvidersSchema } from './types'
import {
createInsertSchema,
createSelectSchema,
@ -42,7 +42,7 @@ export const users = pgTable(
image: text(),
emailConfirmed: boolean().default(false),
emailConfirmedAt: timestamp(),
emailConfirmedAt: timestamp({ mode: 'string' }),
emailConfirmToken: text().unique().default(sha256()),
passwordResetToken: text().unique(),
@ -85,7 +85,9 @@ export const userInsertSchema = createInsertSchema(users, {
{
message: 'Invalid email'
}
)
),
providers: authProvidersSchema.optional()
}).pick({
username: true,
email: true,
@ -95,5 +97,8 @@ export const userInsertSchema = createInsertSchema(users, {
image: true
})
export const userSelectSchema = createSelectSchema(users)
export const userSelectSchema = createSelectSchema(users, {
providers: authProvidersSchema.optional()
}).openapi('User')
export const userUpdateSchema = createUpdateSchema(users)

Wyświetl plik

@ -1,3 +1,5 @@
import { createSchemaFactory } from '@fisch0920/drizzle-zod'
import { z } from '@hono/zod-openapi'
import { createId } from '@paralleldrive/cuid2'
import { sql, type Writable } from 'drizzle-orm'
import {
@ -7,7 +9,6 @@ import {
timestamp,
varchar
} from 'drizzle-orm/pg-core'
import { createSchemaFactory } from 'drizzle-zod'
export function cuid<U extends string, T extends Readonly<[U, ...U[]]>>(
config?: PgVarcharConfig<T | Writable<T>, never>
@ -44,8 +45,8 @@ export const id = varchar('id', { length: 24 })
.$defaultFn(createId)
export const timestamps = {
createdAt: timestamp('createdAt').notNull().defaultNow(),
updatedAt: timestamp('updatedAt')
createdAt: timestamp('createdAt', { mode: 'string' }).notNull().defaultNow(),
updatedAt: timestamp('updatedAt', { mode: 'string' })
.notNull()
.default(sql`now()`)
}
@ -53,8 +54,31 @@ export const timestamps = {
export const userRoleEnum = pgEnum('UserRole', ['user', 'admin'])
export const teamMemberRoleEnum = pgEnum('TeamMemberRole', ['user', 'admin'])
// TODO: Currently unused after forking drizzle-zod.
// export function makeNullablePropsOptional<Schema extends z.AnyZodObject>(
// schema: Schema
// ): z.ZodObject<{
// [key in keyof Schema['shape']]: Schema['shape'][key] extends z.ZodNullable<
// infer T
// >
// ? z.ZodOptional<T>
// : Schema['shape'][key]
// }> {
// const entries = Object.entries(schema.shape)
// const newProps: any = {}
// for (const [key, value] of entries) {
// newProps[key] =
// value instanceof z.ZodNullable ? value.unwrap().optional() : value
// return newProps
// }
// return z.object(newProps) as any
// }
export const { createInsertSchema, createSelectSchema, createUpdateSchema } =
createSchemaFactory({
zodInstance: z,
coerce: {
// Coerce dates / strings to timetamps
date: true

Wyświetl plik

@ -0,0 +1,23 @@
import { validators } from '@agentic/validators'
import { z } from '@hono/zod-openapi'
function getCuidSchema(idLabel: string) {
return z.string().refine((id) => validators.cuid(id), {
message: `Invalid ${idLabel}`
})
}
export const cuidSchema = getCuidSchema('id')
export const userIdSchema = getCuidSchema('user id')
export const projectIdSchema = z
.string()
.refine((id) => validators.project(id), {
message: 'Invalid project id'
})
export const deploymentIdSchema = z
.string()
.refine((id) => validators.deployment(id), {
message: 'Invalid deployment id'
})

Wyświetl plik

@ -1,19 +1,20 @@
import type { z } from '@hono/zod-openapi'
import type { BuildQueryResult, ExtractTablesWithRelations } from 'drizzle-orm'
import type * as schema from './schema'
export type Tables = ExtractTablesWithRelations<typeof schema>
export type User = typeof schema.users.$inferSelect
export type User = z.infer<typeof schema.userSelectSchema>
export type Team = typeof schema.teams.$inferSelect
export type Team = z.infer<typeof schema.teamSelectSchema>
export type TeamWithMembers = BuildQueryResult<
Tables,
Tables['teams'],
{ with: { members: true } }
>
export type TeamMember = typeof schema.teamMembers.$inferSelect
export type TeamMember = z.infer<typeof schema.teamMemberSelectSchema>
export type TeamMemberWithTeam = BuildQueryResult<
Tables,
Tables['teamMembers'],

Wyświetl plik

@ -20,7 +20,11 @@ export function initExitHooks({
// Gracefully shutdown the HTTP server
asyncExitHook(
async function shutdownServerExitHook() {
await promisify(server.close)()
try {
await promisify(server.close)()
} catch {
// TODO
}
},
{
wait: timeoutMs
@ -30,9 +34,13 @@ export function initExitHooks({
// Gracefully shutdown the postgres database connection
asyncExitHook(
async function shutdownDbExitHook() {
await db.$client.end({
timeout: timeoutMs
})
try {
await db.$client.end({
timeout: timeoutMs
})
} catch {
// TODO
}
},
{
wait: timeoutMs

Wyświetl plik

@ -2,7 +2,7 @@ import '@/lib/instrument'
import { serve } from '@hono/node-server'
import { sentry } from '@hono/sentry'
import { Hono } from 'hono'
import { OpenAPIHono } from '@hono/zod-openapi'
import { compress } from 'hono/compress'
import { cors } from 'hono/cors'
@ -12,20 +12,26 @@ import * as middleware from '@/lib/middleware'
import { initExitHooks } from './lib/exit-hooks'
export const app = new Hono()
export const app = new OpenAPIHono()
app.use(sentry())
app.use(compress())
app.use(middleware.accessLogger)
// app.use(middleware.accessLogger)
app.use(middleware.responseTime)
app.use(middleware.errorHandler)
app.use(cors())
app.route('/v1', apiV1)
app.doc31('/docs', {
openapi: '3.1.0',
info: { title: 'Agentic', version: '1.0.0' }
})
const server = serve({
fetch: app.fetch,
port: env.PORT
})
console.log(`Server running on port ${env.PORT}`)
initExitHooks({ server })

Wyświetl plik

@ -1,14 +1,14 @@
{
"name": "@agentic/faas-utils",
"name": "@agentic/validators",
"private": true,
"version": "0.1.0",
"description": "Agentic platform FaaS utils.",
"description": "Validation utils for the Agentic platform.",
"author": "Travis Fischer <travis@transitivebullsh.it>",
"license": "UNLICENSED",
"repository": {
"type": "git",
"url": "git+https://github.com/transitive-bullshit/agentic-platform.git",
"directory": "packages/faas-utils"
"directory": "packages/validators"
},
"type": "module",
"source": "./src/index.ts",
@ -24,6 +24,7 @@
"test:unit": "vitest run"
},
"dependencies": {
"@paralleldrive/cuid2": "^2.2.2",
"email-validator": "^2.0.4",
"is-relative-url": "^4.0.0"
}

Wyświetl plik

@ -1,3 +1,4 @@
import { isCuid } from '@paralleldrive/cuid2'
import emailValidator from 'email-validator'
import isRelativeUrl from 'is-relative-url'
@ -50,3 +51,7 @@ export function serviceName(value: string): boolean {
export function servicePath(value: string): boolean {
return !!value && servicePathRe.test(value) && isRelativeUrl(value)
}
export function cuid(value: string): boolean {
return !!value && isCuid(value)
}

Wyświetl plik

@ -125,9 +125,12 @@ importers:
apps/api:
dependencies:
'@agentic/faas-utils':
'@agentic/validators':
specifier: workspace:*
version: link:../../packages/faas-utils
version: link:../../packages/validators
'@fisch0920/drizzle-zod':
specifier: ^0.7.2
version: 0.7.2(drizzle-orm@0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5))(zod@3.24.3)
'@google-cloud/logging':
specifier: ^11.2.0
version: 11.2.0
@ -137,6 +140,9 @@ importers:
'@hono/sentry':
specifier: ^1.2.1
version: 1.2.1(hono@4.7.7)
'@hono/zod-openapi':
specifier: ^0.19.5
version: 0.19.5(hono@4.7.7)(zod@3.24.3)
'@hono/zod-validator':
specifier: ^0.4.3
version: 0.4.3(hono@4.7.7)(zod@3.24.3)
@ -148,13 +154,10 @@ importers:
version: 9.14.0
'@workos-inc/node':
specifier: ^7.47.0
version: 7.47.0
version: 7.48.0
drizzle-orm:
specifier: ^0.43.0
version: 0.43.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5)
drizzle-zod:
specifier: ^0.7.1
version: 0.7.1(drizzle-orm@0.43.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5))(zod@3.24.3)
version: 0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5)
eventid:
specifier: ^2.0.1
version: 2.0.1
@ -196,8 +199,11 @@ importers:
specifier: ^0.31.0
version: 0.31.0
packages/faas-utils:
packages/validators:
dependencies:
'@paralleldrive/cuid2':
specifier: ^2.2.2
version: 2.2.2
email-validator:
specifier: ^2.0.4
version: 2.0.4
@ -207,6 +213,11 @@ importers:
packages:
'@asteasolutions/zod-to-openapi@7.3.0':
resolution: {integrity: sha512-7tE/r1gXwMIvGnXVUdIqUhCU1RevEFC4Jk6Bussa0fk1ecbnnINkZzj1EOAJyE/M3AI25DnHT/zKQL1/FPFi8Q==}
peerDependencies:
zod: ^3.20.2
'@babel/code-frame@7.26.2':
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'}
@ -558,6 +569,12 @@ packages:
prettier: '>= 3'
typescript: '>= 5'
'@fisch0920/drizzle-zod@0.7.2':
resolution: {integrity: sha512-f+ltSymKaD14RsZKiSBMoYsbxFrlKYHiybIDkDTPVUMrMQgpjdNleeYvjmyV2h47n73WxCQHF6K/4sTH8/GuTA==}
peerDependencies:
drizzle-orm: '>=0.36.0'
zod: '>=3.0.0'
'@google-cloud/common@5.0.2':
resolution: {integrity: sha512-V7bmBKYQyu0eVG2BFejuUjlBt+zrya6vtsKdY+JxMM/dNntPF41vZ9+LhOshEUH01zOHEqBSvI7Dad7ZS6aUeA==}
engines: {node: '>=14.0.0'}
@ -598,6 +615,13 @@ packages:
peerDependencies:
hono: '>=3.*'
'@hono/zod-openapi@0.19.5':
resolution: {integrity: sha512-n2RqdZL7XIaWPwBNygctG/1eySyRtSBnS7l+pIsP3f2JW5P2l7Smm6SLluscrGwB5l2C2fxbfvhWoC6Ig+SxXw==}
engines: {node: '>=16.0.0'}
peerDependencies:
hono: '>=4.3.6'
zod: 3.*
'@hono/zod-validator@0.4.3':
resolution: {integrity: sha512-xIgMYXDyJ4Hj6ekm9T9Y27s080Nl9NXHcJkOvkXPhubOLj8hZkOL8pDnnXfvCf5xEE8Q4oMFenQUZZREUY2gqQ==}
peerDependencies:
@ -1257,8 +1281,8 @@ packages:
'@vitest/utils@3.1.2':
resolution: {integrity: sha512-5GGd0ytZ7BH3H6JTj9Kw7Prn1Nbg0wZVrIvou+UWxm54d+WoXXgAgjFJ8wn3LdagWLFSEfpPeyYrByZaGEZHLg==}
'@workos-inc/node@7.47.0':
resolution: {integrity: sha512-A7K6uIIGmD5qbrLxoXah2BcOzbxyxnrhps+crZ/CFImrkq4CdVAm6BV/wvRaTeAinRF+Ea9cIFFeEAvJ++RaSw==}
'@workos-inc/node@7.48.0':
resolution: {integrity: sha512-dS0wpf8MqezcPsYcEbpW4eLcXZ7wOh0X9Qne4VVumrDTnC60kuxpMWIUAH1iPjXlocd8LKg13aYeP7mHSLVeCw==}
engines: {node: '>=16'}
abort-controller@3.0.0:
@ -1616,8 +1640,8 @@ packages:
resolution: {integrity: sha512-pcKVT+GbfPA+bUovPIilgVOoq+onNBo/YQBG86sf3/GFHkN6lRJPm1l7dKN0IMAk57RQoIm4GUllRrasLlcaSg==}
hasBin: true
drizzle-orm@0.43.0:
resolution: {integrity: sha512-OF6ZOtpGJs3CNXHGwKLfP+mYXEzTnXNL/WRXgAGR+SrtPl6quIBbTPEQZNQ6HhVQchMmJeaezBIcpFBpJD3x+g==}
drizzle-orm@0.43.1:
resolution: {integrity: sha512-dUcDaZtE/zN4RV/xqGrVSMpnEczxd5cIaoDeor7Zst9wOe/HzC/7eAaulywWGYXdDEc9oBPMjayVEDg0ziTLJA==}
peerDependencies:
'@aws-sdk/client-rds-data': '>=3'
'@cloudflare/workers-types': '>=4'
@ -1705,12 +1729,6 @@ packages:
sqlite3:
optional: true
drizzle-zod@0.7.1:
resolution: {integrity: sha512-nZzALOdz44/AL2U005UlmMqaQ1qe5JfanvLujiTHiiT8+vZJTBFhj3pY4Vk+L6UWyKFfNmLhk602Hn4kCTynKQ==}
peerDependencies:
drizzle-orm: '>=0.36.0'
zod: '>=3.0.0'
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@ -2733,6 +2751,9 @@ packages:
resolution: {integrity: sha512-M7CJbmv7UCopc0neRKdzfoGWaVZC+xC1925GitKH9EAqYFzX9//25Q7oX4+jw0tiCCj+t5l6VZh8UPH23NZkMA==}
hasBin: true
openapi3-ts@4.4.0:
resolution: {integrity: sha512-9asTNB9IkKEzWMcHmVZE7Ts3kC9G7AFHfs8i7caD8HbI76gEjdkId4z/AkP83xdZsH7PLAnnbl47qZkXuxpArw==}
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@ -2808,8 +2829,8 @@ packages:
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
engines: {node: '>=4'}
pg-pool@3.9.5:
resolution: {integrity: sha512-DxyAlOgvUzRFpFAZjbCc8fUfG7BcETDHgepFPf724B0i08k9PAiZV1tkGGgQIL0jbMEuR9jW1YN7eX+WgXxCsQ==}
pg-pool@3.9.6:
resolution: {integrity: sha512-rFen0G7adh1YmgvrmE5IPIqbb+IgEzENUm+tzm6MLLDSlPRoZVhzU1WdML9PV2W5GOdRA9qBKURlbt1OsXOsPw==}
peerDependencies:
pg: '>=8.0'
@ -3703,6 +3724,11 @@ packages:
snapshots:
'@asteasolutions/zod-to-openapi@7.3.0(zod@3.24.3)':
dependencies:
openapi3-ts: 4.4.0
zod: 3.24.3
'@babel/code-frame@7.26.2':
dependencies:
'@babel/helper-validator-identifier': 7.25.9
@ -3941,6 +3967,11 @@ snapshots:
- supports-color
- vitest
'@fisch0920/drizzle-zod@0.7.2(drizzle-orm@0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5))(zod@3.24.3)':
dependencies:
drizzle-orm: 0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5)
zod: 3.24.3
'@google-cloud/common@5.0.2':
dependencies:
'@google-cloud/projectify': 4.0.0
@ -4008,6 +4039,13 @@ snapshots:
hono: 4.7.7
toucan-js: 4.1.1
'@hono/zod-openapi@0.19.5(hono@4.7.7)(zod@3.24.3)':
dependencies:
'@asteasolutions/zod-to-openapi': 7.3.0(zod@3.24.3)
'@hono/zod-validator': 0.4.3(hono@4.7.7)(zod@3.24.3)
hono: 4.7.7
zod: 3.24.3
'@hono/zod-validator@0.4.3(hono@4.7.7)(zod@3.24.3)':
dependencies:
hono: 4.7.7
@ -4769,7 +4807,7 @@ snapshots:
loupe: 3.1.3
tinyrainbow: 2.0.0
'@workos-inc/node@7.47.0':
'@workos-inc/node@7.48.0':
dependencies:
iron-session: 6.3.1
jose: 5.6.3
@ -5140,18 +5178,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
drizzle-orm@0.43.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5):
drizzle-orm@0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5):
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@types/pg': 8.11.13
pg: 8.15.5
postgres: 3.4.5
drizzle-zod@0.7.1(drizzle-orm@0.43.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5))(zod@3.24.3):
dependencies:
drizzle-orm: 0.43.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.13)(pg@8.15.5)(postgres@3.4.5)
zod: 3.24.3
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@ -6381,6 +6414,10 @@ snapshots:
dependencies:
which-pm-runs: 1.1.0
openapi3-ts@4.4.0:
dependencies:
yaml: 2.7.1
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@ -6447,7 +6484,7 @@ snapshots:
pg-numeric@1.0.2: {}
pg-pool@3.9.5(pg@8.15.5):
pg-pool@3.9.6(pg@8.15.5):
dependencies:
pg: 8.15.5
optional: true
@ -6475,7 +6512,7 @@ snapshots:
pg@8.15.5:
dependencies:
pg-connection-string: 2.8.5
pg-pool: 3.9.5(pg@8.15.5)
pg-pool: 3.9.6(pg@8.15.5)
pg-protocol: 1.9.5
pg-types: 2.2.0
pgpass: 1.0.5