@visulima/crud 3.0.0-alpha.17 → 3.0.0-alpha.18

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +127 -5
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.cts +64 -3
  5. package/dist/index.d.mts +64 -3
  6. package/dist/index.d.ts +64 -3
  7. package/dist/index.mjs +1 -1
  8. package/dist/next/index.cjs +1 -1
  9. package/dist/next/index.d.cts +21 -13
  10. package/dist/next/index.d.mts +21 -13
  11. package/dist/next/index.d.ts +21 -13
  12. package/dist/next/index.mjs +1 -1
  13. package/dist/packem_shared/CrudApiError-BH1byAwV.mjs +1 -0
  14. package/dist/packem_shared/CrudApiError-DkRqkpib.cjs +1 -0
  15. package/dist/packem_shared/PrismaAdapter-Bhocjq94.mjs +1 -0
  16. package/dist/packem_shared/PrismaAdapter-DDoEjhQy.cjs +1 -0
  17. package/dist/packem_shared/baseHandler-BGTzX4YA.mjs +1 -0
  18. package/dist/packem_shared/baseHandler-DnuGeT2-.cjs +1 -0
  19. package/dist/packem_shared/edgeHandler-CjCFAdvT.mjs +1 -0
  20. package/dist/packem_shared/edgeHandler-DQ2KLGlC.cjs +1 -0
  21. package/dist/packem_shared/get-accessible-routes-BCUs20dV.cjs +1 -0
  22. package/dist/packem_shared/get-accessible-routes-CGvT_kuy.mjs +1 -0
  23. package/dist/packem_shared/models-to-route-names-BFpwjyxy.mjs +1 -0
  24. package/dist/packem_shared/models-to-route-names-CWnxPVCQ.cjs +1 -0
  25. package/dist/packem_shared/modelsToOpenApi-QqR_HHsz.cjs +1 -0
  26. package/dist/packem_shared/modelsToOpenApi-pOMrwJIY.mjs +1 -0
  27. package/dist/packem_shared/nodeHandler-atOpJB2d.mjs +1 -0
  28. package/dist/packem_shared/nodeHandler-tp623oY3.cjs +1 -0
  29. package/dist/packem_shared/{types.d-BDmE9rKc.d.cts → types.d-CQwyFrf3.d.cts} +84 -3
  30. package/dist/packem_shared/{types.d-BDmE9rKc.d.mts → types.d-CQwyFrf3.d.mts} +84 -3
  31. package/dist/packem_shared/{types.d-BDmE9rKc.d.ts → types.d-CQwyFrf3.d.ts} +84 -3
  32. package/package.json +4 -4
  33. package/dist/packem_shared/PrismaAdapter-BVs7BWSG.mjs +0 -1
  34. package/dist/packem_shared/PrismaAdapter-Buz6dEMm.cjs +0 -1
  35. package/dist/packem_shared/base-crud-handler-BJJ5vmOh.mjs +0 -1
  36. package/dist/packem_shared/base-crud-handler-Cm23eHkD.cjs +0 -1
  37. package/dist/packem_shared/edgeHandler-CHig8R94.cjs +0 -1
  38. package/dist/packem_shared/edgeHandler-DfRlSUUt.mjs +0 -1
  39. package/dist/packem_shared/get-accessible-routes-DLLL11KB.cjs +0 -1
  40. package/dist/packem_shared/get-accessible-routes-xHYBQ_6q.mjs +0 -1
  41. package/dist/packem_shared/models-to-route-names-Dh2b_kIL.cjs +0 -1
  42. package/dist/packem_shared/models-to-route-names-UU1lZmbK.mjs +0 -1
  43. package/dist/packem_shared/modelsToOpenApi-CsQL5VTy.cjs +0 -1
  44. package/dist/packem_shared/modelsToOpenApi-ocNrUF5p.mjs +0 -1
  45. package/dist/packem_shared/nodeHandler-BdR0fuw-.mjs +0 -1
  46. package/dist/packem_shared/nodeHandler-Di5MpzCj.cjs +0 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ ## @visulima/crud [3.0.0-alpha.18](https://github.com/visulima/visulima/compare/@visulima/crud@3.0.0-alpha.17...@visulima/crud@3.0.0-alpha.18) (2026-06-13)
