omni-rest 0.4.8 → 0.4.9

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.
@@ -346,62 +346,63 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
346
346
  const selectArg = select && Object.keys(select).length > 0 ? select : void 0;
347
347
  const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};
348
348
  const safeBody = sanitizeBody(body, fg);
349
+ if (method === "POST" && id === "bulk") {
350
+ if (!Array.isArray(body) || body.length === 0) {
351
+ return { status: 400, data: { error: "Request body must be a non-empty array" } };
352
+ }
353
+ const result = await delegate.createMany({ data: body });
354
+ return { status: 201, data: { count: result.count } };
355
+ }
356
+ if (method === "PUT" && id === "bulk") {
357
+ const { where: bulkWhere, data: bulkData } = body || {};
358
+ if (!bulkWhere || !bulkData) {
359
+ return { status: 400, data: { error: "Body must contain { where, data }" } };
360
+ }
361
+ const result = await delegate.updateMany({ where: bulkWhere, data: bulkData });
362
+ return { status: 200, data: { count: result.count } };
363
+ }
364
+ if (method === "DELETE" && id === "bulk") {
365
+ const { where: bulkWhere } = body || {};
366
+ if (!bulkWhere) {
367
+ return { status: 400, data: { error: "Body must contain { where }" } };
368
+ }
369
+ const result = await delegate.deleteMany({ where: bulkWhere });
370
+ return { status: 200, data: { count: result.count } };
371
+ }
349
372
  if (method === "PATCH" && operation === "bulk-update") {
350
373
  if (!Array.isArray(body) || body.length === 0) {
351
- return {
352
- status: 400,
353
- data: { error: "Request body must be a non-empty array of update records" }
354
- };
374
+ return { status: 400, data: { error: "Request body must be a non-empty array of update records" } };
355
375
  }
356
376
  for (const item of body) {
357
377
  if (!item[meta.idField]) {
358
- return {
359
- status: 400,
360
- data: { error: `Each record must have an ${meta.idField} field` }
361
- };
378
+ return { status: 400, data: { error: `Each record must have an ${meta.idField} field` } };
362
379
  }
363
380
  }
364
381
  const results = await Promise.all(
365
382
  body.map((item) => {
366
- const id2 = item[meta.idField];
383
+ const itemId = item[meta.idField];
367
384
  const updateData = { ...item };
368
385
  delete updateData[meta.idField];
369
386
  return delegate.update({
370
- where: { [meta.idField]: coerceId(id2) },
387
+ where: { [meta.idField]: coerceId(itemId) },
371
388
  data: updateData,
372
389
  ...projection
373
390
  });
374
391
  })
375
392
  );
376
- return {
377
- status: 200,
378
- data: {
379
- updated: results.length,
380
- records: results
381
- }
382
- };
393
+ return { status: 200, data: { updated: results.length, records: results } };
383
394
  }
384
395
  if (method === "DELETE" && operation === "bulk-delete") {
385
396
  if (!Array.isArray(body) || body.length === 0) {
386
- return {
387
- status: 400,
388
- data: { error: "Request body must be a non-empty array of IDs" }
389
- };
397
+ return { status: 400, data: { error: "Request body must be a non-empty array of IDs" } };
390
398
  }
391
399
  const ids = body.map(
392
400
  (item) => typeof item === "object" ? item[meta.idField] : item
393
401
  );
394
402
  const result = await delegate.deleteMany({
395
- where: {
396
- [meta.idField]: { in: ids.map(coerceId) }
397
- }
403
+ where: { [meta.idField]: { in: ids.map(coerceId) } }
398
404
  });
399
- return {
400
- status: 200,
401
- data: {
402
- deleted: result.count
403
- }
404
- };
405
+ return { status: 200, data: { deleted: result.count } };
405
406
  }
406
407
  if (method === "GET" && !id) {
407
408
  const softDeleteInfo = softDelete ? detectSoftDeleteField(meta.fields, softDeleteField) : null;
@@ -412,11 +413,7 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
412
413
  ]);
413
414
  const safeData = data.map((r) => stripResponse(r, fg));
414
415
  if (!envelope) {
415
- return {
416
- status: 200,
417
- data: safeData,
418
- headers: { "X-Total-Count": String(total) }
419
- };
416
+ return { status: 200, data: safeData, headers: { "X-Total-Count": String(total) } };
420
417
  }
421
418
  return {
422
419
  status: 200,
@@ -461,9 +458,7 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
461
458
  });
462
459
  return { status: 200, data: record };
463
460
  }
464
- await delegate.delete({
465
- where: { [meta.idField]: coerceId(id) }
466
- });
461
+ await delegate.delete({ where: { [meta.idField]: coerceId(id) } });
467
462
  return { status: 204, data: null };
468
463
  }
469
464
  return { status: 405, data: { error: `Method ${method} not allowed.` } };
