omni-rest 0.3.3 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +51 -9
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +51 -9
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/fastify.d.mts +1 -1
- package/dist/adapters/fastify.d.ts +1 -1
- package/dist/adapters/fastify.js +51 -9
- package/dist/adapters/fastify.js.map +1 -1
- package/dist/adapters/fastify.mjs +51 -9
- package/dist/adapters/fastify.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +51 -9
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +51 -9
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/cli.js +75 -2
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +75 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +22 -5
- package/dist/index.d.ts +22 -5
- package/dist/index.js +114 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +114 -10
- package/dist/index.mjs.map +1 -1
- package/dist/{types-jvppYvku.d.mts → types-Dhk8VaWX.d.mts} +12 -0
- package/dist/{types-jvppYvku.d.ts → types-Dhk8VaWX.d.ts} +12 -0
- package/frontend-next/form-generator.tsx +52 -59
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/introspect.ts","../../src/query-builder.ts","../../src/middleware-helpers.ts","../../src/router.ts","../../src/adapters/nextjs.ts"],"names":["id"],"mappings":"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","file":"nextjs.js","sourcesContent":["import type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Reads Prisma's DMMF (Data Model Meta Format) at runtime\r\n * and returns structured metadata for every model in your schema.\r\n *\r\n * No file reading. No code generation. Pure runtime introspection.\r\n */\r\nexport function getModels(prisma?: any): ModelMeta[] {\r\n let raw: any[] | undefined;\r\n\r\n // Try to get from PrismaClient instance first (new v5 format)\r\n if (prisma?._runtimeDataModel?.models) {\r\n const modelsObj = prisma._runtimeDataModel.models;\r\n // Convert object to array, adding name from key\r\n raw = Object.entries(modelsObj).map(([name, model]: [string, any]) => ({\r\n name,\r\n ...model,\r\n fields: (model.fields || []).map((f: any) => ({\r\n ...f,\r\n relationName: f.kind === \"object\" ? f.name : undefined,\r\n })),\r\n }));\r\n }\r\n\r\n // Fallback to DMMF from @prisma/client module — use plain require so\r\n // vi.mock(\"@prisma/client\") can intercept it in tests. The CLI handles\r\n // the global-install path resolution separately before calling getModels.\r\n if (!raw) {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const prismaModule = require(\"@prisma/client\");\r\n const dmmfModels = prismaModule?.Prisma?.dmmf?.datamodel?.models;\r\n if (dmmfModels) {\r\n raw = dmmfModels;\r\n }\r\n } catch {\r\n // @prisma/client not available or not generated — handled below\r\n }\r\n }\r\n\r\n if (!raw) {\r\n throw new Error(\r\n \"[omni-rest] Could not find Prisma DMMF. Ensure Prisma client is generated and you're passing a PrismaClient instance to omni-rest.\"\r\n );\r\n }\r\n\r\n if (!Array.isArray(raw)) {\r\n throw new Error(\r\n `[omni-rest] Expected models to be an array, got ${typeof raw}. Debug: prisma._runtimeDataModel.models=${!!prisma?._runtimeDataModel?.models}, raw value=${JSON.stringify(raw).slice(0, 100)}`\r\n );\r\n }\r\n\r\n return raw.map((model: any) => {\r\n const fields: FieldMeta[] = model.fields.map((f: any) => ({\r\n name: f.name,\r\n type: f.type,\r\n isId: f.isId,\r\n isRequired: f.isRequired,\r\n isList: f.isList,\r\n isRelation: !!f.relationName,\r\n hasDefaultValue: !!f.hasDefaultValue || !!f.default,\r\n isUpdatedAt: !!f.isUpdatedAt,\r\n }));\r\n\r\n const idField =\r\n model.fields.find((f: any) => f.isId)?.name ?? \"id\";\r\n\r\n return {\r\n name: model.name,\r\n routeName: toRouteName(model.name),\r\n fields,\r\n idField,\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Converts a Prisma model name to a URL-safe route segment.\r\n * \"UserProfile\" → \"userprofile\"\r\n * \"OrderItem\" → \"orderitem\"\r\n */\r\nexport function toRouteName(modelName: string): string {\r\n return modelName.toLowerCase();\r\n}\r\n\r\n/**\r\n * Returns a map of routeName → ModelMeta for O(1) lookups.\r\n */\r\nexport function buildModelMap(\r\n models: ModelMeta[],\r\n allowList?: string[]\r\n): Record<string, ModelMeta> {\r\n const filtered = allowList\r\n ? models.filter((m) => allowList.includes(m.routeName))\r\n : models;\r\n\r\n return Object.fromEntries(filtered.map((m) => [m.routeName, m]));\r\n}\r\n\r\n/**\r\n * Gets the Prisma client delegate for a model.\r\n * prisma[\"userProfile\"] or prisma[\"user\"] — handles camelCase.\r\n */\r\nexport function getDelegate(prisma: any, meta: ModelMeta): any {\r\n // Prisma client properties are camelCase of model name\r\n // \"UserProfile\" → \"userProfile\"\r\n const key =\r\n meta.name.charAt(0).toLowerCase() + meta.name.slice(1);\r\n const delegate = prisma[key];\r\n\r\n if (!delegate) {\r\n throw new Error(\r\n `Could not find Prisma delegate for model \"${meta.name}\". ` +\r\n `Expected prisma.${key} to exist.`\r\n );\r\n }\r\n\r\n return delegate;\r\n}","import type { ParsedQuery } from \"./types\";\r\n\r\n/**\r\n * Supported filter suffixes and their Prisma equivalents.\r\n *\r\n * Usage in URL:\r\n * ?name_contains=john\r\n * ?age_gte=18\r\n * ?status_in=active,inactive\r\n * ?email_not=test@test.com\r\n */\r\nconst FILTER_OPERATORS: Record<string, string> = {\r\n _gte: \"gte\",\r\n _lte: \"lte\",\r\n _gt: \"gt\",\r\n _lt: \"lt\",\r\n _contains: \"contains\",\r\n _icontains: \"contains\", // case-insensitive version (mode: insensitive)\r\n _startsWith: \"startsWith\",\r\n _endsWith: \"endsWith\",\r\n _in: \"in\",\r\n _notIn: \"notIn\",\r\n _not: \"not\",\r\n};\r\n\r\n/**\r\n * Reserved query keys — these are NOT treated as filters.\r\n */\r\nconst RESERVED_KEYS = new Set([\r\n \"page\",\r\n \"limit\",\r\n \"sort\",\r\n \"include\",\r\n \"select\",\r\n]);\r\n\r\n/**\r\n * Parses URLSearchParams into a full Prisma query object.\r\n *\r\n * Supports:\r\n * Filtering → ?name=John ?age_gte=18 ?status_in=a,b\r\n * Sorting → ?sort=createdAt:desc or ?sort=name:asc\r\n * Pagination → ?page=2&limit=10\r\n * Relations → ?include=posts,profile\r\n * Fields → ?select=id,name,email\r\n */\r\nexport function buildQuery(\r\n searchParams: URLSearchParams,\r\n defaultLimit = 20,\r\n maxLimit = 100\r\n): ParsedQuery {\r\n const where: Record<string, any> = {};\r\n const orderBy: Record<string, \"asc\" | \"desc\"> = {};\r\n let include: Record<string, boolean> = {};\r\n let select: Record<string, boolean> | null = null;\r\n\r\n // ─── Pagination ────────────────────────────────────────────────────────────\r\n const page = Math.max(1, parseInt(searchParams.get(\"page\") ?? \"1\"));\r\n const rawLimit = parseInt(searchParams.get(\"limit\") ?? String(defaultLimit));\r\n const take = Math.min(rawLimit, maxLimit);\r\n const skip = (page - 1) * take;\r\n\r\n // ─── Sort ──────────────────────────────────────────────────────────────────\r\n const sortParam = searchParams.get(\"sort\");\r\n if (sortParam) {\r\n // Supports multiple sorts: ?sort=name:asc,createdAt:desc\r\n for (const part of sortParam.split(\",\")) {\r\n const [field, dir] = part.trim().split(\":\");\r\n if (field) {\r\n orderBy[field] = (dir === \"desc\" ? \"desc\" : \"asc\");\r\n }\r\n }\r\n }\r\n\r\n // ─── Include (relations) ───────────────────────────────────────────────────\r\n const includeParam = searchParams.get(\"include\");\r\n if (includeParam) {\r\n for (const rel of includeParam.split(\",\")) {\r\n if (rel.trim()) include[rel.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Select (fields) ──────────────────────────────────────────────────────\r\n const selectParam = searchParams.get(\"select\");\r\n if (selectParam) {\r\n select = {};\r\n for (const field of selectParam.split(\",\")) {\r\n if (field.trim()) select[field.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Filters ───────────────────────────────────────────────────────────────\r\n for (const [key, value] of searchParams.entries()) {\r\n if (RESERVED_KEYS.has(key)) continue;\r\n\r\n // Check operator suffixes (longest match first)\r\n let matched = false;\r\n const sortedOps = Object.keys(FILTER_OPERATORS).sort(\r\n (a, b) => b.length - a.length\r\n );\r\n\r\n for (const suffix of sortedOps) {\r\n if (key.endsWith(suffix)) {\r\n const field = key.slice(0, -suffix.length);\r\n const prismaOp = FILTER_OPERATORS[suffix];\r\n\r\n let parsedValue: any = value;\r\n\r\n // Parse arrays\r\n if (prismaOp === \"in\" || prismaOp === \"notIn\") {\r\n parsedValue = value.split(\",\").map((v) => v.trim());\r\n }\r\n\r\n // Attempt numeric coercion\r\n if (!isNaN(Number(parsedValue)) && typeof parsedValue === \"string\") {\r\n parsedValue = Number(parsedValue);\r\n }\r\n\r\n // Case-insensitive flag\r\n const extra = suffix === \"_icontains\" ? { mode: \"insensitive\" } : {};\r\n\r\n where[field] = { [prismaOp]: parsedValue, ...extra };\r\n matched = true;\r\n break;\r\n }\r\n }\r\n\r\n // No operator — exact match\r\n if (!matched) {\r\n let parsedValue: any = value;\r\n\r\n // Coerce booleans\r\n if (value === \"true\") parsedValue = true;\r\n else if (value === \"false\") parsedValue = false;\r\n // Coerce numbers\r\n else if (!isNaN(Number(value)) && value !== \"\") {\r\n parsedValue = Number(value);\r\n }\r\n\r\n where[key] = parsedValue;\r\n }\r\n }\r\n\r\n return { where, orderBy, skip, take, include, select };\r\n}","import type { GuardMap, HookFn, HookContext } from \"./types\";\r\n\r\n/**\r\n * Runs the guard for the given model+method combo.\r\n * Returns an error string if blocked, null if allowed.\r\n */\r\nexport async function runGuard(\r\n guards: GuardMap,\r\n model: string,\r\n method: string,\r\n ctx: { id?: string | null; body?: any }\r\n): Promise<string | null> {\r\n const modelGuards = guards[model];\r\n if (!modelGuards) return null;\r\n\r\n const fn = modelGuards[method as keyof typeof modelGuards];\r\n if (!fn) return null;\r\n\r\n return fn({ ...ctx, method });\r\n}\r\n\r\n/**\r\n * Runs a lifecycle hook (beforeOperation / afterOperation).\r\n * Silently swallows errors so hooks never crash the main flow.\r\n */\r\nexport async function runHook(\r\n hook: HookFn | undefined,\r\n ctx: HookContext\r\n): Promise<void> {\r\n if (!hook) return;\r\n try {\r\n await hook(ctx);\r\n } catch (e) {\r\n // Hooks should not crash the request\r\n console.error(\"[omni-rest] Hook error:\", e);\r\n }\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { getModels, buildModelMap, getDelegate } from \"./introspect\";\r\nimport { buildQuery } from \"./query-builder\";\r\nimport { runGuard, runHook } from \"./middleware-helpers\";\r\nimport type {\r\n PrismaRestOptions,\r\n HandlerResult,\r\n RouterInstance,\r\n ModelMeta,\r\n} from \"./types\";\r\n\r\n/**\r\n * Creates a framework-agnostic CRUD router powered by Prisma DMMF.\r\n *\r\n * All adapters (Express, Next.js, Fastify) use this under the hood.\r\n */\r\nexport function createRouter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n): RouterInstance {\r\n const {\r\n allow,\r\n guards = {},\r\n beforeOperation,\r\n afterOperation,\r\n defaultLimit = 20,\r\n maxLimit = 100,\r\n } = options;\r\n\r\n // Introspect schema once at startup\r\n const models = getModels(prisma);\r\n const modelMap = buildModelMap(models, allow);\r\n\r\n async function handle(\r\n method: string,\r\n modelName: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n operation?: string\r\n ): Promise<HandlerResult> {\r\n // ── 1. Resolve model ───────────────────────────────────────────────────\r\n const meta = modelMap[modelName.toLowerCase()];\r\n if (!meta) {\r\n return {\r\n status: 404,\r\n data: {\r\n error: `Model \"${modelName}\" not found or not exposed.`,\r\n available: Object.keys(modelMap),\r\n },\r\n };\r\n }\r\n\r\n // ── 2. Guard check ─────────────────────────────────────────────────────\r\n const guardError = await runGuard(guards, meta.routeName, method, {\r\n id,\r\n body,\r\n });\r\n if (guardError) {\r\n return { status: 403, data: { error: guardError } };\r\n }\r\n\r\n // ── 3. Before hook ─────────────────────────────────────────────────────\r\n await runHook(beforeOperation, { model: meta.name, method, id, body });\r\n\r\n // ── 4. Execute operation ───────────────────────────────────────────────\r\n let result: HandlerResult;\r\n\r\n try {\r\n result = await executeOperation(\r\n prisma,\r\n meta,\r\n method,\r\n id,\r\n body,\r\n searchParams,\r\n defaultLimit,\r\n maxLimit,\r\n operation\r\n );\r\n } catch (e: any) {\r\n return handlePrismaError(e);\r\n }\r\n\r\n // ── 5. After hook ──────────────────────────────────────────────────────\r\n await runHook(afterOperation, {\r\n model: meta.name,\r\n method,\r\n id,\r\n body,\r\n result: result.data,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n return { handle, modelMap, models };\r\n}\r\n\r\n// ─── Operation executor ────────────────────────────────────────────────────────\r\n\r\nasync function executeOperation(\r\n prisma: PrismaClient,\r\n meta: ModelMeta,\r\n method: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n defaultLimit: number,\r\n maxLimit: number,\r\n operation?: string\r\n): Promise<HandlerResult> {\r\n const delegate = getDelegate(prisma, meta);\r\n const { where, orderBy, skip, take, include, select } = buildQuery(\r\n searchParams,\r\n defaultLimit,\r\n maxLimit\r\n );\r\n\r\n // Build include/select args (mutually exclusive in Prisma)\r\n const includeArg =\r\n Object.keys(include).length > 0 ? include : undefined;\r\n const selectArg =\r\n select && Object.keys(select).length > 0 ? select : undefined;\r\n const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};\r\n\r\n // ── PATCH /model/bulk/update ────────────────────────────────────────────────\r\n if (method === \"PATCH\" && operation === \"bulk-update\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of update records\" },\r\n };\r\n }\r\n\r\n // Validate that each item has an id\r\n for (const item of body) {\r\n if (!item[meta.idField]) {\r\n return {\r\n status: 400,\r\n data: { error: `Each record must have an ${meta.idField} field` },\r\n };\r\n }\r\n }\r\n\r\n // Execute updates in parallel\r\n const results = await Promise.all(\r\n body.map((item) => {\r\n const id = item[meta.idField];\r\n const updateData = { ...item };\r\n delete updateData[meta.idField]; // Remove id from update data\r\n\r\n return delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: updateData,\r\n ...projection,\r\n });\r\n })\r\n );\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n updated: results.length,\r\n records: results,\r\n },\r\n };\r\n }\r\n\r\n // ── DELETE /model/bulk/delete ──────────────────────────────────────────────\r\n if (method === \"DELETE\" && operation === \"bulk-delete\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of IDs\" },\r\n };\r\n }\r\n\r\n // Handle both array of IDs and array of objects with id field\r\n const ids = body.map((item: any) =>\r\n typeof item === \"object\" ? item[meta.idField] : item\r\n );\r\n\r\n // Use deleteMany with a where clause\r\n const result = await delegate.deleteMany({\r\n where: {\r\n [meta.idField]: { in: ids.map(coerceId) },\r\n },\r\n });\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n deleted: result.count,\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model ─────────────────────────────────────────────────────────────\r\n if (method === \"GET\" && !id) {\r\n const [data, total] = await (prisma as any).$transaction([\r\n delegate.findMany({ where, orderBy, skip, take, ...projection }),\r\n delegate.count({ where }),\r\n ]);\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n data,\r\n meta: {\r\n total,\r\n page: Math.floor(skip / take) + 1,\r\n limit: take,\r\n totalPages: Math.ceil(total / take),\r\n },\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model/:id ─────────────────────────────────────────────────────────\r\n if (method === \"GET\" && id) {\r\n const record = await delegate.findUnique({\r\n where: { [meta.idField]: coerceId(id) },\r\n ...projection,\r\n });\r\n\r\n if (!record) {\r\n return { status: 404, data: { error: `${meta.name} with id \"${id}\" not found.` } };\r\n }\r\n\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── POST /model ────────────────────────────────────────────────────────────\r\n if (method === \"POST\" && !id) {\r\n const record = await delegate.create({ data: body });\r\n return { status: 201, data: record };\r\n }\r\n\r\n // ── PUT /model/:id ─────────────────────────────────────────────────────────\r\n if ((method === \"PUT\" || method === \"PATCH\") && id) {\r\n const record = await delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: body,\r\n });\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── DELETE /model/:id ──────────────────────────────────────────────────────\r\n if (method === \"DELETE\" && id) {\r\n await delegate.delete({\r\n where: { [meta.idField]: coerceId(id) },\r\n });\r\n return { status: 204, data: null };\r\n }\r\n\r\n return { status: 405, data: { error: `Method ${method} not allowed.` } };\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Coerces an ID string to number when possible (common with Int PKs).\r\n */\r\nfunction coerceId(id: string): string | number {\r\n const n = Number(id);\r\n return isNaN(n) ? id : n;\r\n}\r\n\r\n/**\r\n * Maps Prisma error codes to meaningful HTTP responses.\r\n */\r\nfunction handlePrismaError(e: any): HandlerResult {\r\n const code = e?.code;\r\n\r\n if (code === \"P2025\") {\r\n return { status: 404, data: { error: \"Record not found.\" } };\r\n }\r\n if (code === \"P2002\") {\r\n const fields = e?.meta?.target ?? \"unknown fields\";\r\n return {\r\n status: 409,\r\n data: { error: `Unique constraint failed on: ${fields}` },\r\n };\r\n }\r\n if (code === \"P2003\") {\r\n return { status: 400, data: { error: \"Foreign key constraint failed.\" } };\r\n }\r\n if (code === \"P2014\") {\r\n return { status: 400, data: { error: \"Relation violation.\" } };\r\n }\r\n\r\n return { status: 500, data: { error: e?.message ?? \"Internal server error.\" } };\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { createRouter } from \"../router\";\r\nimport type { PrismaRestOptions } from \"../types\";\r\n\r\n/**\r\n * Next.js App Router adapter for omni-rest.\r\n *\r\n * @example\r\n * ```ts\r\n * // app/api/[...prismaRest]/route.ts\r\n * import { PrismaClient } from \"@prisma/client\";\r\n * import { nextjsAdapter } from \"omni-rest/nextjs\";\r\n *\r\n * const prisma = new PrismaClient();\r\n * const handler = nextjsAdapter(prisma, {\r\n * allow: [\"department\", \"category\"],\r\n * });\r\n *\r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n *\r\n * This covers:\r\n * GET /api/department\r\n * POST /api/department\r\n * GET /api/department/5\r\n * PUT /api/department/5\r\n * PATCH /api/department/5\r\n * DELETE /api/department/5\r\n * PATCH /api/department/bulk/update\r\n * DELETE /api/department/bulk/delete\r\n */\r\nexport function nextjsAdapter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n) {\r\n const { handle } = createRouter(prisma, options);\r\n\r\n return async function handler(\r\n req: Request,\r\n context: { params: { prismaRest: string[] } }\r\n ): Promise<Response> {\r\n const segments = context.params.prismaRest ?? [];\r\n const [modelName, ...pathSegments] = segments;\r\n\r\n if (!modelName) {\r\n return Response.json(\r\n { error: \"No model specified in path.\" },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n const url = new URL(req.url);\r\n\r\n let body: any = {};\r\n if (req.method !== \"GET\" && req.method !== \"DELETE\") {\r\n try {\r\n body = await req.json();\r\n } catch {\r\n body = {};\r\n }\r\n }\r\n\r\n // Detect bulk operations\r\n let operation: string | undefined;\r\n let id: string | null = null;\r\n\r\n if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"update\") {\r\n operation = \"bulk-update\";\r\n } else if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"delete\") {\r\n operation = \"bulk-delete\";\r\n } else {\r\n id = pathSegments[0] ?? null;\r\n }\r\n\r\n const { status, data } = await handle(\r\n req.method,\r\n modelName,\r\n id,\r\n body,\r\n url.searchParams,\r\n operation\r\n );\r\n\r\n if (status === 204) {\r\n return new Response(null, { status: 204 });\r\n }\r\n\r\n return Response.json(data, { status });\r\n };\r\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../src/introspect.ts","../../src/query-builder.ts","../../src/middleware-helpers.ts","../../src/router.ts","../../src/adapters/nextjs.ts"],"names":["f","id"],"mappings":";;;;;;;;;;AAQO,SAAS,UAAU,MAAA,EAA2B;AACnD,EAAA,IAAI,GAAA;AAGJ,EAAA,IAAI,MAAA,EAAQ,mBAAmB,MAAA,EAAQ;AACrC,IAAA,MAAM,SAAA,GAAY,OAAO,iBAAA,CAAkB,MAAA;AAE3C,IAAA,GAAA,GAAM,MAAA,CAAO,QAAQ,SAAS,CAAA,CAAE,IAAI,CAAC,CAAC,IAAA,EAAM,KAAK,CAAA,MAAsB;AAAA,MACrE,IAAA;AAAA,MACA,GAAG,KAAA;AAAA,MACH,SAAS,KAAA,CAAM,MAAA,IAAU,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,MAAY;AAAA,QAC5C,GAAG,CAAA;AAAA,QACH,YAAA,EAAc,CAAA,CAAE,IAAA,KAAS,QAAA,GAAW,EAAE,IAAA,GAAO;AAAA,OAC/C,CAAE;AAAA,KACJ,CAAE,CAAA;AAAA,EACJ;AAKA,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,IAAI;AAEF,MAAA,MAAM,YAAA,GAAe,UAAQ,gBAAgB,CAAA;AAC7C,MAAA,MAAM,UAAA,GAAa,YAAA,EAAc,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW,MAAA;AAC1D,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,GAAA,GAAM,UAAA;AAAA,MACR;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mDAAmD,OAAO,GAAG,CAAA,yCAAA,EAA4C,CAAC,CAAC,MAAA,EAAQ,iBAAA,EAAmB,MAAM,CAAA,YAAA,EAAe,KAAK,SAAA,CAAU,GAAG,EAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA;AAAA,KAC9L;AAAA,EACF;AAEA,EAAA,OAAO,GAAA,CAAI,GAAA,CAAI,CAAC,KAAA,KAAe;AAC7B,IAAA,MAAM,MAAA,GAAsB,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAY;AAAA,MACxD,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,QAAQ,CAAA,CAAE,MAAA;AAAA,MACV,UAAA,EAAY,CAAC,CAAC,CAAA,CAAE,YAAA;AAAA,MAChB,iBAAiB,CAAC,CAAC,EAAE,eAAA,IAAmB,CAAC,CAAC,CAAA,CAAE,OAAA;AAAA,MAC5C,WAAA,EAAa,CAAC,CAAC,CAAA,CAAE;AAAA,KACnB,CAAE,CAAA;AAEF,IAAA,MAAM,OAAA,GACJ,MAAM,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAW,CAAA,CAAE,IAAI,CAAA,EAAG,IAAA,IAAQ,IAAA;AAEjD,IAAA,OAAO;AAAA,MACL,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,SAAA,EAAW,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA;AAAA,MACjC,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAOO,SAAS,YAAY,SAAA,EAA2B;AACrD,EAAA,OAAO,UAAU,WAAA,EAAY;AAC/B;AAKO,SAAS,aAAA,CACd,QACA,SAAA,EAC2B;AAC3B,EAAA,MAAM,QAAA,GAAW,SAAA,GACb,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,SAAA,CAAU,QAAA,CAAS,CAAA,CAAE,SAAS,CAAC,CAAA,GACpD,MAAA;AAEJ,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,SAAA,EAAW,CAAC,CAAC,CAAC,CAAA;AACjE;AAWO,SAAS,qBAAA,CACd,QACA,aAAA,EACiD;AACjD,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,MAAM,IAAI,MAAA,CAAO,IAAA,CAAK,CAACA,EAAAA,KAAMA,EAAAA,CAAE,SAAS,aAAa,CAAA;AACrD,IAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AAEf,IAAA,MAAM,QAAQ,CAAA,CAAE,IAAA,KAAS,SAAA,GAAY,KAAA,uBAAY,IAAA,EAAK;AACtD,IAAA,OAAO,EAAE,KAAA,EAAO,aAAA,EAAe,KAAA,EAAM;AAAA,EACvC;AAEA,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,WAAA,IAAe,CAAA,CAAE,IAAA,KAAS,UAAU,CAAA;AACpF,EAAA,IAAI,SAAA,SAAkB,EAAE,KAAA,EAAO,aAAa,KAAA,kBAAO,IAAI,MAAK,EAAE;AAE9D,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,UAAA,IAAc,CAAA,CAAE,IAAA,KAAS,SAAS,CAAA;AACjF,EAAA,IAAI,UAAU,OAAO,EAAE,KAAA,EAAO,UAAA,EAAY,OAAO,KAAA,EAAM;AAEvD,EAAA,OAAO,IAAA;AACT;AAMO,SAAS,WAAA,CAAY,QAAa,IAAA,EAAsB;AAG7D,EAAA,MAAM,GAAA,GACJ,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,GAAI,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACvD,EAAA,MAAM,QAAA,GAAW,OAAO,GAAG,CAAA;AAE3B,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,0CAAA,EAA6C,IAAA,CAAK,IAAI,CAAA,mBAAA,EACjC,GAAG,CAAA,UAAA;AAAA,KAC1B;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;;;AC1IA,IAAM,gBAAA,GAA2C;AAAA,EAC/C,IAAA,EAAM,KAAA;AAAA,EACN,IAAA,EAAM,KAAA;AAAA,EACN,GAAA,EAAK,IAAA;AAAA,EACL,GAAA,EAAK,IAAA;AAAA,EACL,SAAA,EAAW,UAAA;AAAA,EACX,UAAA,EAAY,UAAA;AAAA;AAAA,EACZ,WAAA,EAAa,YAAA;AAAA,EACb,SAAA,EAAW,UAAA;AAAA,EACX,GAAA,EAAK,IAAA;AAAA,EACL,MAAA,EAAQ,OAAA;AAAA,EACR,IAAA,EAAM;AACR,CAAA;AAKA,IAAM,aAAA,uBAAoB,GAAA,CAAI;AAAA,EAC5B,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAC,CAAA;AAaM,SAAS,WACd,YAAA,EACA,YAAA,GAAe,EAAA,EACf,QAAA,GAAW,KACX,WAAA,EACa;AACb,EAAA,MAAM,QAA6B,EAAC;AACpC,EAAA,MAAM,UAA0C,EAAC;AACjD,EAAA,IAAI,UAAmC,EAAC;AACxC,EAAA,IAAI,MAAA,GAAyC,IAAA;AAG7C,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,QAAA,CAAS,aAAa,GAAA,CAAI,MAAM,CAAA,IAAK,GAAG,CAAC,CAAA;AAClE,EAAA,MAAM,QAAA,GAAW,SAAS,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA,IAAK,MAAA,CAAO,YAAY,CAAC,CAAA;AAC3E,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,QAAQ,CAAA;AACxC,EAAA,MAAM,IAAA,GAAA,CAAQ,OAAO,CAAA,IAAK,IAAA;AAG1B,EAAA,MAAM,SAAA,GAAY,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACzC,EAAA,IAAI,SAAA,EAAW;AAEb,IAAA,KAAA,MAAW,IAAA,IAAQ,SAAA,CAAU,KAAA,CAAM,GAAG,CAAA,EAAG;AACvC,MAAA,MAAM,CAAC,OAAO,GAAG,CAAA,GAAI,KAAK,IAAA,EAAK,CAAE,MAAM,GAAG,CAAA;AAC1C,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,OAAA,CAAQ,KAAK,CAAA,GAAK,GAAA,KAAQ,MAAA,GAAS,MAAA,GAAS,KAAA;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,YAAA,GAAe,YAAA,CAAa,GAAA,CAAI,SAAS,CAAA;AAC/C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,KAAA,MAAW,GAAA,IAAO,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,EAAG;AACzC,MAAA,IAAI,IAAI,IAAA,EAAK,UAAW,GAAA,CAAI,IAAA,EAAM,CAAA,GAAI,IAAA;AAAA,IACxC;AAAA,EACF;AAGA,EAAA,MAAM,cAAc,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA,IAAK,YAAA,CAAa,IAAI,QAAQ,CAAA;AAC3E,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAA,GAAS,EAAC;AACV,IAAA,KAAA,MAAW,KAAA,IAAS,WAAA,CAAY,KAAA,CAAM,GAAG,CAAA,EAAG;AAC1C,MAAA,IAAI,MAAM,IAAA,EAAK,SAAU,KAAA,CAAM,IAAA,EAAM,CAAA,GAAI,IAAA;AAAA,IAC3C;AAAA,EACF;AAGA,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA;AAC7C,EAAA,IAAI,eAAe,WAAA,EAAa;AAC9B,IAAA,MAAM,eAAe,WAAA,CAAY,MAAA;AAAA,MAC/B,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,QAAA,IAAY,CAAC,CAAA,CAAE;AAAA,KACnC;AACA,IAAA,IAAI,YAAA,CAAa,SAAS,CAAA,EAAG;AAC3B,MAAA,MAAM,SAAA,GAAY,YAAA,CAAa,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACzC,CAAC,EAAE,IAAI,GAAG,EAAE,QAAA,EAAU,WAAA,EAAa,MAAM,aAAA;AAAc,OACzD,CAAE,CAAA;AAEF,MAAA,KAAA,CAAM,IAAI,CAAA,GAAI,SAAA;AAAA,IAChB;AAAA,EACF;AAGA,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,YAAA,CAAa,SAAQ,EAAG;AACjD,IAAA,IAAI,aAAA,CAAc,GAAA,CAAI,GAAG,CAAA,EAAG;AAG5B,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,gBAAgB,CAAA,CAAE,IAAA;AAAA,MAC9C,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,SAAS,CAAA,CAAE;AAAA,KACzB;AAEA,IAAA,KAAA,MAAW,UAAU,SAAA,EAAW;AAC9B,MAAA,IAAI,GAAA,CAAI,QAAA,CAAS,MAAM,CAAA,EAAG;AACxB,QAAA,MAAM,QAAQ,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAC,OAAO,MAAM,CAAA;AACzC,QAAA,MAAM,QAAA,GAAW,iBAAiB,MAAM,CAAA;AAExC,QAAA,IAAI,WAAA,GAAmB,KAAA;AAGvB,QAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,QAAA,KAAa,OAAA,EAAS;AAC7C,UAAA,WAAA,GAAc,KAAA,CAAM,MAAM,GAAG,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AAAA,QACpD;AAGA,QAAA,IAAI,CAAC,MAAM,MAAA,CAAO,WAAW,CAAC,CAAA,IAAK,OAAO,gBAAgB,QAAA,EAAU;AAClE,UAAA,WAAA,GAAc,OAAO,WAAW,CAAA;AAAA,QAClC;AAGA,QAAA,MAAM,QAAQ,MAAA,KAAW,YAAA,GAAe,EAAE,IAAA,EAAM,aAAA,KAAkB,EAAC;AAEnE,QAAA,KAAA,CAAM,KAAK,IAAI,EAAE,CAAC,QAAQ,GAAG,WAAA,EAAa,GAAG,KAAA,EAAM;AACnD,QAAA,OAAA,GAAU,IAAA;AACV,QAAA;AAAA,MACF;AAAA,IACF;AAGA,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,IAAI,WAAA,GAAmB,KAAA;AAGvB,MAAA,IAAI,KAAA,KAAU,QAAQ,WAAA,GAAc,IAAA;AAAA,WAAA,IAC3B,KAAA,KAAU,SAAS,WAAA,GAAc,KAAA;AAAA,WAAA,IAEjC,CAAC,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA,IAAK,UAAU,EAAA,EAAI;AAC9C,QAAA,WAAA,GAAc,OAAO,KAAK,CAAA;AAAA,MAC5B;AAEA,MAAA,KAAA,CAAM,GAAG,CAAA,GAAI,WAAA;AAAA,IACf;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,SAAS,MAAA,EAAO;AACvD;;;AC7JA,eAAsB,QAAA,CACpB,MAAA,EACA,KAAA,EACA,MAAA,EACA,GAAA,EACwB;AACxB,EAAA,MAAM,WAAA,GAAc,OAAO,KAAK,CAAA;AAChC,EAAA,IAAI,CAAC,aAAa,OAAO,IAAA;AAEzB,EAAA,MAAM,EAAA,GAAK,YAAY,MAAkC,CAAA;AACzD,EAAA,IAAI,CAAC,IAAI,OAAO,IAAA;AAEhB,EAAA,OAAO,EAAA,CAAG,EAAE,GAAG,GAAA,EAAK,QAAQ,CAAA;AAC9B;AAMA,eAAsB,OAAA,CACpB,MACA,GAAA,EACe;AACf,EAAA,IAAI,CAAC,IAAA,EAAM;AACX,EAAA,IAAI;AACF,IAAA,MAAM,KAAK,GAAG,CAAA;AAAA,EAChB,SAAS,CAAA,EAAG;AAEV,IAAA,OAAA,CAAQ,KAAA,CAAM,2BAA2B,CAAC,CAAA;AAAA,EAC5C;AACF;;;ACpBO,SAAS,YAAA,CACd,MAAA,EACA,OAAA,GAA6B,EAAC,EACd;AAChB,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,SAAS,EAAC;AAAA,IACV,eAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA,GAAe,EAAA;AAAA,IACf,QAAA,GAAW,GAAA;AAAA,IACX,UAAA,GAAa,KAAA;AAAA,IACb;AAAA,GACF,GAAI,OAAA;AAGJ,EAAA,MAAM,MAAA,GAAS,UAAU,MAAM,CAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,MAAA,EAAQ,KAAK,CAAA;AAE5C,EAAA,eAAe,OACb,MAAA,EACA,SAAA,EACA,EAAA,EACA,IAAA,EACA,cACA,SAAA,EACwB;AAExB,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,SAAA,CAAU,WAAA,EAAa,CAAA;AAC7C,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,GAAA;AAAA,QACR,IAAA,EAAM;AAAA,UACJ,KAAA,EAAO,UAAU,SAAS,CAAA,2BAAA,CAAA;AAAA,UAC1B,SAAA,EAAW,MAAA,CAAO,IAAA,CAAK,QAAQ;AAAA;AACjC,OACF;AAAA,IACF;AAGA,IAAA,MAAM,aAAa,MAAM,QAAA,CAAS,MAAA,EAAQ,IAAA,CAAK,WAAW,MAAA,EAAQ;AAAA,MAChE,EAAA;AAAA,MACA;AAAA,KACD,CAAA;AACD,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,YAAW,EAAE;AAAA,IACpD;AAGA,IAAA,MAAM,OAAA,CAAQ,iBAAiB,EAAE,KAAA,EAAO,KAAK,IAAA,EAAM,MAAA,EAAQ,EAAA,EAAI,IAAA,EAAM,CAAA;AAGrE,IAAA,IAAI,MAAA;AAEJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,MAAM,gBAAA;AAAA,QACb,MAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAA;AAAA,QACA,EAAA;AAAA,QACA,IAAA;AAAA,QACA,YAAA;AAAA,QACA,YAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,SAAS,CAAA,EAAQ;AACf,MAAA,OAAO,kBAAkB,CAAC,CAAA;AAAA,IAC5B;AAGA,IAAA,MAAM,QAAQ,cAAA,EAAgB;AAAA,MAC5B,OAAO,IAAA,CAAK,IAAA;AAAA,MACZ,MAAA;AAAA,MACA,EAAA;AAAA,MACA,IAAA;AAAA,MACA,QAAQ,MAAA,CAAO;AAAA,KAChB,CAAA;AAED,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,MAAA,EAAO;AACpC;AAIA,eAAe,gBAAA,CACb,MAAA,EACA,IAAA,EACA,MAAA,EACA,EAAA,EACA,IAAA,EACA,YAAA,EACA,YAAA,EACA,QAAA,EACA,SAAA,EACA,UAAA,GAAa,KAAA,EACb,eAAA,EACwB;AACxB,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,MAAA,EAAQ,IAAI,CAAA;AACzC,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,MAAM,IAAA,EAAM,OAAA,EAAS,QAAO,GAAI,UAAA;AAAA,IACtD,YAAA;AAAA,IACA,YAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA,CAAK;AAAA,GACP;AAGA,EAAA,MAAM,aACJ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,MAAA,GAAS,IAAI,OAAA,GAAU,MAAA;AAC9C,EAAA,MAAM,SAAA,GACJ,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,GAAS,IAAI,MAAA,GAAS,MAAA;AACtD,EAAA,MAAM,UAAA,GAAa,SAAA,GAAY,EAAE,MAAA,EAAQ,SAAA,EAAU,GAAI,UAAA,GAAa,EAAE,OAAA,EAAS,UAAA,EAAW,GAAI,EAAC;AAG/F,EAAA,IAAI,MAAA,KAAW,OAAA,IAAW,SAAA,KAAc,aAAA,EAAe;AACrD,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC7C,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,GAAA;AAAA,QACR,IAAA,EAAM,EAAE,KAAA,EAAO,0DAAA;AAA2D,OAC5E;AAAA,IACF;AAGA,IAAA,KAAA,MAAW,QAAQ,IAAA,EAAM;AACvB,MAAA,IAAI,CAAC,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,EAAG;AACvB,QAAA,OAAO;AAAA,UACL,MAAA,EAAQ,GAAA;AAAA,UACR,MAAM,EAAE,KAAA,EAAO,CAAA,yBAAA,EAA4B,IAAA,CAAK,OAAO,CAAA,MAAA,CAAA;AAAS,SAClE;AAAA,MACF;AAAA,IACF;AAGA,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA;AAAA,MAC5B,IAAA,CAAK,GAAA,CAAI,CAAC,IAAA,KAAS;AACjB,QAAA,MAAMC,GAAAA,GAAK,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA;AAC5B,QAAA,MAAM,UAAA,GAAa,EAAE,GAAG,IAAA,EAAK;AAC7B,QAAA,OAAO,UAAA,CAAW,KAAK,OAAO,CAAA;AAE9B,QAAA,OAAO,SAAS,MAAA,CAAO;AAAA,UACrB,KAAA,EAAO,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,QAAA,CAASA,GAAE,CAAA,EAAE;AAAA,UACtC,IAAA,EAAM,UAAA;AAAA,UACN,GAAG;AAAA,SACJ,CAAA;AAAA,MACH,CAAC;AAAA,KACH;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,GAAA;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,SAAS,OAAA,CAAQ,MAAA;AAAA,QACjB,OAAA,EAAS;AAAA;AACX,KACF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,KAAW,QAAA,IAAY,SAAA,KAAc,aAAA,EAAe;AACtD,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC7C,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,GAAA;AAAA,QACR,IAAA,EAAM,EAAE,KAAA,EAAO,+CAAA;AAAgD,OACjE;AAAA,IACF;AAGA,IAAA,MAAM,MAAM,IAAA,CAAK,GAAA;AAAA,MAAI,CAAC,SACpB,OAAO,IAAA,KAAS,WAAW,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,GAAI;AAAA,KAClD;AAGA,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,UAAA,CAAW;AAAA,MACvC,KAAA,EAAO;AAAA,QACL,CAAC,KAAK,OAAO,GAAG,EAAE,EAAA,EAAI,GAAA,CAAI,GAAA,CAAI,QAAQ,CAAA;AAAE;AAC1C,KACD,CAAA;AAED,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,GAAA;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,SAAS,MAAA,CAAO;AAAA;AAClB,KACF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,KAAW,KAAA,IAAS,CAAC,EAAA,EAAI;AAE3B,IAAA,MAAM,iBAAiB,UAAA,GACnB,qBAAA,CAAsB,IAAA,CAAK,MAAA,EAAQ,eAAe,CAAA,GAClD,IAAA;AACJ,IAAA,MAAM,SAAA,GAAY,cAAA,GACd,EAAE,GAAG,OAAO,CAAC,cAAA,CAAe,KAAK,GAAG,cAAA,CAAe,KAAA,KAAU,UAAA,GAAa,IAAA,GAAO,MAAK,GACtF,KAAA;AAEJ,IAAA,MAAM,CAAC,IAAA,EAAM,KAAK,CAAA,GAAI,MAAO,OAAe,YAAA,CAAa;AAAA,MACvD,QAAA,CAAS,QAAA,CAAS,EAAE,KAAA,EAAO,SAAA,EAAW,SAAS,IAAA,EAAM,IAAA,EAAM,GAAG,UAAA,EAAY,CAAA;AAAA,MAC1E,QAAA,CAAS,KAAA,CAAM,EAAE,KAAA,EAAO,WAAW;AAAA,KACpC,CAAA;AAED,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,GAAA;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,IAAA;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,KAAA;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,IAAI,CAAA,GAAI,CAAA;AAAA,UAChC,KAAA,EAAO,IAAA;AAAA,UACP,UAAA,EAAY,IAAA,CAAK,IAAA,CAAK,KAAA,GAAQ,IAAI;AAAA;AACpC;AACF,KACF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,KAAW,SAAS,EAAA,EAAI;AAC1B,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,UAAA,CAAW;AAAA,MACvC,KAAA,EAAO,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,QAAA,CAAS,EAAE,CAAA,EAAE;AAAA,MACtC,GAAG;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,EAAE,KAAA,EAAO,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,UAAA,EAAa,EAAE,CAAA,YAAA,CAAA,EAAe,EAAE;AAAA,IACnF;AAEA,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,MAAA,EAAO;AAAA,EACrC;AAGA,EAAA,IAAI,MAAA,KAAW,MAAA,IAAU,CAAC,EAAA,EAAI;AAC5B,IAAA,MAAM,SAAS,MAAM,QAAA,CAAS,OAAO,EAAE,IAAA,EAAM,MAAM,CAAA;AACnD,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,MAAA,EAAO;AAAA,EACrC;AAGA,EAAA,IAAA,CAAK,MAAA,KAAW,KAAA,IAAS,MAAA,KAAW,OAAA,KAAY,EAAA,EAAI;AAClD,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,MAAA,CAAO;AAAA,MACnC,KAAA,EAAO,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,QAAA,CAAS,EAAE,CAAA,EAAE;AAAA,MACtC,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,MAAA,EAAO;AAAA,EACrC;AAGA,EAAA,IAAI,MAAA,KAAW,YAAY,EAAA,EAAI;AAC7B,IAAA,MAAM,iBAAiB,UAAA,GACnB,qBAAA,CAAsB,IAAA,CAAK,MAAA,EAAQ,eAAe,CAAA,GAClD,IAAA;AAEJ,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,MAAA,CAAO;AAAA,QACnC,KAAA,EAAO,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,QAAA,CAAS,EAAE,CAAA,EAAE;AAAA,QACtC,MAAM,EAAE,CAAC,eAAe,KAAK,GAAG,eAAe,KAAA;AAAM,OACtD,CAAA;AACD,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,MAAA,EAAO;AAAA,IACrC;AAEA,IAAA,MAAM,SAAS,MAAA,CAAO;AAAA,MACpB,KAAA,EAAO,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,QAAA,CAAS,EAAE,CAAA;AAAE,KACvC,CAAA;AACD,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,IAAA,EAAK;AAAA,EACnC;AAEA,EAAA,OAAO,EAAE,QAAQ,GAAA,EAAK,IAAA,EAAM,EAAE,KAAA,EAAO,CAAA,OAAA,EAAU,MAAM,CAAA,aAAA,CAAA,EAAgB,EAAE;AACzE;AAOA,SAAS,SAAS,EAAA,EAA6B;AAC7C,EAAA,MAAM,CAAA,GAAI,OAAO,EAAE,CAAA;AACnB,EAAA,OAAO,KAAA,CAAM,CAAC,CAAA,GAAI,EAAA,GAAK,CAAA;AACzB;AAKA,SAAS,kBAAkB,CAAA,EAAuB;AAChD,EAAA,MAAM,OAAO,CAAA,EAAG,IAAA;AAEhB,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,qBAAoB,EAAE;AAAA,EAC7D;AACA,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,MAAM,MAAA,GAAS,CAAA,EAAG,IAAA,EAAM,MAAA,IAAU,gBAAA;AAClC,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,GAAA;AAAA,MACR,IAAA,EAAM,EAAE,KAAA,EAAO,CAAA,6BAAA,EAAgC,MAAM,CAAA,CAAA;AAAG,KAC1D;AAAA,EACF;AACA,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,kCAAiC,EAAE;AAAA,EAC1E;AACA,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,uBAAsB,EAAE;AAAA,EAC/D;AAEA,EAAA,OAAO,EAAE,QAAQ,GAAA,EAAK,IAAA,EAAM,EAAE,KAAA,EAAO,CAAA,EAAG,OAAA,IAAW,wBAAA,EAAyB,EAAE;AAChF;;;AC7RO,SAAS,aAAA,CACd,MAAA,EACA,OAAA,GAA6B,EAAC,EAC9B;AACA,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,YAAA,CAAa,QAAQ,OAAO,CAAA;AAE/C,EAAA,OAAO,eAAe,OAAA,CACpB,GAAA,EACA,OAAA,EACmB;AACnB,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAA,CAAO,UAAA,IAAc,EAAC;AAC/C,IAAA,MAAM,CAAC,SAAA,EAAW,GAAG,YAAY,CAAA,GAAI,QAAA;AAErC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,OAAO,6BAAA,EAA8B;AAAA,QACvC,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAE3B,IAAA,IAAI,OAAY,EAAC;AACjB,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,KAAA,IAAS,GAAA,CAAI,WAAW,QAAA,EAAU;AACnD,MAAA,IAAI;AACF,QAAA,IAAA,GAAO,MAAM,IAAI,IAAA,EAAK;AAAA,MACxB,CAAA,CAAA,MAAQ;AACN,QAAA,IAAA,GAAO,EAAC;AAAA,MACV;AAAA,IACF;AAGA,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI,EAAA,GAAoB,IAAA;AAExB,IAAA,IAAI,aAAa,CAAC,CAAA,KAAM,UAAU,YAAA,CAAa,CAAC,MAAM,QAAA,EAAU;AAC9D,MAAA,SAAA,GAAY,aAAA;AAAA,IACd,CAAA,MAAA,IAAW,aAAa,CAAC,CAAA,KAAM,UAAU,YAAA,CAAa,CAAC,MAAM,QAAA,EAAU;AACrE,MAAA,SAAA,GAAY,aAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,EAAA,GAAK,YAAA,CAAa,CAAC,CAAA,IAAK,IAAA;AAAA,IAC1B;AAEA,IAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAK,GAAI,MAAM,MAAA;AAAA,MAC7B,GAAA,CAAI,MAAA;AAAA,MACJ,SAAA;AAAA,MACA,EAAA;AAAA,MACA,IAAA;AAAA,MACA,GAAA,CAAI,YAAA;AAAA,MACJ;AAAA,KACF;AAEA,IAAA,IAAI,WAAW,GAAA,EAAK;AAClB,MAAA,OAAO,IAAI,QAAA,CAAS,IAAA,EAAM,EAAE,MAAA,EAAQ,KAAK,CAAA;AAAA,IAC3C;AAEA,IAAA,OAAO,QAAA,CAAS,IAAA,CAAK,IAAA,EAAM,EAAE,QAAQ,CAAA;AAAA,EACvC,CAAA;AACF","file":"nextjs.js","sourcesContent":["import type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Reads Prisma's DMMF (Data Model Meta Format) at runtime\r\n * and returns structured metadata for every model in your schema.\r\n *\r\n * No file reading. No code generation. Pure runtime introspection.\r\n */\r\nexport function getModels(prisma?: any): ModelMeta[] {\r\n let raw: any[] | undefined;\r\n\r\n // Try to get from PrismaClient instance first (new v5 format)\r\n if (prisma?._runtimeDataModel?.models) {\r\n const modelsObj = prisma._runtimeDataModel.models;\r\n // Convert object to array, adding name from key\r\n raw = Object.entries(modelsObj).map(([name, model]: [string, any]) => ({\r\n name,\r\n ...model,\r\n fields: (model.fields || []).map((f: any) => ({\r\n ...f,\r\n relationName: f.kind === \"object\" ? f.name : undefined,\r\n })),\r\n }));\r\n }\r\n\r\n // Fallback to DMMF from @prisma/client module — use plain require so\r\n // vi.mock(\"@prisma/client\") can intercept it in tests. The CLI handles\r\n // the global-install path resolution separately before calling getModels.\r\n if (!raw) {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const prismaModule = require(\"@prisma/client\");\r\n const dmmfModels = prismaModule?.Prisma?.dmmf?.datamodel?.models;\r\n if (dmmfModels) {\r\n raw = dmmfModels;\r\n }\r\n } catch {\r\n // @prisma/client not available or not generated — handled below\r\n }\r\n }\r\n\r\n if (!raw) {\r\n throw new Error(\r\n \"[omni-rest] Could not find Prisma DMMF. Ensure Prisma client is generated and you're passing a PrismaClient instance to omni-rest.\"\r\n );\r\n }\r\n\r\n if (!Array.isArray(raw)) {\r\n throw new Error(\r\n `[omni-rest] Expected models to be an array, got ${typeof raw}. Debug: prisma._runtimeDataModel.models=${!!prisma?._runtimeDataModel?.models}, raw value=${JSON.stringify(raw).slice(0, 100)}`\r\n );\r\n }\r\n\r\n return raw.map((model: any) => {\r\n const fields: FieldMeta[] = model.fields.map((f: any) => ({\r\n name: f.name,\r\n type: f.type,\r\n isId: f.isId,\r\n isRequired: f.isRequired,\r\n isList: f.isList,\r\n isRelation: !!f.relationName,\r\n hasDefaultValue: !!f.hasDefaultValue || !!f.default,\r\n isUpdatedAt: !!f.isUpdatedAt,\r\n }));\r\n\r\n const idField =\r\n model.fields.find((f: any) => f.isId)?.name ?? \"id\";\r\n\r\n return {\r\n name: model.name,\r\n routeName: toRouteName(model.name),\r\n fields,\r\n idField,\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Converts a Prisma model name to a URL-safe route segment.\r\n * \"UserProfile\" → \"userprofile\"\r\n * \"OrderItem\" → \"orderitem\"\r\n */\r\nexport function toRouteName(modelName: string): string {\r\n return modelName.toLowerCase();\r\n}\r\n\r\n/**\r\n * Returns a map of routeName → ModelMeta for O(1) lookups.\r\n */\r\nexport function buildModelMap(\r\n models: ModelMeta[],\r\n allowList?: string[]\r\n): Record<string, ModelMeta> {\r\n const filtered = allowList\r\n ? models.filter((m) => allowList.includes(m.routeName))\r\n : models;\r\n\r\n return Object.fromEntries(filtered.map((m) => [m.routeName, m]));\r\n}\r\n\r\n/**\r\n * Auto-detects the soft-delete field for a model.\r\n * Returns the field name and the value to set, or null if not found.\r\n *\r\n * Priority:\r\n * 1. Explicit `softDeleteField` option\r\n * 2. A field named \"deletedAt\" with type DateTime\r\n * 3. A field named \"isActive\" with type Boolean\r\n */\r\nexport function detectSoftDeleteField(\r\n fields: FieldMeta[],\r\n explicitField?: string\r\n): { field: string; value: Date | boolean } | null {\r\n if (explicitField) {\r\n const f = fields.find((f) => f.name === explicitField);\r\n if (!f) return null;\r\n // Infer value from type\r\n const value = f.type === \"Boolean\" ? false : new Date();\r\n return { field: explicitField, value };\r\n }\r\n\r\n const deletedAt = fields.find((f) => f.name === \"deletedAt\" && f.type === \"DateTime\");\r\n if (deletedAt) return { field: \"deletedAt\", value: new Date() };\r\n\r\n const isActive = fields.find((f) => f.name === \"isActive\" && f.type === \"Boolean\");\r\n if (isActive) return { field: \"isActive\", value: false };\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Gets the Prisma client delegate for a model.\r\n * prisma[\"userProfile\"] or prisma[\"user\"] — handles camelCase.\r\n */\r\nexport function getDelegate(prisma: any, meta: ModelMeta): any {\r\n // Prisma client properties are camelCase of model name\r\n // \"UserProfile\" → \"userProfile\"\r\n const key =\r\n meta.name.charAt(0).toLowerCase() + meta.name.slice(1);\r\n const delegate = prisma[key];\r\n\r\n if (!delegate) {\r\n throw new Error(\r\n `Could not find Prisma delegate for model \"${meta.name}\". ` +\r\n `Expected prisma.${key} to exist.`\r\n );\r\n }\r\n\r\n return delegate;\r\n}","import type { ParsedQuery, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Supported filter suffixes and their Prisma equivalents.\r\n *\r\n * Usage in URL:\r\n * ?name_contains=john\r\n * ?age_gte=18\r\n * ?status_in=active,inactive\r\n * ?email_not=test@test.com\r\n */\r\nconst FILTER_OPERATORS: Record<string, string> = {\r\n _gte: \"gte\",\r\n _lte: \"lte\",\r\n _gt: \"gt\",\r\n _lt: \"lt\",\r\n _contains: \"contains\",\r\n _icontains: \"contains\", // case-insensitive version (mode: insensitive)\r\n _startsWith: \"startsWith\",\r\n _endsWith: \"endsWith\",\r\n _in: \"in\",\r\n _notIn: \"notIn\",\r\n _not: \"not\",\r\n};\r\n\r\n/**\r\n * Reserved query keys — these are NOT treated as filters.\r\n */\r\nconst RESERVED_KEYS = new Set([\r\n \"page\",\r\n \"limit\",\r\n \"sort\",\r\n \"include\",\r\n \"select\",\r\n \"fields\",\r\n \"search\",\r\n]);\r\n\r\n/**\r\n * Parses URLSearchParams into a full Prisma query object.\r\n *\r\n * Supports:\r\n * Filtering → ?name=John ?age_gte=18 ?status_in=a,b\r\n * Sorting → ?sort=createdAt:desc or ?sort=name:asc\r\n * Pagination → ?page=2&limit=10\r\n * Relations → ?include=posts,profile\r\n * Fields → ?select=id,name,email or ?fields=id,name,email\r\n * Search → ?search=eng (queries all String fields with OR)\r\n */\r\nexport function buildQuery(\r\n searchParams: URLSearchParams,\r\n defaultLimit = 20,\r\n maxLimit = 100,\r\n modelFields?: FieldMeta[]\r\n): ParsedQuery {\r\n const where: Record<string, any> = {};\r\n const orderBy: Record<string, \"asc\" | \"desc\"> = {};\r\n let include: Record<string, boolean> = {};\r\n let select: Record<string, boolean> | null = null;\r\n\r\n // ─── Pagination ────────────────────────────────────────────────────────────\r\n const page = Math.max(1, parseInt(searchParams.get(\"page\") ?? \"1\"));\r\n const rawLimit = parseInt(searchParams.get(\"limit\") ?? String(defaultLimit));\r\n const take = Math.min(rawLimit, maxLimit);\r\n const skip = (page - 1) * take;\r\n\r\n // ─── Sort ──────────────────────────────────────────────────────────────────\r\n const sortParam = searchParams.get(\"sort\");\r\n if (sortParam) {\r\n // Supports multiple sorts: ?sort=name:asc,createdAt:desc\r\n for (const part of sortParam.split(\",\")) {\r\n const [field, dir] = part.trim().split(\":\");\r\n if (field) {\r\n orderBy[field] = (dir === \"desc\" ? \"desc\" : \"asc\");\r\n }\r\n }\r\n }\r\n\r\n // ─── Include (relations) ───────────────────────────────────────────────────\r\n const includeParam = searchParams.get(\"include\");\r\n if (includeParam) {\r\n for (const rel of includeParam.split(\",\")) {\r\n if (rel.trim()) include[rel.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Select (fields) — ?select= or ?fields= alias ────────────────────────\r\n const selectParam = searchParams.get(\"select\") ?? searchParams.get(\"fields\");\r\n if (selectParam) {\r\n select = {};\r\n for (const field of selectParam.split(\",\")) {\r\n if (field.trim()) select[field.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Global search (?search=) ─────────────────────────────────────────────\r\n const searchValue = searchParams.get(\"search\");\r\n if (searchValue && modelFields) {\r\n const stringFields = modelFields.filter(\r\n (f) => f.type === \"String\" && !f.isRelation\r\n );\r\n if (stringFields.length > 0) {\r\n const orClauses = stringFields.map((f) => ({\r\n [f.name]: { contains: searchValue, mode: \"insensitive\" },\r\n }));\r\n // Merge with any existing where via AND so other filters still apply\r\n where[\"OR\"] = orClauses;\r\n }\r\n }\r\n\r\n // ─── Filters ───────────────────────────────────────────────────────────────\r\n for (const [key, value] of searchParams.entries()) {\r\n if (RESERVED_KEYS.has(key)) continue;\r\n\r\n // Check operator suffixes (longest match first)\r\n let matched = false;\r\n const sortedOps = Object.keys(FILTER_OPERATORS).sort(\r\n (a, b) => b.length - a.length\r\n );\r\n\r\n for (const suffix of sortedOps) {\r\n if (key.endsWith(suffix)) {\r\n const field = key.slice(0, -suffix.length);\r\n const prismaOp = FILTER_OPERATORS[suffix];\r\n\r\n let parsedValue: any = value;\r\n\r\n // Parse arrays\r\n if (prismaOp === \"in\" || prismaOp === \"notIn\") {\r\n parsedValue = value.split(\",\").map((v) => v.trim());\r\n }\r\n\r\n // Attempt numeric coercion\r\n if (!isNaN(Number(parsedValue)) && typeof parsedValue === \"string\") {\r\n parsedValue = Number(parsedValue);\r\n }\r\n\r\n // Case-insensitive flag\r\n const extra = suffix === \"_icontains\" ? { mode: \"insensitive\" } : {};\r\n\r\n where[field] = { [prismaOp]: parsedValue, ...extra };\r\n matched = true;\r\n break;\r\n }\r\n }\r\n\r\n // No operator — exact match\r\n if (!matched) {\r\n let parsedValue: any = value;\r\n\r\n // Coerce booleans\r\n if (value === \"true\") parsedValue = true;\r\n else if (value === \"false\") parsedValue = false;\r\n // Coerce numbers\r\n else if (!isNaN(Number(value)) && value !== \"\") {\r\n parsedValue = Number(value);\r\n }\r\n\r\n where[key] = parsedValue;\r\n }\r\n }\r\n\r\n return { where, orderBy, skip, take, include, select };\r\n}","import type { GuardMap, HookFn, HookContext } from \"./types\";\r\n\r\n/**\r\n * Runs the guard for the given model+method combo.\r\n * Returns an error string if blocked, null if allowed.\r\n */\r\nexport async function runGuard(\r\n guards: GuardMap,\r\n model: string,\r\n method: string,\r\n ctx: { id?: string | null; body?: any }\r\n): Promise<string | null> {\r\n const modelGuards = guards[model];\r\n if (!modelGuards) return null;\r\n\r\n const fn = modelGuards[method as keyof typeof modelGuards];\r\n if (!fn) return null;\r\n\r\n return fn({ ...ctx, method });\r\n}\r\n\r\n/**\r\n * Runs a lifecycle hook (beforeOperation / afterOperation).\r\n * Silently swallows errors so hooks never crash the main flow.\r\n */\r\nexport async function runHook(\r\n hook: HookFn | undefined,\r\n ctx: HookContext\r\n): Promise<void> {\r\n if (!hook) return;\r\n try {\r\n await hook(ctx);\r\n } catch (e) {\r\n // Hooks should not crash the request\r\n console.error(\"[omni-rest] Hook error:\", e);\r\n }\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { getModels, buildModelMap, getDelegate, detectSoftDeleteField } from \"./introspect\";\r\nimport { buildQuery } from \"./query-builder\";\r\nimport { runGuard, runHook } from \"./middleware-helpers\";\r\nimport type {\r\n PrismaRestOptions,\r\n HandlerResult,\r\n RouterInstance,\r\n ModelMeta,\r\n} from \"./types\";\r\n\r\n/**\r\n * Creates a framework-agnostic CRUD router powered by Prisma DMMF.\r\n *\r\n * All adapters (Express, Next.js, Fastify) use this under the hood.\r\n */\r\nexport function createRouter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n): RouterInstance {\r\n const {\r\n allow,\r\n guards = {},\r\n beforeOperation,\r\n afterOperation,\r\n defaultLimit = 20,\r\n maxLimit = 100,\r\n softDelete = false,\r\n softDeleteField,\r\n } = options;\r\n\r\n // Introspect schema once at startup\r\n const models = getModels(prisma);\r\n const modelMap = buildModelMap(models, allow);\r\n\r\n async function handle(\r\n method: string,\r\n modelName: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n operation?: string\r\n ): Promise<HandlerResult> {\r\n // ── 1. Resolve model ───────────────────────────────────────────────────\r\n const meta = modelMap[modelName.toLowerCase()];\r\n if (!meta) {\r\n return {\r\n status: 404,\r\n data: {\r\n error: `Model \"${modelName}\" not found or not exposed.`,\r\n available: Object.keys(modelMap),\r\n },\r\n };\r\n }\r\n\r\n // ── 2. Guard check ─────────────────────────────────────────────────────\r\n const guardError = await runGuard(guards, meta.routeName, method, {\r\n id,\r\n body,\r\n });\r\n if (guardError) {\r\n return { status: 403, data: { error: guardError } };\r\n }\r\n\r\n // ── 3. Before hook ─────────────────────────────────────────────────────\r\n await runHook(beforeOperation, { model: meta.name, method, id, body });\r\n\r\n // ── 4. Execute operation ───────────────────────────────────────────────\r\n let result: HandlerResult;\r\n\r\n try {\r\n result = await executeOperation(\r\n prisma,\r\n meta,\r\n method,\r\n id,\r\n body,\r\n searchParams,\r\n defaultLimit,\r\n maxLimit,\r\n operation,\r\n softDelete,\r\n softDeleteField\r\n );\r\n } catch (e: any) {\r\n return handlePrismaError(e);\r\n }\r\n\r\n // ── 5. After hook ──────────────────────────────────────────────────────\r\n await runHook(afterOperation, {\r\n model: meta.name,\r\n method,\r\n id,\r\n body,\r\n result: result.data,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n return { handle, modelMap, models };\r\n}\r\n\r\n// ─── Operation executor ────────────────────────────────────────────────────────\r\n\r\nasync function executeOperation(\r\n prisma: PrismaClient,\r\n meta: ModelMeta,\r\n method: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n defaultLimit: number,\r\n maxLimit: number,\r\n operation?: string,\r\n softDelete = false,\r\n softDeleteField?: string\r\n): Promise<HandlerResult> {\r\n const delegate = getDelegate(prisma, meta);\r\n const { where, orderBy, skip, take, include, select } = buildQuery(\r\n searchParams,\r\n defaultLimit,\r\n maxLimit,\r\n meta.fields\r\n );\r\n\r\n // Build include/select args (mutually exclusive in Prisma)\r\n const includeArg =\r\n Object.keys(include).length > 0 ? include : undefined;\r\n const selectArg =\r\n select && Object.keys(select).length > 0 ? select : undefined;\r\n const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};\r\n\r\n // ── PATCH /model/bulk/update ────────────────────────────────────────────────\r\n if (method === \"PATCH\" && operation === \"bulk-update\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of update records\" },\r\n };\r\n }\r\n\r\n // Validate that each item has an id\r\n for (const item of body) {\r\n if (!item[meta.idField]) {\r\n return {\r\n status: 400,\r\n data: { error: `Each record must have an ${meta.idField} field` },\r\n };\r\n }\r\n }\r\n\r\n // Execute updates in parallel\r\n const results = await Promise.all(\r\n body.map((item) => {\r\n const id = item[meta.idField];\r\n const updateData = { ...item };\r\n delete updateData[meta.idField]; // Remove id from update data\r\n\r\n return delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: updateData,\r\n ...projection,\r\n });\r\n })\r\n );\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n updated: results.length,\r\n records: results,\r\n },\r\n };\r\n }\r\n\r\n // ── DELETE /model/bulk/delete ──────────────────────────────────────────────\r\n if (method === \"DELETE\" && operation === \"bulk-delete\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of IDs\" },\r\n };\r\n }\r\n\r\n // Handle both array of IDs and array of objects with id field\r\n const ids = body.map((item: any) =>\r\n typeof item === \"object\" ? item[meta.idField] : item\r\n );\r\n\r\n // Use deleteMany with a where clause\r\n const result = await delegate.deleteMany({\r\n where: {\r\n [meta.idField]: { in: ids.map(coerceId) },\r\n },\r\n });\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n deleted: result.count,\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model ─────────────────────────────────────────────────────────────\r\n if (method === \"GET\" && !id) {\r\n // Exclude soft-deleted records from list when soft delete is active\r\n const softDeleteInfo = softDelete\r\n ? detectSoftDeleteField(meta.fields, softDeleteField)\r\n : null;\r\n const listWhere = softDeleteInfo\r\n ? { ...where, [softDeleteInfo.field]: softDeleteInfo.field === \"isActive\" ? true : null }\r\n : where;\r\n\r\n const [data, total] = await (prisma as any).$transaction([\r\n delegate.findMany({ where: listWhere, orderBy, skip, take, ...projection }),\r\n delegate.count({ where: listWhere }),\r\n ]);\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n data,\r\n meta: {\r\n total,\r\n page: Math.floor(skip / take) + 1,\r\n limit: take,\r\n totalPages: Math.ceil(total / take),\r\n },\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model/:id ─────────────────────────────────────────────────────────\r\n if (method === \"GET\" && id) {\r\n const record = await delegate.findUnique({\r\n where: { [meta.idField]: coerceId(id) },\r\n ...projection,\r\n });\r\n\r\n if (!record) {\r\n return { status: 404, data: { error: `${meta.name} with id \"${id}\" not found.` } };\r\n }\r\n\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── POST /model ────────────────────────────────────────────────────────────\r\n if (method === \"POST\" && !id) {\r\n const record = await delegate.create({ data: body });\r\n return { status: 201, data: record };\r\n }\r\n\r\n // ── PUT /model/:id ─────────────────────────────────────────────────────────\r\n if ((method === \"PUT\" || method === \"PATCH\") && id) {\r\n const record = await delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: body,\r\n });\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── DELETE /model/:id ──────────────────────────────────────────────────────\r\n if (method === \"DELETE\" && id) {\r\n const softDeleteInfo = softDelete\r\n ? detectSoftDeleteField(meta.fields, softDeleteField)\r\n : null;\r\n\r\n if (softDeleteInfo) {\r\n const record = await delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: { [softDeleteInfo.field]: softDeleteInfo.value },\r\n });\r\n return { status: 200, data: record };\r\n }\r\n\r\n await delegate.delete({\r\n where: { [meta.idField]: coerceId(id) },\r\n });\r\n return { status: 204, data: null };\r\n }\r\n\r\n return { status: 405, data: { error: `Method ${method} not allowed.` } };\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Coerces an ID string to number when possible (common with Int PKs).\r\n */\r\nfunction coerceId(id: string): string | number {\r\n const n = Number(id);\r\n return isNaN(n) ? id : n;\r\n}\r\n\r\n/**\r\n * Maps Prisma error codes to meaningful HTTP responses.\r\n */\r\nfunction handlePrismaError(e: any): HandlerResult {\r\n const code = e?.code;\r\n\r\n if (code === \"P2025\") {\r\n return { status: 404, data: { error: \"Record not found.\" } };\r\n }\r\n if (code === \"P2002\") {\r\n const fields = e?.meta?.target ?? \"unknown fields\";\r\n return {\r\n status: 409,\r\n data: { error: `Unique constraint failed on: ${fields}` },\r\n };\r\n }\r\n if (code === \"P2003\") {\r\n return { status: 400, data: { error: \"Foreign key constraint failed.\" } };\r\n }\r\n if (code === \"P2014\") {\r\n return { status: 400, data: { error: \"Relation violation.\" } };\r\n }\r\n\r\n return { status: 500, data: { error: e?.message ?? \"Internal server error.\" } };\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { createRouter } from \"../router\";\r\nimport type { PrismaRestOptions } from \"../types\";\r\n\r\n/**\r\n * Next.js App Router adapter for omni-rest.\r\n *\r\n * @example\r\n * ```ts\r\n * // app/api/[...prismaRest]/route.ts\r\n * import { PrismaClient } from \"@prisma/client\";\r\n * import { nextjsAdapter } from \"omni-rest/nextjs\";\r\n *\r\n * const prisma = new PrismaClient();\r\n * const handler = nextjsAdapter(prisma, {\r\n * allow: [\"department\", \"category\"],\r\n * });\r\n *\r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n *\r\n * This covers:\r\n * GET /api/department\r\n * POST /api/department\r\n * GET /api/department/5\r\n * PUT /api/department/5\r\n * PATCH /api/department/5\r\n * DELETE /api/department/5\r\n * PATCH /api/department/bulk/update\r\n * DELETE /api/department/bulk/delete\r\n */\r\nexport function nextjsAdapter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n) {\r\n const { handle } = createRouter(prisma, options);\r\n\r\n return async function handler(\r\n req: Request,\r\n context: { params: { prismaRest: string[] } }\r\n ): Promise<Response> {\r\n const segments = context.params.prismaRest ?? [];\r\n const [modelName, ...pathSegments] = segments;\r\n\r\n if (!modelName) {\r\n return Response.json(\r\n { error: \"No model specified in path.\" },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n const url = new URL(req.url);\r\n\r\n let body: any = {};\r\n if (req.method !== \"GET\" && req.method !== \"DELETE\") {\r\n try {\r\n body = await req.json();\r\n } catch {\r\n body = {};\r\n }\r\n }\r\n\r\n // Detect bulk operations\r\n let operation: string | undefined;\r\n let id: string | null = null;\r\n\r\n if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"update\") {\r\n operation = \"bulk-update\";\r\n } else if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"delete\") {\r\n operation = \"bulk-delete\";\r\n } else {\r\n id = pathSegments[0] ?? null;\r\n }\r\n\r\n const { status, data } = await handle(\r\n req.method,\r\n modelName,\r\n id,\r\n body,\r\n url.searchParams,\r\n operation\r\n );\r\n\r\n if (status === 204) {\r\n return new Response(null, { status: 204 });\r\n }\r\n\r\n return Response.json(data, { status });\r\n };\r\n}"]}
|
package/dist/adapters/nextjs.mjs
CHANGED
|
@@ -66,6 +66,19 @@ function buildModelMap(models, allowList) {
|
|
|
66
66
|
const filtered = allowList ? models.filter((m) => allowList.includes(m.routeName)) : models;
|
|
67
67
|
return Object.fromEntries(filtered.map((m) => [m.routeName, m]));
|
|
68
68
|
}
|
|
69
|
+
function detectSoftDeleteField(fields, explicitField) {
|
|
70
|
+
if (explicitField) {
|
|
71
|
+
const f = fields.find((f2) => f2.name === explicitField);
|
|
72
|
+
if (!f) return null;
|
|
73
|
+
const value = f.type === "Boolean" ? false : /* @__PURE__ */ new Date();
|
|
74
|
+
return { field: explicitField, value };
|
|
75
|
+
}
|
|
76
|
+
const deletedAt = fields.find((f) => f.name === "deletedAt" && f.type === "DateTime");
|
|
77
|
+
if (deletedAt) return { field: "deletedAt", value: /* @__PURE__ */ new Date() };
|
|
78
|
+
const isActive = fields.find((f) => f.name === "isActive" && f.type === "Boolean");
|
|
79
|
+
if (isActive) return { field: "isActive", value: false };
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
69
82
|
function getDelegate(prisma, meta) {
|
|
70
83
|
const key = meta.name.charAt(0).toLowerCase() + meta.name.slice(1);
|
|
71
84
|
const delegate = prisma[key];
|
|
@@ -97,9 +110,11 @@ var RESERVED_KEYS = /* @__PURE__ */ new Set([
|
|
|
97
110
|
"limit",
|
|
98
111
|
"sort",
|
|
99
112
|
"include",
|
|
100
|
-
"select"
|
|
113
|
+
"select",
|
|
114
|
+
"fields",
|
|
115
|
+
"search"
|
|
101
116
|
]);
|
|
102
|
-
function buildQuery(searchParams, defaultLimit = 20, maxLimit = 100) {
|
|
117
|
+
function buildQuery(searchParams, defaultLimit = 20, maxLimit = 100, modelFields) {
|
|
103
118
|
const where = {};
|
|
104
119
|
const orderBy = {};
|
|
105
120
|
let include = {};
|
|
@@ -123,13 +138,25 @@ function buildQuery(searchParams, defaultLimit = 20, maxLimit = 100) {
|
|
|
123
138
|
if (rel.trim()) include[rel.trim()] = true;
|
|
124
139
|
}
|
|
125
140
|
}
|
|
126
|
-
const selectParam = searchParams.get("select");
|
|
141
|
+
const selectParam = searchParams.get("select") ?? searchParams.get("fields");
|
|
127
142
|
if (selectParam) {
|
|
128
143
|
select = {};
|
|
129
144
|
for (const field of selectParam.split(",")) {
|
|
130
145
|
if (field.trim()) select[field.trim()] = true;
|
|
131
146
|
}
|
|
132
147
|
}
|
|
148
|
+
const searchValue = searchParams.get("search");
|
|
149
|
+
if (searchValue && modelFields) {
|
|
150
|
+
const stringFields = modelFields.filter(
|
|
151
|
+
(f) => f.type === "String" && !f.isRelation
|
|
152
|
+
);
|
|
153
|
+
if (stringFields.length > 0) {
|
|
154
|
+
const orClauses = stringFields.map((f) => ({
|
|
155
|
+
[f.name]: { contains: searchValue, mode: "insensitive" }
|
|
156
|
+
}));
|
|
157
|
+
where["OR"] = orClauses;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
133
160
|
for (const [key, value] of searchParams.entries()) {
|
|
134
161
|
if (RESERVED_KEYS.has(key)) continue;
|
|
135
162
|
let matched = false;
|
|
@@ -191,7 +218,9 @@ function createRouter(prisma, options = {}) {
|
|
|
191
218
|
beforeOperation,
|
|
192
219
|
afterOperation,
|
|
193
220
|
defaultLimit = 20,
|
|
194
|
-
maxLimit = 100
|
|
221
|
+
maxLimit = 100,
|
|
222
|
+
softDelete = false,
|
|
223
|
+
softDeleteField
|
|
195
224
|
} = options;
|
|
196
225
|
const models = getModels(prisma);
|
|
197
226
|
const modelMap = buildModelMap(models, allow);
|
|
@@ -225,7 +254,9 @@ function createRouter(prisma, options = {}) {
|
|
|
225
254
|
searchParams,
|
|
226
255
|
defaultLimit,
|
|
227
256
|
maxLimit,
|
|
228
|
-
operation
|
|
257
|
+
operation,
|
|
258
|
+
softDelete,
|
|
259
|
+
softDeleteField
|
|
229
260
|
);
|
|
230
261
|
} catch (e) {
|
|
231
262
|
return handlePrismaError(e);
|
|
@@ -241,12 +272,13 @@ function createRouter(prisma, options = {}) {
|
|
|
241
272
|
}
|
|
242
273
|
return { handle, modelMap, models };
|
|
243
274
|
}
|
|
244
|
-
async function executeOperation(prisma, meta, method, id, body, searchParams, defaultLimit, maxLimit, operation) {
|
|
275
|
+
async function executeOperation(prisma, meta, method, id, body, searchParams, defaultLimit, maxLimit, operation, softDelete = false, softDeleteField) {
|
|
245
276
|
const delegate = getDelegate(prisma, meta);
|
|
246
277
|
const { where, orderBy, skip, take, include, select } = buildQuery(
|
|
247
278
|
searchParams,
|
|
248
279
|
defaultLimit,
|
|
249
|
-
maxLimit
|
|
280
|
+
maxLimit,
|
|
281
|
+
meta.fields
|
|
250
282
|
);
|
|
251
283
|
const includeArg = Object.keys(include).length > 0 ? include : void 0;
|
|
252
284
|
const selectArg = select && Object.keys(select).length > 0 ? select : void 0;
|
|
@@ -309,9 +341,11 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
|
|
|
309
341
|
};
|
|
310
342
|
}
|
|
311
343
|
if (method === "GET" && !id) {
|
|
344
|
+
const softDeleteInfo = softDelete ? detectSoftDeleteField(meta.fields, softDeleteField) : null;
|
|
345
|
+
const listWhere = softDeleteInfo ? { ...where, [softDeleteInfo.field]: softDeleteInfo.field === "isActive" ? true : null } : where;
|
|
312
346
|
const [data, total] = await prisma.$transaction([
|
|
313
|
-
delegate.findMany({ where, orderBy, skip, take, ...projection }),
|
|
314
|
-
delegate.count({ where })
|
|
347
|
+
delegate.findMany({ where: listWhere, orderBy, skip, take, ...projection }),
|
|
348
|
+
delegate.count({ where: listWhere })
|
|
315
349
|
]);
|
|
316
350
|
return {
|
|
317
351
|
status: 200,
|
|
@@ -348,6 +382,14 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
|
|
|
348
382
|
return { status: 200, data: record };
|
|
349
383
|
}
|
|
350
384
|
if (method === "DELETE" && id) {
|
|
385
|
+
const softDeleteInfo = softDelete ? detectSoftDeleteField(meta.fields, softDeleteField) : null;
|
|
386
|
+
if (softDeleteInfo) {
|
|
387
|
+
const record = await delegate.update({
|
|
388
|
+
where: { [meta.idField]: coerceId(id) },
|
|
389
|
+
data: { [softDeleteInfo.field]: softDeleteInfo.value }
|
|
390
|
+
});
|
|
391
|
+
return { status: 200, data: record };
|
|
392
|
+
}
|
|
351
393
|
await delegate.delete({
|
|
352
394
|
where: { [meta.idField]: coerceId(id) }
|
|
353
395
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/introspect.ts","../../src/query-builder.ts","../../src/middleware-helpers.ts","../../src/router.ts","../../src/adapters/nextjs.ts"],"names":["id"],"mappings":"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","file":"nextjs.mjs","sourcesContent":["import type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Reads Prisma's DMMF (Data Model Meta Format) at runtime\r\n * and returns structured metadata for every model in your schema.\r\n *\r\n * No file reading. No code generation. Pure runtime introspection.\r\n */\r\nexport function getModels(prisma?: any): ModelMeta[] {\r\n let raw: any[] | undefined;\r\n\r\n // Try to get from PrismaClient instance first (new v5 format)\r\n if (prisma?._runtimeDataModel?.models) {\r\n const modelsObj = prisma._runtimeDataModel.models;\r\n // Convert object to array, adding name from key\r\n raw = Object.entries(modelsObj).map(([name, model]: [string, any]) => ({\r\n name,\r\n ...model,\r\n fields: (model.fields || []).map((f: any) => ({\r\n ...f,\r\n relationName: f.kind === \"object\" ? f.name : undefined,\r\n })),\r\n }));\r\n }\r\n\r\n // Fallback to DMMF from @prisma/client module — use plain require so\r\n // vi.mock(\"@prisma/client\") can intercept it in tests. The CLI handles\r\n // the global-install path resolution separately before calling getModels.\r\n if (!raw) {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const prismaModule = require(\"@prisma/client\");\r\n const dmmfModels = prismaModule?.Prisma?.dmmf?.datamodel?.models;\r\n if (dmmfModels) {\r\n raw = dmmfModels;\r\n }\r\n } catch {\r\n // @prisma/client not available or not generated — handled below\r\n }\r\n }\r\n\r\n if (!raw) {\r\n throw new Error(\r\n \"[omni-rest] Could not find Prisma DMMF. Ensure Prisma client is generated and you're passing a PrismaClient instance to omni-rest.\"\r\n );\r\n }\r\n\r\n if (!Array.isArray(raw)) {\r\n throw new Error(\r\n `[omni-rest] Expected models to be an array, got ${typeof raw}. Debug: prisma._runtimeDataModel.models=${!!prisma?._runtimeDataModel?.models}, raw value=${JSON.stringify(raw).slice(0, 100)}`\r\n );\r\n }\r\n\r\n return raw.map((model: any) => {\r\n const fields: FieldMeta[] = model.fields.map((f: any) => ({\r\n name: f.name,\r\n type: f.type,\r\n isId: f.isId,\r\n isRequired: f.isRequired,\r\n isList: f.isList,\r\n isRelation: !!f.relationName,\r\n hasDefaultValue: !!f.hasDefaultValue || !!f.default,\r\n isUpdatedAt: !!f.isUpdatedAt,\r\n }));\r\n\r\n const idField =\r\n model.fields.find((f: any) => f.isId)?.name ?? \"id\";\r\n\r\n return {\r\n name: model.name,\r\n routeName: toRouteName(model.name),\r\n fields,\r\n idField,\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Converts a Prisma model name to a URL-safe route segment.\r\n * \"UserProfile\" → \"userprofile\"\r\n * \"OrderItem\" → \"orderitem\"\r\n */\r\nexport function toRouteName(modelName: string): string {\r\n return modelName.toLowerCase();\r\n}\r\n\r\n/**\r\n * Returns a map of routeName → ModelMeta for O(1) lookups.\r\n */\r\nexport function buildModelMap(\r\n models: ModelMeta[],\r\n allowList?: string[]\r\n): Record<string, ModelMeta> {\r\n const filtered = allowList\r\n ? models.filter((m) => allowList.includes(m.routeName))\r\n : models;\r\n\r\n return Object.fromEntries(filtered.map((m) => [m.routeName, m]));\r\n}\r\n\r\n/**\r\n * Gets the Prisma client delegate for a model.\r\n * prisma[\"userProfile\"] or prisma[\"user\"] — handles camelCase.\r\n */\r\nexport function getDelegate(prisma: any, meta: ModelMeta): any {\r\n // Prisma client properties are camelCase of model name\r\n // \"UserProfile\" → \"userProfile\"\r\n const key =\r\n meta.name.charAt(0).toLowerCase() + meta.name.slice(1);\r\n const delegate = prisma[key];\r\n\r\n if (!delegate) {\r\n throw new Error(\r\n `Could not find Prisma delegate for model \"${meta.name}\". ` +\r\n `Expected prisma.${key} to exist.`\r\n );\r\n }\r\n\r\n return delegate;\r\n}","import type { ParsedQuery } from \"./types\";\r\n\r\n/**\r\n * Supported filter suffixes and their Prisma equivalents.\r\n *\r\n * Usage in URL:\r\n * ?name_contains=john\r\n * ?age_gte=18\r\n * ?status_in=active,inactive\r\n * ?email_not=test@test.com\r\n */\r\nconst FILTER_OPERATORS: Record<string, string> = {\r\n _gte: \"gte\",\r\n _lte: \"lte\",\r\n _gt: \"gt\",\r\n _lt: \"lt\",\r\n _contains: \"contains\",\r\n _icontains: \"contains\", // case-insensitive version (mode: insensitive)\r\n _startsWith: \"startsWith\",\r\n _endsWith: \"endsWith\",\r\n _in: \"in\",\r\n _notIn: \"notIn\",\r\n _not: \"not\",\r\n};\r\n\r\n/**\r\n * Reserved query keys — these are NOT treated as filters.\r\n */\r\nconst RESERVED_KEYS = new Set([\r\n \"page\",\r\n \"limit\",\r\n \"sort\",\r\n \"include\",\r\n \"select\",\r\n]);\r\n\r\n/**\r\n * Parses URLSearchParams into a full Prisma query object.\r\n *\r\n * Supports:\r\n * Filtering → ?name=John ?age_gte=18 ?status_in=a,b\r\n * Sorting → ?sort=createdAt:desc or ?sort=name:asc\r\n * Pagination → ?page=2&limit=10\r\n * Relations → ?include=posts,profile\r\n * Fields → ?select=id,name,email\r\n */\r\nexport function buildQuery(\r\n searchParams: URLSearchParams,\r\n defaultLimit = 20,\r\n maxLimit = 100\r\n): ParsedQuery {\r\n const where: Record<string, any> = {};\r\n const orderBy: Record<string, \"asc\" | \"desc\"> = {};\r\n let include: Record<string, boolean> = {};\r\n let select: Record<string, boolean> | null = null;\r\n\r\n // ─── Pagination ────────────────────────────────────────────────────────────\r\n const page = Math.max(1, parseInt(searchParams.get(\"page\") ?? \"1\"));\r\n const rawLimit = parseInt(searchParams.get(\"limit\") ?? String(defaultLimit));\r\n const take = Math.min(rawLimit, maxLimit);\r\n const skip = (page - 1) * take;\r\n\r\n // ─── Sort ──────────────────────────────────────────────────────────────────\r\n const sortParam = searchParams.get(\"sort\");\r\n if (sortParam) {\r\n // Supports multiple sorts: ?sort=name:asc,createdAt:desc\r\n for (const part of sortParam.split(\",\")) {\r\n const [field, dir] = part.trim().split(\":\");\r\n if (field) {\r\n orderBy[field] = (dir === \"desc\" ? \"desc\" : \"asc\");\r\n }\r\n }\r\n }\r\n\r\n // ─── Include (relations) ───────────────────────────────────────────────────\r\n const includeParam = searchParams.get(\"include\");\r\n if (includeParam) {\r\n for (const rel of includeParam.split(\",\")) {\r\n if (rel.trim()) include[rel.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Select (fields) ──────────────────────────────────────────────────────\r\n const selectParam = searchParams.get(\"select\");\r\n if (selectParam) {\r\n select = {};\r\n for (const field of selectParam.split(\",\")) {\r\n if (field.trim()) select[field.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Filters ───────────────────────────────────────────────────────────────\r\n for (const [key, value] of searchParams.entries()) {\r\n if (RESERVED_KEYS.has(key)) continue;\r\n\r\n // Check operator suffixes (longest match first)\r\n let matched = false;\r\n const sortedOps = Object.keys(FILTER_OPERATORS).sort(\r\n (a, b) => b.length - a.length\r\n );\r\n\r\n for (const suffix of sortedOps) {\r\n if (key.endsWith(suffix)) {\r\n const field = key.slice(0, -suffix.length);\r\n const prismaOp = FILTER_OPERATORS[suffix];\r\n\r\n let parsedValue: any = value;\r\n\r\n // Parse arrays\r\n if (prismaOp === \"in\" || prismaOp === \"notIn\") {\r\n parsedValue = value.split(\",\").map((v) => v.trim());\r\n }\r\n\r\n // Attempt numeric coercion\r\n if (!isNaN(Number(parsedValue)) && typeof parsedValue === \"string\") {\r\n parsedValue = Number(parsedValue);\r\n }\r\n\r\n // Case-insensitive flag\r\n const extra = suffix === \"_icontains\" ? { mode: \"insensitive\" } : {};\r\n\r\n where[field] = { [prismaOp]: parsedValue, ...extra };\r\n matched = true;\r\n break;\r\n }\r\n }\r\n\r\n // No operator — exact match\r\n if (!matched) {\r\n let parsedValue: any = value;\r\n\r\n // Coerce booleans\r\n if (value === \"true\") parsedValue = true;\r\n else if (value === \"false\") parsedValue = false;\r\n // Coerce numbers\r\n else if (!isNaN(Number(value)) && value !== \"\") {\r\n parsedValue = Number(value);\r\n }\r\n\r\n where[key] = parsedValue;\r\n }\r\n }\r\n\r\n return { where, orderBy, skip, take, include, select };\r\n}","import type { GuardMap, HookFn, HookContext } from \"./types\";\r\n\r\n/**\r\n * Runs the guard for the given model+method combo.\r\n * Returns an error string if blocked, null if allowed.\r\n */\r\nexport async function runGuard(\r\n guards: GuardMap,\r\n model: string,\r\n method: string,\r\n ctx: { id?: string | null; body?: any }\r\n): Promise<string | null> {\r\n const modelGuards = guards[model];\r\n if (!modelGuards) return null;\r\n\r\n const fn = modelGuards[method as keyof typeof modelGuards];\r\n if (!fn) return null;\r\n\r\n return fn({ ...ctx, method });\r\n}\r\n\r\n/**\r\n * Runs a lifecycle hook (beforeOperation / afterOperation).\r\n * Silently swallows errors so hooks never crash the main flow.\r\n */\r\nexport async function runHook(\r\n hook: HookFn | undefined,\r\n ctx: HookContext\r\n): Promise<void> {\r\n if (!hook) return;\r\n try {\r\n await hook(ctx);\r\n } catch (e) {\r\n // Hooks should not crash the request\r\n console.error(\"[omni-rest] Hook error:\", e);\r\n }\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { getModels, buildModelMap, getDelegate } from \"./introspect\";\r\nimport { buildQuery } from \"./query-builder\";\r\nimport { runGuard, runHook } from \"./middleware-helpers\";\r\nimport type {\r\n PrismaRestOptions,\r\n HandlerResult,\r\n RouterInstance,\r\n ModelMeta,\r\n} from \"./types\";\r\n\r\n/**\r\n * Creates a framework-agnostic CRUD router powered by Prisma DMMF.\r\n *\r\n * All adapters (Express, Next.js, Fastify) use this under the hood.\r\n */\r\nexport function createRouter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n): RouterInstance {\r\n const {\r\n allow,\r\n guards = {},\r\n beforeOperation,\r\n afterOperation,\r\n defaultLimit = 20,\r\n maxLimit = 100,\r\n } = options;\r\n\r\n // Introspect schema once at startup\r\n const models = getModels(prisma);\r\n const modelMap = buildModelMap(models, allow);\r\n\r\n async function handle(\r\n method: string,\r\n modelName: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n operation?: string\r\n ): Promise<HandlerResult> {\r\n // ── 1. Resolve model ───────────────────────────────────────────────────\r\n const meta = modelMap[modelName.toLowerCase()];\r\n if (!meta) {\r\n return {\r\n status: 404,\r\n data: {\r\n error: `Model \"${modelName}\" not found or not exposed.`,\r\n available: Object.keys(modelMap),\r\n },\r\n };\r\n }\r\n\r\n // ── 2. Guard check ─────────────────────────────────────────────────────\r\n const guardError = await runGuard(guards, meta.routeName, method, {\r\n id,\r\n body,\r\n });\r\n if (guardError) {\r\n return { status: 403, data: { error: guardError } };\r\n }\r\n\r\n // ── 3. Before hook ─────────────────────────────────────────────────────\r\n await runHook(beforeOperation, { model: meta.name, method, id, body });\r\n\r\n // ── 4. Execute operation ───────────────────────────────────────────────\r\n let result: HandlerResult;\r\n\r\n try {\r\n result = await executeOperation(\r\n prisma,\r\n meta,\r\n method,\r\n id,\r\n body,\r\n searchParams,\r\n defaultLimit,\r\n maxLimit,\r\n operation\r\n );\r\n } catch (e: any) {\r\n return handlePrismaError(e);\r\n }\r\n\r\n // ── 5. After hook ──────────────────────────────────────────────────────\r\n await runHook(afterOperation, {\r\n model: meta.name,\r\n method,\r\n id,\r\n body,\r\n result: result.data,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n return { handle, modelMap, models };\r\n}\r\n\r\n// ─── Operation executor ────────────────────────────────────────────────────────\r\n\r\nasync function executeOperation(\r\n prisma: PrismaClient,\r\n meta: ModelMeta,\r\n method: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n defaultLimit: number,\r\n maxLimit: number,\r\n operation?: string\r\n): Promise<HandlerResult> {\r\n const delegate = getDelegate(prisma, meta);\r\n const { where, orderBy, skip, take, include, select } = buildQuery(\r\n searchParams,\r\n defaultLimit,\r\n maxLimit\r\n );\r\n\r\n // Build include/select args (mutually exclusive in Prisma)\r\n const includeArg =\r\n Object.keys(include).length > 0 ? include : undefined;\r\n const selectArg =\r\n select && Object.keys(select).length > 0 ? select : undefined;\r\n const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};\r\n\r\n // ── PATCH /model/bulk/update ────────────────────────────────────────────────\r\n if (method === \"PATCH\" && operation === \"bulk-update\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of update records\" },\r\n };\r\n }\r\n\r\n // Validate that each item has an id\r\n for (const item of body) {\r\n if (!item[meta.idField]) {\r\n return {\r\n status: 400,\r\n data: { error: `Each record must have an ${meta.idField} field` },\r\n };\r\n }\r\n }\r\n\r\n // Execute updates in parallel\r\n const results = await Promise.all(\r\n body.map((item) => {\r\n const id = item[meta.idField];\r\n const updateData = { ...item };\r\n delete updateData[meta.idField]; // Remove id from update data\r\n\r\n return delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: updateData,\r\n ...projection,\r\n });\r\n })\r\n );\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n updated: results.length,\r\n records: results,\r\n },\r\n };\r\n }\r\n\r\n // ── DELETE /model/bulk/delete ──────────────────────────────────────────────\r\n if (method === \"DELETE\" && operation === \"bulk-delete\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of IDs\" },\r\n };\r\n }\r\n\r\n // Handle both array of IDs and array of objects with id field\r\n const ids = body.map((item: any) =>\r\n typeof item === \"object\" ? item[meta.idField] : item\r\n );\r\n\r\n // Use deleteMany with a where clause\r\n const result = await delegate.deleteMany({\r\n where: {\r\n [meta.idField]: { in: ids.map(coerceId) },\r\n },\r\n });\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n deleted: result.count,\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model ─────────────────────────────────────────────────────────────\r\n if (method === \"GET\" && !id) {\r\n const [data, total] = await (prisma as any).$transaction([\r\n delegate.findMany({ where, orderBy, skip, take, ...projection }),\r\n delegate.count({ where }),\r\n ]);\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n data,\r\n meta: {\r\n total,\r\n page: Math.floor(skip / take) + 1,\r\n limit: take,\r\n totalPages: Math.ceil(total / take),\r\n },\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model/:id ─────────────────────────────────────────────────────────\r\n if (method === \"GET\" && id) {\r\n const record = await delegate.findUnique({\r\n where: { [meta.idField]: coerceId(id) },\r\n ...projection,\r\n });\r\n\r\n if (!record) {\r\n return { status: 404, data: { error: `${meta.name} with id \"${id}\" not found.` } };\r\n }\r\n\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── POST /model ────────────────────────────────────────────────────────────\r\n if (method === \"POST\" && !id) {\r\n const record = await delegate.create({ data: body });\r\n return { status: 201, data: record };\r\n }\r\n\r\n // ── PUT /model/:id ─────────────────────────────────────────────────────────\r\n if ((method === \"PUT\" || method === \"PATCH\") && id) {\r\n const record = await delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: body,\r\n });\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── DELETE /model/:id ──────────────────────────────────────────────────────\r\n if (method === \"DELETE\" && id) {\r\n await delegate.delete({\r\n where: { [meta.idField]: coerceId(id) },\r\n });\r\n return { status: 204, data: null };\r\n }\r\n\r\n return { status: 405, data: { error: `Method ${method} not allowed.` } };\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Coerces an ID string to number when possible (common with Int PKs).\r\n */\r\nfunction coerceId(id: string): string | number {\r\n const n = Number(id);\r\n return isNaN(n) ? id : n;\r\n}\r\n\r\n/**\r\n * Maps Prisma error codes to meaningful HTTP responses.\r\n */\r\nfunction handlePrismaError(e: any): HandlerResult {\r\n const code = e?.code;\r\n\r\n if (code === \"P2025\") {\r\n return { status: 404, data: { error: \"Record not found.\" } };\r\n }\r\n if (code === \"P2002\") {\r\n const fields = e?.meta?.target ?? \"unknown fields\";\r\n return {\r\n status: 409,\r\n data: { error: `Unique constraint failed on: ${fields}` },\r\n };\r\n }\r\n if (code === \"P2003\") {\r\n return { status: 400, data: { error: \"Foreign key constraint failed.\" } };\r\n }\r\n if (code === \"P2014\") {\r\n return { status: 400, data: { error: \"Relation violation.\" } };\r\n }\r\n\r\n return { status: 500, data: { error: e?.message ?? \"Internal server error.\" } };\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { createRouter } from \"../router\";\r\nimport type { PrismaRestOptions } from \"../types\";\r\n\r\n/**\r\n * Next.js App Router adapter for omni-rest.\r\n *\r\n * @example\r\n * ```ts\r\n * // app/api/[...prismaRest]/route.ts\r\n * import { PrismaClient } from \"@prisma/client\";\r\n * import { nextjsAdapter } from \"omni-rest/nextjs\";\r\n *\r\n * const prisma = new PrismaClient();\r\n * const handler = nextjsAdapter(prisma, {\r\n * allow: [\"department\", \"category\"],\r\n * });\r\n *\r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n *\r\n * This covers:\r\n * GET /api/department\r\n * POST /api/department\r\n * GET /api/department/5\r\n * PUT /api/department/5\r\n * PATCH /api/department/5\r\n * DELETE /api/department/5\r\n * PATCH /api/department/bulk/update\r\n * DELETE /api/department/bulk/delete\r\n */\r\nexport function nextjsAdapter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n) {\r\n const { handle } = createRouter(prisma, options);\r\n\r\n return async function handler(\r\n req: Request,\r\n context: { params: { prismaRest: string[] } }\r\n ): Promise<Response> {\r\n const segments = context.params.prismaRest ?? [];\r\n const [modelName, ...pathSegments] = segments;\r\n\r\n if (!modelName) {\r\n return Response.json(\r\n { error: \"No model specified in path.\" },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n const url = new URL(req.url);\r\n\r\n let body: any = {};\r\n if (req.method !== \"GET\" && req.method !== \"DELETE\") {\r\n try {\r\n body = await req.json();\r\n } catch {\r\n body = {};\r\n }\r\n }\r\n\r\n // Detect bulk operations\r\n let operation: string | undefined;\r\n let id: string | null = null;\r\n\r\n if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"update\") {\r\n operation = \"bulk-update\";\r\n } else if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"delete\") {\r\n operation = \"bulk-delete\";\r\n } else {\r\n id = pathSegments[0] ?? null;\r\n }\r\n\r\n const { status, data } = await handle(\r\n req.method,\r\n modelName,\r\n id,\r\n body,\r\n url.searchParams,\r\n operation\r\n );\r\n\r\n if (status === 204) {\r\n return new Response(null, { status: 204 });\r\n }\r\n\r\n return Response.json(data, { status });\r\n };\r\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../src/introspect.ts","../../src/query-builder.ts","../../src/middleware-helpers.ts","../../src/router.ts","../../src/adapters/nextjs.ts"],"names":["f","id"],"mappings":"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","file":"nextjs.mjs","sourcesContent":["import type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Reads Prisma's DMMF (Data Model Meta Format) at runtime\r\n * and returns structured metadata for every model in your schema.\r\n *\r\n * No file reading. No code generation. Pure runtime introspection.\r\n */\r\nexport function getModels(prisma?: any): ModelMeta[] {\r\n let raw: any[] | undefined;\r\n\r\n // Try to get from PrismaClient instance first (new v5 format)\r\n if (prisma?._runtimeDataModel?.models) {\r\n const modelsObj = prisma._runtimeDataModel.models;\r\n // Convert object to array, adding name from key\r\n raw = Object.entries(modelsObj).map(([name, model]: [string, any]) => ({\r\n name,\r\n ...model,\r\n fields: (model.fields || []).map((f: any) => ({\r\n ...f,\r\n relationName: f.kind === \"object\" ? f.name : undefined,\r\n })),\r\n }));\r\n }\r\n\r\n // Fallback to DMMF from @prisma/client module — use plain require so\r\n // vi.mock(\"@prisma/client\") can intercept it in tests. The CLI handles\r\n // the global-install path resolution separately before calling getModels.\r\n if (!raw) {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const prismaModule = require(\"@prisma/client\");\r\n const dmmfModels = prismaModule?.Prisma?.dmmf?.datamodel?.models;\r\n if (dmmfModels) {\r\n raw = dmmfModels;\r\n }\r\n } catch {\r\n // @prisma/client not available or not generated — handled below\r\n }\r\n }\r\n\r\n if (!raw) {\r\n throw new Error(\r\n \"[omni-rest] Could not find Prisma DMMF. Ensure Prisma client is generated and you're passing a PrismaClient instance to omni-rest.\"\r\n );\r\n }\r\n\r\n if (!Array.isArray(raw)) {\r\n throw new Error(\r\n `[omni-rest] Expected models to be an array, got ${typeof raw}. Debug: prisma._runtimeDataModel.models=${!!prisma?._runtimeDataModel?.models}, raw value=${JSON.stringify(raw).slice(0, 100)}`\r\n );\r\n }\r\n\r\n return raw.map((model: any) => {\r\n const fields: FieldMeta[] = model.fields.map((f: any) => ({\r\n name: f.name,\r\n type: f.type,\r\n isId: f.isId,\r\n isRequired: f.isRequired,\r\n isList: f.isList,\r\n isRelation: !!f.relationName,\r\n hasDefaultValue: !!f.hasDefaultValue || !!f.default,\r\n isUpdatedAt: !!f.isUpdatedAt,\r\n }));\r\n\r\n const idField =\r\n model.fields.find((f: any) => f.isId)?.name ?? \"id\";\r\n\r\n return {\r\n name: model.name,\r\n routeName: toRouteName(model.name),\r\n fields,\r\n idField,\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Converts a Prisma model name to a URL-safe route segment.\r\n * \"UserProfile\" → \"userprofile\"\r\n * \"OrderItem\" → \"orderitem\"\r\n */\r\nexport function toRouteName(modelName: string): string {\r\n return modelName.toLowerCase();\r\n}\r\n\r\n/**\r\n * Returns a map of routeName → ModelMeta for O(1) lookups.\r\n */\r\nexport function buildModelMap(\r\n models: ModelMeta[],\r\n allowList?: string[]\r\n): Record<string, ModelMeta> {\r\n const filtered = allowList\r\n ? models.filter((m) => allowList.includes(m.routeName))\r\n : models;\r\n\r\n return Object.fromEntries(filtered.map((m) => [m.routeName, m]));\r\n}\r\n\r\n/**\r\n * Auto-detects the soft-delete field for a model.\r\n * Returns the field name and the value to set, or null if not found.\r\n *\r\n * Priority:\r\n * 1. Explicit `softDeleteField` option\r\n * 2. A field named \"deletedAt\" with type DateTime\r\n * 3. A field named \"isActive\" with type Boolean\r\n */\r\nexport function detectSoftDeleteField(\r\n fields: FieldMeta[],\r\n explicitField?: string\r\n): { field: string; value: Date | boolean } | null {\r\n if (explicitField) {\r\n const f = fields.find((f) => f.name === explicitField);\r\n if (!f) return null;\r\n // Infer value from type\r\n const value = f.type === \"Boolean\" ? false : new Date();\r\n return { field: explicitField, value };\r\n }\r\n\r\n const deletedAt = fields.find((f) => f.name === \"deletedAt\" && f.type === \"DateTime\");\r\n if (deletedAt) return { field: \"deletedAt\", value: new Date() };\r\n\r\n const isActive = fields.find((f) => f.name === \"isActive\" && f.type === \"Boolean\");\r\n if (isActive) return { field: \"isActive\", value: false };\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Gets the Prisma client delegate for a model.\r\n * prisma[\"userProfile\"] or prisma[\"user\"] — handles camelCase.\r\n */\r\nexport function getDelegate(prisma: any, meta: ModelMeta): any {\r\n // Prisma client properties are camelCase of model name\r\n // \"UserProfile\" → \"userProfile\"\r\n const key =\r\n meta.name.charAt(0).toLowerCase() + meta.name.slice(1);\r\n const delegate = prisma[key];\r\n\r\n if (!delegate) {\r\n throw new Error(\r\n `Could not find Prisma delegate for model \"${meta.name}\". ` +\r\n `Expected prisma.${key} to exist.`\r\n );\r\n }\r\n\r\n return delegate;\r\n}","import type { ParsedQuery, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Supported filter suffixes and their Prisma equivalents.\r\n *\r\n * Usage in URL:\r\n * ?name_contains=john\r\n * ?age_gte=18\r\n * ?status_in=active,inactive\r\n * ?email_not=test@test.com\r\n */\r\nconst FILTER_OPERATORS: Record<string, string> = {\r\n _gte: \"gte\",\r\n _lte: \"lte\",\r\n _gt: \"gt\",\r\n _lt: \"lt\",\r\n _contains: \"contains\",\r\n _icontains: \"contains\", // case-insensitive version (mode: insensitive)\r\n _startsWith: \"startsWith\",\r\n _endsWith: \"endsWith\",\r\n _in: \"in\",\r\n _notIn: \"notIn\",\r\n _not: \"not\",\r\n};\r\n\r\n/**\r\n * Reserved query keys — these are NOT treated as filters.\r\n */\r\nconst RESERVED_KEYS = new Set([\r\n \"page\",\r\n \"limit\",\r\n \"sort\",\r\n \"include\",\r\n \"select\",\r\n \"fields\",\r\n \"search\",\r\n]);\r\n\r\n/**\r\n * Parses URLSearchParams into a full Prisma query object.\r\n *\r\n * Supports:\r\n * Filtering → ?name=John ?age_gte=18 ?status_in=a,b\r\n * Sorting → ?sort=createdAt:desc or ?sort=name:asc\r\n * Pagination → ?page=2&limit=10\r\n * Relations → ?include=posts,profile\r\n * Fields → ?select=id,name,email or ?fields=id,name,email\r\n * Search → ?search=eng (queries all String fields with OR)\r\n */\r\nexport function buildQuery(\r\n searchParams: URLSearchParams,\r\n defaultLimit = 20,\r\n maxLimit = 100,\r\n modelFields?: FieldMeta[]\r\n): ParsedQuery {\r\n const where: Record<string, any> = {};\r\n const orderBy: Record<string, \"asc\" | \"desc\"> = {};\r\n let include: Record<string, boolean> = {};\r\n let select: Record<string, boolean> | null = null;\r\n\r\n // ─── Pagination ────────────────────────────────────────────────────────────\r\n const page = Math.max(1, parseInt(searchParams.get(\"page\") ?? \"1\"));\r\n const rawLimit = parseInt(searchParams.get(\"limit\") ?? String(defaultLimit));\r\n const take = Math.min(rawLimit, maxLimit);\r\n const skip = (page - 1) * take;\r\n\r\n // ─── Sort ──────────────────────────────────────────────────────────────────\r\n const sortParam = searchParams.get(\"sort\");\r\n if (sortParam) {\r\n // Supports multiple sorts: ?sort=name:asc,createdAt:desc\r\n for (const part of sortParam.split(\",\")) {\r\n const [field, dir] = part.trim().split(\":\");\r\n if (field) {\r\n orderBy[field] = (dir === \"desc\" ? \"desc\" : \"asc\");\r\n }\r\n }\r\n }\r\n\r\n // ─── Include (relations) ───────────────────────────────────────────────────\r\n const includeParam = searchParams.get(\"include\");\r\n if (includeParam) {\r\n for (const rel of includeParam.split(\",\")) {\r\n if (rel.trim()) include[rel.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Select (fields) — ?select= or ?fields= alias ────────────────────────\r\n const selectParam = searchParams.get(\"select\") ?? searchParams.get(\"fields\");\r\n if (selectParam) {\r\n select = {};\r\n for (const field of selectParam.split(\",\")) {\r\n if (field.trim()) select[field.trim()] = true;\r\n }\r\n }\r\n\r\n // ─── Global search (?search=) ─────────────────────────────────────────────\r\n const searchValue = searchParams.get(\"search\");\r\n if (searchValue && modelFields) {\r\n const stringFields = modelFields.filter(\r\n (f) => f.type === \"String\" && !f.isRelation\r\n );\r\n if (stringFields.length > 0) {\r\n const orClauses = stringFields.map((f) => ({\r\n [f.name]: { contains: searchValue, mode: \"insensitive\" },\r\n }));\r\n // Merge with any existing where via AND so other filters still apply\r\n where[\"OR\"] = orClauses;\r\n }\r\n }\r\n\r\n // ─── Filters ───────────────────────────────────────────────────────────────\r\n for (const [key, value] of searchParams.entries()) {\r\n if (RESERVED_KEYS.has(key)) continue;\r\n\r\n // Check operator suffixes (longest match first)\r\n let matched = false;\r\n const sortedOps = Object.keys(FILTER_OPERATORS).sort(\r\n (a, b) => b.length - a.length\r\n );\r\n\r\n for (const suffix of sortedOps) {\r\n if (key.endsWith(suffix)) {\r\n const field = key.slice(0, -suffix.length);\r\n const prismaOp = FILTER_OPERATORS[suffix];\r\n\r\n let parsedValue: any = value;\r\n\r\n // Parse arrays\r\n if (prismaOp === \"in\" || prismaOp === \"notIn\") {\r\n parsedValue = value.split(\",\").map((v) => v.trim());\r\n }\r\n\r\n // Attempt numeric coercion\r\n if (!isNaN(Number(parsedValue)) && typeof parsedValue === \"string\") {\r\n parsedValue = Number(parsedValue);\r\n }\r\n\r\n // Case-insensitive flag\r\n const extra = suffix === \"_icontains\" ? { mode: \"insensitive\" } : {};\r\n\r\n where[field] = { [prismaOp]: parsedValue, ...extra };\r\n matched = true;\r\n break;\r\n }\r\n }\r\n\r\n // No operator — exact match\r\n if (!matched) {\r\n let parsedValue: any = value;\r\n\r\n // Coerce booleans\r\n if (value === \"true\") parsedValue = true;\r\n else if (value === \"false\") parsedValue = false;\r\n // Coerce numbers\r\n else if (!isNaN(Number(value)) && value !== \"\") {\r\n parsedValue = Number(value);\r\n }\r\n\r\n where[key] = parsedValue;\r\n }\r\n }\r\n\r\n return { where, orderBy, skip, take, include, select };\r\n}","import type { GuardMap, HookFn, HookContext } from \"./types\";\r\n\r\n/**\r\n * Runs the guard for the given model+method combo.\r\n * Returns an error string if blocked, null if allowed.\r\n */\r\nexport async function runGuard(\r\n guards: GuardMap,\r\n model: string,\r\n method: string,\r\n ctx: { id?: string | null; body?: any }\r\n): Promise<string | null> {\r\n const modelGuards = guards[model];\r\n if (!modelGuards) return null;\r\n\r\n const fn = modelGuards[method as keyof typeof modelGuards];\r\n if (!fn) return null;\r\n\r\n return fn({ ...ctx, method });\r\n}\r\n\r\n/**\r\n * Runs a lifecycle hook (beforeOperation / afterOperation).\r\n * Silently swallows errors so hooks never crash the main flow.\r\n */\r\nexport async function runHook(\r\n hook: HookFn | undefined,\r\n ctx: HookContext\r\n): Promise<void> {\r\n if (!hook) return;\r\n try {\r\n await hook(ctx);\r\n } catch (e) {\r\n // Hooks should not crash the request\r\n console.error(\"[omni-rest] Hook error:\", e);\r\n }\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { getModels, buildModelMap, getDelegate, detectSoftDeleteField } from \"./introspect\";\r\nimport { buildQuery } from \"./query-builder\";\r\nimport { runGuard, runHook } from \"./middleware-helpers\";\r\nimport type {\r\n PrismaRestOptions,\r\n HandlerResult,\r\n RouterInstance,\r\n ModelMeta,\r\n} from \"./types\";\r\n\r\n/**\r\n * Creates a framework-agnostic CRUD router powered by Prisma DMMF.\r\n *\r\n * All adapters (Express, Next.js, Fastify) use this under the hood.\r\n */\r\nexport function createRouter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n): RouterInstance {\r\n const {\r\n allow,\r\n guards = {},\r\n beforeOperation,\r\n afterOperation,\r\n defaultLimit = 20,\r\n maxLimit = 100,\r\n softDelete = false,\r\n softDeleteField,\r\n } = options;\r\n\r\n // Introspect schema once at startup\r\n const models = getModels(prisma);\r\n const modelMap = buildModelMap(models, allow);\r\n\r\n async function handle(\r\n method: string,\r\n modelName: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n operation?: string\r\n ): Promise<HandlerResult> {\r\n // ── 1. Resolve model ───────────────────────────────────────────────────\r\n const meta = modelMap[modelName.toLowerCase()];\r\n if (!meta) {\r\n return {\r\n status: 404,\r\n data: {\r\n error: `Model \"${modelName}\" not found or not exposed.`,\r\n available: Object.keys(modelMap),\r\n },\r\n };\r\n }\r\n\r\n // ── 2. Guard check ─────────────────────────────────────────────────────\r\n const guardError = await runGuard(guards, meta.routeName, method, {\r\n id,\r\n body,\r\n });\r\n if (guardError) {\r\n return { status: 403, data: { error: guardError } };\r\n }\r\n\r\n // ── 3. Before hook ─────────────────────────────────────────────────────\r\n await runHook(beforeOperation, { model: meta.name, method, id, body });\r\n\r\n // ── 4. Execute operation ───────────────────────────────────────────────\r\n let result: HandlerResult;\r\n\r\n try {\r\n result = await executeOperation(\r\n prisma,\r\n meta,\r\n method,\r\n id,\r\n body,\r\n searchParams,\r\n defaultLimit,\r\n maxLimit,\r\n operation,\r\n softDelete,\r\n softDeleteField\r\n );\r\n } catch (e: any) {\r\n return handlePrismaError(e);\r\n }\r\n\r\n // ── 5. After hook ──────────────────────────────────────────────────────\r\n await runHook(afterOperation, {\r\n model: meta.name,\r\n method,\r\n id,\r\n body,\r\n result: result.data,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n return { handle, modelMap, models };\r\n}\r\n\r\n// ─── Operation executor ────────────────────────────────────────────────────────\r\n\r\nasync function executeOperation(\r\n prisma: PrismaClient,\r\n meta: ModelMeta,\r\n method: string,\r\n id: string | null,\r\n body: any,\r\n searchParams: URLSearchParams,\r\n defaultLimit: number,\r\n maxLimit: number,\r\n operation?: string,\r\n softDelete = false,\r\n softDeleteField?: string\r\n): Promise<HandlerResult> {\r\n const delegate = getDelegate(prisma, meta);\r\n const { where, orderBy, skip, take, include, select } = buildQuery(\r\n searchParams,\r\n defaultLimit,\r\n maxLimit,\r\n meta.fields\r\n );\r\n\r\n // Build include/select args (mutually exclusive in Prisma)\r\n const includeArg =\r\n Object.keys(include).length > 0 ? include : undefined;\r\n const selectArg =\r\n select && Object.keys(select).length > 0 ? select : undefined;\r\n const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};\r\n\r\n // ── PATCH /model/bulk/update ────────────────────────────────────────────────\r\n if (method === \"PATCH\" && operation === \"bulk-update\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of update records\" },\r\n };\r\n }\r\n\r\n // Validate that each item has an id\r\n for (const item of body) {\r\n if (!item[meta.idField]) {\r\n return {\r\n status: 400,\r\n data: { error: `Each record must have an ${meta.idField} field` },\r\n };\r\n }\r\n }\r\n\r\n // Execute updates in parallel\r\n const results = await Promise.all(\r\n body.map((item) => {\r\n const id = item[meta.idField];\r\n const updateData = { ...item };\r\n delete updateData[meta.idField]; // Remove id from update data\r\n\r\n return delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: updateData,\r\n ...projection,\r\n });\r\n })\r\n );\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n updated: results.length,\r\n records: results,\r\n },\r\n };\r\n }\r\n\r\n // ── DELETE /model/bulk/delete ──────────────────────────────────────────────\r\n if (method === \"DELETE\" && operation === \"bulk-delete\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return {\r\n status: 400,\r\n data: { error: \"Request body must be a non-empty array of IDs\" },\r\n };\r\n }\r\n\r\n // Handle both array of IDs and array of objects with id field\r\n const ids = body.map((item: any) =>\r\n typeof item === \"object\" ? item[meta.idField] : item\r\n );\r\n\r\n // Use deleteMany with a where clause\r\n const result = await delegate.deleteMany({\r\n where: {\r\n [meta.idField]: { in: ids.map(coerceId) },\r\n },\r\n });\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n deleted: result.count,\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model ─────────────────────────────────────────────────────────────\r\n if (method === \"GET\" && !id) {\r\n // Exclude soft-deleted records from list when soft delete is active\r\n const softDeleteInfo = softDelete\r\n ? detectSoftDeleteField(meta.fields, softDeleteField)\r\n : null;\r\n const listWhere = softDeleteInfo\r\n ? { ...where, [softDeleteInfo.field]: softDeleteInfo.field === \"isActive\" ? true : null }\r\n : where;\r\n\r\n const [data, total] = await (prisma as any).$transaction([\r\n delegate.findMany({ where: listWhere, orderBy, skip, take, ...projection }),\r\n delegate.count({ where: listWhere }),\r\n ]);\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n data,\r\n meta: {\r\n total,\r\n page: Math.floor(skip / take) + 1,\r\n limit: take,\r\n totalPages: Math.ceil(total / take),\r\n },\r\n },\r\n };\r\n }\r\n\r\n // ── GET /model/:id ─────────────────────────────────────────────────────────\r\n if (method === \"GET\" && id) {\r\n const record = await delegate.findUnique({\r\n where: { [meta.idField]: coerceId(id) },\r\n ...projection,\r\n });\r\n\r\n if (!record) {\r\n return { status: 404, data: { error: `${meta.name} with id \"${id}\" not found.` } };\r\n }\r\n\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── POST /model ────────────────────────────────────────────────────────────\r\n if (method === \"POST\" && !id) {\r\n const record = await delegate.create({ data: body });\r\n return { status: 201, data: record };\r\n }\r\n\r\n // ── PUT /model/:id ─────────────────────────────────────────────────────────\r\n if ((method === \"PUT\" || method === \"PATCH\") && id) {\r\n const record = await delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: body,\r\n });\r\n return { status: 200, data: record };\r\n }\r\n\r\n // ── DELETE /model/:id ──────────────────────────────────────────────────────\r\n if (method === \"DELETE\" && id) {\r\n const softDeleteInfo = softDelete\r\n ? detectSoftDeleteField(meta.fields, softDeleteField)\r\n : null;\r\n\r\n if (softDeleteInfo) {\r\n const record = await delegate.update({\r\n where: { [meta.idField]: coerceId(id) },\r\n data: { [softDeleteInfo.field]: softDeleteInfo.value },\r\n });\r\n return { status: 200, data: record };\r\n }\r\n\r\n await delegate.delete({\r\n where: { [meta.idField]: coerceId(id) },\r\n });\r\n return { status: 204, data: null };\r\n }\r\n\r\n return { status: 405, data: { error: `Method ${method} not allowed.` } };\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Coerces an ID string to number when possible (common with Int PKs).\r\n */\r\nfunction coerceId(id: string): string | number {\r\n const n = Number(id);\r\n return isNaN(n) ? id : n;\r\n}\r\n\r\n/**\r\n * Maps Prisma error codes to meaningful HTTP responses.\r\n */\r\nfunction handlePrismaError(e: any): HandlerResult {\r\n const code = e?.code;\r\n\r\n if (code === \"P2025\") {\r\n return { status: 404, data: { error: \"Record not found.\" } };\r\n }\r\n if (code === \"P2002\") {\r\n const fields = e?.meta?.target ?? \"unknown fields\";\r\n return {\r\n status: 409,\r\n data: { error: `Unique constraint failed on: ${fields}` },\r\n };\r\n }\r\n if (code === \"P2003\") {\r\n return { status: 400, data: { error: \"Foreign key constraint failed.\" } };\r\n }\r\n if (code === \"P2014\") {\r\n return { status: 400, data: { error: \"Relation violation.\" } };\r\n }\r\n\r\n return { status: 500, data: { error: e?.message ?? \"Internal server error.\" } };\r\n}","import { PrismaClient } from \"@prisma/client\";\r\nimport { createRouter } from \"../router\";\r\nimport type { PrismaRestOptions } from \"../types\";\r\n\r\n/**\r\n * Next.js App Router adapter for omni-rest.\r\n *\r\n * @example\r\n * ```ts\r\n * // app/api/[...prismaRest]/route.ts\r\n * import { PrismaClient } from \"@prisma/client\";\r\n * import { nextjsAdapter } from \"omni-rest/nextjs\";\r\n *\r\n * const prisma = new PrismaClient();\r\n * const handler = nextjsAdapter(prisma, {\r\n * allow: [\"department\", \"category\"],\r\n * });\r\n *\r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n *\r\n * This covers:\r\n * GET /api/department\r\n * POST /api/department\r\n * GET /api/department/5\r\n * PUT /api/department/5\r\n * PATCH /api/department/5\r\n * DELETE /api/department/5\r\n * PATCH /api/department/bulk/update\r\n * DELETE /api/department/bulk/delete\r\n */\r\nexport function nextjsAdapter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n) {\r\n const { handle } = createRouter(prisma, options);\r\n\r\n return async function handler(\r\n req: Request,\r\n context: { params: { prismaRest: string[] } }\r\n ): Promise<Response> {\r\n const segments = context.params.prismaRest ?? [];\r\n const [modelName, ...pathSegments] = segments;\r\n\r\n if (!modelName) {\r\n return Response.json(\r\n { error: \"No model specified in path.\" },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n const url = new URL(req.url);\r\n\r\n let body: any = {};\r\n if (req.method !== \"GET\" && req.method !== \"DELETE\") {\r\n try {\r\n body = await req.json();\r\n } catch {\r\n body = {};\r\n }\r\n }\r\n\r\n // Detect bulk operations\r\n let operation: string | undefined;\r\n let id: string | null = null;\r\n\r\n if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"update\") {\r\n operation = \"bulk-update\";\r\n } else if (pathSegments[0] === \"bulk\" && pathSegments[1] === \"delete\") {\r\n operation = \"bulk-delete\";\r\n } else {\r\n id = pathSegments[0] ?? null;\r\n }\r\n\r\n const { status, data } = await handle(\r\n req.method,\r\n modelName,\r\n id,\r\n body,\r\n url.searchParams,\r\n operation\r\n );\r\n\r\n if (status === 204) {\r\n return new Response(null, { status: 204 });\r\n }\r\n\r\n return Response.json(data, { status });\r\n };\r\n}"]}
|