2
+
3
+ ### Features
4
+
5
+ * **crud:** harden crud handler and add prisma 5/6 + policy support ([fc565cf](https://github.com/visulima/visulima/commit/fc565cf4e87b871f466f3789536a1dc9402bac9f))
6
+
7
+ ### Bug Fixes
8
+
9
+ * **crud:** return 400 on malformed query json ([01247a6](https://github.com/visulima/visulima/commit/01247a63aad83266947588bccf789df4b58370bb))
10
+
11
+ ### Miscellaneous Chores
12
+
13
+ * **crud:** clear baseline eslint violations ([1964225](https://github.com/visulima/visulima/commit/196422505694b06ad8239bc836a34e45ad8c8ff3))
14
+ * **crud:** reformat README tables and collapse test expect calls ([2957165](https://github.com/visulima/visulima/commit/295716512272b71b6a67b68633204cc4dd78caf9))
15
+
16
+ ### Build System
17
+
18
+ * regenerate bundled-license manifests and types ordering ([af26588](https://github.com/visulima/visulima/commit/af26588d75aaa937fd4862800560bd4070a4878c))
19
+
20
+
21
+ ### Dependencies
22
+
23
+ * **@visulima/pagination:** upgraded to 5.0.0-alpha.14
24
+ * **@visulima/prisma-dmmf-transformer:** upgraded to 3.0.0-alpha.16
25
+
1
26
  ## @visulima/crud [3.0.0-alpha.17](https://github.com/visulima/visulima/compare/@visulima/crud@3.0.0-alpha.16...@visulima/crud@3.0.0-alpha.17) (2026-06-04)
2
27
 
3
28
  ### Bug Fixes
package/README.md CHANGED
@@ -36,6 +36,13 @@
36
36
 
37
37
  ## Features
38
38
 
39
+ - Auto-generated RESTful CRUD routes (`list`, `read`, `create`, `update`, `delete`) from your Prisma models.
40
+ - Rich query syntax over the URL: `select`, `include`, `where` (with `$eq`/`$cont`/`$in`/… operators), `orderBy`, `limit`/`page` pagination, `cursor`, `distinct`.
41
+ - Framework-agnostic core (`baseHandler` + the `Adapter` interface) with a ready-made Prisma adapter and Next.js (`nodeHandler`/`edgeHandler`) bindings.
42
+ - OpenAPI 3 generation from your Prisma DMMF via `modelsToOpenApi`.
43
+ - Built-in guardrails: per-model field allowlists (`writableFields`/`selectableFields`/`filterableFields`/`includableRelations`/`readableFields`), body validation schemas (`createSchema`/`updateSchema`, e.g. zod), an `onRequest` access hook, and a `maxPerPage` cap.
44
+ - Prisma 3, 4, 5 and 6 support.
45
+
39
46
  ## Installation
40
47
 
41
48
  ```sh
@@ -54,28 +61,60 @@ pnpm add @visulima/crud prisma @prisma/client
54
61
 
55
62
  To use the `@visulima/crud` package, you need to have a [Prisma](https://www.prisma.io/) schema.
56
63
 
64
+ > **Important:** build the handler **once** (at module scope), not inside the request callback.
65
+ > `nodeHandler`/`edgeHandler` are async factories that run `adapter.init()`, map the DMMF and open
66
+ > the connection pool — doing that per request is slow. Reuse the returned handler across requests.
67
+
57
68
  ```ts
58
69
  // pages/api/[...crud].ts
59
70
 
60
71
  // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
61
72
  import type { NextApiRequest, NextApiResponse } from "next";
73
+ import { Prisma } from "@prisma/client";
74
+ import type { User, Post } from "@prisma/client";
62
75
  import { PrismaAdapter } from "@visulima/crud";
63
76
  import { nodeHandler } from "@visulima/crud/next";
64
- import type { User, Post, Prisma } from "@prisma/client";
65
77
 
66
78
  import { prisma } from "../../lib/prisma-client";
67
79
 
68
80
  const prismaAdapter = new PrismaAdapter<User | Post, Prisma.ModelName>({
69
81
  prismaClient: prisma,
82
+ // Required for Prisma 5/6 (the private DMMF internals were removed):
83
+ dmmf: Prisma.dmmf,
70
84
  });
71
85
 
72
- export default async (request, response) => {
73
- const handler = await nodeHandler<User | Post, any, NextApiRequest, NextApiResponse, Prisma.ModelName>(prismaAdapter);
86
+ // Created once — `nodeHandler` runs adapter.init() and connects the pool here.
87
+ const handlerPromise = nodeHandler<User | Post, any, NextApiRequest, NextApiResponse, Prisma.ModelName>(prismaAdapter);
88
+
89
+ export default async (request: NextApiRequest, response: NextApiResponse) => {
90
+ const handler = await handlerPromise;
74
91
 
75
92
  await handler(request, response);
76
93
  };
77
94
  ```
78
95
 
96
+ For the **App Router / edge runtime**, use `edgeHandler`, which returns the `Response`:
97
+
98
+ ```ts
99
+ // app/api/[...crud]/route.ts
100
+ import { Prisma } from "@prisma/client";
101
+ import { PrismaAdapter } from "@visulima/crud";
102
+ import { edgeHandler } from "@visulima/crud/next";
103
+
104
+ import { prisma } from "../../../lib/prisma-client";
105
+
106
+ const adapter = new PrismaAdapter({ prismaClient: prisma, dmmf: Prisma.dmmf });
107
+ const handlerPromise = edgeHandler(adapter);
108
+
109
+ const route = async (request: Request) => {
110
+ const handler = await handlerPromise;
111
+
112
+ return handler(request, undefined);
113
+ };
114
+
115
+ export { route as GET, route as POST, route as PUT, route as PATCH, route as DELETE };
116
+ ```
117
+
79
118
  To use it with `api-platform connect` you need to install the `@visulima/api-platform` package.
80
119
 
81
120
  ```ts
@@ -83,19 +122,23 @@ To use it with `api-platform connect` you need to install the `@visulima/api-pla
83
122
 
84
123
  // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
85
124
  import type { NextApiRequest, NextApiResponse } from "next";
125
+ import { Prisma } from "@prisma/client";
126
+ import type { User, Post } from "@prisma/client";
86
127
  import { createNodeRouter } from "@visulima/api-platform";
87
128
  import { PrismaAdapter } from "@visulima/crud";
88
129
  import { nodeHandler } from "@visulima/crud/next";
89
- import type { User, Post, Prisma } from "@prisma/client";
90
130
 
91
131
  import { prisma } from "../../lib/prisma-client";
92
132
 
93
133
  const prismaAdapter = new PrismaAdapter<User | Post, Prisma.ModelName>({
94
134
  prismaClient: prisma,
135
+ dmmf: Prisma.dmmf,
95
136
  });
96
137
 
138
+ const handlerPromise = nodeHandler<User | Post, any, NextApiRequest, NextApiResponse, Prisma.ModelName>(prismaAdapter);
139
+
97
140
  const router = createNodeRouter<NextApiRequest, NextApiResponse>().all(async (request, response) => {
98
- const handler = await nodeHandler<User | Post, any, NextApiRequest, NextApiResponse, Prisma.ModelName>(prismaAdapter);
141
+ const handler = await handlerPromise;
99
142
 
100
143
  await handler(request, response);
101
144
  });
@@ -103,6 +146,85 @@ const router = createNodeRouter<NextApiRequest, NextApiResponse>().all(async (re
103
146
  export default router.handler();
104
147
  ```
105
148
 
149
+ ### Query syntax
150
+
151
+ CRUD endpoints accept the following query-string parameters (all optional):
152
+
153
+ | Param | Example | Description |
154
+ | ---------- | --------------------------------- | -------------------------------------------------------------------------- |
155
+ | `select` | `?select=id,name,profile.bio` | Comma-separated fields to return. Dotted paths select nested fields. |
156
+ | `include` | `?include=posts,profile` | Comma-separated relations to expand. |
157
+ | `where` | `?where={"name":{"$cont":"ada"}}` | JSON filter object (see operators below). URL-encode it. |
158
+ | `orderBy` | `?orderBy={"createdAt":"$desc"}` | JSON object with exactly one field and `$asc`/`$desc`. |
159
+ | `limit` | `?limit=20` | Page size / `take`. Capped by `maxPerPage` when configured. |
160
+ | `page` | `?page=2` | 1-based page number; enables paginated (`@visulima/pagination`) responses. |
161
+ | `skip` | `?skip=40` | Offset (`skip`) for non-paginated reads. |
162
+ | `cursor` | `?cursor={"id":42}` | JSON cursor for cursor-based pagination. |
163
+ | `distinct` | `?distinct=email` | Field name to apply `distinct` on. |
164
+
165
+ #### `where` operators
166
+
167
+ | Operator | Prisma equivalent | Meaning |
168
+ | --------- | ----------------- | --------------------- |
169
+ | `$eq` | `equals` | equals |
170
+ | `$neq` | `not` | not equal |
171
+ | `$in` | `in` | in list |
172
+ | `$notin` | `notIn` | not in list |
173
+ | `$lt` | `lt` | less than |
174
+ | `$lte` | `lte` | less than or equal |
175
+ | `$gt` | `gt` | greater than |
176
+ | `$gte` | `gte` | greater than or equal |
177
+ | `$cont` | `contains` | string contains |
178
+ | `$starts` | `startsWith` | string starts with |
179
+ | `$ends` | `endsWith` | string ends with |
180
+ | `$isnull` | `null` | is null |
181
+
182
+ `where` also supports the `$and`, `$or` and `$not` combinators. By default ISO-date-looking
183
+ strings are coerced to `Date` instances so they match `DateTime` columns; pass
184
+ `coerceWhereDates: false` to the `PrismaAdapter` constructor to keep them as strings (needed when
185
+ filtering a _string_ column whose values look like dates).
186
+
187
+ ### Security & access control
188
+
189
+ CRUD exposes every model with no field-level restrictions by default. Lock it down per model:
190
+
191
+ ```ts
192
+ import { RouteType } from "@visulima/crud";
193
+
194
+ const handlerPromise = nodeHandler(adapter, {
195
+ // Global cap so `?limit=100000000` can't dump a whole table.
196
+ maxPerPage: 100,
197
+ // Throw to deny a request (row/field access guard).
198
+ onRequest: async ({ routeType, resourceName }) => {
199
+ if (routeType === RouteType.DELETE) throw createHttpError(403, "forbidden");
200
+ },
201
+ models: {
202
+ User: {
203
+ only: [RouteType.READ_ALL, RouteType.READ_ONE, RouteType.UPDATE],
204
+ // Mass-assignment guard: clients can only write these columns.
205
+ writableFields: ["name", "email"],
206
+ // Never return these even if a client requests ?select=passwordHash.
207
+ readableFields: ["passwordHash"],
208
+ // Allowlist what may be filtered/sorted and selected/included.
209
+ filterableFields: ["id", "name", "email"],
210
+ selectableFields: ["id", "name", "email"],
211
+ includableRelations: ["posts"],
212
+ // Validate/transform the body (any zod-like schema works).
213
+ updateSchema: userUpdateSchema,
214
+ },
215
+ },
216
+ });
217
+ ```
218
+
219
+ ### Framework-agnostic usage
220
+
221
+ The `baseHandler` and `Adapter` interface are exported from the root entry, so you can wire CRUD to
222
+ Express, Fastify, Hono or any runtime without Next.js:
223
+
224
+ ```ts
225
+ import { baseHandler, PrismaAdapter } from "@visulima/crud";
226
+ ```
227
+
106
228
  ## Supported Node.js Versions
107
229
 
108
230
  Libraries in this ecosystem make the best effort to track
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./packem_shared/PrismaAdapter-Buz6dEMm.cjs"),r=require("./packem_shared/modelsToOpenApi-CsQL5VTy.cjs"),o=require("./packem_shared/RouteType-DLV_OhhD.cjs");exports.PrismaAdapter=e;exports.modelsToOpenApi=r;exports.RouteType=o.RouteType;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./packem_shared/PrismaAdapter-DDoEjhQy.cjs"),r=require("./packem_shared/CrudApiError-DkRqkpib.cjs"),u=require("./packem_shared/baseHandler-DnuGeT2-.cjs"),i=require("./packem_shared/modelsToOpenApi-QqR_HHsz.cjs"),o=require("./packem_shared/RouteType-DLV_OhhD.cjs");exports.PrismaAdapter=e;exports.CrudApiError=r;exports.baseHandler=u;exports.modelsToOpenApi=i;exports.RouteType=o.RouteType;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { HttpError } from 'http-errors';
2
- import { C as Condition, S as SearchCondition, F as FakePrismaClient, P as PaginationData, a as ParsedQueryParameters, A as Adapter, R as RouteType, M as ModelsOptions } from "./packem_shared/types.d-BDmE9rKc.cjs";
3
- export { type H as CrudHandlerOptions, type b as HandlerParameters, type c as ModelOption, type O as OrderByField, type d as OrderByOperator, type e as PaginationConfig, type f as RecursiveField, type U as UniqueResourceHandlerParameters, type W as WhereCondition, type g as WhereField, type h as WhereOperator } from "./packem_shared/types.d-BDmE9rKc.cjs";
2
+ import { C as Condition, S as SearchCondition, F as FakePrismaClient, P as PaginationData, a as ParsedQueryParameters, A as Adapter, H as HandlerOptions, E as ExecuteHandler, R as RouteType, M as ModelsOptions } from "./packem_shared/types.d-CQwyFrf3.cjs";
3
+ export type { B as BodySchema, b as CreateHandler, D as DeleteHandler, G as GetHandler, c as HandlerParameters, L as ListHandler, d as ModelAccessPolicy, e as ModelOption, O as OrderByField, f as OrderByOperator, g as PaginationConfig, h as RecursiveField, U as UniqueResourceHandlerParameters, i as UpdateHandler, W as WhereCondition, j as WhereField, k as WhereOperator } from "./packem_shared/types.d-CQwyFrf3.cjs";
4
+ import { IncomingMessage, ServerResponse } from 'node:http';
4
5
  import { OpenAPIV3 } from 'openapi-types';
5
6
  type PrismaRecursiveField = "include" | "select";
6
7
  type PrismaRecursive<T extends PrismaRecursiveField> = Record<string, boolean | { [key in T]: PrismaRecursive<T> }>;
@@ -28,7 +29,33 @@ interface PrismaParsedQueryParameters {
28
29
  take?: number;
29
30
  where?: PrismaWhereField;
30
31
  }
32
+ /**
33
+ * The shape of `Prisma.dmmf` exposed by Prisma 5/6 generated clients. Only the
34
+ * model names are needed by this adapter.
35
+ */
36
+ interface PrismaDmmf {
37
+ datamodel?: {
38
+ models?: {
39
+ name: string;
40
+ }[];
41
+ };
42
+ }
31
43
  interface AdapterCtorArguments<M extends string, PrismaClient> {
44
+ /**
45
+ * When `true` (default) ISO date-looking strings in `where` filters are
46
+ * coerced to `Date` instances so they match Prisma `DateTime` columns. Set
47
+ * to `false` to keep them as strings — required when filtering a *string*
48
+ * column whose values happen to look like dates.
49
+ */
50
+ coerceWhereDates?: boolean;
51
+ /**
52
+ * The `Prisma.dmmf` object from your generated client
53
+ * (`import { Prisma } from "@prisma/client"`). Required for Prisma 5/6,
54
+ * where the private `_dmmf`/`_getDmmf` internals this adapter used to read
55
+ * were removed. If omitted, the adapter falls back to those internals for
56
+ * Prisma 3/4 compatibility, then to `prismaClient._runtimeDataModel`.
57
+ */
58
+ dmmf?: PrismaDmmf;
32
59
  manyRelations?: { [key in M]?: string[] };
33
60
  models?: M[];
34
61
  primaryKey?: string;
@@ -41,7 +68,11 @@ declare class PrismaAdapter<T, M extends string, PrismaClient> implements Adapte
41
68
  private readonly manyRelations;
42
69
  private readonly primaryKey;
43
70
  private readonly prismaClient;
71
+ private readonly coerceWhereDates;
72
+ private readonly ctorDmmf?;
44
73
  constructor({
74
+ coerceWhereDates,
75
+ dmmf,
45
76
  manyRelations,
46
77
  models,
47
78
  primaryKey,
@@ -64,6 +95,27 @@ declare class PrismaAdapter<T, M extends string, PrismaClient> implements Adapte
64
95
  private readonly getPrismaClientModels;
65
96
  private getPrismaDelegate;
66
97
  }
98
+ /**
99
+ * Framework-agnostic API error used internally by the base CRUD handler.
100
+ *
101
+ * Previously this package deep-imported `ApiError` from `next/dist/server/api-utils/index.js`,
102
+ * which made the "framework-agnostic" core throw on import when `next` was not
103
+ * installed (it is only an optional peer) and was fragile across Next.js majors.
104
+ *
105
+ * `CrudApiError` is a drop-in replacement: it carries an HTTP `statusCode` and a
106
+ * message, and the handler uses `instanceof CrudApiError` to decide whether an
107
+ * error should bypass the adapter's `handleError` hook.
108
+ */
109
+ declare class CrudApiError extends Error {
110
+ readonly statusCode: number;
111
+ constructor(statusCode: number, message: string);
112
+ }
113
+ interface ResponseConfig {
114
+ data: unknown;
115
+ status: number;
116
+ }
117
+ declare function baseHandler<R extends Request, Context, T, Q extends ParsedQueryParameters = ParsedQueryParameters, M extends string = string>(responseExecutor: (responseOrContext: Context, responseConfig: ResponseConfig) => Promise<Response>, finalExecutor: (responseOrContext: Context) => Promise<void>, adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, Context, Response>>;
118
+ declare function baseHandler<R extends IncomingMessage, RResponse extends ServerResponse, T, Q extends ParsedQueryParameters = ParsedQueryParameters, M extends string = string>(responseExecutor: (responseOrContext: RResponse, responseConfig: ResponseConfig) => Promise<void>, finalExecutor: (responseOrContext: RResponse) => Promise<void>, adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, RResponse>>;
67
119
  interface SwaggerType {
68
120
  description?: string;
69
121
  isArray?: boolean;
@@ -97,6 +149,7 @@ type SwaggerModelsConfig<M extends string> = { [key in M]?: ModelsConfig };
97
149
  declare const modelsToOpenApi: <M extends string = string, PrismaClient = FakePrismaClient>({
98
150
  crud,
99
151
  defaultExposeStrategy,
152
+ dmmf: ctorDmmf,
100
153
  models: ctorModels,
101
154
  prismaClient,
102
155
  swagger
@@ -111,6 +164,14 @@ interface ModelsToOpenApiParameters<M extends string, PrismaClient> {
111
164
  models: ModelsOptions<M>;
112
165
  };
113
166
  defaultExposeStrategy?: "all" | "none";
167
+ /**
168
+ * The full Prisma DMMF document (must contain `mappingsMap`). Required for
169
+ * Prisma 5/6, where the private `_dmmf`/`_getDmmf` internals this generator
170
+ * used to read were removed.
171
+ */
172
+ dmmf?: {
173
+ mappingsMap: Record<string, object>;
174
+ };
114
175
  models?: M[];
115
176
  prismaClient: FakePrismaClient & PrismaClient;
116
177
  swagger?: Partial<{
@@ -118,4 +179,4 @@ interface ModelsToOpenApiParameters<M extends string, PrismaClient> {
118
179
  models: SwaggerModelsConfig<M>;
119
180
  }>;
120
181
  }
121
- export { type Adapter, type Condition, type ModelsOptions, type ModelsToOpenApiParameters, type PaginationData, type ParsedQueryParameters, PrismaAdapter, RouteType, type SearchCondition, type SwaggerModelsConfig, modelsToOpenApi };
182
+ export { type Adapter, type Condition, CrudApiError, type HandlerOptions as CrudHandlerOptions, type ExecuteHandler, type ModelsOptions, type ModelsToOpenApiParameters, type PaginationData, type ParsedQueryParameters, PrismaAdapter, RouteType, type SearchCondition, type SwaggerModelsConfig, baseHandler, modelsToOpenApi };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { HttpError } from 'http-errors';
2
- import { C as Condition, S as SearchCondition, F as FakePrismaClient, P as PaginationData, a as ParsedQueryParameters, A as Adapter, R as RouteType, M as ModelsOptions } from "./packem_shared/types.d-BDmE9rKc.mjs";
3
- export { type H as CrudHandlerOptions, type b as HandlerParameters, type c as ModelOption, type O as OrderByField, type d as OrderByOperator, type e as PaginationConfig, type f as RecursiveField, type U as UniqueResourceHandlerParameters, type W as WhereCondition, type g as WhereField, type h as WhereOperator } from "./packem_shared/types.d-BDmE9rKc.mjs";
2
+ import { C as Condition, S as SearchCondition, F as FakePrismaClient, P as PaginationData, a as ParsedQueryParameters, A as Adapter, H as HandlerOptions, E as ExecuteHandler, R as RouteType, M as ModelsOptions } from "./packem_shared/types.d-CQwyFrf3.mjs";
3
+ export type { B as BodySchema, b as CreateHandler, D as DeleteHandler, G as GetHandler, c as HandlerParameters, L as ListHandler, d as ModelAccessPolicy, e as ModelOption, O as OrderByField, f as OrderByOperator, g as PaginationConfig, h as RecursiveField, U as UniqueResourceHandlerParameters, i as UpdateHandler, W as WhereCondition, j as WhereField, k as WhereOperator } from "./packem_shared/types.d-CQwyFrf3.mjs";
4
+ import { IncomingMessage, ServerResponse } from 'node:http';
4
5
  import { OpenAPIV3 } from 'openapi-types';
5
6
  type PrismaRecursiveField = "include" | "select";
6
7
  type PrismaRecursive<T extends PrismaRecursiveField> = Record<string, boolean | { [key in T]: PrismaRecursive<T> }>;
@@ -28,7 +29,33 @@ interface PrismaParsedQueryParameters {
28
29
  take?: number;
29
30
  where?: PrismaWhereField;
30
31
  }
32
+ /**
33
+ * The shape of `Prisma.dmmf` exposed by Prisma 5/6 generated clients. Only the
34
+ * model names are needed by this adapter.
35
+ */
36
+ interface PrismaDmmf {
37
+ datamodel?: {
38
+ models?: {
39
+ name: string;
40
+ }[];
41
+ };
42
+ }
31
43
  interface AdapterCtorArguments<M extends string, PrismaClient> {
44
+ /**
45
+ * When `true` (default) ISO date-looking strings in `where` filters are
46
+ * coerced to `Date` instances so they match Prisma `DateTime` columns. Set
47
+ * to `false` to keep them as strings — required when filtering a *string*
48
+ * column whose values happen to look like dates.
49
+ */
50
+ coerceWhereDates?: boolean;
51
+ /**
52
+ * The `Prisma.dmmf` object from your generated client
53
+ * (`import { Prisma } from "@prisma/client"`). Required for Prisma 5/6,
54
+ * where the private `_dmmf`/`_getDmmf` internals this adapter used to read
55
+ * were removed. If omitted, the adapter falls back to those internals for
56
+ * Prisma 3/4 compatibility, then to `prismaClient._runtimeDataModel`.
57
+ */
58
+ dmmf?: PrismaDmmf;
32
59
  manyRelations?: { [key in M]?: string[] };
33
60
  models?: M[];
34
61
  primaryKey?: string;
@@ -41,7 +68,11 @@ declare class PrismaAdapter<T, M extends string, PrismaClient> implements Adapte
41
68
  private readonly manyRelations;
42
69
  private readonly primaryKey;
43
70
  private readonly prismaClient;
71
+ private readonly coerceWhereDates;
72
+ private readonly ctorDmmf?;
44
73
  constructor({
74
+ coerceWhereDates,
75
+ dmmf,
45
76
  manyRelations,
46
77
  models,
47
78
  primaryKey,
@@ -64,6 +95,27 @@ declare class PrismaAdapter<T, M extends string, PrismaClient> implements Adapte
64
95
  private readonly getPrismaClientModels;
65
96
  private getPrismaDelegate;
66
97
  }
98
+ /**
99
+ * Framework-agnostic API error used internally by the base CRUD handler.
100
+ *
101
+ * Previously this package deep-imported `ApiError` from `next/dist/server/api-utils/index.js`,
102
+ * which made the "framework-agnostic" core throw on import when `next` was not
103
+ * installed (it is only an optional peer) and was fragile across Next.js majors.
104
+ *
105
+ * `CrudApiError` is a drop-in replacement: it carries an HTTP `statusCode` and a
106
+ * message, and the handler uses `instanceof CrudApiError` to decide whether an
107
+ * error should bypass the adapter's `handleError` hook.
108
+ */
109
+ declare class CrudApiError extends Error {
110
+ readonly statusCode: number;
111
+ constructor(statusCode: number, message: string);
112
+ }
113
+ interface ResponseConfig {
114
+ data: unknown;
115
+ status: number;
116
+ }
117
+ declare function baseHandler<R extends Request, Context, T, Q extends ParsedQueryParameters = ParsedQueryParameters, M extends string = string>(responseExecutor: (responseOrContext: Context, responseConfig: ResponseConfig) => Promise<Response>, finalExecutor: (responseOrContext: Context) => Promise<void>, adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, Context, Response>>;
118
+ declare function baseHandler<R extends IncomingMessage, RResponse extends ServerResponse, T, Q extends ParsedQueryParameters = ParsedQueryParameters, M extends string = string>(responseExecutor: (responseOrContext: RResponse, responseConfig: ResponseConfig) => Promise<void>, finalExecutor: (responseOrContext: RResponse) => Promise<void>, adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, RResponse>>;
67
119
  interface SwaggerType {
68
120
  description?: string;
69
121
  isArray?: boolean;
@@ -97,6 +149,7 @@ type SwaggerModelsConfig<M extends string> = { [key in M]?: ModelsConfig };
97
149
  declare const modelsToOpenApi: <M extends string = string, PrismaClient = FakePrismaClient>({
98
150
  crud,
99
151
  defaultExposeStrategy,
152
+ dmmf: ctorDmmf,
100
153
  models: ctorModels,
101
154
  prismaClient,
102
155
  swagger
@@ -111,6 +164,14 @@ interface ModelsToOpenApiParameters<M extends string, PrismaClient> {
111
164
  models: ModelsOptions<M>;
112
165
  };
113
166
  defaultExposeStrategy?: "all" | "none";
167
+ /**
168
+ * The full Prisma DMMF document (must contain `mappingsMap`). Required for
169
+ * Prisma 5/6, where the private `_dmmf`/`_getDmmf` internals this generator
170
+ * used to read were removed.
171
+ */
172
+ dmmf?: {
173
+ mappingsMap: Record<string, object>;
174
+ };
114
175
  models?: M[];
115
176
  prismaClient: FakePrismaClient & PrismaClient;
116
177
  swagger?: Partial<{
@@ -118,4 +179,4 @@ interface ModelsToOpenApiParameters<M extends string, PrismaClient> {
118
179
  models: SwaggerModelsConfig<M>;
119
180
  }>;
120
181
  }
121
- export { type Adapter, type Condition, type ModelsOptions, type ModelsToOpenApiParameters, type PaginationData, type ParsedQueryParameters, PrismaAdapter, RouteType, type SearchCondition, type SwaggerModelsConfig, modelsToOpenApi };
182
+ export { type Adapter, type Condition, CrudApiError, type HandlerOptions as CrudHandlerOptions, type ExecuteHandler, type ModelsOptions, type ModelsToOpenApiParameters, type PaginationData, type ParsedQueryParameters, PrismaAdapter, RouteType, type SearchCondition, type SwaggerModelsConfig, baseHandler, modelsToOpenApi };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { HttpError } from 'http-errors';
2
- import { C as Condition, S as SearchCondition, F as FakePrismaClient, P as PaginationData, a as ParsedQueryParameters, A as Adapter, R as RouteType, M as ModelsOptions } from "./packem_shared/types.d-BDmE9rKc.js";
3
- export { type H as CrudHandlerOptions, type b as HandlerParameters, type c as ModelOption, type O as OrderByField, type d as OrderByOperator, type e as PaginationConfig, type f as RecursiveField, type U as UniqueResourceHandlerParameters, type W as WhereCondition, type g as WhereField, type h as WhereOperator } from "./packem_shared/types.d-BDmE9rKc.js";
2
+ import { C as Condition, S as SearchCondition, F as FakePrismaClient, P as PaginationData, a as ParsedQueryParameters, A as Adapter, H as HandlerOptions, E as ExecuteHandler, R as RouteType, M as ModelsOptions } from "./packem_shared/types.d-CQwyFrf3.js";
3
+ export type { B as BodySchema, b as CreateHandler, D as DeleteHandler, G as GetHandler, c as HandlerParameters, L as ListHandler, d as ModelAccessPolicy, e as ModelOption, O as OrderByField, f as OrderByOperator, g as PaginationConfig, h as RecursiveField, U as UniqueResourceHandlerParameters, i as UpdateHandler, W as WhereCondition, j as WhereField, k as WhereOperator } from "./packem_shared/types.d-CQwyFrf3.js";
4
+ import { IncomingMessage, ServerResponse } from 'node:http';
4
5
  import { OpenAPIV3 } from 'openapi-types';
5
6
  type PrismaRecursiveField = "include" | "select";
6
7
  type PrismaRecursive<T extends PrismaRecursiveField> = Record<string, boolean | { [key in T]: PrismaRecursive<T> }>;
@@ -28,7 +29,33 @@ interface PrismaParsedQueryParameters {
28
29
  take?: number;
29
30
  where?: PrismaWhereField;
30
31
  }
32
+ /**
33
+ * The shape of `Prisma.dmmf` exposed by Prisma 5/6 generated clients. Only the
34
+ * model names are needed by this adapter.
35
+ */
36
+ interface PrismaDmmf {
37
+ datamodel?: {
38
+ models?: {
39
+ name: string;
40
+ }[];
41
+ };
42
+ }
31
43
  interface AdapterCtorArguments<M extends string, PrismaClient> {
44
+ /**
45
+ * When `true` (default) ISO date-looking strings in `where` filters are
46
+ * coerced to `Date` instances so they match Prisma `DateTime` columns. Set
47
+ * to `false` to keep them as strings — required when filtering a *string*
48
+ * column whose values happen to look like dates.
49
+ */
50
+ coerceWhereDates?: boolean;
51
+ /**
52
+ * The `Prisma.dmmf` object from your generated client
53
+ * (`import { Prisma } from "@prisma/client"`). Required for Prisma 5/6,
54
+ * where the private `_dmmf`/`_getDmmf` internals this adapter used to read
55
+ * were removed. If omitted, the adapter falls back to those internals for
56
+ * Prisma 3/4 compatibility, then to `prismaClient._runtimeDataModel`.
57
+ */
58
+ dmmf?: PrismaDmmf;
32
59
  manyRelations?: { [key in M]?: string[] };
33
60
  models?: M[];
34
61
  primaryKey?: string;
@@ -41,7 +68,11 @@ declare class PrismaAdapter<T, M extends string, PrismaClient> implements Adapte
41
68
  private readonly manyRelations;
42
69
  private readonly primaryKey;
43
70
  private readonly prismaClient;
71
+ private readonly coerceWhereDates;
72
+ private readonly ctorDmmf?;
44
73
  constructor({
74
+ coerceWhereDates,
75
+ dmmf,
45
76
  manyRelations,
46
77
  models,
47
78
  primaryKey,
@@ -64,6 +95,27 @@ declare class PrismaAdapter<T, M extends string, PrismaClient> implements Adapte
64
95
  private readonly getPrismaClientModels;
65
96
  private getPrismaDelegate;
66
97
  }
98
+ /**
99
+ * Framework-agnostic API error used internally by the base CRUD handler.
100
+ *
101
+ * Previously this package deep-imported `ApiError` from `next/dist/server/api-utils/index.js`,
102
+ * which made the "framework-agnostic" core throw on import when `next` was not
103
+ * installed (it is only an optional peer) and was fragile across Next.js majors.
104
+ *
105
+ * `CrudApiError` is a drop-in replacement: it carries an HTTP `statusCode` and a
106
+ * message, and the handler uses `instanceof CrudApiError` to decide whether an
107
+ * error should bypass the adapter's `handleError` hook.
108
+ */
109
+ declare class CrudApiError extends Error {
110
+ readonly statusCode: number;
111
+ constructor(statusCode: number, message: string);
112
+ }
113
+ interface ResponseConfig {
114
+ data: unknown;
115
+ status: number;
116
+ }
117
+ declare function baseHandler<R extends Request, Context, T, Q extends ParsedQueryParameters = ParsedQueryParameters, M extends string = string>(responseExecutor: (responseOrContext: Context, responseConfig: ResponseConfig) => Promise<Response>, finalExecutor: (responseOrContext: Context) => Promise<void>, adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, Context, Response>>;
118
+ declare function baseHandler<R extends IncomingMessage, RResponse extends ServerResponse, T, Q extends ParsedQueryParameters = ParsedQueryParameters, M extends string = string>(responseExecutor: (responseOrContext: RResponse, responseConfig: ResponseConfig) => Promise<void>, finalExecutor: (responseOrContext: RResponse) => Promise<void>, adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, RResponse>>;
67
119
  interface SwaggerType {
68
120
  description?: string;
69
121
  isArray?: boolean;
@@ -97,6 +149,7 @@ type SwaggerModelsConfig<M extends string> = { [key in M]?: ModelsConfig };
97
149
  declare const modelsToOpenApi: <M extends string = string, PrismaClient = FakePrismaClient>({
98
150
  crud,
99
151
  defaultExposeStrategy,
152
+ dmmf: ctorDmmf,
100
153
  models: ctorModels,
101
154
  prismaClient,
102
155
  swagger
@@ -111,6 +164,14 @@ interface ModelsToOpenApiParameters<M extends string, PrismaClient> {
111
164
  models: ModelsOptions<M>;
112
165
  };
113
166
  defaultExposeStrategy?: "all" | "none";
167
+ /**
168
+ * The full Prisma DMMF document (must contain `mappingsMap`). Required for
169
+ * Prisma 5/6, where the private `_dmmf`/`_getDmmf` internals this generator
170
+ * used to read were removed.
171
+ */
172
+ dmmf?: {
173
+ mappingsMap: Record<string, object>;
174
+ };
114
175
  models?: M[];
115
176
  prismaClient: FakePrismaClient & PrismaClient;
116
177
  swagger?: Partial<{
@@ -118,4 +179,4 @@ interface ModelsToOpenApiParameters<M extends string, PrismaClient> {
118
179
  models: SwaggerModelsConfig<M>;
119
180
  }>;
120
181
  }
121
- export { type Adapter, type Condition, type ModelsOptions, type ModelsToOpenApiParameters, type PaginationData, type ParsedQueryParameters, PrismaAdapter, RouteType, type SearchCondition, type SwaggerModelsConfig, modelsToOpenApi };
182
+ export { type Adapter, type Condition, CrudApiError, type HandlerOptions as CrudHandlerOptions, type ExecuteHandler, type ModelsOptions, type ModelsToOpenApiParameters, type PaginationData, type ParsedQueryParameters, PrismaAdapter, RouteType, type SearchCondition, type SwaggerModelsConfig, baseHandler, modelsToOpenApi };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{default as r}from"./packem_shared/PrismaAdapter-BVs7BWSG.mjs";import{default as t}from"./packem_shared/modelsToOpenApi-ocNrUF5p.mjs";import{RouteType as f}from"./packem_shared/RouteType-BQ2RxFPE.mjs";export{r as PrismaAdapter,f as RouteType,t as modelsToOpenApi};
1
+ import{default as o}from"./packem_shared/PrismaAdapter-Bhocjq94.mjs";import{default as t}from"./packem_shared/CrudApiError-BH1byAwV.mjs";import{default as f}from"./packem_shared/baseHandler-BGTzX4YA.mjs";import{default as m}from"./packem_shared/modelsToOpenApi-pOMrwJIY.mjs";import{RouteType as l}from"./packem_shared/RouteType-BQ2RxFPE.mjs";export{t as CrudApiError,o as PrismaAdapter,l as RouteType,f as baseHandler,m as modelsToOpenApi};
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("../packem_shared/edgeHandler-CHig8R94.cjs"),r=require("../packem_shared/nodeHandler-Di5MpzCj.cjs");exports.edgeHandler=e;exports.nodeHandler=r;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("../packem_shared/edgeHandler-DQ2KLGlC.cjs"),r=require("../packem_shared/nodeHandler-tp623oY3.cjs");exports.edgeHandler=e;exports.nodeHandler=r;