@@ -499,10 +494,7 @@ function handlePrismaError(e) {
499
494
  }
500
495
  if (code === "P2002") {
501
496
  const fields = e?.meta?.target ?? "unknown fields";
502
- return {
503
- status: 409,
504
- data: { error: `Unique constraint failed on: ${fields}` }
505
- };
497
+ return { status: 409, data: { error: `Unique constraint failed on: ${fields}` } };
506
498
  }
507
499
  if (code === "P2003") {
508
500
  return { status: 400, data: { error: "Foreign key constraint failed." } };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/introspect.ts","../../src/query-builder.ts","../../src/middleware-helpers.ts","../../src/router.ts","../../src/adapters/express.ts"],"names":["f","sortedOps","id"],"mappings":"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","file":"express.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 * Relation filter → ?employees.isActive=true ?author.name_contains=john\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\n * Dot-notation relation filtering:\r\n * ?relation.field=value → isList → { relation: { some: { field: value } } }\r\n * → singular → { relation: { field: value } }\r\n * Operator suffixes work inside dot notation:\r\n * ?author.name_contains=john → { author: { name: { contains: \"john\" } } }\r\n *\r\n * NOTE: Only one level of nesting is supported (relation.field).\r\n * Deeply nested filters (relation.nested.field) are not supported and will\r\n * be treated as a regular (non-relation) filter key.\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, any> = {};\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,_count.posts:desc\r\n for (const part of sortParam.split(\",\")) {\r\n const [field, dir] = part.trim().split(\":\");\r\n if (!field) continue;\r\n const direction = dir === \"desc\" ? \"desc\" : \"asc\";\r\n\r\n // _count.relation:dir → { relation: { _count: dir } }\r\n if (field.startsWith(\"_count.\")) {\r\n const relation = field.slice(\"_count.\".length);\r\n if (relation) {\r\n orderBy[relation] = { _count: direction };\r\n }\r\n } else {\r\n orderBy[field] = direction;\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 // ── Dot-notation relation filter (?relation.field[_op]=value) ──────────\r\n // Only handle a single dot (one level deep). Deeper nesting falls through.\r\n const dotIndex = key.indexOf(\".\");\r\n if (dotIndex > 0 && key.indexOf(\".\", dotIndex + 1) === -1 && modelFields) {\r\n const relationName = key.slice(0, dotIndex);\r\n const fieldPart = key.slice(dotIndex + 1); // e.g. \"isActive\" or \"name_contains\"\r\n\r\n const relationMeta = modelFields.find(\r\n (f) => f.name === relationName && f.isRelation\r\n );\r\n\r\n if (relationMeta) {\r\n // Parse the field part for operator suffix\r\n const sortedOps = Object.keys(FILTER_OPERATORS).sort(\r\n (a, b) => b.length - a.length\r\n );\r\n let fieldName = fieldPart;\r\n let fieldFilter: any;\r\n\r\n let opMatched = false;\r\n for (const suffix of sortedOps) {\r\n if (fieldPart.endsWith(suffix)) {\r\n fieldName = fieldPart.slice(0, -suffix.length);\r\n const prismaOp = FILTER_OPERATORS[suffix];\r\n let parsedValue: any = value;\r\n\r\n if (prismaOp === \"in\" || prismaOp === \"notIn\") {\r\n parsedValue = value.split(\",\").map((v) => v.trim());\r\n } else if (!isNaN(Number(parsedValue)) && typeof parsedValue === \"string\") {\r\n parsedValue = Number(parsedValue);\r\n }\r\n\r\n const extra = suffix === \"_icontains\" ? { mode: \"insensitive\" } : {};\r\n fieldFilter = { [prismaOp]: parsedValue, ...extra };\r\n opMatched = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!opMatched) {\r\n // Exact match — coerce value\r\n let parsedValue: any = value;\r\n if (value === \"true\") parsedValue = true;\r\n else if (value === \"false\") parsedValue = false;\r\n else if (!isNaN(Number(value)) && value !== \"\") parsedValue = Number(value);\r\n fieldFilter = parsedValue;\r\n }\r\n\r\n // isList relation → some: { field: filter }\r\n // singular relation → direct: { field: filter }\r\n const nested = { [fieldName]: fieldFilter };\r\n where[relationName] = relationMeta.isList\r\n ? { some: nested }\r\n : nested;\r\n\r\n continue; // skip regular filter processing for this key\r\n }\r\n }\r\n\r\n // ── Regular filters ────────────────────────────────────────────────────\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 FieldGuardConfig,\r\n RateLimitFn,\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 envelope = true,\r\n fieldGuards = {},\r\n rateLimit,\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. Rate limit check ────────────────────────────────────────────────\r\n if (rateLimit) {\r\n const rateLimitError = await rateLimit({ model: meta.name, method, id });\r\n if (rateLimitError) {\r\n return { status: 429, data: { error: rateLimitError } };\r\n }\r\n }\r\n\r\n // ── 3. 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 // ── 4. Before hook ─────────────────────────────────────────────────────\r\n await runHook(beforeOperation, { model: meta.name, method, id, body });\r\n\r\n // ── 5. 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 envelope,\r\n fieldGuards[meta.routeName]\r\n );\r\n } catch (e: any) {\r\n return handlePrismaError(e);\r\n }\r\n\r\n // ── 6. 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 envelope = true,\r\n fg?: FieldGuardConfig\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 // Sanitize write body — strip readOnly fields before passing to Prisma\r\n const safeBody = sanitizeBody(body, fg);\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 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 const safeData = (data as any[]).map((r: any) => stripResponse(r, fg));\r\n\r\n if (!envelope) {\r\n return {\r\n status: 200,\r\n data: safeData,\r\n headers: { \"X-Total-Count\": String(total) },\r\n };\r\n }\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n data: safeData,\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: stripResponse(record, fg) };\r\n }\r\n\r\n // ── POST /model ────────────────────────────────────────────────────────────\r\n if (method === \"POST\" && !id) {\r\n const record = await delegate.create({ data: safeBody });\r\n return { status: 201, data: stripResponse(record, fg) };\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: safeBody,\r\n });\r\n return { status: 200, data: stripResponse(record, fg) };\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 * Strips hidden and writeOnly fields from a response record.\r\n * Works on plain objects; passes through null/non-objects unchanged.\r\n */\r\nfunction stripResponse(record: any, fg?: FieldGuardConfig): any {\r\n if (!fg || !record || typeof record !== \"object\") return record;\r\n const blocked = new Set([...(fg.hidden ?? []), ...(fg.writeOnly ?? [])]);\r\n if (blocked.size === 0) return record;\r\n const out: Record<string, any> = {};\r\n for (const [k, v] of Object.entries(record)) {\r\n if (!blocked.has(k)) out[k] = v;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Strips readOnly fields from a write body before passing to Prisma.\r\n */\r\nfunction sanitizeBody(body: any, fg?: FieldGuardConfig): any {\r\n if (!fg || !body || typeof body !== \"object\" || Array.isArray(body)) return body;\r\n const readOnly = new Set(fg.readOnly ?? []);\r\n if (readOnly.size === 0) return body;\r\n const out: Record<string, any> = {};\r\n for (const [k, v] of Object.entries(body)) {\r\n if (!readOnly.has(k)) out[k] = v;\r\n }\r\n return out;\r\n}\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 * Express adapter for omni-rest.\r\n *\r\n * @example\r\n * ```ts\r\n * import express from \"express\";\r\n * import { PrismaClient } from \"@prisma/client\";\r\n * import { expressAdapter } from \"omni-rest/express\";\r\n *\r\n * const app = express();\r\n * const prisma = new PrismaClient();\r\n *\r\n * app.use(express.json());\r\n * app.use(\"/api\", expressAdapter(prisma, {\r\n * allow: [\"department\", \"category\", \"city\"],\r\n * }));\r\n *\r\n * // Auto-generates:\r\n * // GET /api/department\r\n * // POST /api/department\r\n * // GET /api/department/:id\r\n * // PUT /api/department/:id\r\n * // PATCH /api/department/:id\r\n * // DELETE /api/department/:id\r\n * // PATCH /api/department/bulk/update\r\n * // DELETE /api/department/bulk/delete\r\n * ```\r\n */\r\nexport function expressAdapter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n) {\r\n // Lazy require so express stays optional peer dep\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const { Router } = require(\"express\");\r\n const router = Router();\r\n const { handle } = createRouter(prisma, options);\r\n\r\n // PATCH + DELETE /model/bulk/update and /model/bulk/delete\r\n router.patch(\"/:model/bulk/update\", async (req: any, res: any) => {\r\n try {\r\n const { status, data, headers } = await handle(\r\n \"PATCH\",\r\n req.params.model,\r\n null,\r\n req.body ?? [],\r\n new URLSearchParams(\r\n Object.entries(req.query as Record<string, string>)\r\n .map(([k, v]) => `${k}=${v}`)\r\n .join(\"&\")\r\n ),\r\n \"bulk-update\"\r\n );\r\n if (headers) Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));\r\n if (status === 204) return res.sendStatus(204);\r\n return res.status(status).json(data);\r\n } catch (e: any) {\r\n return res.status(500).json({ error: e.message });\r\n }\r\n });\r\n\r\n router.delete(\"/:model/bulk/delete\", async (req: any, res: any) => {\r\n try {\r\n const { status, data, headers } = await handle(\r\n \"DELETE\",\r\n req.params.model,\r\n null,\r\n req.body ?? [],\r\n new URLSearchParams(\r\n Object.entries(req.query as Record<string, string>)\r\n .map(([k, v]) => `${k}=${v}`)\r\n .join(\"&\")\r\n ),\r\n \"bulk-delete\"\r\n );\r\n if (headers) Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));\r\n if (status === 204) return res.sendStatus(204);\r\n return res.status(status).json(data);\r\n } catch (e: any) {\r\n return res.status(500).json({ error: e.message });\r\n }\r\n });\r\n\r\n // GET + POST /model\r\n router.route(\"/:model\").get(handler).post(handler);\r\n\r\n // GET + PUT + PATCH + DELETE /model/:id\r\n router\r\n .route(\"/:model/:id\")\r\n .get(handler)\r\n .put(handler)\r\n .patch(handler)\r\n .delete(handler);\r\n\r\n async function handler(req: any, res: any) {\r\n try {\r\n const { status, data, headers } = await handle(\r\n req.method,\r\n req.params.model,\r\n req.params.id ?? null,\r\n req.body ?? {},\r\n new URLSearchParams(\r\n Object.entries(req.query as Record<string, string>)\r\n .map(([k, v]) => `${k}=${v}`)\r\n .join(\"&\")\r\n )\r\n );\r\n\r\n if (headers) Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));\r\n if (status === 204) return res.sendStatus(204);\r\n return res.status(status).json(data);\r\n } catch (e: any) {\r\n return res.status(500).json({ error: e.message });\r\n }\r\n }\r\n\r\n return router;\r\n}\r\n\r\n/**\r\n * Express error-handling middleware that maps Prisma error codes to clean\r\n * JSON responses. Mount it after all routes to catch Prisma errors from\r\n * both omni-rest and your own custom routes.\r\n *\r\n * @example\r\n * ```ts\r\n * import { expressAdapter, omniRestErrorHandler } from \"omni-rest/express\";\r\n *\r\n * app.use(\"/api\", expressAdapter(prisma));\r\n * app.use(\"/custom\", myCustomRoutes);\r\n * app.use(omniRestErrorHandler());\r\n * ```\r\n */\r\nexport function omniRestErrorHandler() {\r\n // Standard Express 4-argument error middleware\r\n return function (err: any, _req: any, res: any, next: any) {\r\n const code = err?.code;\r\n\r\n if (code === \"P2025\") {\r\n return res.status(404).json({ error: \"Record not found.\" });\r\n }\r\n if (code === \"P2002\") {\r\n const fields = err?.meta?.target ?? \"unknown fields\";\r\n return res.status(409).json({ error: `Unique constraint failed on: ${fields}` });\r\n }\r\n if (code === \"P2003\") {\r\n return res.status(400).json({ error: \"Foreign key constraint failed.\" });\r\n }\r\n if (code === \"P2014\") {\r\n return res.status(400).json({ error: \"Relation violation.\" });\r\n }\r\n\r\n // Not a known Prisma error — pass through to next error handler\r\n if (!code) {\r\n return next(err);\r\n }\r\n\r\n return res.status(500).json({ error: err?.message ?? \"Internal server error.\" });\r\n };\r\n}"]}
1
+ {"version":3,"sources":["../../src/introspect.ts","../../src/query-builder.ts","../../src/middleware-helpers.ts","../../src/router.ts","../../src/adapters/express.ts"],"names":["f","sortedOps"],"mappings":"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","file":"express.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 * Relation filter → ?employees.isActive=true ?author.name_contains=john\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\n * Dot-notation relation filtering:\r\n * ?relation.field=value → isList → { relation: { some: { field: value } } }\r\n * → singular → { relation: { field: value } }\r\n * Operator suffixes work inside dot notation:\r\n * ?author.name_contains=john → { author: { name: { contains: \"john\" } } }\r\n *\r\n * NOTE: Only one level of nesting is supported (relation.field).\r\n * Deeply nested filters (relation.nested.field) are not supported and will\r\n * be treated as a regular (non-relation) filter key.\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, any> = {};\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,_count.posts:desc\r\n for (const part of sortParam.split(\",\")) {\r\n const [field, dir] = part.trim().split(\":\");\r\n if (!field) continue;\r\n const direction = dir === \"desc\" ? \"desc\" : \"asc\";\r\n\r\n // _count.relation:dir → { relation: { _count: dir } }\r\n if (field.startsWith(\"_count.\")) {\r\n const relation = field.slice(\"_count.\".length);\r\n if (relation) {\r\n orderBy[relation] = { _count: direction };\r\n }\r\n } else {\r\n orderBy[field] = direction;\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 // ── Dot-notation relation filter (?relation.field[_op]=value) ──────────\r\n // Only handle a single dot (one level deep). Deeper nesting falls through.\r\n const dotIndex = key.indexOf(\".\");\r\n if (dotIndex > 0 && key.indexOf(\".\", dotIndex + 1) === -1 && modelFields) {\r\n const relationName = key.slice(0, dotIndex);\r\n const fieldPart = key.slice(dotIndex + 1); // e.g. \"isActive\" or \"name_contains\"\r\n\r\n const relationMeta = modelFields.find(\r\n (f) => f.name === relationName && f.isRelation\r\n );\r\n\r\n if (relationMeta) {\r\n // Parse the field part for operator suffix\r\n const sortedOps = Object.keys(FILTER_OPERATORS).sort(\r\n (a, b) => b.length - a.length\r\n );\r\n let fieldName = fieldPart;\r\n let fieldFilter: any;\r\n\r\n let opMatched = false;\r\n for (const suffix of sortedOps) {\r\n if (fieldPart.endsWith(suffix)) {\r\n fieldName = fieldPart.slice(0, -suffix.length);\r\n const prismaOp = FILTER_OPERATORS[suffix];\r\n let parsedValue: any = value;\r\n\r\n if (prismaOp === \"in\" || prismaOp === \"notIn\") {\r\n parsedValue = value.split(\",\").map((v) => v.trim());\r\n } else if (!isNaN(Number(parsedValue)) && typeof parsedValue === \"string\") {\r\n parsedValue = Number(parsedValue);\r\n }\r\n\r\n const extra = suffix === \"_icontains\" ? { mode: \"insensitive\" } : {};\r\n fieldFilter = { [prismaOp]: parsedValue, ...extra };\r\n opMatched = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!opMatched) {\r\n // Exact match — coerce value\r\n let parsedValue: any = value;\r\n if (value === \"true\") parsedValue = true;\r\n else if (value === \"false\") parsedValue = false;\r\n else if (!isNaN(Number(value)) && value !== \"\") parsedValue = Number(value);\r\n fieldFilter = parsedValue;\r\n }\r\n\r\n // isList relation → some: { field: filter }\r\n // singular relation → direct: { field: filter }\r\n const nested = { [fieldName]: fieldFilter };\r\n where[relationName] = relationMeta.isList\r\n ? { some: nested }\r\n : nested;\r\n\r\n continue; // skip regular filter processing for this key\r\n }\r\n }\r\n\r\n // ── Regular filters ────────────────────────────────────────────────────\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 FieldGuardConfig,\r\n RateLimitFn,\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 envelope = true,\r\n fieldGuards = {},\r\n rateLimit,\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. Rate limit check ────────────────────────────────────────────────\r\n if (rateLimit) {\r\n const rateLimitError = await rateLimit({ model: meta.name, method, id });\r\n if (rateLimitError) {\r\n return { status: 429, data: { error: rateLimitError } };\r\n }\r\n }\r\n\r\n // ── 3. 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 // ── 4. Before hook ─────────────────────────────────────────────────────\r\n await runHook(beforeOperation, { model: meta.name, method, id, body });\r\n\r\n // ── 5. 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 envelope,\r\n fieldGuards[meta.routeName]\r\n );\r\n } catch (e: any) {\r\n return handlePrismaError(e);\r\n }\r\n\r\n // ── 6. 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 envelope = true,\r\n fg?: FieldGuardConfig\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 = Object.keys(include).length > 0 ? include : undefined;\r\n const selectArg = select && Object.keys(select).length > 0 ? select : undefined;\r\n const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};\r\n\r\n // Sanitize write body — strip readOnly fields before passing to Prisma\r\n const safeBody = sanitizeBody(body, fg);\r\n\r\n // ── POST /model/bulk — createMany ──────────────────────────────────────────\r\n if (method === \"POST\" && id === \"bulk\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return { status: 400, data: { error: \"Request body must be a non-empty array\" } };\r\n }\r\n const result = await delegate.createMany({ data: body });\r\n return { status: 201, data: { count: result.count } };\r\n }\r\n\r\n // ── PUT /model/bulk — updateMany ───────────────────────────────────────────\r\n if (method === \"PUT\" && id === \"bulk\") {\r\n const { where: bulkWhere, data: bulkData } = body || {};\r\n if (!bulkWhere || !bulkData) {\r\n return { status: 400, data: { error: \"Body must contain { where, data }\" } };\r\n }\r\n const result = await delegate.updateMany({ where: bulkWhere, data: bulkData });\r\n return { status: 200, data: { count: result.count } };\r\n }\r\n\r\n // ── DELETE /model/bulk — deleteMany ───────────────────────────────────────\r\n if (method === \"DELETE\" && id === \"bulk\") {\r\n const { where: bulkWhere } = body || {};\r\n if (!bulkWhere) {\r\n return { status: 400, data: { error: \"Body must contain { where }\" } };\r\n }\r\n const result = await delegate.deleteMany({ where: bulkWhere });\r\n return { status: 200, data: { count: result.count } };\r\n }\r\n\r\n // ── PATCH /model/bulk/update (legacy per-ID array) ─────────────────────────\r\n if (method === \"PATCH\" && operation === \"bulk-update\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return { status: 400, data: { error: \"Request body must be a non-empty array of update records\" } };\r\n }\r\n for (const item of body) {\r\n if (!item[meta.idField]) {\r\n return { status: 400, data: { error: `Each record must have an ${meta.idField} field` } };\r\n }\r\n }\r\n const results = await Promise.all(\r\n body.map((item) => {\r\n const itemId = item[meta.idField];\r\n const updateData = { ...item };\r\n delete updateData[meta.idField];\r\n return delegate.update({\r\n where: { [meta.idField]: coerceId(itemId) },\r\n data: updateData,\r\n ...projection,\r\n });\r\n })\r\n );\r\n return { status: 200, data: { updated: results.length, records: results } };\r\n }\r\n\r\n // ── DELETE /model/bulk/delete (legacy ID array) ────────────────────────────\r\n if (method === \"DELETE\" && operation === \"bulk-delete\") {\r\n if (!Array.isArray(body) || body.length === 0) {\r\n return { status: 400, data: { error: \"Request body must be a non-empty array of IDs\" } };\r\n }\r\n const ids = body.map((item: any) =>\r\n typeof item === \"object\" ? item[meta.idField] : item\r\n );\r\n const result = await delegate.deleteMany({\r\n where: { [meta.idField]: { in: ids.map(coerceId) } },\r\n });\r\n return { status: 200, data: { deleted: result.count } };\r\n }\r\n\r\n // ── GET /model ─────────────────────────────────────────────────────────────\r\n if (method === \"GET\" && !id) {\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 const safeData = (data as any[]).map((r: any) => stripResponse(r, fg));\r\n\r\n if (!envelope) {\r\n return { status: 200, data: safeData, headers: { \"X-Total-Count\": String(total) } };\r\n }\r\n\r\n return {\r\n status: 200,\r\n data: {\r\n data: safeData,\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 if (!record) {\r\n return { status: 404, data: { error: `${meta.name} with id \"${id}\" not found.` } };\r\n }\r\n return { status: 200, data: stripResponse(record, fg) };\r\n }\r\n\r\n // ── POST /model ────────────────────────────────────────────────────────────\r\n if (method === \"POST\" && !id) {\r\n const record = await delegate.create({ data: safeBody });\r\n return { status: 201, data: stripResponse(record, fg) };\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: safeBody,\r\n });\r\n return { status: 200, data: stripResponse(record, fg) };\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({ where: { [meta.idField]: coerceId(id) } });\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 * Strips hidden and writeOnly fields from a response record.\r\n */\r\nfunction stripResponse(record: any, fg?: FieldGuardConfig): any {\r\n if (!fg || !record || typeof record !== \"object\") return record;\r\n const blocked = new Set([...(fg.hidden ?? []), ...(fg.writeOnly ?? [])]);\r\n if (blocked.size === 0) return record;\r\n const out: Record<string, any> = {};\r\n for (const [k, v] of Object.entries(record)) {\r\n if (!blocked.has(k)) out[k] = v;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Strips readOnly fields from a write body before passing to Prisma.\r\n */\r\nfunction sanitizeBody(body: any, fg?: FieldGuardConfig): any {\r\n if (!fg || !body || typeof body !== \"object\" || Array.isArray(body)) return body;\r\n const readOnly = new Set(fg.readOnly ?? []);\r\n if (readOnly.size === 0) return body;\r\n const out: Record<string, any> = {};\r\n for (const [k, v] of Object.entries(body)) {\r\n if (!readOnly.has(k)) out[k] = v;\r\n }\r\n return out;\r\n}\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 { status: 409, data: { error: `Unique constraint failed on: ${fields}` } };\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}\r\n","import { PrismaClient } from \"@prisma/client\";\r\nimport { createRouter } from \"../router\";\r\nimport type { PrismaRestOptions } from \"../types\";\r\n\r\n/**\r\n * Express adapter for omni-rest.\r\n *\r\n * @example\r\n * ```ts\r\n * import express from \"express\";\r\n * import { PrismaClient } from \"@prisma/client\";\r\n * import { expressAdapter } from \"omni-rest/express\";\r\n *\r\n * const app = express();\r\n * const prisma = new PrismaClient();\r\n *\r\n * app.use(express.json());\r\n * app.use(\"/api\", expressAdapter(prisma, {\r\n * allow: [\"department\", \"category\", \"city\"],\r\n * }));\r\n *\r\n * // Auto-generates:\r\n * // GET /api/department\r\n * // POST /api/department\r\n * // GET /api/department/:id\r\n * // PUT /api/department/:id\r\n * // PATCH /api/department/:id\r\n * // DELETE /api/department/:id\r\n * // PATCH /api/department/bulk/update\r\n * // DELETE /api/department/bulk/delete\r\n * ```\r\n */\r\nexport function expressAdapter(\r\n prisma: PrismaClient,\r\n options: PrismaRestOptions = {}\r\n) {\r\n // Lazy require so express stays optional peer dep\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const { Router } = require(\"express\");\r\n const router = Router();\r\n const { handle } = createRouter(prisma, options);\r\n\r\n // PATCH + DELETE /model/bulk/update and /model/bulk/delete\r\n router.patch(\"/:model/bulk/update\", async (req: any, res: any) => {\r\n try {\r\n const { status, data, headers } = await handle(\r\n \"PATCH\",\r\n req.params.model,\r\n null,\r\n req.body ?? [],\r\n new URLSearchParams(\r\n Object.entries(req.query as Record<string, string>)\r\n .map(([k, v]) => `${k}=${v}`)\r\n .join(\"&\")\r\n ),\r\n \"bulk-update\"\r\n );\r\n if (headers) Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));\r\n if (status === 204) return res.sendStatus(204);\r\n return res.status(status).json(data);\r\n } catch (e: any) {\r\n return res.status(500).json({ error: e.message });\r\n }\r\n });\r\n\r\n router.delete(\"/:model/bulk/delete\", async (req: any, res: any) => {\r\n try {\r\n const { status, data, headers } = await handle(\r\n \"DELETE\",\r\n req.params.model,\r\n null,\r\n req.body ?? [],\r\n new URLSearchParams(\r\n Object.entries(req.query as Record<string, string>)\r\n .map(([k, v]) => `${k}=${v}`)\r\n .join(\"&\")\r\n ),\r\n \"bulk-delete\"\r\n );\r\n if (headers) Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));\r\n if (status === 204) return res.sendStatus(204);\r\n return res.status(status).json(data);\r\n } catch (e: any) {\r\n return res.status(500).json({ error: e.message });\r\n }\r\n });\r\n\r\n // GET + POST /model\r\n router.route(\"/:model\").get(handler).post(handler);\r\n\r\n // GET + PUT + PATCH + DELETE /model/:id\r\n router\r\n .route(\"/:model/:id\")\r\n .get(handler)\r\n .put(handler)\r\n .patch(handler)\r\n .delete(handler);\r\n\r\n async function handler(req: any, res: any) {\r\n try {\r\n const { status, data, headers } = await handle(\r\n req.method,\r\n req.params.model,\r\n req.params.id ?? null,\r\n req.body ?? {},\r\n new URLSearchParams(\r\n Object.entries(req.query as Record<string, string>)\r\n .map(([k, v]) => `${k}=${v}`)\r\n .join(\"&\")\r\n )\r\n );\r\n\r\n if (headers) Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));\r\n if (status === 204) return res.sendStatus(204);\r\n return res.status(status).json(data);\r\n } catch (e: any) {\r\n return res.status(500).json({ error: e.message });\r\n }\r\n }\r\n\r\n return router;\r\n}\r\n\r\n/**\r\n * Express error-handling middleware that maps Prisma error codes to clean\r\n * JSON responses. Mount it after all routes to catch Prisma errors from\r\n * both omni-rest and your own custom routes.\r\n *\r\n * @example\r\n * ```ts\r\n * import { expressAdapter, omniRestErrorHandler } from \"omni-rest/express\";\r\n *\r\n * app.use(\"/api\", expressAdapter(prisma));\r\n * app.use(\"/custom\", myCustomRoutes);\r\n * app.use(omniRestErrorHandler());\r\n * ```\r\n */\r\nexport function omniRestErrorHandler() {\r\n // Standard Express 4-argument error middleware\r\n return function (err: any, _req: any, res: any, next: any) {\r\n const code = err?.code;\r\n\r\n if (code === \"P2025\") {\r\n return res.status(404).json({ error: \"Record not found.\" });\r\n }\r\n if (code === \"P2002\") {\r\n const fields = err?.meta?.target ?? \"unknown fields\";\r\n return res.status(409).json({ error: `Unique constraint failed on: ${fields}` });\r\n }\r\n if (code === \"P2003\") {\r\n return res.status(400).json({ error: \"Foreign key constraint failed.\" });\r\n }\r\n if (code === \"P2014\") {\r\n return res.status(400).json({ error: \"Relation violation.\" });\r\n }\r\n\r\n // Not a known Prisma error — pass through to next error handler\r\n if (!code) {\r\n return next(err);\r\n }\r\n\r\n return res.status(500).json({ error: err?.message ?? \"Internal server error.\" });\r\n };\r\n}"]}
@@ -344,62 +344,63 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
344
344
  const selectArg = select && Object.keys(select).length > 0 ? select : void 0;
345
345
  const projection = selectArg ? { select: selectArg } : includeArg ? { include: includeArg } : {};
346
346
  const safeBody = sanitizeBody(body, fg);
347
+ if (method === "POST" && id === "bulk") {
348
+ if (!Array.isArray(body) || body.length === 0) {
349
+ return { status: 400, data: { error: "Request body must be a non-empty array" } };
350
+ }
351
+ const result = await delegate.createMany({ data: body });
352
+ return { status: 201, data: { count: result.count } };
353
+ }
354
+ if (method === "PUT" && id === "bulk") {
355
+ const { where: bulkWhere, data: bulkData } = body || {};
356
+ if (!bulkWhere || !bulkData) {
357
+ return { status: 400, data: { error: "Body must contain { where, data }" } };
358
+ }
359
+ const result = await delegate.updateMany({ where: bulkWhere, data: bulkData });
360
+ return { status: 200, data: { count: result.count } };
361
+ }
362
+ if (method === "DELETE" && id === "bulk") {
363
+ const { where: bulkWhere } = body || {};
364
+ if (!bulkWhere) {
365
+ return { status: 400, data: { error: "Body must contain { where }" } };
366
+ }
367
+ const result = await delegate.deleteMany({ where: bulkWhere });
368
+ return { status: 200, data: { count: result.count } };
369
+ }
347
370
  if (method === "PATCH" && operation === "bulk-update") {
348
371
  if (!Array.isArray(body) || body.length === 0) {
349
- return {
350
- status: 400,
351
- data: { error: "Request body must be a non-empty array of update records" }
352
- };
372
+ return { status: 400, data: { error: "Request body must be a non-empty array of update records" } };
353
373
  }
354
374
  for (const item of body) {
355
375
  if (!item[meta.idField]) {
356
- return {
357
- status: 400,
358
- data: { error: `Each record must have an ${meta.idField} field` }
359
- };
376
+ return { status: 400, data: { error: `Each record must have an ${meta.idField} field` } };
360
377
  }
361
378
  }
362
379
  const results = await Promise.all(
363
380
  body.map((item) => {
364
- const id2 = item[meta.idField];
381
+ const itemId = item[meta.idField];
365
382
  const updateData = { ...item };
366
383
  delete updateData[meta.idField];
367
384
  return delegate.update({
368
- where: { [meta.idField]: coerceId(id2) },
385
+ where: { [meta.idField]: coerceId(itemId) },
369
386
  data: updateData,
370
387
  ...projection
371
388
  });
372
389
  })
373
390
  );
374
- return {
375
- status: 200,
376
- data: {
377
- updated: results.length,
378
- records: results
379
- }
380
- };
391
+ return { status: 200, data: { updated: results.length, records: results } };
381
392
  }
382
393
  if (method === "DELETE" && operation === "bulk-delete") {
383
394
  if (!Array.isArray(body) || body.length === 0) {
384
- return {
385
- status: 400,
386
- data: { error: "Request body must be a non-empty array of IDs" }
387
- };
395
+ return { status: 400, data: { error: "Request body must be a non-empty array of IDs" } };
388
396
  }
389
397
  const ids = body.map(
390
398
  (item) => typeof item === "object" ? item[meta.idField] : item
391
399
  );
392
400
  const result = await delegate.deleteMany({
393
- where: {
394
- [meta.idField]: { in: ids.map(coerceId) }
395
- }
401
+ where: { [meta.idField]: { in: ids.map(coerceId) } }
396
402
  });
397
- return {
398
- status: 200,
399
- data: {
400
- deleted: result.count
401
- }
402
- };
403
+ return { status: 200, data: { deleted: result.count } };
403
404
  }
404
405
  if (method === "GET" && !id) {
405
406
  const softDeleteInfo = softDelete ? detectSoftDeleteField(meta.fields, softDeleteField) : null;
@@ -410,11 +411,7 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
410
411
  ]);
