+ * - Json: any
+ * - Param: Record
+ * - Header: Record
+ * - Cookie: Record
+ *
+ * Schemas can transform to any output type (pipes/transforms allowed).
+ */
+export type EndpointDefinitionSchemas = {
+ [K in keyof ValidationTargets as Capitalize]?:
+ ValidationTargets[K] extends Record
+ ? RecordSchemaFor[K]>
+ : SchemaFor[K]>
+}
+
+// Endpoint definition contract
+export type EndpointDefinition = {
+ Name: string
+ Route: string
+ Description?: string
+ Methods: readonly ('GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH')[]
+ Input: z.ZodType
+ Output: z.ZodType
+ Schemas: EndpointDefinitionSchemas
+}
diff --git a/supabase/functions/_shared/server/schemas.ts b/packages/backend/src/endpoint/schemas.ts
similarity index 98%
rename from supabase/functions/_shared/server/schemas.ts
rename to packages/backend/src/endpoint/schemas.ts
index 5c2dac0..d73d5ad 100644
--- a/supabase/functions/_shared/server/schemas.ts
+++ b/packages/backend/src/endpoint/schemas.ts
@@ -1,6 +1,6 @@
// schemas.ts
import type { FormValue, ParsedFormValue } from 'hono/types';
-import type { EndpointDefinitionSchemas } from './types.ts';
+import type { EndpointDefinitionSchemas } from './definitions.ts';
import { z } from 'zod';
/**
diff --git a/packages/backend/src/query/fields.ts b/packages/backend/src/query/fields.ts
index 7da4870..623530d 100644
--- a/packages/backend/src/query/fields.ts
+++ b/packages/backend/src/query/fields.ts
@@ -13,7 +13,7 @@
import { z } from 'zod'
-import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema } from '../../../../supabase/functions/_shared/server/schemas.ts'
+import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema } from '../endpoint/schemas.ts'
import {
FieldSelectionNormalizedSchema,
type FieldsConfig,
diff --git a/packages/backend/src/query/filtering.ts b/packages/backend/src/query/filtering.ts
index 1c0659d..26532d7 100644
--- a/packages/backend/src/query/filtering.ts
+++ b/packages/backend/src/query/filtering.ts
@@ -132,7 +132,7 @@
import { z } from 'zod'
-import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema } from '../../../../supabase/functions/_shared/server/schemas.ts'
+import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema } from '../endpoint/schemas.ts'
import {
FiltersNormalizedSchema,
type FilterNormalized,
diff --git a/packages/backend/src/query/pagination.ts b/packages/backend/src/query/pagination.ts
index 70d06c5..1cf07db 100644
--- a/packages/backend/src/query/pagination.ts
+++ b/packages/backend/src/query/pagination.ts
@@ -18,7 +18,7 @@ import { z } from 'zod'
import { createHmac } from 'node:crypto'
import { Buffer } from 'node:buffer'
-import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema, ZStringOrStringArray } from '../../../../supabase/functions/_shared/server/schemas.ts'
+import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema, ZStringOrStringArray } from '../endpoint/schemas.ts'
import {
PaginationNormalizedSchema,
CursorDataSchema,
diff --git a/packages/backend/src/query/query.ts b/packages/backend/src/query/query.ts
index 27687fa..4c42c77 100644
--- a/packages/backend/src/query/query.ts
+++ b/packages/backend/src/query/query.ts
@@ -26,7 +26,7 @@ import { createFiltersSchema } from './filtering.ts'
import { createSortsSchema } from './sorting.ts'
import { createFieldsSchema } from './fields.ts'
-import { BaseFormSchema, BaseJsonSchema, BaseQuerySchema } from '../../../../supabase/functions/_shared/server/schemas.ts'
+import { BaseFormSchema, BaseJsonSchema, BaseQuerySchema } from '../endpoint/schemas.ts'
// Re-export QuerySpec type
export { QuerySpecSchema, type QuerySpec } from './schemas.ts'
diff --git a/packages/backend/src/query/sorting.ts b/packages/backend/src/query/sorting.ts
index 538b8fe..9aa7b63 100644
--- a/packages/backend/src/query/sorting.ts
+++ b/packages/backend/src/query/sorting.ts
@@ -12,7 +12,7 @@
import { z } from 'zod'
-import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema, ZStringOrStringArray } from '../../../../supabase/functions/_shared/server/schemas.ts'
+import { BaseQuerySchema, BaseJsonSchema, BaseFormSchema, ZStringOrStringArray } from '../endpoint/schemas.ts'
import {
SortsNormalizedSchema,
type SortNormalized,
diff --git a/supabase/functions/_shared/server/types.ts b/supabase/functions/_shared/server/types.ts
index 9926315..2b56786 100644
--- a/supabase/functions/_shared/server/types.ts
+++ b/supabase/functions/_shared/server/types.ts
@@ -1,86 +1,11 @@
import type { AppEnv as SharedAppEnv } from './create-app.ts'
-import type { Handler, MiddlewareHandler, ValidationTargets, Input } from 'hono'
-import type { FormValue, HandlerResponse, ParsedFormValue } from 'hono/types'
+import type { Handler, MiddlewareHandler, Input } from 'hono'
+import type { HandlerResponse } from 'hono/types'
import type z from 'zod'
-/**
- * Schema accepting input type I, producing any output
- *
- * No structural constraints - accepts:
- * - Plain objects: z.object({ ... })
- * - Pipes: z.object({ ... }).pipe(...)
- * - Transforms: z.object({ ... }).transform(...)
- * - Unions, intersections, etc.
- *
- * Use this when you need input type safety but want to allow transformations.
- */
-export type SchemaFor = z.ZodType
-
-/**
- * Helper to normalize record types for compatibility checking
- *
- * Converts Record to { [key: string]: V } to allow index signature
- * schemas to satisfy specific key union requirements.
- *
- * This enables: z.object({}).catchall(z.string()) to satisfy
- * RecordSchemaFor>
- */
-type NormalizedRecordInput =
- T extends Record
- ? K extends string
- ? { [key: string]: V }
- : T
- : T
-
-/**
- * Schema with record-shaped input
- *
- * Accepts schemas with index signatures that can parse the expected record type.
- * This allows catchall schemas to satisfy specific key union requirements.
- *
- * @example
- * // ✓ This works - catchall accepts any string keys
- * const schema = z.object({}).catchall(z.string())
- * satisfies RecordSchemaFor>
- */
-export type RecordSchemaFor , Output = any> =
- SchemaFor, Output>
-
-/**
- * @deprecated Use SchemaFor instead - allows transformations
- */
-export type AnySchemaFor = SchemaFor
-
-/**
- * Validation schemas for each input source
- *
- * Each schema must accept the raw input type from its source:
- * - Query: Record
- * - Form: Record
- * - Json: any
- * - Param: Record
- * - Header: Record
- * - Cookie: Record
- *
- * Schemas can transform to any output type (pipes/transforms allowed).
- */
-export type EndpointDefinitionSchemas = {
- [K in keyof ValidationTargets as Capitalize]?:
- ValidationTargets[K] extends Record
- ? RecordSchemaFor[K]>
- : SchemaFor[K]>
-}
+import type { EndpointDefinition, EndpointDefinitionSchemas } from '@platform/backend/endpoint/definitions.ts'
+export type * from '@platform/backend/endpoint/definitions.ts'
-// Endpoint definition contract
-export type EndpointDefinition = {
- Name: string
- Route: string
- Description?: string
- Methods: readonly ('GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH')[]
- Input: z.ZodType
- Output: z.ZodType
- Schemas: EndpointDefinitionSchemas
-}
/**
* FunctionAppEnv with specific variable requirements.
diff --git a/supabase/functions/social/endpoints/follows/check/definition.ts b/supabase/functions/social/endpoints/follows/check/definition.ts
index fdee08a..b0f1576 100644
--- a/supabase/functions/social/endpoints/follows/check/definition.ts
+++ b/supabase/functions/social/endpoints/follows/check/definition.ts
@@ -12,7 +12,7 @@
import type { EndpointDefinition } from '#shared/server/types.ts'
import { makeSuccessResponseSchema } from '@platform/backend/response/schemas.ts'
-import { BaseQuerySchema } from '#shared/server/schemas.ts'
+import { BaseQuerySchema } from '@platform/backend/endpoint/schemas.ts'
import { FollowPreferencesSchema } from '../../../utils/_schemas.ts'
import { z } from 'zod'
diff --git a/supabase/functions/social/endpoints/follows/follow/definition.ts b/supabase/functions/social/endpoints/follows/follow/definition.ts
index 87e0f3f..f79ce0b 100644
--- a/supabase/functions/social/endpoints/follows/follow/definition.ts
+++ b/supabase/functions/social/endpoints/follows/follow/definition.ts
@@ -16,7 +16,7 @@
import type { EndpointDefinition } from '#shared/server/types.ts'
import { makeSuccessResponseSchema } from '@platform/backend/response/schemas.ts'
-import { BaseJsonSchema } from '#shared/server/schemas.ts'
+import { BaseJsonSchema } from '@platform/backend/endpoint/schemas.ts'
import { FollowPreferencesSchema, FollowItemSchema } from '../../../utils/_schemas.ts'
import { z } from 'zod'
diff --git a/supabase/functions/social/endpoints/follows/list/definition.ts b/supabase/functions/social/endpoints/follows/list/definition.ts
index 7fa197a..e0f6676 100644
--- a/supabase/functions/social/endpoints/follows/list/definition.ts
+++ b/supabase/functions/social/endpoints/follows/list/definition.ts
@@ -16,7 +16,7 @@ import type { EndpointDefinition } from '#shared/server/types.ts'
import { makePaginationResultSchema } from '@platform/backend/response/schemas.ts'
import { createEndpointQuerySchema } from '@platform/backend/query/query.ts'
-import { BaseQuerySchema } from '#shared/server/schemas.ts'
+import { BaseQuerySchema } from '@platform/backend/endpoint/schemas.ts'
import { FollowItemSchema } from '../../../utils/_schemas.ts'
import { CURSOR_SECRET } from './_env.ts'
import { z } from 'zod'
diff --git a/supabase/functions/social/endpoints/follows/unfollow/definition.ts b/supabase/functions/social/endpoints/follows/unfollow/definition.ts
index ea98e56..0acb52b 100644
--- a/supabase/functions/social/endpoints/follows/unfollow/definition.ts
+++ b/supabase/functions/social/endpoints/follows/unfollow/definition.ts
@@ -15,7 +15,7 @@
import type { EndpointDefinition } from '#shared/server/types.ts'
import { makeSuccessResponseSchema } from '@platform/backend/response/schemas.ts'
-import { BaseQuerySchema, BaseParamSchema } from '#shared/server/schemas.ts'
+import { BaseQuerySchema, BaseParamSchema } from '@platform/backend/endpoint/schemas.ts'
import { z } from 'zod'
// ============================================================================
diff --git a/supabase/functions/social/endpoints/follows/update/definition.ts b/supabase/functions/social/endpoints/follows/update/definition.ts
index 4ed4f0c..e64b66a 100644
--- a/supabase/functions/social/endpoints/follows/update/definition.ts
+++ b/supabase/functions/social/endpoints/follows/update/definition.ts
@@ -14,7 +14,7 @@
import type { EndpointDefinition } from '#shared/server/types.ts'
import { makeSuccessResponseSchema } from '@platform/backend/response/schemas.ts'
-import { BaseJsonSchema, BaseParamSchema } from '#shared/server/schemas.ts'
+import { BaseJsonSchema, BaseParamSchema } from '@platform/backend/endpoint/schemas.ts'
import { FollowPreferencesSchema, FollowItemSchema } from '../../../utils/_schemas.ts'
import { z } from 'zod'
diff --git a/supabase/functions/social/endpoints/likes/check/definition.ts b/supabase/functions/social/endpoints/likes/check/definition.ts
index 4906df3..78586a2 100644
--- a/supabase/functions/social/endpoints/likes/check/definition.ts
+++ b/supabase/functions/social/endpoints/likes/check/definition.ts
@@ -1,7 +1,7 @@
// endpoint/likes/check/definition.ts
import type { EndpointDefinition } from '#shared/server/types.ts'
-import { BaseQuerySchema } from '#shared/server/schemas.ts'
+import { BaseQuerySchema } from '@platform/backend/endpoint/schemas.ts'
import { z } from 'zod'
export const QuerySchema = BaseQuerySchema.extend({
diff --git a/supabase/functions/social/endpoints/likes/like/definition.ts b/supabase/functions/social/endpoints/likes/like/definition.ts
index d060d32..dac1346 100644
--- a/supabase/functions/social/endpoints/likes/like/definition.ts
+++ b/supabase/functions/social/endpoints/likes/like/definition.ts
@@ -2,7 +2,7 @@
import type { EndpointDefinition } from '#shared/server/types.ts'
import { makeSuccessResponseSchema } from '@platform/backend/response/schemas.ts'
-import { BaseJsonSchema } from '#shared/server/schemas.ts'
+import { BaseJsonSchema } from '@platform/backend/endpoint/schemas.ts'
import { z } from 'zod'
export const JsonSchema = z.object({
diff --git a/supabase/functions/social/endpoints/likes/list/definition.ts b/supabase/functions/social/endpoints/likes/list/definition.ts
index 9f931bb..e7d5530 100644
--- a/supabase/functions/social/endpoints/likes/list/definition.ts
+++ b/supabase/functions/social/endpoints/likes/list/definition.ts
@@ -5,7 +5,7 @@ import type { EndpointDefinition } from '#shared/server/types.ts'
import { makePaginationResultSchema } from '@platform/backend/response/schemas.ts'
import { createEndpointQuerySchema } from '@platform/backend/query/query.ts'
-import { BaseQuerySchema } from '#shared/server/schemas.ts'
+import { BaseQuerySchema } from '@platform/backend/endpoint/schemas.ts'
import { CURSOR_SECRET } from './_env.ts'
import { z } from 'zod'
diff --git a/supabase/functions/social/endpoints/likes/unlike/definition.ts b/supabase/functions/social/endpoints/likes/unlike/definition.ts
index d901a95..61a5f22 100644
--- a/supabase/functions/social/endpoints/likes/unlike/definition.ts
+++ b/supabase/functions/social/endpoints/likes/unlike/definition.ts
@@ -1,7 +1,7 @@
// endpoint/likes/unlike/definition.ts
import { z } from 'zod'
import type { EndpointDefinition } from '#shared/server/types.ts'
-import { BaseQuerySchema, BaseParamSchema } from '#shared/server/schemas.ts'
+import { BaseQuerySchema, BaseParamSchema } from '@platform/backend/endpoint/schemas.ts'
export const Route = '/likes/:target_id';
export const ParamSchema = BaseParamSchema.extend({