411
412
  const safeData = data.map((r) => stripResponse(r, fg));
412
413
  if (!envelope) {
413
- return {
414
- status: 200,
415
- data: safeData,
416
- headers: { "X-Total-Count": String(total) }
417
- };
414
+ return { status: 200, data: safeData, headers: { "X-Total-Count": String(total) } };
418
415
  }
419
416
  return {
420
417
  status: 200,
@@ -459,9 +456,7 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
459
456
  });
460
457
  return { status: 200, data: record };
461
458
  }
462
- await delegate.delete({
463
- where: { [meta.idField]: coerceId(id) }
464
- });
459
+ await delegate.delete({ where: { [meta.idField]: coerceId(id) } });
465
460
  return { status: 204, data: null };
466
461
  }
467
462
  return { status: 405, data: { error: `Method ${method} not allowed.` } };
@@ -497,10 +492,7 @@ function handlePrismaError(e) {
497
492
  }
498
493
  if (code === "P2002") {
499
494
  const fields = e?.meta?.target ?? "unknown fields";
500
- return {
501
- status: 409,
502
- data: { error: `Unique constraint failed on: ${fields}` }
503
- };
495
+ return { status: 409, data: { error: `Unique constraint failed on: ${fields}` } };
504
496
  }
505
497
  if (code === "P2003") {
506
498
  return { status: 400, data: { error: "Foreign key constraint failed." } };