@nest-admin/nestjs 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/prisma.cjs CHANGED
@@ -531,6 +531,16 @@ function toConstraintError(cause, model) {
531
531
  return new ConstraintError(constraint, model, fieldsFrom(cause.meta));
532
532
  }
533
533
  __name(toConstraintError, "toConstraintError");
534
+ function coerceId(model, fieldName, id) {
535
+ const field = model.fields.find((candidate) => candidate.name === fieldName);
536
+ if (field?.kind !== "number" || typeof id === "number") return id;
537
+ const numeric = Number(id);
538
+ if (!Number.isFinite(numeric)) {
539
+ throw new InvalidQueryError(`Invalid id ${JSON.stringify(id)} for numeric primary key "${model.name}.${fieldName}".`);
540
+ }
541
+ return numeric;
542
+ }
543
+ __name(coerceId, "coerceId");
534
544
  function toRelatedWhere(parent, relationFieldName, parentId, models) {
535
545
  const field = parent.fields.find((candidate) => candidate.name === relationFieldName);
536
546
  if (!field?.relation) {
@@ -552,7 +562,7 @@ function toRelatedWhere(parent, relationFieldName, parentId, models) {
552
562
  throw new FieldNotFoundError(parent.name, relationFieldName, `${parent.name} has no primary key.`);
553
563
  }
554
564
  const match = {
555
- [parentKey]: parentId
565
+ [parentKey]: coerceId(parent, parentKey, parentId)
556
566
  };
557
567
  return {
558
568
  target,
@@ -935,8 +945,10 @@ var PrismaAdapter = class {
935
945
  where: this.#whereById(metadata, id),
936
946
  data: {
937
947
  [relationField]: {
948
+ // Against the *target's* key, not this model's - the two ends of
949
+ // a relation can be typed differently.
938
950
  [operation]: {
939
- [targetKey]: targetId
951
+ [targetKey]: coerceId(target, targetKey, targetId)
940
952
  }
941
953
  }
942
954
  }
@@ -978,25 +990,10 @@ var PrismaAdapter = class {
978
990
  throw new InvalidQueryError(`Model "${model.name}" has a composite primary key (${model.primaryKey.join(", ")}), which is not supported in this version.`);
979
991
  }
980
992
  return {
981
- [primaryKeyField]: this.#coerceId(model, primaryKeyField, id)
993
+ [primaryKeyField]: coerceId(model, primaryKeyField, id)
982
994
  };
983
995
  }
984
996
  /**
985
- * Coerce an id to the type the schema declares.
986
- *
987
- * Ids arriving from a URL are always strings, but a Prisma `Int @id` column
988
- * must be queried with a number or Prisma rejects the argument.
989
- */
990
- #coerceId(model, fieldName, id) {
991
- const field = model.fields.find((candidate) => candidate.name === fieldName);
992
- if (field?.kind !== "number" || typeof id === "number") return id;
993
- const numeric = Number(id);
994
- if (!Number.isFinite(numeric)) {
995
- throw new InvalidQueryError(`Invalid id ${JSON.stringify(id)} for numeric primary key "${model.name}.${fieldName}".`);
996
- }
997
- return numeric;
998
- }
999
- /**
1000
997
  * Reject anything the caller has no business writing.
1001
998
  *
1002
999
  * Unknown keys are an error rather than silently dropped: quietly discarding
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/prisma.ts","../../core/src/auth/account.ts","../../core/src/metadata/created-field.ts","../../core/src/metadata/display-field.ts","../../core/src/metadata/relation-shape.ts","../../core/src/config/resources.ts","../../core/src/config/overrides.ts","../../core/src/errors/errors.ts","../../prisma/src/adapter.ts","../../prisma/src/client/delegate.ts","../../prisma/src/client/version-gate.ts","../../prisma/src/metadata/read-dmmf.ts","../../prisma/src/metadata/to-metadata.ts","../../prisma/src/query/to-include.ts","../../prisma/src/errors/constraints.ts","../../prisma/src/query/to-related-where.ts","../../prisma/src/query/to-prisma-args.ts","../../prisma/src/auth/store.ts"],"sourcesContent":["/**\n * `@nest-admin/nestjs/prisma` - the Prisma adapter subpath.\n *\n * Keeping the adapter behind a subpath rather than the root entrypoint means\n * an application that never touches Prisma never loads Prisma code, and a\n * future `@nest-admin/nestjs/typeorm` slots in beside it without changing\n * the root export.\n *\n * The adapter itself is not implemented yet.\n */\n\nexport * from '@nest-admin/prisma'\n","/**\n * Where admin accounts live, as a contract.\n *\n * ## Why this exists at all\n *\n * Until 0.9.0 the answer to \"who may open the admin?\" was always the host\n * application's: it already had sessions, and `AdminAuth` asked it one\n * question. That is still right for a team that has an identity system, and\n * nothing about it changes.\n *\n * It is a wall for everyone else. An application with no login of its own had\n * to write a password hash, a session cookie and a form before the admin could\n * go anywhere near production - which is a strange thing to ask of a package\n * whose whole claim is that you do not build an admin.\n *\n * ## Why it is a contract rather than a table\n *\n * The same reason `OrmAdapter` is. An admin whose accounts can only live in\n * Prisma has learned about Prisma, and the second ORM would find out the hard\n * way. Everything here is plain data and promises; nothing knows what a\n * database is.\n *\n * ## These accounts are not the application's users\n *\n * Deliberately, and this is the point most worth getting right. The people who\n * administer a system are usually not rows in the table they administer, and\n * conflating the two means a customer record with a password that opens the\n * admin. The store is separate storage - a different model, or a different\n * database entirely - and the admin never reads or writes the application's\n * own users to decide who may sign in.\n */\n\n/** One account that may sign in to the admin. */\nexport interface AdminAccount {\n readonly id: string\n\n /**\n * What is typed into the login form.\n *\n * Called `email` because that is what it almost always is, and a name people\n * recognise is worth more than one that covers a case nobody has. A store is\n * free to hold usernames in it.\n */\n readonly email: string\n\n /** Shown in the interface. Falls back to the email when absent. */\n readonly name?: string | undefined\n\n /**\n * The stored password hash, in whatever form the hasher produced.\n *\n * Read by the sign-in check and by nothing else. It must never reach a\n * response, and the account the interface is told about is a projection that\n * does not include it.\n */\n readonly passwordHash: string\n\n /**\n * Suspended without being deleted.\n *\n * Distinct from removing the row: an account that has done things is worth\n * keeping for the record, and \"cannot sign in\" is not the same fact as\n * \"never existed\".\n */\n readonly disabled?: boolean | undefined\n}\n\n/**\n * The account as the interface may see it.\n *\n * A separate type rather than a comment on {@link AdminAccount}, because \"do\n * not send the hash\" is a rule that gets forgotten and a type that cannot\n * carry it does not.\n */\nexport interface AdminAccountSummary {\n readonly id: string\n readonly email: string\n readonly name?: string | undefined\n}\n\n/** Everything but the hash. The only shape that may reach a client. */\nexport function summarise(account: AdminAccount): AdminAccountSummary {\n return {\n id: account.id,\n email: account.email,\n ...(account.name !== undefined ? { name: account.name } : {}),\n }\n}\n\n/**\n * How the admin reaches its accounts.\n *\n * Read-only by design. Creating and editing accounts is the application's\n * business: it owns the storage, it knows whether that is a migration, a seed\n * script or a form somewhere else, and an admin that could mint its own\n * administrators is an escalation waiting for its first mistake.\n */\nexport interface AdminAccountStore {\n /**\n * Find an account by what was typed into the login form.\n *\n * Matching is the store's decision, and it should be case-insensitive on the\n * local part in practice: someone who registered as `Ada@example.com` will\n * type `ada@example.com` eventually.\n *\n * Returns `null` when there is none. The caller must not behave observably\n * differently for `null` than for a wrong password - see the sign-in code.\n */\n findByEmail(email: string): Promise<AdminAccount | null>\n\n /**\n * Find an account by its id, for a request that arrives with a session.\n *\n * Called on every authenticated request, so it should be cheap. It is also\n * what makes a disabled or deleted account stop working immediately rather\n * than when its session happens to expire.\n */\n findById(id: string): Promise<AdminAccount | null>\n\n /**\n * How many accounts exist.\n *\n * Used once, at startup, to say so when the answer is zero - an admin nobody\n * can sign in to is a configuration mistake that otherwise announces itself\n * as a login form that rejects everything.\n */\n count(): Promise<number>\n\n /**\n * Note that an account signed in. Optional.\n *\n * A store that does not care about this can leave it out; the sign-in path\n * does not wait for it and a failure is logged rather than surfaced, because\n * \"your login worked but we could not write down that it did\" is not\n * something the person signing in can act on.\n */\n recordLogin?(id: string): Promise<void>\n\n /**\n * What this store reads, for diagnostics. Optional.\n *\n * A model name, a table, a directory - whatever names the storage in a way a\n * person would recognise. It exists so a startup check can say something\n * useful rather than something generic: an admin that exposes its own\n * account model as an editable resource is an escalation, and a warning that\n * cannot name the model is a warning nobody acts on.\n *\n * Never used to decide anything, and never sent to a client.\n */\n readonly describes?: string\n}\n","/**\n * Which field records when a row appeared.\n *\n * A dashboard's most useful question is \"how much of this arrived recently\",\n * and answering it needs one column: the timestamp a record was created. Every\n * conventional schema has one and none of them declare it as such.\n *\n * ## Why this is a guess\n *\n * The metadata cannot tell a creation timestamp from any other generated date.\n * Prisma reports both `@default(now())` and `@updatedAt` the same way - the\n * adapter collapses them into `isGenerated`, because for *editing* they are the\n * same thing: neither is asked of a person. That is the right call for a form\n * and leaves nothing to distinguish them here.\n *\n * So this reads names, exactly as `displayFieldFor` does, and for the same\n * reason: the convention is near-universal and the alternative is a dashboard\n * that shows nothing until every application has annotated its schema.\n *\n * ## What it refuses to guess\n *\n * `updatedAt` and its variants are excluded rather than merely ranked lower. A\n * chart of \"records updated per day\" plotted under the heading \"new records\"\n * is worse than no chart: it is confidently wrong, and nothing about it looks\n * wrong. Where the convention is not followed, the answer is `undefined` and\n * the widget is simply not offered.\n */\nimport type { FieldMetadata, ModelMetadata } from './model.js'\n\n/**\n * Names that mean \"when this was created\", most conventional first.\n *\n * Snake case is included because a schema mapped onto an existing database\n * often keeps the column names it found there.\n */\nconst CREATED = ['createdAt', 'created_at', 'created', 'createdOn', 'insertedAt', 'inserted_at']\n\n/**\n * Names that must never be taken for it.\n *\n * Checked case-insensitively and by prefix, so `updatedAt`, `updated_at` and\n * `updateTime` are all excluded. Being wrong here is silent: a chart titled\n * \"new this month\" that is actually counting edits.\n */\nconst NOT_CREATED = ['updated', 'modified', 'deleted', 'archived', 'expires', 'expired']\n\nfunction isDate(field: FieldMetadata): boolean {\n return field.kind === 'datetime' && !field.isList && !field.relation\n}\n\nfunction excluded(name: string): boolean {\n const lower = name.toLowerCase()\n return NOT_CREATED.some((word) => lower.startsWith(word))\n}\n\n/**\n * The field that records when a record of this model was created, if the model\n * follows the convention.\n *\n * Order of preference:\n *\n * 1. a conventional name, most conventional first;\n * 2. the only remaining generated date on the model - a model with exactly\n * one date the database fills in has no ambiguity to resolve;\n * 3. nothing.\n *\n * The third is a real answer. A widget that cannot be built correctly is not\n * offered, which is a better outcome than one built on a column that means\n * something else.\n */\nexport function createdFieldFor(model: ModelMetadata): string | undefined {\n const dates = model.fields.filter(isDate)\n\n for (const conventional of CREATED) {\n const match = dates.find((field) => field.name.toLowerCase() === conventional.toLowerCase())\n if (match) return match.name\n }\n\n const generated = dates.filter((field) => field.isGenerated && !excluded(field.name))\n return generated.length === 1 ? generated[0]?.name : undefined\n}\n","/**\n * Which field names a record when it has to be referred to in one line.\n *\n * A relation is stored as an id, and an id is not something a person can read.\n * An admin that renders `cmtf50g710000mocjbygyfyfr` where it means \"Ada\n * Lovelace\" is technically correct and useless, so every model needs one field\n * that stands for the record.\n *\n * The rule lives in Core rather than in an adapter because it is a question\n * about a *model*, not about an ORM: the same reasoning applies whatever\n * produced the metadata. Two places need the answer and must agree on it - the\n * adapter, which selects the column when loading a relation, and the metadata\n * document, which tells the UI what to render.\n */\nimport type { FieldMetadata, ModelMetadata } from './model.js'\n\n/**\n * Conventional names for \"the human-readable one\", most specific first.\n *\n * Ordered by how strongly the name implies a label. `name` and `title` are\n * unambiguous; `email` is a real identifier people recognise; `slug` is a\n * last resort among the conventional names because it is machine-shaped, but\n * it is still readable, which an id is not.\n */\nconst CONVENTIONAL = ['name', 'title', 'label', 'displayName', 'username', 'email', 'slug']\n\n/** Could this field stand in for the record in a list or a dropdown? */\nfunction isReadable(field: FieldMetadata): boolean {\n return (\n field.kind === 'string' &&\n !field.isList &&\n !field.relation &&\n // A generated string is a cuid or a uuid: readable characters, no meaning.\n !field.isGenerated\n )\n}\n\n/**\n * Pick the field that names a record of this model.\n *\n * Order of preference:\n *\n * 1. a conventional name (`name`, `title`, ...), most specific first;\n * 2. any other unique string - unique suggests it identifies the record;\n * 3. any other plain string;\n * 4. the first primary-key field.\n *\n * The last step is the honest fallback rather than a good answer: a model with\n * nothing but an id and a timestamp has no readable field, and showing the id\n * is better than showing nothing. Adapters and applications may override the\n * result; this is the default, not a rule.\n */\nexport function displayFieldFor(model: ModelMetadata): string {\n // A declared choice wins outright. The rule below is a guess, and the\n // application knows things the schema does not.\n if (model.displayField !== undefined) return model.displayField\n\n const readable = model.fields.filter(isReadable)\n\n for (const candidate of CONVENTIONAL) {\n const match = readable.find((field) => field.name === candidate)\n if (match) return match.name\n }\n\n const unique = readable.find((field) => field.isUnique && !field.isId)\n if (unique) return unique.name\n\n const plain = readable.find((field) => !field.isId)\n if (plain) return plain.name\n\n return model.primaryKey[0] ?? model.fields[0]?.name ?? 'id'\n}\n","/**\n * Reading a to-many relation from the parent's side.\n *\n * From `User`, both `posts` (one-to-many) and `Post.tags` (many-to-many) look\n * identical: a list of related records. What differs is where the link is\n * stored, and therefore what changing it means.\n *\n * one-to-many the child owns a column. Attaching a post to a user rewrites\n * `post.authorId`, which also *detaches it from whoever had it*.\n * Detaching means clearing that column, which is impossible if\n * it is required.\n *\n * many-to-many neither side owns a column; the link lives in a join table.\n * Attaching and detaching add and remove a row there and change\n * nothing about either record.\n *\n * An interface that offers the same buttons for both is lying about one of\n * them, so the difference is resolved here, once, from metadata both adapters\n * already produce.\n */\nimport type { FieldMetadata, ModelMetadata } from './model.js'\n\nexport type RelationShape = 'to-one' | 'one-to-many' | 'many-to-many'\n\n/**\n * The field on the target model that is the other half of this relation.\n *\n * Matched by relation name, which is the only reliable pairing: two relations\n * between the same models (`author` and `reviewer`, both to `User`) are\n * otherwise indistinguishable. Returns `undefined` when the name is absent -\n * an adapter that does not supply one - or when the target is not in `models`.\n */\nexport function inverseRelationField(\n field: FieldMetadata,\n models: readonly ModelMetadata[],\n): FieldMetadata | undefined {\n const relation = field.relation\n if (!relation?.name) return undefined\n\n const target = models.find((model) => model.name === relation.targetModel)\n if (!target) return undefined\n\n return target.fields.find(\n (candidate) => candidate.relation?.name === relation.name && candidate !== field,\n )\n}\n\n/**\n * What kind of relation this is, from the side the field is declared on.\n *\n * A to-many whose other half is also a list is a many-to-many. Without an\n * inverse to look at - no relation name, or a target outside this admin - a\n * to-many is reported as `one-to-many`, the more conservative answer: it is the\n * shape whose write operations have preconditions, so treating a many-to-many\n * as one costs a refused detach rather than a corrupted record.\n */\nexport function relationShape(\n field: FieldMetadata,\n models: readonly ModelMetadata[],\n): RelationShape | undefined {\n const relation = field.relation\n if (!relation) return undefined\n if (relation.cardinality === 'one') return 'to-one'\n\n const inverse = inverseRelationField(field, models)\n return inverse?.relation?.cardinality === 'many' ? 'many-to-many' : 'one-to-many'\n}\n\n/**\n * Why a one-to-many relation cannot be detached, or `undefined` if it can.\n *\n * Detaching means clearing the child's foreign key, and a required column\n * cannot be cleared. The database would refuse it; saying so first is the\n * difference between \"you cannot remove this here, delete the record instead\"\n * and a constraint violation.\n */\nexport function detachBlockedReason(\n field: FieldMetadata,\n models: readonly ModelMetadata[],\n): string | undefined {\n if (relationShape(field, models) !== 'one-to-many') return undefined\n\n const inverse = inverseRelationField(field, models)\n if (!inverse?.isRequired) return undefined\n\n const target = field.relation?.targetModel ?? 'the related model'\n return (\n `${target}.${inverse.name} is required, so a ${target} record cannot exist ` +\n `without one. Delete the record, or point it at something else, instead of ` +\n `detaching it.`\n )\n}\n","/**\n * Which models the admin exposes at all.\n *\n * Distinct from resource authorization, and the two answer different questions.\n * A `ResourceSelection` is structural: it decides what the admin *is*, the same\n * for everyone, and a model outside it does not exist as far as the admin is\n * concerned. `AdminResourceAuth` is per-principal: the model exists, and this\n * caller may or may not act on it.\n *\n * That difference is visible in the response. An excluded model answers 404 -\n * there is no such resource - where a denied one answers 403.\n */\n\nexport interface ResourceSelection {\n /**\n * When present, only these models are exposed. Everything else is dropped,\n * including models added to the schema later - which is the point: an\n * allow-list does not quietly grow when someone edits the schema.\n */\n readonly include?: readonly string[]\n\n /**\n * Models removed from the selection, applied after `include`.\n *\n * The usual reason is a table that is not domain data: session stores,\n * migration bookkeeping, queue tables.\n */\n readonly exclude?: readonly string[]\n}\n\n/** Anything with a name - `ModelMetadata`, or a test's stand-in for one. */\ninterface Named {\n readonly name: string\n}\n\n/**\n * Apply a selection, preserving the adapter's own order.\n *\n * Order comes from the schema rather than from `include`, so that adding a name\n * to the list does not silently reshuffle the admin. Deciding the order models\n * appear in is a separate feature and is not this option's job.\n */\nexport function selectModels<T extends Named>(\n models: readonly T[],\n selection?: ResourceSelection,\n): readonly T[] {\n if (!selection) return models\n\n const included = selection.include ? new Set(selection.include) : undefined\n const excluded = new Set(selection.exclude ?? [])\n\n return models.filter(\n (model) => (included === undefined || included.has(model.name)) && !excluded.has(model.name),\n )\n}\n\n/**\n * Names in the selection that no model answers to.\n *\n * Worth reporting rather than ignoring: a typo in `exclude` leaves the model\n * exposed, which is the opposite of what was asked for and is invisible until\n * someone finds the table in the admin. A typo in `include` is louder - the\n * model simply never appears - but has the same cause.\n */\nexport function unknownSelectionNames<T extends Named>(\n models: readonly T[],\n selection?: ResourceSelection,\n): readonly string[] {\n if (!selection) return []\n\n const known = new Set(models.map((model) => model.name))\n const referenced = [...(selection.include ?? []), ...(selection.exclude ?? [])]\n\n return [...new Set(referenced.filter((name) => !known.has(name)))]\n}\n","/**\n * Per-model and per-field configuration.\n *\n * The schema says what a model *is*; this says how the admin should treat it.\n * Two different questions, so they are two different inputs - a column being a\n * string is a fact about the database, and that column being a password is a\n * fact about the application.\n *\n * The overrides divide into two kinds, and the difference matters:\n *\n * behaviour `hidden`, `readOnly`, `displayField`. Enforced. A hidden\n * field is removed from the metadata every layer reads, so it\n * cannot be filtered, sorted, written or returned - see\n * `applyOverrides`.\n *\n * behaviour `writeOnly` too - accepted on a write and stripped from\n * every read.\n *\n * presentation `label`, `widget`, `order`. Passed to the client, which is\n * free to ignore them. Nothing depends on them being honoured.\n *\n * Anything in the first group that were only presentation would be a security\n * hole with a reassuring name.\n */\nimport type { FieldMetadata, ModelMetadata } from '../metadata/model.js'\n\n/**\n * How a field should be edited, when its type does not say enough.\n *\n * A `string` column may be a sentence, a password, an address or a colour, and\n * the schema cannot tell them apart. Deliberately a closed list: a client has\n * to know how to render each one, so an open string would mean silently\n * falling back to a plain input and no way to notice.\n */\nexport type FieldWidget = 'textarea' | 'password' | 'email' | 'url' | 'color' | 'json'\n\nexport interface FieldOverride {\n /**\n * Remove the field from the admin entirely.\n *\n * **Enforced, not cosmetic.** The field is dropped from the metadata before\n * anything reads it, so it is absent from the schema document, rejected in\n * filters and sorts, refused in writes, and stripped from every response.\n * A password hash is the reason this exists.\n */\n readonly hidden?: boolean\n\n /** Show the field, refuse to write it. Generated columns are already this. */\n readonly readOnly?: boolean\n\n /**\n * Write the field, never read it back. The mirror of `readOnly`.\n *\n * **Enforced, not cosmetic.** The column is left out of the query the adapter\n * makes and out of the projection applied to the result, so it is absent from\n * a list, from a detail page and from the record a write returns - while\n * still being accepted in the write itself.\n *\n * A password is what this is for. `hidden` is the wrong tool: it refuses the\n * field in both directions, so a hidden password column can never be set.\n */\n readonly writeOnly?: boolean\n\n /** What to call it, when the column name is not what people call the thing. */\n readonly label?: string\n\n /** How to edit it. See {@link FieldWidget}. */\n readonly widget?: FieldWidget\n\n /** Where it sits among the others. Lower comes first; unset comes last. */\n readonly order?: number\n}\n\n/**\n * Icons a model may be given in the navigation.\n *\n * A closed list, for the same reason `FieldWidget` is one: the interface has to\n * know how to draw each name, so an open string would mean silently rendering\n * nothing and no way to notice. It is also a bundle decision - the icon set has\n * about fifteen hundred entries, and only the ones named here are shipped.\n *\n * Chosen to cover what an admin's resources usually are rather than to be\n * complete. A model with no icon is drawn without one, which is the default and\n * is not a lesser state: identical icons down a column are decoration, and the\n * navigation reads better with none than with thirty of the same shape.\n */\nexport type ModelIcon =\n | 'users'\n | 'user'\n | 'building'\n | 'box'\n | 'package'\n | 'tag'\n | 'shopping-cart'\n | 'credit-card'\n | 'receipt'\n | 'file-text'\n | 'folder'\n | 'image'\n | 'calendar'\n | 'clock'\n | 'mail'\n | 'message-square'\n | 'bell'\n | 'star'\n | 'map-pin'\n | 'globe'\n | 'settings'\n | 'key'\n | 'shield'\n | 'database'\n | 'table'\n | 'layers'\n | 'list'\n | 'chart-bar'\n | 'activity'\n | 'truck'\n | 'gift'\n | 'bookmark'\n | 'link'\n\nexport interface ModelOverride {\n /** What to call the model. */\n readonly label?: string\n\n /**\n * Which icon to show beside it in the navigation.\n *\n * Presentational: the client may ignore it, and nothing depends on it being\n * honoured. See {@link ModelIcon} for why the list is closed.\n */\n readonly icon?: ModelIcon\n\n /**\n * Which field names a record, overriding what would be detected.\n *\n * The detection rule guesses well on conventional schemas and has no way to\n * know that a `code` column is the one people recognise.\n */\n readonly displayField?: string\n\n /** Where the model sits in the resource list. Lower first; unset last. */\n readonly order?: number\n\n readonly fields?: Readonly<Record<string, FieldOverride>>\n}\n\nexport type ModelOverrides = Readonly<Record<string, ModelOverride>>\n\n/** The override for one field, if the application declared one. */\nexport function fieldOverride(\n overrides: ModelOverrides | undefined,\n model: string,\n field: string,\n): FieldOverride | undefined {\n return overrides?.[model]?.fields?.[field]\n}\n\n/** Is this field one the application refuses to write? */\nexport function isReadOnly(\n overrides: ModelOverrides | undefined,\n model: string,\n field: FieldMetadata,\n): boolean {\n // Generated values are read-only whatever the configuration says: they are\n // the database's to produce, and were never writable.\n return field.isGenerated || fieldOverride(overrides, model, field.name)?.readOnly === true\n}\n\n/**\n * The models as the admin should see them.\n *\n * Hidden fields are **removed** rather than marked, so that every layer\n * downstream is correct without knowing this option exists. The query parser\n * rejects a filter on a field it cannot find; the metadata mapper cannot\n * describe one; write validation refuses one. A flag would have needed each of\n * those to remember to check it.\n *\n * A declared `displayField` is carried through the same way, so the adapter and\n * the metadata document agree on it without either consulting the config.\n */\nexport function applyOverrides(\n models: readonly ModelMetadata[],\n overrides: ModelOverrides | undefined,\n): readonly ModelMetadata[] {\n if (!overrides) return models\n\n return models.map((model) => {\n const override = overrides[model.name]\n if (!override) return model\n\n const hidden = new Set(\n Object.entries(override.fields ?? {})\n .filter(([, field]) => field.hidden === true)\n .map(([name]) => name),\n )\n\n const writeOnly = new Set(\n Object.entries(override.fields ?? {})\n .filter(([, field]) => field.writeOnly === true)\n .map(([name]) => name),\n )\n\n const kept = hidden.size === 0 ? model.fields : model.fields.filter((f) => !hidden.has(f.name))\n\n return {\n ...model,\n ...(override.displayField !== undefined ? { displayField: override.displayField } : {}),\n // Carried onto the metadata rather than looked up again later, so\n // everything downstream - the field scope, the projection, the DTO -\n // reads one flag instead of each re-deriving it from the configuration.\n fields:\n writeOnly.size === 0\n ? kept\n : kept.map((field) =>\n writeOnly.has(field.name) ? { ...field, writeOnly: true } : field,\n ),\n }\n })\n}\n\n/**\n * Names in the configuration that no model or field answers to.\n *\n * Reported so a typo fails at startup. The cost of ignoring one is not\n * symmetrical: a mistyped `label` is invisible and harmless, but a mistyped\n * `passwordHash` leaves the real column exposed while the configuration looks\n * like it is protecting it.\n */\nexport function unknownOverrideNames(\n models: readonly ModelMetadata[],\n overrides: ModelOverrides | undefined,\n): readonly string[] {\n if (!overrides) return []\n\n const unknown: string[] = []\n\n for (const [modelName, override] of Object.entries(overrides)) {\n const model = models.find((candidate) => candidate.name === modelName)\n if (!model) {\n unknown.push(modelName)\n continue\n }\n\n const names = new Set(model.fields.map((field) => field.name))\n\n if (override.displayField !== undefined && !names.has(override.displayField)) {\n unknown.push(`${modelName}.${override.displayField}`)\n }\n\n for (const fieldName of Object.keys(override.fields ?? {})) {\n if (!names.has(fieldName)) unknown.push(`${modelName}.${fieldName}`)\n }\n }\n\n return unknown\n}\n\n/**\n * Hidden fields that make creating a record impossible.\n *\n * A column that is required, is not produced by the database, and has no\n * default is a value the *caller* must supply. Hiding it removes the only way\n * to supply it, so every create fails - and fails in the database, as a\n * constraint violation the admin can only report as an internal error.\n *\n * Reported at startup for that reason: the configuration is self-defeating, and\n * the symptom otherwise appears far from the cause.\n */\nexport function unwritableHiddenFields(\n models: readonly ModelMetadata[],\n overrides: ModelOverrides | undefined,\n): readonly string[] {\n if (!overrides) return []\n\n const blocked: string[] = []\n\n for (const [modelName, override] of Object.entries(overrides)) {\n const model = models.find((candidate) => candidate.name === modelName)\n if (!model) continue\n\n for (const [fieldName, field] of Object.entries(override.fields ?? {})) {\n if (field.hidden !== true) continue\n\n const declared = model.fields.find((candidate) => candidate.name === fieldName)\n if (!declared) continue\n\n if (declared.isRequired && !declared.isGenerated && declared.defaultValue === undefined) {\n blocked.push(`${modelName}.${fieldName}`)\n }\n }\n }\n\n return blocked\n}\n","/**\n * Framework error vocabulary.\n *\n * Deliberately small. These exist so that adapters raise ORM-independent\n * errors and the transport layer can map them to status codes without knowing\n * which ORM produced them. Resist growing this taxonomy - add a new type only\n * when a caller genuinely needs to branch on it.\n *\n * ## Why these are not identified with `instanceof`\n *\n * A published bundle can contain more than one copy of this module. The\n * package ships two CommonJS entrypoints and each inlines its own copy of\n * Core, so an error thrown inside the Prisma adapter is an instance of a\n * *different* `FieldNotFoundError` class than the one the exception filter\n * holds. `instanceof` compares class identity, so it answered `false` and\n * every adapter-raised error was mapped to a generic 500 - a caller who\n * mistyped a sort field got \"internal error\" instead of \"unknown field\".\n *\n * That was invisible to this repository's own tests, which resolve Core to a\n * single source module, and only appeared when the built package was installed\n * and run. So errors are identified by *value* rather than identity: a\n * `Symbol.for` brand, which duplicate copies agree on by definition, plus a\n * stable `kind` string. Neither depends on which copy created the object.\n *\n * `scripts/verify-packed-consumer.mjs` asserts the arrangement every release:\n * one shared copy in ESM, one per entrypoint in CJS. If that ever changes, the\n * count changes there first.\n *\n * @experimental Draft contract. Expected to change during MVP implementation.\n */\n\n/**\n * Cross-copy brand.\n *\n * `Symbol.for` resolves through the global symbol registry, so two copies of\n * this file agree on the key where two `Symbol()` calls would not.\n */\nconst BRAND = Symbol.for('nest-admin.error')\n\n/**\n * Stable discriminator for each error type.\n *\n * A declared string rather than the class, so it survives duplicate bundles,\n * and rather than `name`, so it survives minification.\n */\nexport type AdminErrorKind =\n | 'unauthorized'\n | 'forbidden'\n | 'model-not-found'\n | 'field-not-found'\n | 'record-not-found'\n | 'invalid-query'\n /** Application code refused the input. Its message reaches the client. */\n | 'validation'\n /** The database refused the write: unique, foreign key, or required. */\n | 'constraint'\n | 'adapter'\n /** A subclass that declared no kind of its own. Treated as internal. */\n | 'unknown'\n\n/**\n * Base error type. Every error raised by Nest Admin extends it so that the\n * NestJS integration can distinguish framework errors from application errors\n * without depending on concrete subclasses.\n */\nexport class NestAdminError extends Error {\n /**\n * Which error this is.\n *\n * Subclasses override it with a literal. The base value covers anything that\n * extends this class without declaring one - the Prisma schema errors, for\n * instance - which the transport layer treats as internal.\n */\n readonly kind: AdminErrorKind = 'unknown'\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = new.target.name\n // Non-enumerable, so it can never reach a serialised response body.\n Object.defineProperty(this, BRAND, { value: true, enumerable: false })\n }\n}\n\n/**\n * Is this one of ours?\n *\n * Works across duplicate copies of this module, which `instanceof` does not.\n */\nexport function isNestAdminError(value: unknown): value is NestAdminError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[BRAND] === true\n )\n}\n\n/** The requested model is not part of the admin's resource set. */\nexport class ModelNotFoundError extends NestAdminError {\n override readonly kind = 'model-not-found' as const\n\n constructor(\n readonly model: string,\n readonly availableModels: readonly string[] = [],\n ) {\n const known = availableModels.length > 0 ? ` Known models: ${availableModels.join(', ')}.` : ''\n super(`Unknown model \"${model}\".${known}`)\n }\n}\n\n/** A referenced field does not exist on the model, or cannot be used this way. */\nexport class FieldNotFoundError extends NestAdminError {\n override readonly kind = 'field-not-found' as const\n\n constructor(\n readonly model: string,\n readonly field: string,\n reason?: string,\n ) {\n super(`Unknown field \"${field}\" on model \"${model}\".${reason ? ` ${reason}` : ''}`)\n }\n}\n\n/** No record matched the given identifier. */\nexport class RecordNotFoundError extends NestAdminError {\n override readonly kind = 'record-not-found' as const\n\n constructor(\n readonly model: string,\n readonly id: unknown,\n ) {\n super(`No ${model} record found for id ${JSON.stringify(id)}.`)\n }\n}\n\n/**\n * The query is structurally invalid - an unusable operator/field combination,\n * a malformed value, or a request the adapter cannot express.\n */\nexport class InvalidQueryError extends NestAdminError {\n override readonly kind = 'invalid-query' as const\n}\n\n/**\n * The input is not acceptable, and the caller should be told why.\n *\n * Raised by application code - a hook rejecting a value, a rule the schema\n * cannot express - rather than by the framework. It exists because such a\n * refusal has to reach the person who typed the value, and the alternatives are\n * wrong in one direction or the other: `InvalidQueryError` claims the *query*\n * was malformed, and anything unrecognised becomes a generic 500 with the\n * message withheld.\n *\n * The message **is** forwarded to the client, which is the point of it and also\n * the responsibility that comes with it: whatever goes in is published.\n *\n * Naming the fields it is about is optional and worth doing. An interface that\n * knows which input was refused can say so next to that input, where the person\n * is looking, instead of in a banner above a form they then have to re-read.\n */\nexport class ValidationError extends NestAdminError {\n override readonly kind = 'validation' as const\n\n constructor(\n message: string,\n /** The inputs this is about. Empty when it is about the record as a whole. */\n readonly fields: readonly string[] = [],\n options?: { cause?: unknown },\n ) {\n super(message, options)\n }\n}\n\n/**\n * What the database refused, and about which fields.\n *\n * The distinction that matters is between a request that is *wrong* and a\n * database that is *broken*. A duplicate email, a foreign key pointing at\n * nothing, a missing required value - these are ordinary mistakes a person\n * makes in a form, and until they were told apart from a real failure the admin\n * answered every one of them with \"an internal error occurred\".\n *\n * The message is built here, from the constraint and the field names, rather\n * than taken from the ORM. An ORM's own text carries file paths, generated\n * query fragments and the values that collided, none of which should be\n * published - which is exactly why the generic 500 existed in the first place.\n */\nexport type ConstraintKind =\n /** A value that has to be unique is not. */\n | 'unique'\n /** A reference points at a record that is not there, or is still referenced. */\n | 'foreign-key'\n /** A value the database requires was not supplied. */\n | 'required'\n\nexport class ConstraintError extends NestAdminError {\n override readonly kind = 'constraint' as const\n\n constructor(\n readonly constraint: ConstraintKind,\n readonly model: string,\n /** The columns involved. Empty when the ORM did not say. */\n readonly fields: readonly string[] = [],\n ) {\n super(describeConstraint(constraint, model, fields))\n }\n}\n\n/**\n * A sentence for the person who filled in the form.\n *\n * Written from the field names alone, so it is safe to forward. Where the ORM\n * did not name a field the wording stays true rather than guessing at one.\n */\nfunction describeConstraint(\n constraint: ConstraintKind,\n model: string,\n fields: readonly string[],\n): string {\n const named = fields.length > 0 ? fields.join(', ') : undefined\n\n switch (constraint) {\n case 'unique':\n return named\n ? `Another ${model} already has this ${named}.`\n : `Another ${model} already has one of these values.`\n\n case 'foreign-key':\n return named\n ? `The ${named} does not refer to an existing record, or the record it refers to is still in use.`\n : `A reference on this ${model} does not point at an existing record, or is still in use.`\n\n case 'required':\n return named ? `${named} is required.` : `A required value on this ${model} is missing.`\n }\n}\n\n/**\n * The underlying ORM or database failed. Always wraps the original error as\n * `cause` so the real failure is never lost.\n */\nexport class AdapterError extends NestAdminError {\n override readonly kind = 'adapter' as const\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n }\n}\n\n/**\n * No authenticated identity was presented with the request.\n *\n * Raised by the host application's admin auth implementation, never by Core\n * itself - Core has no notion of a request, a header or a session, and must\n * not acquire one. It exists here so the transport layer can map it without\n * knowing which framework produced it.\n *\n * The default message is deliberately uninformative. An authentication failure\n * must not reveal whether a credential was absent, malformed, expired or\n * simply wrong.\n */\nexport class UnauthorizedError extends NestAdminError {\n override readonly kind = 'unauthorized' as const\n\n constructor(message = 'Authentication is required to access the admin API.') {\n super(message)\n }\n}\n\n/**\n * An identity was established, but it is not permitted to do this.\n *\n * Deliberately distinct from {@link UnauthorizedError}: collapsing the two\n * leaves a client unable to tell \"log in\" from \"you cannot do this\", and\n * pushes that guesswork into every consumer.\n */\nexport class ForbiddenError extends NestAdminError {\n override readonly kind = 'forbidden' as const\n\n constructor(message = 'You do not have permission to access the admin API.') {\n super(message)\n }\n}\n","/**\n * `PrismaAdapter` - the Prisma implementation of Core's `OrmAdapter`.\n *\n * The adapter never constructs a Prisma Client. Prisma 7 builds clients from\n * driver adapters, so only the consuming application knows the provider, the\n * credentials and the connection strategy. We receive a constructed client and\n * use it.\n */\nimport {\n AdapterError,\n FieldNotFoundError,\n InvalidQueryError,\n ModelNotFoundError,\n isNestAdminError,\n RecordNotFoundError,\n type ListQuery,\n type ModelMetadata,\n type OrmAdapter,\n type Page,\n type RecordData,\n type RecordId,\n} from '@nest-admin/core'\n\nimport { resolveDelegate, type PrismaModelDelegate } from './client/delegate.js'\nimport { assertSupportedPrismaVersion } from './client/version-gate.js'\nimport { readDatasourceProvider, readPrismaDmmf } from './metadata/read-dmmf.js'\nimport { toModelMetadata } from './metadata/to-metadata.js'\nimport { toIncludeClause } from './query/to-include.js'\nimport { toConstraintError } from './errors/constraints.js'\nimport { toRelatedWhere } from './query/to-related-where.js'\nimport { resolvePagination, toFindManyArgs } from './query/to-prisma-args.js'\n\n/** Prisma's error code for \"record required but not found\". */\nconst PRISMA_RECORD_NOT_FOUND = 'P2025'\n\nexport interface PrismaAdapterOptions {\n /**\n * A constructed Prisma Client. Owned entirely by the consuming application:\n * the adapter never calls `new PrismaClient()`, because under Prisma 7 the\n * client is built from a driver adapter that only the application can supply.\n */\n readonly client: unknown\n /**\n * Path to `schema.prisma`, or to a directory of `.prisma` files. When\n * omitted, `prisma/schema.prisma`, `prisma/schema` and `schema.prisma` are\n * tried in that order, relative to `cwd`.\n */\n readonly schemaPath?: string\n /** Base directory for schema resolution. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\nexport class PrismaAdapter implements OrmAdapter {\n readonly name = 'prisma'\n\n readonly #client: unknown\n readonly #schemaPath: string | undefined\n readonly #cwd: string | undefined\n\n /**\n * Metadata is derived from a static schema, so it is read once and reused.\n * Every operation validates against it, which would otherwise re-parse the\n * schema on each call.\n */\n #models: readonly ModelMetadata[] | undefined\n\n /**\n * Which database this is, so a search can ignore capitalisation the way that\n * database allows. Read alongside the metadata, and `undefined` when the\n * schema does not say - see `insensitively` in `to-prisma-args.ts`.\n */\n #provider: string | undefined\n\n constructor(options: PrismaAdapterOptions) {\n if (options.client === null || options.client === undefined) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client. ' +\n 'Pass one via `new PrismaAdapter({ client })`.',\n )\n }\n this.#client = options.client\n this.#schemaPath = options.schemaPath\n this.#cwd = options.cwd\n }\n\n async getModels(): Promise<readonly ModelMetadata[]> {\n if (this.#models) return this.#models\n // Checked before parsing: a version mismatch would otherwise surface as\n // \"Prisma rejected the schema\", pointing at the user's valid schema.\n assertSupportedPrismaVersion(this.#client)\n const dmmf = readPrismaDmmf({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n this.#models = toModelMetadata(dmmf)\n this.#provider = readDatasourceProvider({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n return this.#models\n }\n\n async list(model: string, query: ListQuery): Promise<Page<RecordData>> {\n const declared = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n\n // Narrowed first: everything below reads the model, so restricting it once\n // restricts field lookup, free-text search and relation loading together.\n const metadata = narrowFields(declared, query.fields)\n\n const args = toFindManyArgs(metadata, query, this.#provider)\n const include = toIncludeClause(metadata, await this.getModels())\n const omit = omitClause(declared, query.fields)\n const withRelations = { ...args, ...(include ? { include } : {}), ...(omit ? { omit } : {}) }\n const { page, perPage } = resolvePagination(query)\n\n const [rows, total] = await this.#run(model, () =>\n Promise.all([\n delegate.findMany(withRelations),\n delegate.count(args.where ? { where: args.where } : {}),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async findOne(model: string, id: RecordId): Promise<RecordData | null> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n const include = toIncludeClause(metadata, await this.getModels())\n const record = await this.#run(model, () =>\n delegate.findUnique(include ? { where, include } : { where }),\n )\n return (record as RecordData | null) ?? null\n }\n\n async create(model: string, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const writable = this.#validateWritableData(metadata, data)\n\n const created = await this.#run(model, () => delegate.create({ data: writable }))\n return created as RecordData\n }\n\n async update(model: string, id: RecordId, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n const writable = this.#validateWritableData(metadata, data)\n\n const updated = await this.#run(model, () => delegate.update({ where, data: writable }), id)\n return updated as RecordData\n }\n\n async delete(model: string, id: RecordId): Promise<void> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n await this.#run(model, () => delegate.delete({ where }), id)\n }\n\n /**\n * A page of the records on the far side of a to-many relation.\n *\n * Implemented as an ordinary list of the *target* model with one extra\n * condition, so pagination, sorting, filtering and relation loading all\n * behave exactly as they do on a top-level list. See `to-related-where.ts`.\n */\n async listRelated(\n model: string,\n id: RecordId,\n relationField: string,\n query: ListQuery,\n ): Promise<Page<RecordData>> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n\n // The relation is validated first: a bad field name is wrong whether or\n // not the record exists, and rejecting it here costs no query.\n const { target, where } = toRelatedWhere(metadata, relationField, id, models)\n\n // A missing parent is a 404, not an empty page. The condition below would\n // simply match nothing, which reads as \"this record has no children\".\n await this.#requireRecord(model, metadata, id)\n const delegate = await this.#delegate(target.name)\n\n const narrowed = narrowFields(target, query.fields)\n const args = toFindManyArgs(narrowed, query, this.#provider)\n const combined = args.where ? { AND: [args.where, where] } : where\n const include = toIncludeClause(narrowed, models)\n const omit = omitClause(target, query.fields)\n\n const { page, perPage } = resolvePagination(query)\n const [rows, total] = await this.#run(target.name, () =>\n Promise.all([\n delegate.findMany({\n ...args,\n where: combined,\n ...(include ? { include } : {}),\n ...(omit ? { omit } : {}),\n }),\n delegate.count({ where: combined }),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async attachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'connect')\n }\n\n async detachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'disconnect')\n }\n\n // ---------------------------------------------------------------- internals\n\n /**\n * Add or remove one link, from the parent's side.\n *\n * Prisma expresses both the same way and works out where the link is stored -\n * a join-table row for a many-to-many, the child's foreign key for a\n * one-to-many. Whether the operation is allowed is the caller's decision;\n * this performs it.\n */\n async #link(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n operation: 'connect' | 'disconnect',\n ): Promise<void> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n const { target } = toRelatedWhere(metadata, relationField, id, models)\n\n const [targetKey] = target.primaryKey\n if (targetKey === undefined) {\n throw new FieldNotFoundError(target.name, relationField, 'The target has no primary key.')\n }\n\n const delegate = await this.#delegate(model)\n await this.#run(\n model,\n () =>\n delegate.update({\n where: this.#whereById(metadata, id),\n data: { [relationField]: { [operation]: { [targetKey]: targetId } } },\n }),\n id,\n )\n }\n\n /** Throw `RecordNotFoundError` unless the record exists. */\n async #requireRecord(model: string, metadata: ModelMetadata, id: RecordId): Promise<void> {\n const delegate = await this.#delegate(model)\n const found = await this.#run(\n model,\n () => delegate.findUnique({ where: this.#whereById(metadata, id) }),\n id,\n )\n if (found === null || found === undefined) throw new RecordNotFoundError(model, id)\n }\n\n async #requireModel(model: string): Promise<ModelMetadata> {\n const models = await this.getModels()\n const found = models.find((candidate) => candidate.name === model)\n if (!found) {\n throw new ModelNotFoundError(\n model,\n models.map((candidate) => candidate.name),\n )\n }\n return found\n }\n\n async #delegate(model: string): Promise<PrismaModelDelegate> {\n const models = await this.getModels()\n return resolveDelegate(\n this.#client,\n model,\n models.map((candidate) => candidate.name),\n )\n }\n\n /**\n * Build a `where` clause addressing a single record by primary key.\n *\n * Composite keys are represented in metadata but not supported here: a\n * `RecordId` is a single scalar, so there is nothing to map the second\n * column from. Rejected explicitly rather than silently mis-querying.\n */\n #whereById(model: ModelMetadata, id: RecordId): Record<string, unknown> {\n const [primaryKeyField, ...rest] = model.primaryKey\n\n if (primaryKeyField === undefined) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has no primary key, so records cannot be addressed by id.`,\n )\n }\n if (rest.length > 0) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has a composite primary key ` +\n `(${model.primaryKey.join(', ')}), which is not supported in this version.`,\n )\n }\n\n return { [primaryKeyField]: this.#coerceId(model, primaryKeyField, id) }\n }\n\n /**\n * Coerce an id to the type the schema declares.\n *\n * Ids arriving from a URL are always strings, but a Prisma `Int @id` column\n * must be queried with a number or Prisma rejects the argument.\n */\n #coerceId(model: ModelMetadata, fieldName: string, id: RecordId): RecordId {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (field?.kind !== 'number' || typeof id === 'number') return id\n\n const numeric = Number(id)\n if (!Number.isFinite(numeric)) {\n throw new InvalidQueryError(\n `Invalid id ${JSON.stringify(id)} for numeric primary key ` +\n `\"${model.name}.${fieldName}\".`,\n )\n }\n return numeric\n }\n\n /**\n * Reject anything the caller has no business writing.\n *\n * Unknown keys are an error rather than silently dropped: quietly discarding\n * a field the user filled in is worse than telling them it does not exist.\n * Relation and list fields are rejected because nested writes are not\n * implemented - see the Phase 2 report.\n */\n #validateWritableData(model: ModelMetadata, data: RecordData): RecordData {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new InvalidQueryError(`Write payload for \"${model.name}\" must be an object.`)\n }\n\n const writable: RecordData = {}\n for (const [key, value] of Object.entries(data)) {\n const field = model.fields.find((candidate) => candidate.name === key)\n if (!field) {\n throw new FieldNotFoundError(model.name, key)\n }\n if (field.kind === 'relation') {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing relation fields is not supported in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing list fields is not supported in this version.',\n )\n }\n writable[key] = value\n }\n return writable\n }\n\n /**\n * Run a client call, translating Prisma failures into Core errors.\n *\n * Prisma error types are identified by their `code` property rather than\n * `instanceof`. Importing `@prisma/client` to get the error classes would\n * mean loading a second copy of a package the consumer owns, and would tie\n * us to their Prisma version.\n */\n async #run<T>(model: string, operation: () => Promise<T>, id?: RecordId): Promise<T> {\n try {\n return await operation()\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n\n if (isPrismaError(cause) && cause.code === PRISMA_RECORD_NOT_FOUND && id !== undefined) {\n throw new RecordNotFoundError(model, id)\n }\n\n // A refused write is a fact about the request, not a failure of the\n // database. Reporting it as an internal error is what made a duplicate\n // email indistinguishable from a dead connection.\n const constraint = toConstraintError(cause, model)\n if (constraint) throw constraint\n\n const detail = cause instanceof Error ? cause.message : String(cause)\n throw new AdapterError(`Prisma operation failed for model \"${model}\": ${detail}`, { cause })\n }\n }\n}\n\nfunction isPrismaError(value: unknown): value is { code: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The model as this query is allowed to see it.\n *\n * Narrowing once, at the top, is what keeps the rest of the adapter honest:\n * field lookup, free-text search and relation loading all read the model, so\n * they inherit the restriction without knowing it exists. Doing it per-concern\n * would mean three places to forget.\n */\nfunction narrowFields(model: ModelMetadata, fields: readonly string[] | undefined): ModelMetadata {\n if (!fields) return model\n\n const allowed = new Set(fields)\n return { ...model, fields: model.fields.filter((field) => allowed.has(field.name)) }\n}\n\n/**\n * Columns to leave out of the result.\n *\n * `omit` rather than `select` because it composes with `include`: a `select`\n * would have to enumerate the relations too, and would silently drop any the\n * caller forgot. This way a hidden column is never read at all, which is a\n * stronger guarantee than removing it from the response afterwards.\n */\nfunction omitClause(\n model: ModelMetadata,\n fields: readonly string[] | undefined,\n): Record<string, true> | undefined {\n if (!fields) return undefined\n\n const allowed = new Set(fields)\n const omitted: Record<string, true> = {}\n\n for (const field of model.fields) {\n // Relations are excluded through `include`, not `omit`; Prisma rejects\n // naming them here.\n if (!allowed.has(field.name) && field.kind !== 'relation') omitted[field.name] = true\n }\n\n return Object.keys(omitted).length > 0 ? omitted : undefined\n}\n","/**\n * Dynamic model resolution.\n *\n * The admin addresses models by name at runtime (`\"User\"`), so the Prisma\n * Client's statically-typed delegates cannot be reached through their types.\n * This module is the single, deliberately narrow place where that type escape\n * happens. Nothing else in the package casts the client.\n */\nimport { AdapterError, ModelNotFoundError } from '@nest-admin/core'\n\n/**\n * The subset of a Prisma model delegate the adapter uses.\n *\n * Declared structurally rather than imported from `@prisma/client`: the client\n * is generated in the consumer's project against their schema, so there is no\n * meaningful shared type to import, and depending on one would couple us to a\n * Prisma version we do not control.\n */\nexport interface PrismaModelDelegate {\n findMany(args?: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown>\n count(args?: unknown): Promise<number>\n create(args: unknown): Promise<unknown>\n update(args: unknown): Promise<unknown>\n delete(args: unknown): Promise<unknown>\n}\n\nconst REQUIRED_METHODS = [\n 'findMany',\n 'findUnique',\n 'count',\n 'create',\n 'update',\n 'delete',\n] as const satisfies readonly (keyof PrismaModelDelegate)[]\n\n/**\n * Property names that must never be used as a delegate lookup key, regardless\n * of what the caller passes. Model names are validated against known metadata\n * before we get here, so this is defence in depth rather than the only guard.\n */\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype'])\n\n/**\n * Prisma exposes `model User` as `prisma.user` - the model name with only its\n * first character lower-cased. Note this is not general camelCase conversion:\n * `UserProfile` becomes `userProfile`, and `HTTPLog` becomes `hTTPLog`.\n */\nexport function toDelegateKey(modelName: string): string {\n if (modelName.length === 0) return modelName\n return modelName.charAt(0).toLowerCase() + modelName.slice(1)\n}\n\n/**\n * Resolve a model name to its Prisma Client delegate.\n *\n * `knownModels` is the metadata-derived allowlist. A name outside it is\n * rejected before the client is touched at all, so an attacker-controlled\n * model name can never reach arbitrary client properties.\n */\nexport function resolveDelegate(\n client: unknown,\n modelName: string,\n knownModels: readonly string[],\n): PrismaModelDelegate {\n if (!knownModels.includes(modelName)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n const key = toDelegateKey(modelName)\n if (FORBIDDEN_KEYS.has(key)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n if (typeof client !== 'object' || client === null) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client instance. ' +\n `Received ${client === null ? 'null' : typeof client}.`,\n )\n }\n\n // The one type escape. Guarded above by the metadata allowlist and below by\n // a shape check, so the cast is asserted rather than assumed.\n const candidate = (client as Record<string, unknown>)[key]\n\n if (typeof candidate !== 'object' || candidate === null) {\n throw new AdapterError(\n `The Prisma Client has no delegate \"${key}\" for model \"${modelName}\". ` +\n 'This usually means the client was generated from a different schema ' +\n 'than the one Nest Admin read - re-run `prisma generate`.',\n )\n }\n\n const delegate = candidate as Record<string, unknown>\n const missing = REQUIRED_METHODS.filter((method) => typeof delegate[method] !== 'function')\n if (missing.length > 0) {\n throw new AdapterError(\n `Prisma Client delegate \"${key}\" is missing expected methods: ${missing.join(', ')}.`,\n )\n }\n\n return candidate as PrismaModelDelegate\n}\n","/**\n * Prisma version gate.\n *\n * Phase 1 established that `@prisma/get-dmmf` is pinned exactly and enforces\n * *its own* Prisma version's schema rules: given a Prisma 6 schema, the 7.x\n * parser rejects `url` inside `datasource` even though the schema is perfectly\n * valid for that consumer. Without a gate, that surfaces as a confusing\n * \"Prisma rejected the schema\" error pointing at the user's own valid file.\n *\n * The gate turns that into a statement about versions.\n *\n * ## Two deliberate design choices\n *\n * **It fails open on detection.** The client version is read from\n * `client._clientVersion`, an underscore-prefixed internal. If Prisma renames\n * or removes it, the gate silently does nothing rather than breaking every\n * consumer on an otherwise-fine upgrade. A version check that itself becomes\n * the outage is worse than no version check.\n *\n * **It compares majors only.** Minor and patch releases have not changed the\n * schema language; majors have. Pinning tighter would produce false alarms on\n * every routine bump.\n *\n * This lives in `packages/prisma`, not Core - Core must never learn what\n * Prisma is.\n */\nimport { NestAdminError } from '@nest-admin/core'\n\n/**\n * Prisma majors whose schema language this adapter's pinned parser handles.\n *\n * Derived from the parser we ship (`@prisma/get-dmmf`, pinned in\n * package.json), not from what we wish were true. Widen this only after\n * testing against the new major.\n */\nexport const SUPPORTED_PRISMA_MAJORS: readonly number[] = [7]\n\n/** Raised when the consumer's Prisma Client major is outside the tested range. */\nexport class PrismaVersionUnsupportedError extends NestAdminError {\n constructor(\n readonly clientVersion: string,\n readonly supportedMajors: readonly number[],\n ) {\n super(\n `Nest Admin ships a Prisma ${supportedMajors.join('/')} schema parser, ` +\n `but this application uses Prisma Client ${clientVersion}. ` +\n 'Schema parsing would likely fail with a misleading error, so it was ' +\n 'stopped here instead. Align the versions, or open an issue if ' +\n `Prisma ${clientVersion.split('.')[0]} should be supported.`,\n )\n }\n}\n\n/**\n * Read the Prisma Client version from an instance.\n *\n * Returns `undefined` when it cannot be determined - see \"fails open\" above.\n */\nexport function readClientVersion(client: unknown): string | undefined {\n if (typeof client !== 'object' || client === null) return undefined\n const version = (client as Record<string, unknown>)['_clientVersion']\n return typeof version === 'string' && version !== '' ? version : undefined\n}\n\nfunction majorOf(version: string): number | undefined {\n const major = Number(version.split('.')[0])\n return Number.isInteger(major) ? major : undefined\n}\n\n/**\n * Throw when the client's major is known and unsupported.\n *\n * Silent when the version is unreadable or unparseable.\n */\nexport function assertSupportedPrismaVersion(\n client: unknown,\n supportedMajors: readonly number[] = SUPPORTED_PRISMA_MAJORS,\n): void {\n const version = readClientVersion(client)\n if (version === undefined) return\n\n const major = majorOf(version)\n if (major === undefined) return\n\n if (!supportedMajors.includes(major)) {\n throw new PrismaVersionUnsupportedError(version, supportedMajors)\n }\n}\n","/**\n * Prisma schema acquisition.\n *\n * This is the ONLY module in the repository permitted to import\n * `@prisma/get-dmmf`. Everything downstream consumes the returned\n * `DMMF.Document` and nothing else, which is what keeps the eventual switch to\n * a build-time Prisma generator a change to this file alone.\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport { AdapterError, isNestAdminError, NestAdminError } from '@nest-admin/core'\nimport { getDMMF } from '@prisma/get-dmmf'\nimport type * as DMMF from '@prisma/dmmf'\n\n/** Paths tried, in order, when no explicit schema location is configured. */\nconst DEFAULT_SCHEMA_CANDIDATES = ['prisma/schema.prisma', 'prisma/schema', 'schema.prisma']\n\n/** Raised when the Prisma schema cannot be located or read. */\nexport class PrismaSchemaNotFoundError extends NestAdminError {\n constructor(\n readonly triedPaths: readonly string[],\n explicit: boolean,\n ) {\n super(\n explicit\n ? `Prisma schema not found at \"${triedPaths[0]}\".`\n : `Could not locate a Prisma schema. Tried: ${triedPaths.join(', ')}. ` +\n 'Pass `schemaPath` to PrismaAdapter if your schema lives elsewhere.',\n )\n }\n}\n\n/** Raised when Prisma rejects the schema. Carries Prisma's own validation text. */\nexport class PrismaSchemaInvalidError extends NestAdminError {\n constructor(\n readonly prismaMessage: string,\n options?: { cause?: unknown },\n ) {\n super(`Prisma rejected the schema:\\n${prismaMessage}`, options)\n }\n}\n\n/**\n * Resolve the schema location to an absolute path.\n *\n * `schemaPath` may point at a single `.prisma` file or, since Prisma 7, at a\n * directory of `.prisma` files. Both are supported.\n */\nfunction locateSchema(schemaPath: string | undefined, cwd: string): string {\n if (schemaPath !== undefined) {\n const absolute = resolve(cwd, schemaPath)\n if (!existsSync(absolute)) throw new PrismaSchemaNotFoundError([absolute], true)\n return absolute\n }\n\n const tried: string[] = []\n for (const candidate of DEFAULT_SCHEMA_CANDIDATES) {\n const absolute = resolve(cwd, candidate)\n tried.push(absolute)\n if (existsSync(absolute)) return absolute\n }\n throw new PrismaSchemaNotFoundError(tried, false)\n}\n\n/**\n * Read the schema as `[filename, content]` tuples.\n *\n * `getDMMF` accepts this shape natively (`SchemaFileInput = string |\n * Array<[filename, content]>`), so multi-file schemas need no concatenation\n * and no parsing on our side. Passing real filenames also means Prisma's\n * validation errors point at the right file.\n */\nfunction readSchemaFiles(absolutePath: string): Array<[string, string]> {\n if (statSync(absolutePath).isDirectory()) {\n const files = readdirSync(absolutePath)\n .filter((name) => name.endsWith('.prisma'))\n .sort()\n if (files.length === 0) {\n throw new PrismaSchemaNotFoundError([join(absolutePath, '*.prisma')], true)\n }\n return files.map((name) => {\n const file = join(absolutePath, name)\n return [file, readFileSync(file, 'utf8')] as [string, string]\n })\n }\n\n return [[absolutePath, readFileSync(absolutePath, 'utf8')]]\n}\n\nexport interface ReadDmmfOptions {\n /** Path to a `.prisma` file or a directory of them. Auto-detected if absent. */\n readonly schemaPath?: string\n /** Base directory for relative paths and auto-detection. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\n/**\n * Load and parse the Prisma schema into a DMMF document.\n *\n * Note the two traps this function exists to absorb:\n *\n * 1. `getDMMF` is **synchronous** and returns `DMMF.Document | GetDMMFError` -\n * it does not throw and does not reject. Reading `.datamodel` off an error\n * result yields a bare `TypeError` with none of Prisma's diagnostics.\n * 2. Returning empty metadata on failure would surface as an admin panel with\n * no resources, which reads as a configuration mistake and costs hours.\n * Every failure here is loud.\n */\nexport function readPrismaDmmf(options: ReadDmmfOptions = {}): DMMF.Document {\n const cwd = options.cwd ?? process.cwd()\n const absolutePath = locateSchema(options.schemaPath, cwd)\n\n let files: Array<[string, string]>\n try {\n files = readSchemaFiles(absolutePath)\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n throw new AdapterError(`Failed to read the Prisma schema at \"${absolutePath}\".`, { cause })\n }\n\n const result = getDMMF({ datamodel: files })\n\n if (!isDmmfDocument(result)) {\n throw new PrismaSchemaInvalidError(extractPrismaMessage(result), { cause: result.error })\n }\n return result\n}\n\n/**\n * The datasource provider the schema declares - `postgresql`, `sqlite`, and so\n * on - or `undefined` when it cannot be read.\n *\n * Needed because Prisma accepts `mode: 'insensitive'` on some providers and\n * *throws* on the rest, so a search that ignores capitalisation has to know\n * which database it is talking to. See `to-prisma-args.ts`.\n *\n * ## Why this is read from the text\n *\n * The provider is not in the DMMF: `getDMMF` returns the datamodel, and the\n * datasource block is not part of it. Nor can it be asked of the client -\n * Prisma 7 builds clients from driver adapters, and what the application passed\n * is not something this package is allowed to introspect. The declaration is a\n * fixed one-line form in a file we are already reading, so it is read from\n * there, and every failure is answered with `undefined` rather than a throw:\n * an unreadable provider must degrade to the case-sensitive search that was the\n * behaviour before this existed, never to a broken panel.\n *\n * It reads the schema a second time. That happens once, at startup, on a file\n * of a few kilobytes - cheaper than threading a second return value through\n * every caller of `readPrismaDmmf`.\n */\nexport function readDatasourceProvider(options: ReadDmmfOptions = {}): string | undefined {\n try {\n const files = readSchemaFiles(locateSchema(options.schemaPath, options.cwd ?? process.cwd()))\n for (const [, content] of files) {\n const declared = /datasources+w+s*{[^}]*?providers*=s*\"([a-z]+)\"/i.exec(content)\n if (declared?.[1] !== undefined) return declared[1].toLowerCase()\n }\n } catch {\n // Unreadable schema. The DMMF read reports that properly; this one is an\n // optimisation and has nothing useful to add.\n }\n return undefined\n}\n\nfunction isDmmfDocument(value: DMMF.Document | { error: Error }): value is DMMF.Document {\n return 'datamodel' in value\n}\n\n/**\n * Prisma reports validation failures as a JSON string inside `error.message`,\n * carrying an ANSI-coloured `P1012` report. Unwrap it where possible so the\n * message we surface is the one a developer would see from the Prisma CLI.\n */\nfunction extractPrismaMessage(result: { reason: string; error: Error }): string {\n const raw = result.error?.message ?? result.reason\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed === 'object' && parsed !== null && 'message' in parsed) {\n const message = (parsed as { message: unknown }).message\n if (typeof message === 'string') return stripAnsi(message)\n }\n } catch {\n // Not JSON - fall through and use the raw text.\n }\n return stripAnsi(raw)\n}\n\nconst ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;]*m`, 'g')\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_PATTERN, '')\n}\n","/**\n * DMMF -> Core `ModelMetadata`.\n *\n * The one place Prisma's vocabulary is translated into ours. No DMMF type\n * escapes this module: everything downstream (the adapter, the future HTTP\n * layer, the admin UI) sees only Core shapes.\n *\n * This mapper is deliberately independent of *how* the DMMF was obtained, so\n * it is unaffected by a later switch to a build-time Prisma generator.\n */\nimport type { FieldKind, FieldMetadata, ModelMetadata } from '@nest-admin/core'\nimport type * as DMMF from '@prisma/dmmf'\n\n/**\n * Prisma scalar type -> Core field kind.\n *\n * `BigInt`, `Decimal` and `Bytes` are intentionally mapped to `'unknown'`\n * rather than squeezed into `'number'` or `'string'`. They do not round-trip\n * through JSON without losing precision or fidelity, and the MVP has not\n * tested editing them - claiming support we have not verified would be worse\n * than declaring them unhandled. They are still listed, so the admin can show\n * them read-only.\n */\nconst SCALAR_KINDS: Readonly<Record<string, FieldKind>> = {\n String: 'string',\n Int: 'number',\n Float: 'number',\n Boolean: 'boolean',\n DateTime: 'datetime',\n Json: 'json',\n}\n\nfunction toFieldKind(field: DMMF.Field): FieldKind {\n if (field.kind === 'object') return 'relation'\n if (field.kind === 'enum') return 'enum'\n if (field.kind === 'scalar') return SCALAR_KINDS[field.type] ?? 'unknown'\n return 'unknown'\n}\n\n/**\n * Is this default produced by the database or the ORM, rather than supplied by\n * the user?\n *\n * Measured against Prisma 7.10.0, DMMF distinguishes the two by *shape*:\n *\n * @default(cuid()) -> { name: 'cuid', args: [1] } (object)\n * @default(now()) -> { name: 'now', args: [] } (object)\n * @default(autoincrement()) -> { name: 'autoincrement' } (object)\n * @default(dbgenerated(..)) -> { name: 'dbgenerated', ... } (object)\n * @default(true) -> true (primitive)\n * @default(0) -> 0 (primitive)\n * @default(\"USER\") -> \"USER\" (primitive)\n *\n * So a function default is an object carrying `name`; a literal default is a\n * primitive. Treating \"has a default\" as \"generated\" would wrongly lock\n * `active Boolean @default(true)` out of every create form.\n */\nfunction isFunctionDefault(value: unknown): value is { name: string; args?: unknown[] } {\n return typeof value === 'object' && value !== null && !Array.isArray(value) && 'name' in value\n}\n\nfunction toFieldMetadata(\n field: DMMF.Field,\n enums: ReadonlyMap<string, readonly string[]>,\n): FieldMetadata {\n const kind = toFieldKind(field)\n\n // A value the database or ORM supplies: a function default, or @updatedAt.\n const isGenerated = field.isUpdatedAt === true || isFunctionDefault(field.default)\n\n // A literal default is a pre-fill for the create form, not a generated value.\n const hasLiteralDefault = field.hasDefaultValue === true && !isFunctionDefault(field.default)\n\n const base = {\n name: field.name,\n kind,\n isId: field.isId === true,\n isRequired: field.isRequired === true,\n isUnique: field.isUnique === true,\n isList: field.isList === true,\n isGenerated,\n } satisfies Omit<FieldMetadata, 'defaultValue' | 'enumValues' | 'relation'>\n\n return {\n ...base,\n ...(hasLiteralDefault ? { defaultValue: field.default } : {}),\n ...(kind === 'enum' ? { enumValues: enums.get(field.type) ?? [] } : {}),\n ...(kind === 'relation'\n ? {\n relation: {\n targetModel: field.type,\n // Cardinality follows directly from isList - the single attribute\n // the generated Prisma Client does not expose at runtime, which is\n // why metadata comes from the schema rather than the client.\n cardinality: field.isList === true ? ('many' as const) : ('one' as const),\n // Present only on the owning side of a to-one relation. Prisma\n // gives both sides a relation field but only one of them a column,\n // and these arrays are empty on the side that has none - so an\n // empty array means \"no foreign key here\", not \"unknown\".\n ...(field.relationFromFields?.[0] !== undefined\n ? { from: field.relationFromFields[0] }\n : {}),\n ...(field.relationToFields?.[0] !== undefined ? { to: field.relationToFields[0] } : {}),\n // Shared by both halves, so the other side can be found. Prisma\n // generates one when the schema does not name it.\n ...(field.relationName !== undefined ? { name: field.relationName } : {}),\n },\n }\n : {}),\n }\n}\n\n/**\n * Field names forming the model's primary key.\n *\n * Prisma expresses a single-column key as `@id` on the field and a composite\n * key as a model-level `@@id`, which DMMF surfaces as `primaryKey.fields`.\n * Both are represented here; the adapter is what limits the MVP to\n * single-column keys.\n */\nfunction toPrimaryKey(model: DMMF.Model): readonly string[] {\n const compositeFields = model.primaryKey?.fields\n if (compositeFields && compositeFields.length > 0) return [...compositeFields]\n return model.fields.filter((field) => field.isId === true).map((field) => field.name)\n}\n\n/** Translate a whole DMMF document into Core model metadata. */\nexport function toModelMetadata(dmmf: DMMF.Document): readonly ModelMetadata[] {\n const enums = new Map<string, readonly string[]>(\n dmmf.datamodel.enums.map((enumType) => [\n enumType.name,\n enumType.values.map((value) => value.name),\n ]),\n )\n\n return dmmf.datamodel.models.map((model) => ({\n name: model.name,\n primaryKey: toPrimaryKey(model),\n fields: model.fields.map((field) => toFieldMetadata(field, enums)),\n }))\n}\n","/**\n * Loading the readable side of a to-one relation.\n *\n * A record stores `authorId`. A person needs \"Ada Lovelace\". Resolving that in\n * the caller would mean one query per row - the classic N+1 - so it is done in\n * the same query, with an `include`.\n *\n * ## Only two columns are ever selected\n *\n * The `include` carries an explicit `select` of the target's primary key and\n * its display field, and nothing else. That is a security boundary, not an\n * optimisation: `include: { author: true }` would attach the *whole* related\n * record to every row, so a `User.passwordHash` would be published by the act\n * of listing `Post`. Naming the two columns means a relation can never widen\n * what a response contains.\n *\n * To-many relations are not loaded. They have no column on this side, they can\n * be unbounded, and one `include` per row would turn a list page into an\n * unpredictable amount of work. They arrive in 0.4.0, paginated and asked for\n * explicitly.\n */\nimport { displayFieldFor, type ModelMetadata } from '@nest-admin/core'\n\n/** A Prisma `include` clause, or `undefined` when the model has no to-one relations. */\nexport type IncludeClause = Record<string, { select: Record<string, true> }>\n\n/**\n * Build the `include` for every to-one relation the model owns.\n *\n * `models` is the full set, because the display field belongs to the *target*\n * model and can only be resolved by looking it up. A relation whose target is\n * missing from that set is skipped rather than guessed at: the target may have\n * been excluded from the admin by configuration, and inventing a column name\n * would produce a Prisma error blaming the schema.\n */\nexport function toIncludeClause(\n model: ModelMetadata,\n models: readonly ModelMetadata[],\n): IncludeClause | undefined {\n const include: IncludeClause = {}\n\n for (const field of model.fields) {\n const relation = field.relation\n // `from` is what distinguishes the owning side from the other one. Without\n // it there is no column here, so there is nothing to resolve.\n if (!relation || relation.cardinality !== 'one' || relation.from === undefined) continue\n\n const target = models.find((candidate) => candidate.name === relation.targetModel)\n if (!target) continue\n\n const select: Record<string, true> = {}\n for (const key of target.primaryKey) select[key] = true\n select[displayFieldFor(target)] = true\n\n include[field.name] = { select }\n }\n\n return Object.keys(include).length > 0 ? include : undefined\n}\n","/**\n * Prisma error codes -> Core constraint errors.\n *\n * Everything here exists so that an ordinary mistake in a form stops being\n * reported as an internal error. Before it, a duplicate email, a foreign key\n * pointing at nothing and a missing required value all came back as\n * \"an internal error occurred\" - the correct treatment for a broken database\n * and the wrong one for a person who typed the same address twice.\n *\n * ## Codes, not classes\n *\n * Matched by `code` rather than `instanceof PrismaClientKnownRequestError`, for\n * the reason the adapter already gives: importing `@prisma/client` here would\n * load a second copy of a package the consumer owns and tie this package to\n * their Prisma version.\n *\n * ## Field names come from `meta`, and may not be there\n *\n * Prisma reports the columns involved differently per code and per connector,\n * and sometimes not at all - a SQLite unique violation on a composite index\n * names the index rather than the columns. Where a name is missing the error\n * says so in general terms rather than inventing one, because a message that\n * blames the wrong field is worse than one that blames none.\n */\nimport { ConstraintError, type ConstraintKind } from '@nest-admin/core'\n\n/**\n * Measured against Prisma 7.10.0.\n *\n * `P2014` is the one worth naming: it fires when a *delete* would orphan a\n * required relation, so it is a foreign-key problem arriving from the opposite\n * direction to `P2003`.\n */\nconst CONSTRAINT_CODES: Readonly<Record<string, ConstraintKind>> = {\n P2002: 'unique',\n P2003: 'foreign-key',\n P2014: 'foreign-key',\n P2011: 'required',\n P2012: 'required',\n P2013: 'required',\n}\n\ninterface PrismaKnownError {\n readonly code: string\n readonly meta?: Readonly<Record<string, unknown>>\n}\n\nfunction isPrismaKnownError(value: unknown): value is PrismaKnownError {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The columns Prisma named, if it named any.\n *\n * The shape differs by code: `target` for a unique violation (a string or an\n * array, depending on the connector), `field_name` for a foreign key,\n * `constraint` for a null violation. Anything unrecognised yields nothing,\n * which the message handles.\n */\nfunction fieldsFrom(meta: Readonly<Record<string, unknown>> | undefined): readonly string[] {\n if (!meta) return []\n\n // Prisma 7 with a driver adapter nests the connector's own report, and that\n // is the only place the column names appear - `meta.target` is the older,\n // flatter shape and is still what a client without a driver adapter reports.\n // Both are read, because which one arrives depends on how the consumer built\n // their client rather than on anything this package controls.\n const nested = (meta['driverAdapterError'] as { cause?: { constraint?: unknown } } | undefined)\n ?.cause?.constraint\n\n const candidate =\n (nested as { fields?: unknown } | undefined)?.fields ??\n meta['target'] ??\n meta['field_name'] ??\n meta['constraint']\n\n if (Array.isArray(candidate)) {\n return candidate.filter((entry): entry is string => typeof entry === 'string')\n }\n\n if (typeof candidate !== 'string') return []\n\n // Some connectors report the index name rather than the columns -\n // `User_email_key` for `@unique` on `email`. The column is recoverable from\n // the convention, and a wrong guess here would name a field that does not\n // exist, so it is only trusted when the shape matches exactly.\n const index = /^(.+?)_(.+)_key$/.exec(candidate)\n if (index?.[2] !== undefined) return index[2].split('_')\n\n return [candidate]\n}\n\n/**\n * A missing required argument, which Prisma refuses before the database sees it.\n *\n * It arrives as `PrismaClientValidationError`, which carries **no code** - so\n * it cannot be matched the way every other case here is, and without special\n * handling a form submitted without a required field answers with a generic\n * 500.\n *\n * The message names the arguments in a fixed phrase, and that phrase is all\n * that is read from it. The rest of the text is a rendering of the call site\n * and of the data that was submitted - absolute paths and field values - so\n * forwarding any of it is out of the question.\n */\nfunction missingArguments(cause: unknown): readonly string[] {\n if (!(cause instanceof Error) || cause.constructor.name !== 'PrismaClientValidationError') {\n return []\n }\n\n const names: string[] = []\n for (const match of cause.message.matchAll(/Argument `([A-Za-z0-9_]+)` is missing/g)) {\n if (match[1] !== undefined) names.push(match[1])\n }\n\n return names\n}\n\n/**\n * A `ConstraintError` when Prisma refused the write for a reason a caller can\n * act on, or `undefined` when it did not.\n */\nexport function toConstraintError(cause: unknown, model: string): ConstraintError | undefined {\n const missing = missingArguments(cause)\n if (missing.length > 0) return new ConstraintError('required', model, missing)\n\n if (!isPrismaKnownError(cause)) return undefined\n\n const constraint = CONSTRAINT_CODES[cause.code]\n if (!constraint) return undefined\n\n return new ConstraintError(constraint, model, fieldsFrom(cause.meta))\n}\n","/**\n * Asking the target model for the records linked to one parent.\n *\n * A related list could be fetched from the parent - `user.posts()` - but then\n * pagination, sorting, filtering and relation loading would all have to be\n * reimplemented for that path. Asking the *target* model with an extra `where`\n * instead means a related list is an ordinary list that happens to be\n * constrained, and everything already built for lists applies to it unchanged.\n *\n * The constraint is expressed through the relation's other half, which is why\n * relation names matter:\n *\n * User.posts -> inverse is Post.author (to-one) -> { author: { id: <parent> } }\n * Post.tags -> inverse is Tag.posts (to-many) -> { posts: { some: { id: <parent> } } }\n *\n * Both are Prisma relation filters on the target, so neither needs to know\n * whether a foreign key exists or where it lives.\n */\nimport {\n FieldNotFoundError,\n inverseRelationField,\n type ModelMetadata,\n type RecordId,\n} from '@nest-admin/core'\n\n/**\n * A `where` clause selecting the target records linked to `parentId`.\n *\n * `parentKey` is the parent's primary-key field, which the filter matches on.\n */\nexport function toRelatedWhere(\n parent: ModelMetadata,\n relationFieldName: string,\n parentId: RecordId,\n models: readonly ModelMetadata[],\n): { target: ModelMetadata; where: Record<string, unknown> } {\n const field = parent.fields.find((candidate) => candidate.name === relationFieldName)\n\n if (!field?.relation) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'Only a relation field can be listed this way.',\n )\n }\n\n if (field.relation.cardinality !== 'many') {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'This is a to-one relation. It arrives with the record itself.',\n )\n }\n\n const target = models.find((candidate) => candidate.name === field.relation?.targetModel)\n if (!target) {\n // The target is not part of this admin - excluded by configuration, or\n // hidden from this principal. Either way there is nothing to list.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${field.relation.targetModel} is not available.`,\n )\n }\n\n const inverse = inverseRelationField(field, models)\n if (!inverse) {\n // Without the other half there is no way to express the constraint, and\n // returning every record of the target would be catastrophically wrong.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'The other half of this relation could not be resolved.',\n )\n }\n\n const [parentKey] = parent.primaryKey\n if (parentKey === undefined) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${parent.name} has no primary key.`,\n )\n }\n\n const match = { [parentKey]: parentId }\n\n return {\n target,\n where: {\n [inverse.name]: inverse.relation?.cardinality === 'many' ? { some: match } : { is: match },\n },\n }\n}\n","/**\n * Core `ListQuery` -> Prisma `findMany` arguments.\n *\n * Everything here is validated against model metadata before it reaches the\n * client. Field names arriving from an HTTP request eventually flow into this\n * module, so an unvalidated name would become an injection surface into the\n * query object. There is no raw SQL anywhere; all queries go through Prisma's\n * structured API.\n */\nimport {\n FieldNotFoundError,\n InvalidQueryError,\n type FieldMetadata,\n type FilterRule,\n type ListQuery,\n type ModelMetadata,\n} from '@nest-admin/core'\n\nexport const DEFAULT_PER_PAGE = 25\nexport const MAX_PER_PAGE = 100\n\n/** Operators that only make sense on string fields. */\nconst STRING_ONLY_OPERATORS = new Set(['contains', 'startsWith', 'endsWith'])\n\n/** Operators that require an ordered (numeric, date, or string) field. */\nconst COMPARISON_OPERATORS = new Set(['gt', 'gte', 'lt', 'lte'])\n\nexport interface PrismaFindManyArgs {\n where?: Record<string, unknown>\n orderBy?: Array<Record<string, 'asc' | 'desc'>>\n skip?: number\n take?: number\n}\n\n/**\n * What the field is being resolved for.\n *\n * Only relations care, and they care because the two cases are not symmetric.\n * See {@link findQueryableField}.\n */\ntype QueryPurpose = 'filter' | 'sort'\n\n/**\n * A field usable in a filter or a sort.\n *\n * A to-one relation the model owns is stored in a scalar column, so a **filter**\n * on `author` is answerable: it means exactly a filter on `authorId`, and the\n * caller gets to use whichever name they think in.\n *\n * **Sorting** by it is refused, even though it would run. `authorId` holds a\n * cuid, so ordering by it is ordering by a random-looking string - a result\n * that looks sorted, is stable, and means nothing. What someone asking to sort\n * by `author` wants is the author's *name*, which is sorting by a field on\n * another model and is not this version. A refusal that says so is better than\n * a page of rows in an order nobody can explain.\n *\n * List fields are excluded outright: there is no column on this side at all.\n */\nfunction findQueryableField(\n model: ModelMetadata,\n fieldName: string,\n purpose: QueryPurpose,\n): FieldMetadata {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (!field) {\n throw new FieldNotFoundError(model.name, fieldName)\n }\n if (field.kind === 'relation') {\n const owned = field.relation?.from\n if (owned !== undefined && field.relation?.cardinality === 'one') {\n if (purpose === 'filter') return findQueryableField(model, owned, purpose)\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n `Sorting by a relation is not supported in this version. ` +\n `Sorting by \"${owned}\" would order by an opaque key rather than by ` +\n `anything readable.`,\n )\n }\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'Relation fields cannot be filtered or sorted in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'List fields cannot be filtered or sorted in this version.',\n )\n }\n return field\n}\n\nfunction toPrismaCondition(model: ModelMetadata, rule: FilterRule): Record<string, unknown> {\n const field = findQueryableField(model, rule.field, 'filter')\n\n if (STRING_ONLY_OPERATORS.has(rule.operator) && field.kind !== 'string') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" requires a string field, but ` +\n `\"${model.name}.${field.name}\" is of kind \"${field.kind}\".`,\n )\n }\n\n if (COMPARISON_OPERATORS.has(rule.operator) && field.kind === 'boolean') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" cannot be applied to boolean field ` +\n `\"${model.name}.${field.name}\".`,\n )\n }\n\n if (rule.operator === 'in') {\n if (!Array.isArray(rule.value)) {\n throw new InvalidQueryError(\n `Operator \"in\" requires an array value for \"${model.name}.${field.name}\".`,\n )\n }\n return { [field.name]: { in: rule.value } }\n }\n\n if (rule.operator === 'eq') return { [field.name]: { equals: rule.value } }\n if (rule.operator === 'ne') return { [field.name]: { not: rule.value } }\n\n return { [field.name]: { [rule.operator]: rule.value } }\n}\n\n/**\n * Providers where Prisma accepts `mode: 'insensitive'`.\n *\n * The list is short because Prisma *throws* on the others rather than ignoring\n * the option, so being wrong here breaks every search rather than degrading it.\n *\n * The omissions are deliberate, not oversights:\n *\n * | Provider | Why nothing is sent |\n * | ---------- | ---------------------------------------------------------- |\n * | mysql | Its default collations end in `_ci`; `LIKE` already ignores case. |\n * | sqlite | `LIKE` is case-insensitive for ASCII by default. |\n * | sqlserver | Its default collation is case-insensitive. |\n * | cockroachdb | Prisma documents `mode` for PostgreSQL and MongoDB only. |\n *\n * So on the four below, the option is unnecessary; on CockroachDB it is\n * unproven, and this is not the place to guess.\n */\nconst INSENSITIVE_MODE_PROVIDERS: ReadonlySet<string> = new Set([\n 'postgresql',\n 'postgres',\n 'mongodb',\n])\n\n/**\n * The case-insensitivity option for this provider, if it takes one.\n *\n * Spread into every string comparison. Returning an object to spread rather\n * than a boolean to branch on keeps the option out of the query entirely where\n * it is not supported - Prisma rejects `mode: undefined` as readily as it\n * rejects `mode: 'insensitive'` on SQLite.\n */\nexport function insensitively(provider: string | undefined): { mode?: 'insensitive' } {\n return provider !== undefined && INSENSITIVE_MODE_PROVIDERS.has(provider)\n ? { mode: 'insensitive' }\n : {}\n}\n\n/** String comparisons, which are the ones capitalisation applies to. */\nconst TEXTUAL_OPERATORS: ReadonlySet<string> = new Set(['contains', 'startsWith', 'endsWith'])\n\n/**\n * Free-text search: `contains` across the model's meaningful string fields.\n *\n * Generated string fields are excluded. A `cuid()` or `uuid()` primary key is\n * an opaque machine value, and including it makes single-letter searches match\n * essentially at random - searching \"e\" returns any record whose id happens to\n * contain an \"e\". Looking a record up by its id is an exact-match concern, so\n * it belongs in a filter (`{ field: 'id', operator: 'eq' }`), not in free text.\n *\n * Capitalisation is ignored, which needed the provider to say so. Searching\n * \"ada\" and getting nothing because the record says \"Ada\" is the kind of defect\n * people conclude the search is broken from, and they are not wrong. What it\n * takes to ignore case differs per database, and on some of them the option\n * that does it is an error - hence `insensitively`.\n */\nfunction toSearchCondition(\n model: ModelMetadata,\n term: string,\n provider: string | undefined,\n): Record<string, unknown> | undefined {\n // Foreign keys are string columns holding a cuid, so they match the same\n // rule the generated-id exclusion exists for - and they are not generated,\n // so that rule misses them. Left in, a search for \"e\" matches almost every\n // row of any model that references another, because most cuids contain an e.\n const foreignKeys = new Set(\n model.fields.map((field) => field.relation?.from).filter((name) => name !== undefined),\n )\n\n const stringFields = model.fields.filter(\n (field) =>\n field.kind === 'string' &&\n !field.isList &&\n !field.isGenerated &&\n !foreignKeys.has(field.name),\n )\n if (stringFields.length === 0) return undefined\n\n return {\n OR: stringFields.map((field) => ({\n [field.name]: { contains: term, ...insensitively(provider) },\n })),\n }\n}\n\nexport function buildWhere(\n model: ModelMetadata,\n query: Pick<ListQuery, 'filters' | 'search'>,\n provider?: string,\n): Record<string, unknown> | undefined {\n const conditions: Array<Record<string, unknown>> = []\n\n for (const rule of query.filters ?? []) {\n const condition = toPrismaCondition(model, rule)\n // A \"contains\" filter is the same promise the search box makes, typed into\n // a different box. It would be strange for one to ignore case and not the\n // other, and stranger still to have to know which.\n conditions.push(\n TEXTUAL_OPERATORS.has(rule.operator) ? insensitive(condition, provider) : condition,\n )\n }\n\n const search = query.search?.trim()\n if (search) {\n const searchCondition = toSearchCondition(model, search, provider)\n if (searchCondition) conditions.push(searchCondition)\n }\n\n if (conditions.length === 0) return undefined\n if (conditions.length === 1) return conditions[0]\n return { AND: conditions }\n}\n\nfunction buildOrderBy(\n model: ModelMetadata,\n query: Pick<ListQuery, 'sort'>,\n): Array<Record<string, 'asc' | 'desc'>> | undefined {\n const rules = query.sort ?? []\n if (rules.length === 0) return undefined\n\n return rules.map((rule) => {\n const field = findQueryableField(model, rule.field, 'sort')\n return { [field.name]: rule.direction }\n })\n}\n\n/** Normalised, clamped pagination. Page numbers are 1-based. */\nexport function resolvePagination(query: Pick<ListQuery, 'page' | 'perPage'>): {\n page: number\n perPage: number\n skip: number\n take: number\n} {\n const rawPage = query.page ?? 1\n if (!Number.isInteger(rawPage) || rawPage < 1) {\n throw new InvalidQueryError(\n `\"page\" must be an integer >= 1, received ${JSON.stringify(query.page)}.`,\n )\n }\n\n const rawPerPage = query.perPage ?? DEFAULT_PER_PAGE\n if (!Number.isInteger(rawPerPage) || rawPerPage < 1) {\n throw new InvalidQueryError(\n `\"perPage\" must be an integer >= 1, received ${JSON.stringify(query.perPage)}.`,\n )\n }\n\n // Clamped rather than rejected: a UI asking for too much should get a\n // capped page, not an error.\n const perPage = Math.min(rawPerPage, MAX_PER_PAGE)\n return { page: rawPage, perPage, skip: (rawPage - 1) * perPage, take: perPage }\n}\n\n/**\n * The same condition, told to ignore case.\n *\n * A condition is `{ field: { operator: value } }`, and the option belongs\n * beside the operator rather than beside the field, so it cannot simply be\n * spread at the top level.\n */\nfunction insensitive(\n condition: Record<string, unknown>,\n provider: string | undefined,\n): Record<string, unknown> {\n const mode = insensitively(provider)\n if (mode.mode === undefined) return condition\n\n const entries = Object.entries(condition).map(([field, comparison]) => [\n field,\n typeof comparison === 'object' && comparison !== null\n ? { ...(comparison as Record<string, unknown>), ...mode }\n : comparison,\n ])\n return Object.fromEntries(entries) as Record<string, unknown>\n}\n\nexport function toFindManyArgs(\n model: ModelMetadata,\n query: ListQuery,\n provider?: string,\n): PrismaFindManyArgs {\n const { skip, take } = resolvePagination(query)\n const where = buildWhere(model, query, provider)\n const orderBy = buildOrderBy(model, query)\n\n return {\n ...(where ? { where } : {}),\n ...(orderBy ? { orderBy } : {}),\n skip,\n take,\n }\n}\n","/**\n * Admin accounts, in Prisma.\n *\n * ## A model of its own\n *\n * The default is `AdminAccount`, and that default is the design rather than a\n * placeholder. The people who administer a system are usually not rows in the\n * table they administer, and pointing this at the application's `User` would\n * mean every customer record carries a password that opens the admin - which is\n * a decision nobody makes on purpose and several people make by accident.\n *\n * The model name is configurable because some applications already have a\n * `Staff` or an `Operator`. Pointing it at `User` is possible and is a choice,\n * not a default.\n *\n * ## What it does not do\n *\n * Create, update, delete. The store contract is read-only, and this implements\n * only what it declares: an admin that could mint its own administrators is an\n * escalation waiting for its first mistake in a policy. Seeding the first\n * account is the application's job, with `hashAdminPassword`.\n *\n * ## The account model should not be a resource\n *\n * Nothing here can arrange that - which models the admin exposes is the\n * module's business - so it is the one thing a consumer has to remember:\n *\n * ```ts\n * resources: { exclude: ['AdminAccount'] }\n * ```\n *\n * Without it, anyone who may edit that model can grant themselves whatever the\n * admin can do. `builtInAuth` warns at startup when it sees the account model\n * among the exposed resources.\n */\nimport type { AdminAccount, AdminAccountStore } from '@nest-admin/core'\n\nimport { resolveDelegate } from '../client/delegate.js'\n\nexport interface PrismaAccountStoreOptions {\n /** A constructed Prisma Client - the same one the adapter is given. */\n readonly client: unknown\n\n /** The model holding admin accounts. `AdminAccount` by default. */\n readonly model?: string\n\n /**\n * Column names, where they differ from the defaults.\n *\n * A mapping rather than a required schema: an application that already has a\n * `Staff` table with `login` and `hash` should not have to migrate it to use\n * this.\n */\n readonly fields?: {\n readonly id?: string\n readonly email?: string\n readonly name?: string\n readonly passwordHash?: string\n readonly disabled?: string\n /** Written on a successful sign-in, when the column exists. */\n readonly lastLoginAt?: string\n }\n}\n\nconst DEFAULTS = {\n id: 'id',\n email: 'email',\n name: 'name',\n passwordHash: 'passwordHash',\n disabled: 'disabled',\n lastLoginAt: 'lastLoginAt',\n} as const\n\nexport function prismaAccountStore(options: PrismaAccountStoreOptions): AdminAccountStore {\n const model = options.model ?? 'AdminAccount'\n const column = { ...DEFAULTS, ...options.fields }\n\n /*\n * The allowlist is the one configured name.\n *\n * `resolveDelegate` takes a list because the adapter resolves a model named\n * by a *request*, where an allowlist is the whole defence. Here the name\n * comes from the application's own configuration and there is nothing to\n * defend against - but passing it anyway keeps the property-name guard\n * inside `resolveDelegate`, which is the part that still matters, and gives\n * a clear error rather than `undefined.findMany is not a function` when the\n * model does not exist.\n */\n const delegate = () => resolveDelegate(options.client, model, [model])\n\n /**\n * A row as the contract describes it.\n *\n * Returns `null` for a row with no usable hash rather than an account that\n * can never sign in. The difference matters at the point of use: a `null`\n * takes the same path as an unknown email, and an account object with an\n * empty hash would be compared against and fail in a way that takes a\n * measurably different amount of time.\n */\n const toAccount = (row: unknown): AdminAccount | null => {\n if (typeof row !== 'object' || row === null) return null\n const record = row as Record<string, unknown>\n\n const id = record[column.id]\n const email = record[column.email]\n const hash = record[column.passwordHash]\n\n if (typeof id !== 'string' && typeof id !== 'number') return null\n if (typeof email !== 'string') return null\n if (typeof hash !== 'string' || hash === '') return null\n\n const name = record[column.name]\n const disabled = record[column.disabled]\n\n return {\n id: String(id),\n email,\n passwordHash: hash,\n ...(typeof name === 'string' && name !== '' ? { name } : {}),\n ...(typeof disabled === 'boolean' ? { disabled } : {}),\n }\n }\n\n return {\n describes: model,\n\n async findByEmail(email) {\n /*\n * `findFirst`, not `findUnique`.\n *\n * The email column is very likely unique, and this store cannot know\n * that - a consumer mapping it onto an existing table may have it\n * indexed and not constrained. `findUnique` throws on a column Prisma\n * does not consider unique, which would turn a schema difference into a\n * 500 on the login route.\n */\n const rows = await delegate().findMany({\n where: { [column.email]: email },\n take: 1,\n })\n return toAccount(rows[0])\n },\n\n async findById(id) {\n const rows = await delegate().findMany({ where: { [column.id]: id }, take: 1 })\n return toAccount(rows[0])\n },\n\n async count() {\n return delegate().count()\n },\n\n async recordLogin(id) {\n // Best effort. A store mapped onto a table without this column should\n // not turn a successful sign-in into a failure, and the caller already\n // treats a rejection here as something to log rather than to surface.\n await delegate().update({\n where: { [column.id]: id },\n data: { [column.lastLoginAt]: new Date() },\n })\n },\n }\n}\n"],"mappings":"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","names":["NestAdminError","AdapterError","FieldNotFoundError","ModelNotFoundError","InvalidQueryError","isNestAdminError"]}
1
+ {"version":3,"sources":["../src/prisma.ts","../../core/src/auth/account.ts","../../core/src/metadata/created-field.ts","../../core/src/metadata/display-field.ts","../../core/src/metadata/relation-shape.ts","../../core/src/config/resources.ts","../../core/src/config/overrides.ts","../../core/src/errors/errors.ts","../../prisma/src/adapter.ts","../../prisma/src/client/delegate.ts","../../prisma/src/client/version-gate.ts","../../prisma/src/metadata/read-dmmf.ts","../../prisma/src/metadata/to-metadata.ts","../../prisma/src/query/to-include.ts","../../prisma/src/errors/constraints.ts","../../prisma/src/query/coerce-id.ts","../../prisma/src/query/to-related-where.ts","../../prisma/src/query/to-prisma-args.ts","../../prisma/src/auth/store.ts"],"sourcesContent":["/**\n * `@nest-admin/nestjs/prisma` - the Prisma adapter subpath.\n *\n * Keeping the adapter behind a subpath rather than the root entrypoint means\n * an application that never touches Prisma never loads Prisma code, and a\n * future `@nest-admin/nestjs/typeorm` slots in beside it without changing\n * the root export.\n *\n * The adapter itself is not implemented yet.\n */\n\nexport * from '@nest-admin/prisma'\n","/**\n * Where admin accounts live, as a contract.\n *\n * ## Why this exists at all\n *\n * Until 0.9.0 the answer to \"who may open the admin?\" was always the host\n * application's: it already had sessions, and `AdminAuth` asked it one\n * question. That is still right for a team that has an identity system, and\n * nothing about it changes.\n *\n * It is a wall for everyone else. An application with no login of its own had\n * to write a password hash, a session cookie and a form before the admin could\n * go anywhere near production - which is a strange thing to ask of a package\n * whose whole claim is that you do not build an admin.\n *\n * ## Why it is a contract rather than a table\n *\n * The same reason `OrmAdapter` is. An admin whose accounts can only live in\n * Prisma has learned about Prisma, and the second ORM would find out the hard\n * way. Everything here is plain data and promises; nothing knows what a\n * database is.\n *\n * ## These accounts are not the application's users\n *\n * Deliberately, and this is the point most worth getting right. The people who\n * administer a system are usually not rows in the table they administer, and\n * conflating the two means a customer record with a password that opens the\n * admin. The store is separate storage - a different model, or a different\n * database entirely - and the admin never reads or writes the application's\n * own users to decide who may sign in.\n */\n\n/** One account that may sign in to the admin. */\nexport interface AdminAccount {\n readonly id: string\n\n /**\n * What is typed into the login form.\n *\n * Called `email` because that is what it almost always is, and a name people\n * recognise is worth more than one that covers a case nobody has. A store is\n * free to hold usernames in it.\n */\n readonly email: string\n\n /** Shown in the interface. Falls back to the email when absent. */\n readonly name?: string | undefined\n\n /**\n * The stored password hash, in whatever form the hasher produced.\n *\n * Read by the sign-in check and by nothing else. It must never reach a\n * response, and the account the interface is told about is a projection that\n * does not include it.\n */\n readonly passwordHash: string\n\n /**\n * Suspended without being deleted.\n *\n * Distinct from removing the row: an account that has done things is worth\n * keeping for the record, and \"cannot sign in\" is not the same fact as\n * \"never existed\".\n */\n readonly disabled?: boolean | undefined\n}\n\n/**\n * The account as the interface may see it.\n *\n * A separate type rather than a comment on {@link AdminAccount}, because \"do\n * not send the hash\" is a rule that gets forgotten and a type that cannot\n * carry it does not.\n */\nexport interface AdminAccountSummary {\n readonly id: string\n readonly email: string\n readonly name?: string | undefined\n}\n\n/** Everything but the hash. The only shape that may reach a client. */\nexport function summarise(account: AdminAccount): AdminAccountSummary {\n return {\n id: account.id,\n email: account.email,\n ...(account.name !== undefined ? { name: account.name } : {}),\n }\n}\n\n/**\n * How the admin reaches its accounts.\n *\n * Read-only by design. Creating and editing accounts is the application's\n * business: it owns the storage, it knows whether that is a migration, a seed\n * script or a form somewhere else, and an admin that could mint its own\n * administrators is an escalation waiting for its first mistake.\n */\nexport interface AdminAccountStore {\n /**\n * Find an account by what was typed into the login form.\n *\n * Matching is the store's decision, and it should be case-insensitive on the\n * local part in practice: someone who registered as `Ada@example.com` will\n * type `ada@example.com` eventually.\n *\n * Returns `null` when there is none. The caller must not behave observably\n * differently for `null` than for a wrong password - see the sign-in code.\n */\n findByEmail(email: string): Promise<AdminAccount | null>\n\n /**\n * Find an account by its id, for a request that arrives with a session.\n *\n * Called on every authenticated request, so it should be cheap. It is also\n * what makes a disabled or deleted account stop working immediately rather\n * than when its session happens to expire.\n */\n findById(id: string): Promise<AdminAccount | null>\n\n /**\n * How many accounts exist.\n *\n * Used once, at startup, to say so when the answer is zero - an admin nobody\n * can sign in to is a configuration mistake that otherwise announces itself\n * as a login form that rejects everything.\n */\n count(): Promise<number>\n\n /**\n * Note that an account signed in. Optional.\n *\n * A store that does not care about this can leave it out; the sign-in path\n * does not wait for it and a failure is logged rather than surfaced, because\n * \"your login worked but we could not write down that it did\" is not\n * something the person signing in can act on.\n */\n recordLogin?(id: string): Promise<void>\n\n /**\n * What this store reads, for diagnostics. Optional.\n *\n * A model name, a table, a directory - whatever names the storage in a way a\n * person would recognise. It exists so a startup check can say something\n * useful rather than something generic: an admin that exposes its own\n * account model as an editable resource is an escalation, and a warning that\n * cannot name the model is a warning nobody acts on.\n *\n * Never used to decide anything, and never sent to a client.\n */\n readonly describes?: string\n}\n","/**\n * Which field records when a row appeared.\n *\n * A dashboard's most useful question is \"how much of this arrived recently\",\n * and answering it needs one column: the timestamp a record was created. Every\n * conventional schema has one and none of them declare it as such.\n *\n * ## Why this is a guess\n *\n * The metadata cannot tell a creation timestamp from any other generated date.\n * Prisma reports both `@default(now())` and `@updatedAt` the same way - the\n * adapter collapses them into `isGenerated`, because for *editing* they are the\n * same thing: neither is asked of a person. That is the right call for a form\n * and leaves nothing to distinguish them here.\n *\n * So this reads names, exactly as `displayFieldFor` does, and for the same\n * reason: the convention is near-universal and the alternative is a dashboard\n * that shows nothing until every application has annotated its schema.\n *\n * ## What it refuses to guess\n *\n * `updatedAt` and its variants are excluded rather than merely ranked lower. A\n * chart of \"records updated per day\" plotted under the heading \"new records\"\n * is worse than no chart: it is confidently wrong, and nothing about it looks\n * wrong. Where the convention is not followed, the answer is `undefined` and\n * the widget is simply not offered.\n */\nimport type { FieldMetadata, ModelMetadata } from './model.js'\n\n/**\n * Names that mean \"when this was created\", most conventional first.\n *\n * Snake case is included because a schema mapped onto an existing database\n * often keeps the column names it found there.\n */\nconst CREATED = ['createdAt', 'created_at', 'created', 'createdOn', 'insertedAt', 'inserted_at']\n\n/**\n * Names that must never be taken for it.\n *\n * Checked case-insensitively and by prefix, so `updatedAt`, `updated_at` and\n * `updateTime` are all excluded. Being wrong here is silent: a chart titled\n * \"new this month\" that is actually counting edits.\n */\nconst NOT_CREATED = ['updated', 'modified', 'deleted', 'archived', 'expires', 'expired']\n\nfunction isDate(field: FieldMetadata): boolean {\n return field.kind === 'datetime' && !field.isList && !field.relation\n}\n\nfunction excluded(name: string): boolean {\n const lower = name.toLowerCase()\n return NOT_CREATED.some((word) => lower.startsWith(word))\n}\n\n/**\n * The field that records when a record of this model was created, if the model\n * follows the convention.\n *\n * Order of preference:\n *\n * 1. a conventional name, most conventional first;\n * 2. the only remaining generated date on the model - a model with exactly\n * one date the database fills in has no ambiguity to resolve;\n * 3. nothing.\n *\n * The third is a real answer. A widget that cannot be built correctly is not\n * offered, which is a better outcome than one built on a column that means\n * something else.\n */\nexport function createdFieldFor(model: ModelMetadata): string | undefined {\n const dates = model.fields.filter(isDate)\n\n for (const conventional of CREATED) {\n const match = dates.find((field) => field.name.toLowerCase() === conventional.toLowerCase())\n if (match) return match.name\n }\n\n const generated = dates.filter((field) => field.isGenerated && !excluded(field.name))\n return generated.length === 1 ? generated[0]?.name : undefined\n}\n","/**\n * Which field names a record when it has to be referred to in one line.\n *\n * A relation is stored as an id, and an id is not something a person can read.\n * An admin that renders `cmtf50g710000mocjbygyfyfr` where it means \"Ada\n * Lovelace\" is technically correct and useless, so every model needs one field\n * that stands for the record.\n *\n * The rule lives in Core rather than in an adapter because it is a question\n * about a *model*, not about an ORM: the same reasoning applies whatever\n * produced the metadata. Two places need the answer and must agree on it - the\n * adapter, which selects the column when loading a relation, and the metadata\n * document, which tells the UI what to render.\n */\nimport type { FieldMetadata, ModelMetadata } from './model.js'\n\n/**\n * Conventional names for \"the human-readable one\", most specific first.\n *\n * Ordered by how strongly the name implies a label. `name` and `title` are\n * unambiguous; `email` is a real identifier people recognise; `slug` is a\n * last resort among the conventional names because it is machine-shaped, but\n * it is still readable, which an id is not.\n */\nconst CONVENTIONAL = ['name', 'title', 'label', 'displayName', 'username', 'email', 'slug']\n\n/** Could this field stand in for the record in a list or a dropdown? */\nfunction isReadable(field: FieldMetadata): boolean {\n return (\n field.kind === 'string' &&\n !field.isList &&\n !field.relation &&\n // A generated string is a cuid or a uuid: readable characters, no meaning.\n !field.isGenerated\n )\n}\n\n/**\n * Pick the field that names a record of this model.\n *\n * Order of preference:\n *\n * 1. a conventional name (`name`, `title`, ...), most specific first;\n * 2. any other unique string - unique suggests it identifies the record;\n * 3. any other plain string;\n * 4. the first primary-key field.\n *\n * The last step is the honest fallback rather than a good answer: a model with\n * nothing but an id and a timestamp has no readable field, and showing the id\n * is better than showing nothing. Adapters and applications may override the\n * result; this is the default, not a rule.\n */\nexport function displayFieldFor(model: ModelMetadata): string {\n // A declared choice wins outright. The rule below is a guess, and the\n // application knows things the schema does not.\n if (model.displayField !== undefined) return model.displayField\n\n const readable = model.fields.filter(isReadable)\n\n for (const candidate of CONVENTIONAL) {\n const match = readable.find((field) => field.name === candidate)\n if (match) return match.name\n }\n\n const unique = readable.find((field) => field.isUnique && !field.isId)\n if (unique) return unique.name\n\n const plain = readable.find((field) => !field.isId)\n if (plain) return plain.name\n\n return model.primaryKey[0] ?? model.fields[0]?.name ?? 'id'\n}\n","/**\n * Reading a to-many relation from the parent's side.\n *\n * From `User`, both `posts` (one-to-many) and `Post.tags` (many-to-many) look\n * identical: a list of related records. What differs is where the link is\n * stored, and therefore what changing it means.\n *\n * one-to-many the child owns a column. Attaching a post to a user rewrites\n * `post.authorId`, which also *detaches it from whoever had it*.\n * Detaching means clearing that column, which is impossible if\n * it is required.\n *\n * many-to-many neither side owns a column; the link lives in a join table.\n * Attaching and detaching add and remove a row there and change\n * nothing about either record.\n *\n * An interface that offers the same buttons for both is lying about one of\n * them, so the difference is resolved here, once, from metadata both adapters\n * already produce.\n */\nimport type { FieldMetadata, ModelMetadata } from './model.js'\n\nexport type RelationShape = 'to-one' | 'one-to-many' | 'many-to-many'\n\n/**\n * The field on the target model that is the other half of this relation.\n *\n * Matched by relation name, which is the only reliable pairing: two relations\n * between the same models (`author` and `reviewer`, both to `User`) are\n * otherwise indistinguishable. Returns `undefined` when the name is absent -\n * an adapter that does not supply one - or when the target is not in `models`.\n */\nexport function inverseRelationField(\n field: FieldMetadata,\n models: readonly ModelMetadata[],\n): FieldMetadata | undefined {\n const relation = field.relation\n if (!relation?.name) return undefined\n\n const target = models.find((model) => model.name === relation.targetModel)\n if (!target) return undefined\n\n return target.fields.find(\n (candidate) => candidate.relation?.name === relation.name && candidate !== field,\n )\n}\n\n/**\n * What kind of relation this is, from the side the field is declared on.\n *\n * A to-many whose other half is also a list is a many-to-many. Without an\n * inverse to look at - no relation name, or a target outside this admin - a\n * to-many is reported as `one-to-many`, the more conservative answer: it is the\n * shape whose write operations have preconditions, so treating a many-to-many\n * as one costs a refused detach rather than a corrupted record.\n */\nexport function relationShape(\n field: FieldMetadata,\n models: readonly ModelMetadata[],\n): RelationShape | undefined {\n const relation = field.relation\n if (!relation) return undefined\n if (relation.cardinality === 'one') return 'to-one'\n\n const inverse = inverseRelationField(field, models)\n return inverse?.relation?.cardinality === 'many' ? 'many-to-many' : 'one-to-many'\n}\n\n/**\n * Why a one-to-many relation cannot be detached, or `undefined` if it can.\n *\n * Detaching means clearing the child's foreign key, and a required column\n * cannot be cleared. The database would refuse it; saying so first is the\n * difference between \"you cannot remove this here, delete the record instead\"\n * and a constraint violation.\n */\nexport function detachBlockedReason(\n field: FieldMetadata,\n models: readonly ModelMetadata[],\n): string | undefined {\n if (relationShape(field, models) !== 'one-to-many') return undefined\n\n const inverse = inverseRelationField(field, models)\n if (!inverse?.isRequired) return undefined\n\n const target = field.relation?.targetModel ?? 'the related model'\n return (\n `${target}.${inverse.name} is required, so a ${target} record cannot exist ` +\n `without one. Delete the record, or point it at something else, instead of ` +\n `detaching it.`\n )\n}\n","/**\n * Which models the admin exposes at all.\n *\n * Distinct from resource authorization, and the two answer different questions.\n * A `ResourceSelection` is structural: it decides what the admin *is*, the same\n * for everyone, and a model outside it does not exist as far as the admin is\n * concerned. `AdminResourceAuth` is per-principal: the model exists, and this\n * caller may or may not act on it.\n *\n * That difference is visible in the response. An excluded model answers 404 -\n * there is no such resource - where a denied one answers 403.\n */\n\nexport interface ResourceSelection {\n /**\n * When present, only these models are exposed. Everything else is dropped,\n * including models added to the schema later - which is the point: an\n * allow-list does not quietly grow when someone edits the schema.\n */\n readonly include?: readonly string[]\n\n /**\n * Models removed from the selection, applied after `include`.\n *\n * The usual reason is a table that is not domain data: session stores,\n * migration bookkeeping, queue tables.\n */\n readonly exclude?: readonly string[]\n}\n\n/** Anything with a name - `ModelMetadata`, or a test's stand-in for one. */\ninterface Named {\n readonly name: string\n}\n\n/**\n * Apply a selection, preserving the adapter's own order.\n *\n * Order comes from the schema rather than from `include`, so that adding a name\n * to the list does not silently reshuffle the admin. Deciding the order models\n * appear in is a separate feature and is not this option's job.\n */\nexport function selectModels<T extends Named>(\n models: readonly T[],\n selection?: ResourceSelection,\n): readonly T[] {\n if (!selection) return models\n\n const included = selection.include ? new Set(selection.include) : undefined\n const excluded = new Set(selection.exclude ?? [])\n\n return models.filter(\n (model) => (included === undefined || included.has(model.name)) && !excluded.has(model.name),\n )\n}\n\n/**\n * Names in the selection that no model answers to.\n *\n * Worth reporting rather than ignoring: a typo in `exclude` leaves the model\n * exposed, which is the opposite of what was asked for and is invisible until\n * someone finds the table in the admin. A typo in `include` is louder - the\n * model simply never appears - but has the same cause.\n */\nexport function unknownSelectionNames<T extends Named>(\n models: readonly T[],\n selection?: ResourceSelection,\n): readonly string[] {\n if (!selection) return []\n\n const known = new Set(models.map((model) => model.name))\n const referenced = [...(selection.include ?? []), ...(selection.exclude ?? [])]\n\n return [...new Set(referenced.filter((name) => !known.has(name)))]\n}\n","/**\n * Per-model and per-field configuration.\n *\n * The schema says what a model *is*; this says how the admin should treat it.\n * Two different questions, so they are two different inputs - a column being a\n * string is a fact about the database, and that column being a password is a\n * fact about the application.\n *\n * The overrides divide into two kinds, and the difference matters:\n *\n * behaviour `hidden`, `readOnly`, `displayField`. Enforced. A hidden\n * field is removed from the metadata every layer reads, so it\n * cannot be filtered, sorted, written or returned - see\n * `applyOverrides`.\n *\n * behaviour `writeOnly` too - accepted on a write and stripped from\n * every read.\n *\n * presentation `label`, `widget`, `order`. Passed to the client, which is\n * free to ignore them. Nothing depends on them being honoured.\n *\n * Anything in the first group that were only presentation would be a security\n * hole with a reassuring name.\n */\nimport type { FieldMetadata, ModelMetadata } from '../metadata/model.js'\n\n/**\n * How a field should be edited, when its type does not say enough.\n *\n * A `string` column may be a sentence, a password, an address or a colour, and\n * the schema cannot tell them apart. Deliberately a closed list: a client has\n * to know how to render each one, so an open string would mean silently\n * falling back to a plain input and no way to notice.\n */\nexport type FieldWidget = 'textarea' | 'password' | 'email' | 'url' | 'color' | 'json'\n\nexport interface FieldOverride {\n /**\n * Remove the field from the admin entirely.\n *\n * **Enforced, not cosmetic.** The field is dropped from the metadata before\n * anything reads it, so it is absent from the schema document, rejected in\n * filters and sorts, refused in writes, and stripped from every response.\n * A password hash is the reason this exists.\n */\n readonly hidden?: boolean\n\n /** Show the field, refuse to write it. Generated columns are already this. */\n readonly readOnly?: boolean\n\n /**\n * Write the field, never read it back. The mirror of `readOnly`.\n *\n * **Enforced, not cosmetic.** The column is left out of the query the adapter\n * makes and out of the projection applied to the result, so it is absent from\n * a list, from a detail page and from the record a write returns - while\n * still being accepted in the write itself.\n *\n * A password is what this is for. `hidden` is the wrong tool: it refuses the\n * field in both directions, so a hidden password column can never be set.\n */\n readonly writeOnly?: boolean\n\n /** What to call it, when the column name is not what people call the thing. */\n readonly label?: string\n\n /** How to edit it. See {@link FieldWidget}. */\n readonly widget?: FieldWidget\n\n /** Where it sits among the others. Lower comes first; unset comes last. */\n readonly order?: number\n}\n\n/**\n * Icons a model may be given in the navigation.\n *\n * A closed list, for the same reason `FieldWidget` is one: the interface has to\n * know how to draw each name, so an open string would mean silently rendering\n * nothing and no way to notice. It is also a bundle decision - the icon set has\n * about fifteen hundred entries, and only the ones named here are shipped.\n *\n * Chosen to cover what an admin's resources usually are rather than to be\n * complete. A model with no icon is drawn without one, which is the default and\n * is not a lesser state: identical icons down a column are decoration, and the\n * navigation reads better with none than with thirty of the same shape.\n */\nexport type ModelIcon =\n | 'users'\n | 'user'\n | 'building'\n | 'box'\n | 'package'\n | 'tag'\n | 'shopping-cart'\n | 'credit-card'\n | 'receipt'\n | 'file-text'\n | 'folder'\n | 'image'\n | 'calendar'\n | 'clock'\n | 'mail'\n | 'message-square'\n | 'bell'\n | 'star'\n | 'map-pin'\n | 'globe'\n | 'settings'\n | 'key'\n | 'shield'\n | 'database'\n | 'table'\n | 'layers'\n | 'list'\n | 'chart-bar'\n | 'activity'\n | 'truck'\n | 'gift'\n | 'bookmark'\n | 'link'\n\nexport interface ModelOverride {\n /** What to call the model. */\n readonly label?: string\n\n /**\n * Which icon to show beside it in the navigation.\n *\n * Presentational: the client may ignore it, and nothing depends on it being\n * honoured. See {@link ModelIcon} for why the list is closed.\n */\n readonly icon?: ModelIcon\n\n /**\n * Which field names a record, overriding what would be detected.\n *\n * The detection rule guesses well on conventional schemas and has no way to\n * know that a `code` column is the one people recognise.\n */\n readonly displayField?: string\n\n /** Where the model sits in the resource list. Lower first; unset last. */\n readonly order?: number\n\n readonly fields?: Readonly<Record<string, FieldOverride>>\n}\n\nexport type ModelOverrides = Readonly<Record<string, ModelOverride>>\n\n/** The override for one field, if the application declared one. */\nexport function fieldOverride(\n overrides: ModelOverrides | undefined,\n model: string,\n field: string,\n): FieldOverride | undefined {\n return overrides?.[model]?.fields?.[field]\n}\n\n/** Is this field one the application refuses to write? */\nexport function isReadOnly(\n overrides: ModelOverrides | undefined,\n model: string,\n field: FieldMetadata,\n): boolean {\n // Generated values are read-only whatever the configuration says: they are\n // the database's to produce, and were never writable.\n return field.isGenerated || fieldOverride(overrides, model, field.name)?.readOnly === true\n}\n\n/**\n * The models as the admin should see them.\n *\n * Hidden fields are **removed** rather than marked, so that every layer\n * downstream is correct without knowing this option exists. The query parser\n * rejects a filter on a field it cannot find; the metadata mapper cannot\n * describe one; write validation refuses one. A flag would have needed each of\n * those to remember to check it.\n *\n * A declared `displayField` is carried through the same way, so the adapter and\n * the metadata document agree on it without either consulting the config.\n */\nexport function applyOverrides(\n models: readonly ModelMetadata[],\n overrides: ModelOverrides | undefined,\n): readonly ModelMetadata[] {\n if (!overrides) return models\n\n return models.map((model) => {\n const override = overrides[model.name]\n if (!override) return model\n\n const hidden = new Set(\n Object.entries(override.fields ?? {})\n .filter(([, field]) => field.hidden === true)\n .map(([name]) => name),\n )\n\n const writeOnly = new Set(\n Object.entries(override.fields ?? {})\n .filter(([, field]) => field.writeOnly === true)\n .map(([name]) => name),\n )\n\n const kept = hidden.size === 0 ? model.fields : model.fields.filter((f) => !hidden.has(f.name))\n\n return {\n ...model,\n ...(override.displayField !== undefined ? { displayField: override.displayField } : {}),\n // Carried onto the metadata rather than looked up again later, so\n // everything downstream - the field scope, the projection, the DTO -\n // reads one flag instead of each re-deriving it from the configuration.\n fields:\n writeOnly.size === 0\n ? kept\n : kept.map((field) =>\n writeOnly.has(field.name) ? { ...field, writeOnly: true } : field,\n ),\n }\n })\n}\n\n/**\n * Names in the configuration that no model or field answers to.\n *\n * Reported so a typo fails at startup. The cost of ignoring one is not\n * symmetrical: a mistyped `label` is invisible and harmless, but a mistyped\n * `passwordHash` leaves the real column exposed while the configuration looks\n * like it is protecting it.\n */\nexport function unknownOverrideNames(\n models: readonly ModelMetadata[],\n overrides: ModelOverrides | undefined,\n): readonly string[] {\n if (!overrides) return []\n\n const unknown: string[] = []\n\n for (const [modelName, override] of Object.entries(overrides)) {\n const model = models.find((candidate) => candidate.name === modelName)\n if (!model) {\n unknown.push(modelName)\n continue\n }\n\n const names = new Set(model.fields.map((field) => field.name))\n\n if (override.displayField !== undefined && !names.has(override.displayField)) {\n unknown.push(`${modelName}.${override.displayField}`)\n }\n\n for (const fieldName of Object.keys(override.fields ?? {})) {\n if (!names.has(fieldName)) unknown.push(`${modelName}.${fieldName}`)\n }\n }\n\n return unknown\n}\n\n/**\n * Hidden fields that make creating a record impossible.\n *\n * A column that is required, is not produced by the database, and has no\n * default is a value the *caller* must supply. Hiding it removes the only way\n * to supply it, so every create fails - and fails in the database, as a\n * constraint violation the admin can only report as an internal error.\n *\n * Reported at startup for that reason: the configuration is self-defeating, and\n * the symptom otherwise appears far from the cause.\n */\nexport function unwritableHiddenFields(\n models: readonly ModelMetadata[],\n overrides: ModelOverrides | undefined,\n): readonly string[] {\n if (!overrides) return []\n\n const blocked: string[] = []\n\n for (const [modelName, override] of Object.entries(overrides)) {\n const model = models.find((candidate) => candidate.name === modelName)\n if (!model) continue\n\n for (const [fieldName, field] of Object.entries(override.fields ?? {})) {\n if (field.hidden !== true) continue\n\n const declared = model.fields.find((candidate) => candidate.name === fieldName)\n if (!declared) continue\n\n if (declared.isRequired && !declared.isGenerated && declared.defaultValue === undefined) {\n blocked.push(`${modelName}.${fieldName}`)\n }\n }\n }\n\n return blocked\n}\n","/**\n * Framework error vocabulary.\n *\n * Deliberately small. These exist so that adapters raise ORM-independent\n * errors and the transport layer can map them to status codes without knowing\n * which ORM produced them. Resist growing this taxonomy - add a new type only\n * when a caller genuinely needs to branch on it.\n *\n * ## Why these are not identified with `instanceof`\n *\n * A published bundle can contain more than one copy of this module. The\n * package ships two CommonJS entrypoints and each inlines its own copy of\n * Core, so an error thrown inside the Prisma adapter is an instance of a\n * *different* `FieldNotFoundError` class than the one the exception filter\n * holds. `instanceof` compares class identity, so it answered `false` and\n * every adapter-raised error was mapped to a generic 500 - a caller who\n * mistyped a sort field got \"internal error\" instead of \"unknown field\".\n *\n * That was invisible to this repository's own tests, which resolve Core to a\n * single source module, and only appeared when the built package was installed\n * and run. So errors are identified by *value* rather than identity: a\n * `Symbol.for` brand, which duplicate copies agree on by definition, plus a\n * stable `kind` string. Neither depends on which copy created the object.\n *\n * `scripts/verify-packed-consumer.mjs` asserts the arrangement every release:\n * one shared copy in ESM, one per entrypoint in CJS. If that ever changes, the\n * count changes there first.\n *\n * @experimental Draft contract. Expected to change during MVP implementation.\n */\n\n/**\n * Cross-copy brand.\n *\n * `Symbol.for` resolves through the global symbol registry, so two copies of\n * this file agree on the key where two `Symbol()` calls would not.\n */\nconst BRAND = Symbol.for('nest-admin.error')\n\n/**\n * Stable discriminator for each error type.\n *\n * A declared string rather than the class, so it survives duplicate bundles,\n * and rather than `name`, so it survives minification.\n */\nexport type AdminErrorKind =\n | 'unauthorized'\n | 'forbidden'\n | 'model-not-found'\n | 'field-not-found'\n | 'record-not-found'\n | 'invalid-query'\n /** Application code refused the input. Its message reaches the client. */\n | 'validation'\n /** The database refused the write: unique, foreign key, or required. */\n | 'constraint'\n | 'adapter'\n /** A subclass that declared no kind of its own. Treated as internal. */\n | 'unknown'\n\n/**\n * Base error type. Every error raised by Nest Admin extends it so that the\n * NestJS integration can distinguish framework errors from application errors\n * without depending on concrete subclasses.\n */\nexport class NestAdminError extends Error {\n /**\n * Which error this is.\n *\n * Subclasses override it with a literal. The base value covers anything that\n * extends this class without declaring one - the Prisma schema errors, for\n * instance - which the transport layer treats as internal.\n */\n readonly kind: AdminErrorKind = 'unknown'\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = new.target.name\n // Non-enumerable, so it can never reach a serialised response body.\n Object.defineProperty(this, BRAND, { value: true, enumerable: false })\n }\n}\n\n/**\n * Is this one of ours?\n *\n * Works across duplicate copies of this module, which `instanceof` does not.\n */\nexport function isNestAdminError(value: unknown): value is NestAdminError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[BRAND] === true\n )\n}\n\n/** The requested model is not part of the admin's resource set. */\nexport class ModelNotFoundError extends NestAdminError {\n override readonly kind = 'model-not-found' as const\n\n constructor(\n readonly model: string,\n readonly availableModels: readonly string[] = [],\n ) {\n const known = availableModels.length > 0 ? ` Known models: ${availableModels.join(', ')}.` : ''\n super(`Unknown model \"${model}\".${known}`)\n }\n}\n\n/** A referenced field does not exist on the model, or cannot be used this way. */\nexport class FieldNotFoundError extends NestAdminError {\n override readonly kind = 'field-not-found' as const\n\n constructor(\n readonly model: string,\n readonly field: string,\n reason?: string,\n ) {\n super(`Unknown field \"${field}\" on model \"${model}\".${reason ? ` ${reason}` : ''}`)\n }\n}\n\n/** No record matched the given identifier. */\nexport class RecordNotFoundError extends NestAdminError {\n override readonly kind = 'record-not-found' as const\n\n constructor(\n readonly model: string,\n readonly id: unknown,\n ) {\n super(`No ${model} record found for id ${JSON.stringify(id)}.`)\n }\n}\n\n/**\n * The query is structurally invalid - an unusable operator/field combination,\n * a malformed value, or a request the adapter cannot express.\n */\nexport class InvalidQueryError extends NestAdminError {\n override readonly kind = 'invalid-query' as const\n}\n\n/**\n * The input is not acceptable, and the caller should be told why.\n *\n * Raised by application code - a hook rejecting a value, a rule the schema\n * cannot express - rather than by the framework. It exists because such a\n * refusal has to reach the person who typed the value, and the alternatives are\n * wrong in one direction or the other: `InvalidQueryError` claims the *query*\n * was malformed, and anything unrecognised becomes a generic 500 with the\n * message withheld.\n *\n * The message **is** forwarded to the client, which is the point of it and also\n * the responsibility that comes with it: whatever goes in is published.\n *\n * Naming the fields it is about is optional and worth doing. An interface that\n * knows which input was refused can say so next to that input, where the person\n * is looking, instead of in a banner above a form they then have to re-read.\n */\nexport class ValidationError extends NestAdminError {\n override readonly kind = 'validation' as const\n\n constructor(\n message: string,\n /** The inputs this is about. Empty when it is about the record as a whole. */\n readonly fields: readonly string[] = [],\n options?: { cause?: unknown },\n ) {\n super(message, options)\n }\n}\n\n/**\n * What the database refused, and about which fields.\n *\n * The distinction that matters is between a request that is *wrong* and a\n * database that is *broken*. A duplicate email, a foreign key pointing at\n * nothing, a missing required value - these are ordinary mistakes a person\n * makes in a form, and until they were told apart from a real failure the admin\n * answered every one of them with \"an internal error occurred\".\n *\n * The message is built here, from the constraint and the field names, rather\n * than taken from the ORM. An ORM's own text carries file paths, generated\n * query fragments and the values that collided, none of which should be\n * published - which is exactly why the generic 500 existed in the first place.\n */\nexport type ConstraintKind =\n /** A value that has to be unique is not. */\n | 'unique'\n /** A reference points at a record that is not there, or is still referenced. */\n | 'foreign-key'\n /** A value the database requires was not supplied. */\n | 'required'\n\nexport class ConstraintError extends NestAdminError {\n override readonly kind = 'constraint' as const\n\n constructor(\n readonly constraint: ConstraintKind,\n readonly model: string,\n /** The columns involved. Empty when the ORM did not say. */\n readonly fields: readonly string[] = [],\n ) {\n super(describeConstraint(constraint, model, fields))\n }\n}\n\n/**\n * A sentence for the person who filled in the form.\n *\n * Written from the field names alone, so it is safe to forward. Where the ORM\n * did not name a field the wording stays true rather than guessing at one.\n */\nfunction describeConstraint(\n constraint: ConstraintKind,\n model: string,\n fields: readonly string[],\n): string {\n const named = fields.length > 0 ? fields.join(', ') : undefined\n\n switch (constraint) {\n case 'unique':\n return named\n ? `Another ${model} already has this ${named}.`\n : `Another ${model} already has one of these values.`\n\n case 'foreign-key':\n return named\n ? `The ${named} does not refer to an existing record, or the record it refers to is still in use.`\n : `A reference on this ${model} does not point at an existing record, or is still in use.`\n\n case 'required':\n return named ? `${named} is required.` : `A required value on this ${model} is missing.`\n }\n}\n\n/**\n * The underlying ORM or database failed. Always wraps the original error as\n * `cause` so the real failure is never lost.\n */\nexport class AdapterError extends NestAdminError {\n override readonly kind = 'adapter' as const\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n }\n}\n\n/**\n * No authenticated identity was presented with the request.\n *\n * Raised by the host application's admin auth implementation, never by Core\n * itself - Core has no notion of a request, a header or a session, and must\n * not acquire one. It exists here so the transport layer can map it without\n * knowing which framework produced it.\n *\n * The default message is deliberately uninformative. An authentication failure\n * must not reveal whether a credential was absent, malformed, expired or\n * simply wrong.\n */\nexport class UnauthorizedError extends NestAdminError {\n override readonly kind = 'unauthorized' as const\n\n constructor(message = 'Authentication is required to access the admin API.') {\n super(message)\n }\n}\n\n/**\n * An identity was established, but it is not permitted to do this.\n *\n * Deliberately distinct from {@link UnauthorizedError}: collapsing the two\n * leaves a client unable to tell \"log in\" from \"you cannot do this\", and\n * pushes that guesswork into every consumer.\n */\nexport class ForbiddenError extends NestAdminError {\n override readonly kind = 'forbidden' as const\n\n constructor(message = 'You do not have permission to access the admin API.') {\n super(message)\n }\n}\n","/**\n * `PrismaAdapter` - the Prisma implementation of Core's `OrmAdapter`.\n *\n * The adapter never constructs a Prisma Client. Prisma 7 builds clients from\n * driver adapters, so only the consuming application knows the provider, the\n * credentials and the connection strategy. We receive a constructed client and\n * use it.\n */\nimport {\n AdapterError,\n FieldNotFoundError,\n InvalidQueryError,\n ModelNotFoundError,\n isNestAdminError,\n RecordNotFoundError,\n type ListQuery,\n type ModelMetadata,\n type OrmAdapter,\n type Page,\n type RecordData,\n type RecordId,\n} from '@nest-admin/core'\n\nimport { resolveDelegate, type PrismaModelDelegate } from './client/delegate.js'\nimport { assertSupportedPrismaVersion } from './client/version-gate.js'\nimport { readDatasourceProvider, readPrismaDmmf } from './metadata/read-dmmf.js'\nimport { toModelMetadata } from './metadata/to-metadata.js'\nimport { toIncludeClause } from './query/to-include.js'\nimport { toConstraintError } from './errors/constraints.js'\nimport { coerceId } from './query/coerce-id.js'\nimport { toRelatedWhere } from './query/to-related-where.js'\nimport { resolvePagination, toFindManyArgs } from './query/to-prisma-args.js'\n\n/** Prisma's error code for \"record required but not found\". */\nconst PRISMA_RECORD_NOT_FOUND = 'P2025'\n\nexport interface PrismaAdapterOptions {\n /**\n * A constructed Prisma Client. Owned entirely by the consuming application:\n * the adapter never calls `new PrismaClient()`, because under Prisma 7 the\n * client is built from a driver adapter that only the application can supply.\n */\n readonly client: unknown\n /**\n * Path to `schema.prisma`, or to a directory of `.prisma` files. When\n * omitted, `prisma/schema.prisma`, `prisma/schema` and `schema.prisma` are\n * tried in that order, relative to `cwd`.\n */\n readonly schemaPath?: string\n /** Base directory for schema resolution. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\nexport class PrismaAdapter implements OrmAdapter {\n readonly name = 'prisma'\n\n readonly #client: unknown\n readonly #schemaPath: string | undefined\n readonly #cwd: string | undefined\n\n /**\n * Metadata is derived from a static schema, so it is read once and reused.\n * Every operation validates against it, which would otherwise re-parse the\n * schema on each call.\n */\n #models: readonly ModelMetadata[] | undefined\n\n /**\n * Which database this is, so a search can ignore capitalisation the way that\n * database allows. Read alongside the metadata, and `undefined` when the\n * schema does not say - see `insensitively` in `to-prisma-args.ts`.\n */\n #provider: string | undefined\n\n constructor(options: PrismaAdapterOptions) {\n if (options.client === null || options.client === undefined) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client. ' +\n 'Pass one via `new PrismaAdapter({ client })`.',\n )\n }\n this.#client = options.client\n this.#schemaPath = options.schemaPath\n this.#cwd = options.cwd\n }\n\n async getModels(): Promise<readonly ModelMetadata[]> {\n if (this.#models) return this.#models\n // Checked before parsing: a version mismatch would otherwise surface as\n // \"Prisma rejected the schema\", pointing at the user's valid schema.\n assertSupportedPrismaVersion(this.#client)\n const dmmf = readPrismaDmmf({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n this.#models = toModelMetadata(dmmf)\n this.#provider = readDatasourceProvider({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n return this.#models\n }\n\n async list(model: string, query: ListQuery): Promise<Page<RecordData>> {\n const declared = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n\n // Narrowed first: everything below reads the model, so restricting it once\n // restricts field lookup, free-text search and relation loading together.\n const metadata = narrowFields(declared, query.fields)\n\n const args = toFindManyArgs(metadata, query, this.#provider)\n const include = toIncludeClause(metadata, await this.getModels())\n const omit = omitClause(declared, query.fields)\n const withRelations = { ...args, ...(include ? { include } : {}), ...(omit ? { omit } : {}) }\n const { page, perPage } = resolvePagination(query)\n\n const [rows, total] = await this.#run(model, () =>\n Promise.all([\n delegate.findMany(withRelations),\n delegate.count(args.where ? { where: args.where } : {}),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async findOne(model: string, id: RecordId): Promise<RecordData | null> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n const include = toIncludeClause(metadata, await this.getModels())\n const record = await this.#run(model, () =>\n delegate.findUnique(include ? { where, include } : { where }),\n )\n return (record as RecordData | null) ?? null\n }\n\n async create(model: string, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const writable = this.#validateWritableData(metadata, data)\n\n const created = await this.#run(model, () => delegate.create({ data: writable }))\n return created as RecordData\n }\n\n async update(model: string, id: RecordId, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n const writable = this.#validateWritableData(metadata, data)\n\n const updated = await this.#run(model, () => delegate.update({ where, data: writable }), id)\n return updated as RecordData\n }\n\n async delete(model: string, id: RecordId): Promise<void> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n await this.#run(model, () => delegate.delete({ where }), id)\n }\n\n /**\n * A page of the records on the far side of a to-many relation.\n *\n * Implemented as an ordinary list of the *target* model with one extra\n * condition, so pagination, sorting, filtering and relation loading all\n * behave exactly as they do on a top-level list. See `to-related-where.ts`.\n */\n async listRelated(\n model: string,\n id: RecordId,\n relationField: string,\n query: ListQuery,\n ): Promise<Page<RecordData>> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n\n // The relation is validated first: a bad field name is wrong whether or\n // not the record exists, and rejecting it here costs no query.\n const { target, where } = toRelatedWhere(metadata, relationField, id, models)\n\n // A missing parent is a 404, not an empty page. The condition below would\n // simply match nothing, which reads as \"this record has no children\".\n await this.#requireRecord(model, metadata, id)\n const delegate = await this.#delegate(target.name)\n\n const narrowed = narrowFields(target, query.fields)\n const args = toFindManyArgs(narrowed, query, this.#provider)\n const combined = args.where ? { AND: [args.where, where] } : where\n const include = toIncludeClause(narrowed, models)\n const omit = omitClause(target, query.fields)\n\n const { page, perPage } = resolvePagination(query)\n const [rows, total] = await this.#run(target.name, () =>\n Promise.all([\n delegate.findMany({\n ...args,\n where: combined,\n ...(include ? { include } : {}),\n ...(omit ? { omit } : {}),\n }),\n delegate.count({ where: combined }),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async attachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'connect')\n }\n\n async detachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'disconnect')\n }\n\n // ---------------------------------------------------------------- internals\n\n /**\n * Add or remove one link, from the parent's side.\n *\n * Prisma expresses both the same way and works out where the link is stored -\n * a join-table row for a many-to-many, the child's foreign key for a\n * one-to-many. Whether the operation is allowed is the caller's decision;\n * this performs it.\n */\n async #link(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n operation: 'connect' | 'disconnect',\n ): Promise<void> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n const { target } = toRelatedWhere(metadata, relationField, id, models)\n\n const [targetKey] = target.primaryKey\n if (targetKey === undefined) {\n throw new FieldNotFoundError(target.name, relationField, 'The target has no primary key.')\n }\n\n const delegate = await this.#delegate(model)\n await this.#run(\n model,\n () =>\n delegate.update({\n where: this.#whereById(metadata, id),\n data: {\n [relationField]: {\n // Against the *target's* key, not this model's - the two ends of\n // a relation can be typed differently.\n [operation]: { [targetKey]: coerceId(target, targetKey, targetId) },\n },\n },\n }),\n id,\n )\n }\n\n /** Throw `RecordNotFoundError` unless the record exists. */\n async #requireRecord(model: string, metadata: ModelMetadata, id: RecordId): Promise<void> {\n const delegate = await this.#delegate(model)\n const found = await this.#run(\n model,\n () => delegate.findUnique({ where: this.#whereById(metadata, id) }),\n id,\n )\n if (found === null || found === undefined) throw new RecordNotFoundError(model, id)\n }\n\n async #requireModel(model: string): Promise<ModelMetadata> {\n const models = await this.getModels()\n const found = models.find((candidate) => candidate.name === model)\n if (!found) {\n throw new ModelNotFoundError(\n model,\n models.map((candidate) => candidate.name),\n )\n }\n return found\n }\n\n async #delegate(model: string): Promise<PrismaModelDelegate> {\n const models = await this.getModels()\n return resolveDelegate(\n this.#client,\n model,\n models.map((candidate) => candidate.name),\n )\n }\n\n /**\n * Build a `where` clause addressing a single record by primary key.\n *\n * Composite keys are represented in metadata but not supported here: a\n * `RecordId` is a single scalar, so there is nothing to map the second\n * column from. Rejected explicitly rather than silently mis-querying.\n */\n #whereById(model: ModelMetadata, id: RecordId): Record<string, unknown> {\n const [primaryKeyField, ...rest] = model.primaryKey\n\n if (primaryKeyField === undefined) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has no primary key, so records cannot be addressed by id.`,\n )\n }\n if (rest.length > 0) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has a composite primary key ` +\n `(${model.primaryKey.join(', ')}), which is not supported in this version.`,\n )\n }\n\n return { [primaryKeyField]: coerceId(model, primaryKeyField, id) }\n }\n\n /**\n * Reject anything the caller has no business writing.\n *\n * Unknown keys are an error rather than silently dropped: quietly discarding\n * a field the user filled in is worse than telling them it does not exist.\n * Relation and list fields are rejected because nested writes are not\n * implemented - see the Phase 2 report.\n */\n #validateWritableData(model: ModelMetadata, data: RecordData): RecordData {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new InvalidQueryError(`Write payload for \"${model.name}\" must be an object.`)\n }\n\n const writable: RecordData = {}\n for (const [key, value] of Object.entries(data)) {\n const field = model.fields.find((candidate) => candidate.name === key)\n if (!field) {\n throw new FieldNotFoundError(model.name, key)\n }\n if (field.kind === 'relation') {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing relation fields is not supported in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing list fields is not supported in this version.',\n )\n }\n writable[key] = value\n }\n return writable\n }\n\n /**\n * Run a client call, translating Prisma failures into Core errors.\n *\n * Prisma error types are identified by their `code` property rather than\n * `instanceof`. Importing `@prisma/client` to get the error classes would\n * mean loading a second copy of a package the consumer owns, and would tie\n * us to their Prisma version.\n */\n async #run<T>(model: string, operation: () => Promise<T>, id?: RecordId): Promise<T> {\n try {\n return await operation()\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n\n if (isPrismaError(cause) && cause.code === PRISMA_RECORD_NOT_FOUND && id !== undefined) {\n throw new RecordNotFoundError(model, id)\n }\n\n // A refused write is a fact about the request, not a failure of the\n // database. Reporting it as an internal error is what made a duplicate\n // email indistinguishable from a dead connection.\n const constraint = toConstraintError(cause, model)\n if (constraint) throw constraint\n\n const detail = cause instanceof Error ? cause.message : String(cause)\n throw new AdapterError(`Prisma operation failed for model \"${model}\": ${detail}`, { cause })\n }\n }\n}\n\nfunction isPrismaError(value: unknown): value is { code: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The model as this query is allowed to see it.\n *\n * Narrowing once, at the top, is what keeps the rest of the adapter honest:\n * field lookup, free-text search and relation loading all read the model, so\n * they inherit the restriction without knowing it exists. Doing it per-concern\n * would mean three places to forget.\n */\nfunction narrowFields(model: ModelMetadata, fields: readonly string[] | undefined): ModelMetadata {\n if (!fields) return model\n\n const allowed = new Set(fields)\n return { ...model, fields: model.fields.filter((field) => allowed.has(field.name)) }\n}\n\n/**\n * Columns to leave out of the result.\n *\n * `omit` rather than `select` because it composes with `include`: a `select`\n * would have to enumerate the relations too, and would silently drop any the\n * caller forgot. This way a hidden column is never read at all, which is a\n * stronger guarantee than removing it from the response afterwards.\n */\nfunction omitClause(\n model: ModelMetadata,\n fields: readonly string[] | undefined,\n): Record<string, true> | undefined {\n if (!fields) return undefined\n\n const allowed = new Set(fields)\n const omitted: Record<string, true> = {}\n\n for (const field of model.fields) {\n // Relations are excluded through `include`, not `omit`; Prisma rejects\n // naming them here.\n if (!allowed.has(field.name) && field.kind !== 'relation') omitted[field.name] = true\n }\n\n return Object.keys(omitted).length > 0 ? omitted : undefined\n}\n","/**\n * Dynamic model resolution.\n *\n * The admin addresses models by name at runtime (`\"User\"`), so the Prisma\n * Client's statically-typed delegates cannot be reached through their types.\n * This module is the single, deliberately narrow place where that type escape\n * happens. Nothing else in the package casts the client.\n */\nimport { AdapterError, ModelNotFoundError } from '@nest-admin/core'\n\n/**\n * The subset of a Prisma model delegate the adapter uses.\n *\n * Declared structurally rather than imported from `@prisma/client`: the client\n * is generated in the consumer's project against their schema, so there is no\n * meaningful shared type to import, and depending on one would couple us to a\n * Prisma version we do not control.\n */\nexport interface PrismaModelDelegate {\n findMany(args?: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown>\n count(args?: unknown): Promise<number>\n create(args: unknown): Promise<unknown>\n update(args: unknown): Promise<unknown>\n delete(args: unknown): Promise<unknown>\n}\n\nconst REQUIRED_METHODS = [\n 'findMany',\n 'findUnique',\n 'count',\n 'create',\n 'update',\n 'delete',\n] as const satisfies readonly (keyof PrismaModelDelegate)[]\n\n/**\n * Property names that must never be used as a delegate lookup key, regardless\n * of what the caller passes. Model names are validated against known metadata\n * before we get here, so this is defence in depth rather than the only guard.\n */\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype'])\n\n/**\n * Prisma exposes `model User` as `prisma.user` - the model name with only its\n * first character lower-cased. Note this is not general camelCase conversion:\n * `UserProfile` becomes `userProfile`, and `HTTPLog` becomes `hTTPLog`.\n */\nexport function toDelegateKey(modelName: string): string {\n if (modelName.length === 0) return modelName\n return modelName.charAt(0).toLowerCase() + modelName.slice(1)\n}\n\n/**\n * Resolve a model name to its Prisma Client delegate.\n *\n * `knownModels` is the metadata-derived allowlist. A name outside it is\n * rejected before the client is touched at all, so an attacker-controlled\n * model name can never reach arbitrary client properties.\n */\nexport function resolveDelegate(\n client: unknown,\n modelName: string,\n knownModels: readonly string[],\n): PrismaModelDelegate {\n if (!knownModels.includes(modelName)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n const key = toDelegateKey(modelName)\n if (FORBIDDEN_KEYS.has(key)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n if (typeof client !== 'object' || client === null) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client instance. ' +\n `Received ${client === null ? 'null' : typeof client}.`,\n )\n }\n\n // The one type escape. Guarded above by the metadata allowlist and below by\n // a shape check, so the cast is asserted rather than assumed.\n const candidate = (client as Record<string, unknown>)[key]\n\n if (typeof candidate !== 'object' || candidate === null) {\n throw new AdapterError(\n `The Prisma Client has no delegate \"${key}\" for model \"${modelName}\". ` +\n 'This usually means the client was generated from a different schema ' +\n 'than the one Nest Admin read - re-run `prisma generate`.',\n )\n }\n\n const delegate = candidate as Record<string, unknown>\n const missing = REQUIRED_METHODS.filter((method) => typeof delegate[method] !== 'function')\n if (missing.length > 0) {\n throw new AdapterError(\n `Prisma Client delegate \"${key}\" is missing expected methods: ${missing.join(', ')}.`,\n )\n }\n\n return candidate as PrismaModelDelegate\n}\n","/**\n * Prisma version gate.\n *\n * Phase 1 established that `@prisma/get-dmmf` is pinned exactly and enforces\n * *its own* Prisma version's schema rules: given a Prisma 6 schema, the 7.x\n * parser rejects `url` inside `datasource` even though the schema is perfectly\n * valid for that consumer. Without a gate, that surfaces as a confusing\n * \"Prisma rejected the schema\" error pointing at the user's own valid file.\n *\n * The gate turns that into a statement about versions.\n *\n * ## Two deliberate design choices\n *\n * **It fails open on detection.** The client version is read from\n * `client._clientVersion`, an underscore-prefixed internal. If Prisma renames\n * or removes it, the gate silently does nothing rather than breaking every\n * consumer on an otherwise-fine upgrade. A version check that itself becomes\n * the outage is worse than no version check.\n *\n * **It compares majors only.** Minor and patch releases have not changed the\n * schema language; majors have. Pinning tighter would produce false alarms on\n * every routine bump.\n *\n * This lives in `packages/prisma`, not Core - Core must never learn what\n * Prisma is.\n */\nimport { NestAdminError } from '@nest-admin/core'\n\n/**\n * Prisma majors whose schema language this adapter's pinned parser handles.\n *\n * Derived from the parser we ship (`@prisma/get-dmmf`, pinned in\n * package.json), not from what we wish were true. Widen this only after\n * testing against the new major.\n */\nexport const SUPPORTED_PRISMA_MAJORS: readonly number[] = [7]\n\n/** Raised when the consumer's Prisma Client major is outside the tested range. */\nexport class PrismaVersionUnsupportedError extends NestAdminError {\n constructor(\n readonly clientVersion: string,\n readonly supportedMajors: readonly number[],\n ) {\n super(\n `Nest Admin ships a Prisma ${supportedMajors.join('/')} schema parser, ` +\n `but this application uses Prisma Client ${clientVersion}. ` +\n 'Schema parsing would likely fail with a misleading error, so it was ' +\n 'stopped here instead. Align the versions, or open an issue if ' +\n `Prisma ${clientVersion.split('.')[0]} should be supported.`,\n )\n }\n}\n\n/**\n * Read the Prisma Client version from an instance.\n *\n * Returns `undefined` when it cannot be determined - see \"fails open\" above.\n */\nexport function readClientVersion(client: unknown): string | undefined {\n if (typeof client !== 'object' || client === null) return undefined\n const version = (client as Record<string, unknown>)['_clientVersion']\n return typeof version === 'string' && version !== '' ? version : undefined\n}\n\nfunction majorOf(version: string): number | undefined {\n const major = Number(version.split('.')[0])\n return Number.isInteger(major) ? major : undefined\n}\n\n/**\n * Throw when the client's major is known and unsupported.\n *\n * Silent when the version is unreadable or unparseable.\n */\nexport function assertSupportedPrismaVersion(\n client: unknown,\n supportedMajors: readonly number[] = SUPPORTED_PRISMA_MAJORS,\n): void {\n const version = readClientVersion(client)\n if (version === undefined) return\n\n const major = majorOf(version)\n if (major === undefined) return\n\n if (!supportedMajors.includes(major)) {\n throw new PrismaVersionUnsupportedError(version, supportedMajors)\n }\n}\n","/**\n * Prisma schema acquisition.\n *\n * This is the ONLY module in the repository permitted to import\n * `@prisma/get-dmmf`. Everything downstream consumes the returned\n * `DMMF.Document` and nothing else, which is what keeps the eventual switch to\n * a build-time Prisma generator a change to this file alone.\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport { AdapterError, isNestAdminError, NestAdminError } from '@nest-admin/core'\nimport { getDMMF } from '@prisma/get-dmmf'\nimport type * as DMMF from '@prisma/dmmf'\n\n/** Paths tried, in order, when no explicit schema location is configured. */\nconst DEFAULT_SCHEMA_CANDIDATES = ['prisma/schema.prisma', 'prisma/schema', 'schema.prisma']\n\n/** Raised when the Prisma schema cannot be located or read. */\nexport class PrismaSchemaNotFoundError extends NestAdminError {\n constructor(\n readonly triedPaths: readonly string[],\n explicit: boolean,\n ) {\n super(\n explicit\n ? `Prisma schema not found at \"${triedPaths[0]}\".`\n : `Could not locate a Prisma schema. Tried: ${triedPaths.join(', ')}. ` +\n 'Pass `schemaPath` to PrismaAdapter if your schema lives elsewhere.',\n )\n }\n}\n\n/** Raised when Prisma rejects the schema. Carries Prisma's own validation text. */\nexport class PrismaSchemaInvalidError extends NestAdminError {\n constructor(\n readonly prismaMessage: string,\n options?: { cause?: unknown },\n ) {\n super(`Prisma rejected the schema:\\n${prismaMessage}`, options)\n }\n}\n\n/**\n * Resolve the schema location to an absolute path.\n *\n * `schemaPath` may point at a single `.prisma` file or, since Prisma 7, at a\n * directory of `.prisma` files. Both are supported.\n */\nfunction locateSchema(schemaPath: string | undefined, cwd: string): string {\n if (schemaPath !== undefined) {\n const absolute = resolve(cwd, schemaPath)\n if (!existsSync(absolute)) throw new PrismaSchemaNotFoundError([absolute], true)\n return absolute\n }\n\n const tried: string[] = []\n for (const candidate of DEFAULT_SCHEMA_CANDIDATES) {\n const absolute = resolve(cwd, candidate)\n tried.push(absolute)\n if (existsSync(absolute)) return absolute\n }\n throw new PrismaSchemaNotFoundError(tried, false)\n}\n\n/**\n * Read the schema as `[filename, content]` tuples.\n *\n * `getDMMF` accepts this shape natively (`SchemaFileInput = string |\n * Array<[filename, content]>`), so multi-file schemas need no concatenation\n * and no parsing on our side. Passing real filenames also means Prisma's\n * validation errors point at the right file.\n */\nfunction readSchemaFiles(absolutePath: string): Array<[string, string]> {\n if (statSync(absolutePath).isDirectory()) {\n const files = readdirSync(absolutePath)\n .filter((name) => name.endsWith('.prisma'))\n .sort()\n if (files.length === 0) {\n throw new PrismaSchemaNotFoundError([join(absolutePath, '*.prisma')], true)\n }\n return files.map((name) => {\n const file = join(absolutePath, name)\n return [file, readFileSync(file, 'utf8')] as [string, string]\n })\n }\n\n return [[absolutePath, readFileSync(absolutePath, 'utf8')]]\n}\n\nexport interface ReadDmmfOptions {\n /** Path to a `.prisma` file or a directory of them. Auto-detected if absent. */\n readonly schemaPath?: string\n /** Base directory for relative paths and auto-detection. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\n/**\n * Load and parse the Prisma schema into a DMMF document.\n *\n * Note the two traps this function exists to absorb:\n *\n * 1. `getDMMF` is **synchronous** and returns `DMMF.Document | GetDMMFError` -\n * it does not throw and does not reject. Reading `.datamodel` off an error\n * result yields a bare `TypeError` with none of Prisma's diagnostics.\n * 2. Returning empty metadata on failure would surface as an admin panel with\n * no resources, which reads as a configuration mistake and costs hours.\n * Every failure here is loud.\n */\nexport function readPrismaDmmf(options: ReadDmmfOptions = {}): DMMF.Document {\n const cwd = options.cwd ?? process.cwd()\n const absolutePath = locateSchema(options.schemaPath, cwd)\n\n let files: Array<[string, string]>\n try {\n files = readSchemaFiles(absolutePath)\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n throw new AdapterError(`Failed to read the Prisma schema at \"${absolutePath}\".`, { cause })\n }\n\n const result = getDMMF({ datamodel: files })\n\n if (!isDmmfDocument(result)) {\n throw new PrismaSchemaInvalidError(extractPrismaMessage(result), { cause: result.error })\n }\n return result\n}\n\n/**\n * The datasource provider the schema declares - `postgresql`, `sqlite`, and so\n * on - or `undefined` when it cannot be read.\n *\n * Needed because Prisma accepts `mode: 'insensitive'` on some providers and\n * *throws* on the rest, so a search that ignores capitalisation has to know\n * which database it is talking to. See `to-prisma-args.ts`.\n *\n * ## Why this is read from the text\n *\n * The provider is not in the DMMF: `getDMMF` returns the datamodel, and the\n * datasource block is not part of it. Nor can it be asked of the client -\n * Prisma 7 builds clients from driver adapters, and what the application passed\n * is not something this package is allowed to introspect. The declaration is a\n * fixed one-line form in a file we are already reading, so it is read from\n * there, and every failure is answered with `undefined` rather than a throw:\n * an unreadable provider must degrade to the case-sensitive search that was the\n * behaviour before this existed, never to a broken panel.\n *\n * It reads the schema a second time. That happens once, at startup, on a file\n * of a few kilobytes - cheaper than threading a second return value through\n * every caller of `readPrismaDmmf`.\n */\nexport function readDatasourceProvider(options: ReadDmmfOptions = {}): string | undefined {\n try {\n const files = readSchemaFiles(locateSchema(options.schemaPath, options.cwd ?? process.cwd()))\n for (const [, content] of files) {\n const declared = /datasources+w+s*{[^}]*?providers*=s*\"([a-z]+)\"/i.exec(content)\n if (declared?.[1] !== undefined) return declared[1].toLowerCase()\n }\n } catch {\n // Unreadable schema. The DMMF read reports that properly; this one is an\n // optimisation and has nothing useful to add.\n }\n return undefined\n}\n\nfunction isDmmfDocument(value: DMMF.Document | { error: Error }): value is DMMF.Document {\n return 'datamodel' in value\n}\n\n/**\n * Prisma reports validation failures as a JSON string inside `error.message`,\n * carrying an ANSI-coloured `P1012` report. Unwrap it where possible so the\n * message we surface is the one a developer would see from the Prisma CLI.\n */\nfunction extractPrismaMessage(result: { reason: string; error: Error }): string {\n const raw = result.error?.message ?? result.reason\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed === 'object' && parsed !== null && 'message' in parsed) {\n const message = (parsed as { message: unknown }).message\n if (typeof message === 'string') return stripAnsi(message)\n }\n } catch {\n // Not JSON - fall through and use the raw text.\n }\n return stripAnsi(raw)\n}\n\nconst ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;]*m`, 'g')\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_PATTERN, '')\n}\n","/**\n * DMMF -> Core `ModelMetadata`.\n *\n * The one place Prisma's vocabulary is translated into ours. No DMMF type\n * escapes this module: everything downstream (the adapter, the future HTTP\n * layer, the admin UI) sees only Core shapes.\n *\n * This mapper is deliberately independent of *how* the DMMF was obtained, so\n * it is unaffected by a later switch to a build-time Prisma generator.\n */\nimport type { FieldKind, FieldMetadata, ModelMetadata } from '@nest-admin/core'\nimport type * as DMMF from '@prisma/dmmf'\n\n/**\n * Prisma scalar type -> Core field kind.\n *\n * `BigInt`, `Decimal` and `Bytes` are intentionally mapped to `'unknown'`\n * rather than squeezed into `'number'` or `'string'`. They do not round-trip\n * through JSON without losing precision or fidelity, and the MVP has not\n * tested editing them - claiming support we have not verified would be worse\n * than declaring them unhandled. They are still listed, so the admin can show\n * them read-only.\n */\nconst SCALAR_KINDS: Readonly<Record<string, FieldKind>> = {\n String: 'string',\n Int: 'number',\n Float: 'number',\n Boolean: 'boolean',\n DateTime: 'datetime',\n Json: 'json',\n}\n\nfunction toFieldKind(field: DMMF.Field): FieldKind {\n if (field.kind === 'object') return 'relation'\n if (field.kind === 'enum') return 'enum'\n if (field.kind === 'scalar') return SCALAR_KINDS[field.type] ?? 'unknown'\n return 'unknown'\n}\n\n/**\n * Is this default produced by the database or the ORM, rather than supplied by\n * the user?\n *\n * Measured against Prisma 7.10.0, DMMF distinguishes the two by *shape*:\n *\n * @default(cuid()) -> { name: 'cuid', args: [1] } (object)\n * @default(now()) -> { name: 'now', args: [] } (object)\n * @default(autoincrement()) -> { name: 'autoincrement' } (object)\n * @default(dbgenerated(..)) -> { name: 'dbgenerated', ... } (object)\n * @default(true) -> true (primitive)\n * @default(0) -> 0 (primitive)\n * @default(\"USER\") -> \"USER\" (primitive)\n *\n * So a function default is an object carrying `name`; a literal default is a\n * primitive. Treating \"has a default\" as \"generated\" would wrongly lock\n * `active Boolean @default(true)` out of every create form.\n */\nfunction isFunctionDefault(value: unknown): value is { name: string; args?: unknown[] } {\n return typeof value === 'object' && value !== null && !Array.isArray(value) && 'name' in value\n}\n\nfunction toFieldMetadata(\n field: DMMF.Field,\n enums: ReadonlyMap<string, readonly string[]>,\n): FieldMetadata {\n const kind = toFieldKind(field)\n\n // A value the database or ORM supplies: a function default, or @updatedAt.\n const isGenerated = field.isUpdatedAt === true || isFunctionDefault(field.default)\n\n // A literal default is a pre-fill for the create form, not a generated value.\n const hasLiteralDefault = field.hasDefaultValue === true && !isFunctionDefault(field.default)\n\n const base = {\n name: field.name,\n kind,\n isId: field.isId === true,\n isRequired: field.isRequired === true,\n isUnique: field.isUnique === true,\n isList: field.isList === true,\n isGenerated,\n } satisfies Omit<FieldMetadata, 'defaultValue' | 'enumValues' | 'relation'>\n\n return {\n ...base,\n ...(hasLiteralDefault ? { defaultValue: field.default } : {}),\n ...(kind === 'enum' ? { enumValues: enums.get(field.type) ?? [] } : {}),\n ...(kind === 'relation'\n ? {\n relation: {\n targetModel: field.type,\n // Cardinality follows directly from isList - the single attribute\n // the generated Prisma Client does not expose at runtime, which is\n // why metadata comes from the schema rather than the client.\n cardinality: field.isList === true ? ('many' as const) : ('one' as const),\n // Present only on the owning side of a to-one relation. Prisma\n // gives both sides a relation field but only one of them a column,\n // and these arrays are empty on the side that has none - so an\n // empty array means \"no foreign key here\", not \"unknown\".\n ...(field.relationFromFields?.[0] !== undefined\n ? { from: field.relationFromFields[0] }\n : {}),\n ...(field.relationToFields?.[0] !== undefined ? { to: field.relationToFields[0] } : {}),\n // Shared by both halves, so the other side can be found. Prisma\n // generates one when the schema does not name it.\n ...(field.relationName !== undefined ? { name: field.relationName } : {}),\n },\n }\n : {}),\n }\n}\n\n/**\n * Field names forming the model's primary key.\n *\n * Prisma expresses a single-column key as `@id` on the field and a composite\n * key as a model-level `@@id`, which DMMF surfaces as `primaryKey.fields`.\n * Both are represented here; the adapter is what limits the MVP to\n * single-column keys.\n */\nfunction toPrimaryKey(model: DMMF.Model): readonly string[] {\n const compositeFields = model.primaryKey?.fields\n if (compositeFields && compositeFields.length > 0) return [...compositeFields]\n return model.fields.filter((field) => field.isId === true).map((field) => field.name)\n}\n\n/** Translate a whole DMMF document into Core model metadata. */\nexport function toModelMetadata(dmmf: DMMF.Document): readonly ModelMetadata[] {\n const enums = new Map<string, readonly string[]>(\n dmmf.datamodel.enums.map((enumType) => [\n enumType.name,\n enumType.values.map((value) => value.name),\n ]),\n )\n\n return dmmf.datamodel.models.map((model) => ({\n name: model.name,\n primaryKey: toPrimaryKey(model),\n fields: model.fields.map((field) => toFieldMetadata(field, enums)),\n }))\n}\n","/**\n * Loading the readable side of a to-one relation.\n *\n * A record stores `authorId`. A person needs \"Ada Lovelace\". Resolving that in\n * the caller would mean one query per row - the classic N+1 - so it is done in\n * the same query, with an `include`.\n *\n * ## Only two columns are ever selected\n *\n * The `include` carries an explicit `select` of the target's primary key and\n * its display field, and nothing else. That is a security boundary, not an\n * optimisation: `include: { author: true }` would attach the *whole* related\n * record to every row, so a `User.passwordHash` would be published by the act\n * of listing `Post`. Naming the two columns means a relation can never widen\n * what a response contains.\n *\n * To-many relations are not loaded. They have no column on this side, they can\n * be unbounded, and one `include` per row would turn a list page into an\n * unpredictable amount of work. They arrive in 0.4.0, paginated and asked for\n * explicitly.\n */\nimport { displayFieldFor, type ModelMetadata } from '@nest-admin/core'\n\n/** A Prisma `include` clause, or `undefined` when the model has no to-one relations. */\nexport type IncludeClause = Record<string, { select: Record<string, true> }>\n\n/**\n * Build the `include` for every to-one relation the model owns.\n *\n * `models` is the full set, because the display field belongs to the *target*\n * model and can only be resolved by looking it up. A relation whose target is\n * missing from that set is skipped rather than guessed at: the target may have\n * been excluded from the admin by configuration, and inventing a column name\n * would produce a Prisma error blaming the schema.\n */\nexport function toIncludeClause(\n model: ModelMetadata,\n models: readonly ModelMetadata[],\n): IncludeClause | undefined {\n const include: IncludeClause = {}\n\n for (const field of model.fields) {\n const relation = field.relation\n // `from` is what distinguishes the owning side from the other one. Without\n // it there is no column here, so there is nothing to resolve.\n if (!relation || relation.cardinality !== 'one' || relation.from === undefined) continue\n\n const target = models.find((candidate) => candidate.name === relation.targetModel)\n if (!target) continue\n\n const select: Record<string, true> = {}\n for (const key of target.primaryKey) select[key] = true\n select[displayFieldFor(target)] = true\n\n include[field.name] = { select }\n }\n\n return Object.keys(include).length > 0 ? include : undefined\n}\n","/**\n * Prisma error codes -> Core constraint errors.\n *\n * Everything here exists so that an ordinary mistake in a form stops being\n * reported as an internal error. Before it, a duplicate email, a foreign key\n * pointing at nothing and a missing required value all came back as\n * \"an internal error occurred\" - the correct treatment for a broken database\n * and the wrong one for a person who typed the same address twice.\n *\n * ## Codes, not classes\n *\n * Matched by `code` rather than `instanceof PrismaClientKnownRequestError`, for\n * the reason the adapter already gives: importing `@prisma/client` here would\n * load a second copy of a package the consumer owns and tie this package to\n * their Prisma version.\n *\n * ## Field names come from `meta`, and may not be there\n *\n * Prisma reports the columns involved differently per code and per connector,\n * and sometimes not at all - a SQLite unique violation on a composite index\n * names the index rather than the columns. Where a name is missing the error\n * says so in general terms rather than inventing one, because a message that\n * blames the wrong field is worse than one that blames none.\n */\nimport { ConstraintError, type ConstraintKind } from '@nest-admin/core'\n\n/**\n * Measured against Prisma 7.10.0.\n *\n * `P2014` is the one worth naming: it fires when a *delete* would orphan a\n * required relation, so it is a foreign-key problem arriving from the opposite\n * direction to `P2003`.\n */\nconst CONSTRAINT_CODES: Readonly<Record<string, ConstraintKind>> = {\n P2002: 'unique',\n P2003: 'foreign-key',\n P2014: 'foreign-key',\n P2011: 'required',\n P2012: 'required',\n P2013: 'required',\n}\n\ninterface PrismaKnownError {\n readonly code: string\n readonly meta?: Readonly<Record<string, unknown>>\n}\n\nfunction isPrismaKnownError(value: unknown): value is PrismaKnownError {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The columns Prisma named, if it named any.\n *\n * The shape differs by code: `target` for a unique violation (a string or an\n * array, depending on the connector), `field_name` for a foreign key,\n * `constraint` for a null violation. Anything unrecognised yields nothing,\n * which the message handles.\n */\nfunction fieldsFrom(meta: Readonly<Record<string, unknown>> | undefined): readonly string[] {\n if (!meta) return []\n\n // Prisma 7 with a driver adapter nests the connector's own report, and that\n // is the only place the column names appear - `meta.target` is the older,\n // flatter shape and is still what a client without a driver adapter reports.\n // Both are read, because which one arrives depends on how the consumer built\n // their client rather than on anything this package controls.\n const nested = (meta['driverAdapterError'] as { cause?: { constraint?: unknown } } | undefined)\n ?.cause?.constraint\n\n const candidate =\n (nested as { fields?: unknown } | undefined)?.fields ??\n meta['target'] ??\n meta['field_name'] ??\n meta['constraint']\n\n if (Array.isArray(candidate)) {\n return candidate.filter((entry): entry is string => typeof entry === 'string')\n }\n\n if (typeof candidate !== 'string') return []\n\n // Some connectors report the index name rather than the columns -\n // `User_email_key` for `@unique` on `email`. The column is recoverable from\n // the convention, and a wrong guess here would name a field that does not\n // exist, so it is only trusted when the shape matches exactly.\n const index = /^(.+?)_(.+)_key$/.exec(candidate)\n if (index?.[2] !== undefined) return index[2].split('_')\n\n return [candidate]\n}\n\n/**\n * A missing required argument, which Prisma refuses before the database sees it.\n *\n * It arrives as `PrismaClientValidationError`, which carries **no code** - so\n * it cannot be matched the way every other case here is, and without special\n * handling a form submitted without a required field answers with a generic\n * 500.\n *\n * The message names the arguments in a fixed phrase, and that phrase is all\n * that is read from it. The rest of the text is a rendering of the call site\n * and of the data that was submitted - absolute paths and field values - so\n * forwarding any of it is out of the question.\n */\nfunction missingArguments(cause: unknown): readonly string[] {\n if (!(cause instanceof Error) || cause.constructor.name !== 'PrismaClientValidationError') {\n return []\n }\n\n const names: string[] = []\n for (const match of cause.message.matchAll(/Argument `([A-Za-z0-9_]+)` is missing/g)) {\n if (match[1] !== undefined) names.push(match[1])\n }\n\n return names\n}\n\n/**\n * A `ConstraintError` when Prisma refused the write for a reason a caller can\n * act on, or `undefined` when it did not.\n */\nexport function toConstraintError(cause: unknown, model: string): ConstraintError | undefined {\n const missing = missingArguments(cause)\n if (missing.length > 0) return new ConstraintError('required', model, missing)\n\n if (!isPrismaKnownError(cause)) return undefined\n\n const constraint = CONSTRAINT_CODES[cause.code]\n if (!constraint) return undefined\n\n return new ConstraintError(constraint, model, fieldsFrom(cause.meta))\n}\n","/**\n * An id, in the type the schema declares.\n *\n * Ids reach the adapter from a URL, so they are always strings. Prisma refuses\n * a string for an `Int @id` - `Expected IntFilter or Int, provided String` -\n * rather than coercing it, which is the right call for a query builder and\n * leaves the conversion to whoever knows the schema. That is this package.\n *\n * ## Why this is its own module\n *\n * It used to be a private method on the adapter, called from the one place that\n * built a `where` clause by primary key. Two other places also turn an id into\n * a Prisma argument - the parent id in a related-list filter, and the target id\n * in a connect/disconnect - and neither of them could reach a private method,\n * so neither of them converted anything. Every relation route worked against a\n * string-keyed model and failed against an integer-keyed one.\n *\n * Being a module makes it reachable from all three, and makes the rule\n * testable on its own. Being called at each point where a value becomes a\n * Prisma argument - rather than once at the entrance - is deliberate: that is\n * where the mistake was made, so that is where the guard belongs.\n */\nimport { InvalidQueryError, type ModelMetadata, type RecordId } from '@nest-admin/core'\n\n/**\n * Convert `id` to the type `model.fieldName` is declared as.\n *\n * Only numeric keys need anything done. A value that is already a number is\n * returned unchanged, so calling this twice is harmless - which matters,\n * because the paths below overlap.\n */\nexport function coerceId(model: ModelMetadata, fieldName: string, id: RecordId): RecordId {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (field?.kind !== 'number' || typeof id === 'number') return id\n\n const numeric = Number(id)\n if (!Number.isFinite(numeric)) {\n // Refused rather than passed through. Prisma would refuse it too, but with\n // a message about its own argument types rather than about the id someone\n // put in a URL.\n throw new InvalidQueryError(\n `Invalid id ${JSON.stringify(id)} for numeric primary key \"${model.name}.${fieldName}\".`,\n )\n }\n\n return numeric\n}\n\n/**\n * The same, against whatever `model` uses as its primary key.\n *\n * Returns the id untouched when the model has no single primary key: the\n * callers that care raise their own, better-worded error for that, and this\n * one should not pre-empt them.\n */\nexport function coercePrimaryKey(model: ModelMetadata, id: RecordId): RecordId {\n const [primaryKey, ...rest] = model.primaryKey\n if (primaryKey === undefined || rest.length > 0) return id\n return coerceId(model, primaryKey, id)\n}\n","/**\n * Asking the target model for the records linked to one parent.\n *\n * A related list could be fetched from the parent - `user.posts()` - but then\n * pagination, sorting, filtering and relation loading would all have to be\n * reimplemented for that path. Asking the *target* model with an extra `where`\n * instead means a related list is an ordinary list that happens to be\n * constrained, and everything already built for lists applies to it unchanged.\n *\n * The constraint is expressed through the relation's other half, which is why\n * relation names matter:\n *\n * User.posts -> inverse is Post.author (to-one) -> { author: { id: <parent> } }\n * Post.tags -> inverse is Tag.posts (to-many) -> { posts: { some: { id: <parent> } } }\n *\n * Both are Prisma relation filters on the target, so neither needs to know\n * whether a foreign key exists or where it lives.\n */\nimport {\n FieldNotFoundError,\n inverseRelationField,\n type ModelMetadata,\n type RecordId,\n} from '@nest-admin/core'\n\nimport { coerceId } from './coerce-id.js'\n\n/**\n * A `where` clause selecting the target records linked to `parentId`.\n *\n * `parentKey` is the parent's primary-key field, which the filter matches on.\n */\nexport function toRelatedWhere(\n parent: ModelMetadata,\n relationFieldName: string,\n parentId: RecordId,\n models: readonly ModelMetadata[],\n): { target: ModelMetadata; where: Record<string, unknown> } {\n const field = parent.fields.find((candidate) => candidate.name === relationFieldName)\n\n if (!field?.relation) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'Only a relation field can be listed this way.',\n )\n }\n\n if (field.relation.cardinality !== 'many') {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'This is a to-one relation. It arrives with the record itself.',\n )\n }\n\n const target = models.find((candidate) => candidate.name === field.relation?.targetModel)\n if (!target) {\n // The target is not part of this admin - excluded by configuration, or\n // hidden from this principal. Either way there is nothing to list.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${field.relation.targetModel} is not available.`,\n )\n }\n\n const inverse = inverseRelationField(field, models)\n if (!inverse) {\n // Without the other half there is no way to express the constraint, and\n // returning every record of the target would be catastrophically wrong.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'The other half of this relation could not be resolved.',\n )\n }\n\n const [parentKey] = parent.primaryKey\n if (parentKey === undefined) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${parent.name} has no primary key.`,\n )\n }\n\n // Coerced here rather than by the caller, because this is the line that\n // turns an id into a Prisma argument. A string against an `Int @id` is\n // refused by Prisma with a message about its own argument types.\n const match = { [parentKey]: coerceId(parent, parentKey, parentId) }\n\n return {\n target,\n where: {\n [inverse.name]: inverse.relation?.cardinality === 'many' ? { some: match } : { is: match },\n },\n }\n}\n","/**\n * Core `ListQuery` -> Prisma `findMany` arguments.\n *\n * Everything here is validated against model metadata before it reaches the\n * client. Field names arriving from an HTTP request eventually flow into this\n * module, so an unvalidated name would become an injection surface into the\n * query object. There is no raw SQL anywhere; all queries go through Prisma's\n * structured API.\n */\nimport {\n FieldNotFoundError,\n InvalidQueryError,\n type FieldMetadata,\n type FilterRule,\n type ListQuery,\n type ModelMetadata,\n} from '@nest-admin/core'\n\nexport const DEFAULT_PER_PAGE = 25\nexport const MAX_PER_PAGE = 100\n\n/** Operators that only make sense on string fields. */\nconst STRING_ONLY_OPERATORS = new Set(['contains', 'startsWith', 'endsWith'])\n\n/** Operators that require an ordered (numeric, date, or string) field. */\nconst COMPARISON_OPERATORS = new Set(['gt', 'gte', 'lt', 'lte'])\n\nexport interface PrismaFindManyArgs {\n where?: Record<string, unknown>\n orderBy?: Array<Record<string, 'asc' | 'desc'>>\n skip?: number\n take?: number\n}\n\n/**\n * What the field is being resolved for.\n *\n * Only relations care, and they care because the two cases are not symmetric.\n * See {@link findQueryableField}.\n */\ntype QueryPurpose = 'filter' | 'sort'\n\n/**\n * A field usable in a filter or a sort.\n *\n * A to-one relation the model owns is stored in a scalar column, so a **filter**\n * on `author` is answerable: it means exactly a filter on `authorId`, and the\n * caller gets to use whichever name they think in.\n *\n * **Sorting** by it is refused, even though it would run. `authorId` holds a\n * cuid, so ordering by it is ordering by a random-looking string - a result\n * that looks sorted, is stable, and means nothing. What someone asking to sort\n * by `author` wants is the author's *name*, which is sorting by a field on\n * another model and is not this version. A refusal that says so is better than\n * a page of rows in an order nobody can explain.\n *\n * List fields are excluded outright: there is no column on this side at all.\n */\nfunction findQueryableField(\n model: ModelMetadata,\n fieldName: string,\n purpose: QueryPurpose,\n): FieldMetadata {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (!field) {\n throw new FieldNotFoundError(model.name, fieldName)\n }\n if (field.kind === 'relation') {\n const owned = field.relation?.from\n if (owned !== undefined && field.relation?.cardinality === 'one') {\n if (purpose === 'filter') return findQueryableField(model, owned, purpose)\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n `Sorting by a relation is not supported in this version. ` +\n `Sorting by \"${owned}\" would order by an opaque key rather than by ` +\n `anything readable.`,\n )\n }\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'Relation fields cannot be filtered or sorted in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'List fields cannot be filtered or sorted in this version.',\n )\n }\n return field\n}\n\nfunction toPrismaCondition(model: ModelMetadata, rule: FilterRule): Record<string, unknown> {\n const field = findQueryableField(model, rule.field, 'filter')\n\n if (STRING_ONLY_OPERATORS.has(rule.operator) && field.kind !== 'string') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" requires a string field, but ` +\n `\"${model.name}.${field.name}\" is of kind \"${field.kind}\".`,\n )\n }\n\n if (COMPARISON_OPERATORS.has(rule.operator) && field.kind === 'boolean') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" cannot be applied to boolean field ` +\n `\"${model.name}.${field.name}\".`,\n )\n }\n\n if (rule.operator === 'in') {\n if (!Array.isArray(rule.value)) {\n throw new InvalidQueryError(\n `Operator \"in\" requires an array value for \"${model.name}.${field.name}\".`,\n )\n }\n return { [field.name]: { in: rule.value } }\n }\n\n if (rule.operator === 'eq') return { [field.name]: { equals: rule.value } }\n if (rule.operator === 'ne') return { [field.name]: { not: rule.value } }\n\n return { [field.name]: { [rule.operator]: rule.value } }\n}\n\n/**\n * Providers where Prisma accepts `mode: 'insensitive'`.\n *\n * The list is short because Prisma *throws* on the others rather than ignoring\n * the option, so being wrong here breaks every search rather than degrading it.\n *\n * The omissions are deliberate, not oversights:\n *\n * | Provider | Why nothing is sent |\n * | ---------- | ---------------------------------------------------------- |\n * | mysql | Its default collations end in `_ci`; `LIKE` already ignores case. |\n * | sqlite | `LIKE` is case-insensitive for ASCII by default. |\n * | sqlserver | Its default collation is case-insensitive. |\n * | cockroachdb | Prisma documents `mode` for PostgreSQL and MongoDB only. |\n *\n * So on the four below, the option is unnecessary; on CockroachDB it is\n * unproven, and this is not the place to guess.\n */\nconst INSENSITIVE_MODE_PROVIDERS: ReadonlySet<string> = new Set([\n 'postgresql',\n 'postgres',\n 'mongodb',\n])\n\n/**\n * The case-insensitivity option for this provider, if it takes one.\n *\n * Spread into every string comparison. Returning an object to spread rather\n * than a boolean to branch on keeps the option out of the query entirely where\n * it is not supported - Prisma rejects `mode: undefined` as readily as it\n * rejects `mode: 'insensitive'` on SQLite.\n */\nexport function insensitively(provider: string | undefined): { mode?: 'insensitive' } {\n return provider !== undefined && INSENSITIVE_MODE_PROVIDERS.has(provider)\n ? { mode: 'insensitive' }\n : {}\n}\n\n/** String comparisons, which are the ones capitalisation applies to. */\nconst TEXTUAL_OPERATORS: ReadonlySet<string> = new Set(['contains', 'startsWith', 'endsWith'])\n\n/**\n * Free-text search: `contains` across the model's meaningful string fields.\n *\n * Generated string fields are excluded. A `cuid()` or `uuid()` primary key is\n * an opaque machine value, and including it makes single-letter searches match\n * essentially at random - searching \"e\" returns any record whose id happens to\n * contain an \"e\". Looking a record up by its id is an exact-match concern, so\n * it belongs in a filter (`{ field: 'id', operator: 'eq' }`), not in free text.\n *\n * Capitalisation is ignored, which needed the provider to say so. Searching\n * \"ada\" and getting nothing because the record says \"Ada\" is the kind of defect\n * people conclude the search is broken from, and they are not wrong. What it\n * takes to ignore case differs per database, and on some of them the option\n * that does it is an error - hence `insensitively`.\n */\nfunction toSearchCondition(\n model: ModelMetadata,\n term: string,\n provider: string | undefined,\n): Record<string, unknown> | undefined {\n // Foreign keys are string columns holding a cuid, so they match the same\n // rule the generated-id exclusion exists for - and they are not generated,\n // so that rule misses them. Left in, a search for \"e\" matches almost every\n // row of any model that references another, because most cuids contain an e.\n const foreignKeys = new Set(\n model.fields.map((field) => field.relation?.from).filter((name) => name !== undefined),\n )\n\n const stringFields = model.fields.filter(\n (field) =>\n field.kind === 'string' &&\n !field.isList &&\n !field.isGenerated &&\n !foreignKeys.has(field.name),\n )\n if (stringFields.length === 0) return undefined\n\n return {\n OR: stringFields.map((field) => ({\n [field.name]: { contains: term, ...insensitively(provider) },\n })),\n }\n}\n\nexport function buildWhere(\n model: ModelMetadata,\n query: Pick<ListQuery, 'filters' | 'search'>,\n provider?: string,\n): Record<string, unknown> | undefined {\n const conditions: Array<Record<string, unknown>> = []\n\n for (const rule of query.filters ?? []) {\n const condition = toPrismaCondition(model, rule)\n // A \"contains\" filter is the same promise the search box makes, typed into\n // a different box. It would be strange for one to ignore case and not the\n // other, and stranger still to have to know which.\n conditions.push(\n TEXTUAL_OPERATORS.has(rule.operator) ? insensitive(condition, provider) : condition,\n )\n }\n\n const search = query.search?.trim()\n if (search) {\n const searchCondition = toSearchCondition(model, search, provider)\n if (searchCondition) conditions.push(searchCondition)\n }\n\n if (conditions.length === 0) return undefined\n if (conditions.length === 1) return conditions[0]\n return { AND: conditions }\n}\n\nfunction buildOrderBy(\n model: ModelMetadata,\n query: Pick<ListQuery, 'sort'>,\n): Array<Record<string, 'asc' | 'desc'>> | undefined {\n const rules = query.sort ?? []\n if (rules.length === 0) return undefined\n\n return rules.map((rule) => {\n const field = findQueryableField(model, rule.field, 'sort')\n return { [field.name]: rule.direction }\n })\n}\n\n/** Normalised, clamped pagination. Page numbers are 1-based. */\nexport function resolvePagination(query: Pick<ListQuery, 'page' | 'perPage'>): {\n page: number\n perPage: number\n skip: number\n take: number\n} {\n const rawPage = query.page ?? 1\n if (!Number.isInteger(rawPage) || rawPage < 1) {\n throw new InvalidQueryError(\n `\"page\" must be an integer >= 1, received ${JSON.stringify(query.page)}.`,\n )\n }\n\n const rawPerPage = query.perPage ?? DEFAULT_PER_PAGE\n if (!Number.isInteger(rawPerPage) || rawPerPage < 1) {\n throw new InvalidQueryError(\n `\"perPage\" must be an integer >= 1, received ${JSON.stringify(query.perPage)}.`,\n )\n }\n\n // Clamped rather than rejected: a UI asking for too much should get a\n // capped page, not an error.\n const perPage = Math.min(rawPerPage, MAX_PER_PAGE)\n return { page: rawPage, perPage, skip: (rawPage - 1) * perPage, take: perPage }\n}\n\n/**\n * The same condition, told to ignore case.\n *\n * A condition is `{ field: { operator: value } }`, and the option belongs\n * beside the operator rather than beside the field, so it cannot simply be\n * spread at the top level.\n */\nfunction insensitive(\n condition: Record<string, unknown>,\n provider: string | undefined,\n): Record<string, unknown> {\n const mode = insensitively(provider)\n if (mode.mode === undefined) return condition\n\n const entries = Object.entries(condition).map(([field, comparison]) => [\n field,\n typeof comparison === 'object' && comparison !== null\n ? { ...(comparison as Record<string, unknown>), ...mode }\n : comparison,\n ])\n return Object.fromEntries(entries) as Record<string, unknown>\n}\n\nexport function toFindManyArgs(\n model: ModelMetadata,\n query: ListQuery,\n provider?: string,\n): PrismaFindManyArgs {\n const { skip, take } = resolvePagination(query)\n const where = buildWhere(model, query, provider)\n const orderBy = buildOrderBy(model, query)\n\n return {\n ...(where ? { where } : {}),\n ...(orderBy ? { orderBy } : {}),\n skip,\n take,\n }\n}\n","/**\n * Admin accounts, in Prisma.\n *\n * ## A model of its own\n *\n * The default is `AdminAccount`, and that default is the design rather than a\n * placeholder. The people who administer a system are usually not rows in the\n * table they administer, and pointing this at the application's `User` would\n * mean every customer record carries a password that opens the admin - which is\n * a decision nobody makes on purpose and several people make by accident.\n *\n * The model name is configurable because some applications already have a\n * `Staff` or an `Operator`. Pointing it at `User` is possible and is a choice,\n * not a default.\n *\n * ## What it does not do\n *\n * Create, update, delete. The store contract is read-only, and this implements\n * only what it declares: an admin that could mint its own administrators is an\n * escalation waiting for its first mistake in a policy. Seeding the first\n * account is the application's job, with `hashAdminPassword`.\n *\n * ## The account model should not be a resource\n *\n * Nothing here can arrange that - which models the admin exposes is the\n * module's business - so it is the one thing a consumer has to remember:\n *\n * ```ts\n * resources: { exclude: ['AdminAccount'] }\n * ```\n *\n * Without it, anyone who may edit that model can grant themselves whatever the\n * admin can do. `builtInAuth` warns at startup when it sees the account model\n * among the exposed resources.\n */\nimport type { AdminAccount, AdminAccountStore } from '@nest-admin/core'\n\nimport { resolveDelegate } from '../client/delegate.js'\n\nexport interface PrismaAccountStoreOptions {\n /** A constructed Prisma Client - the same one the adapter is given. */\n readonly client: unknown\n\n /** The model holding admin accounts. `AdminAccount` by default. */\n readonly model?: string\n\n /**\n * Column names, where they differ from the defaults.\n *\n * A mapping rather than a required schema: an application that already has a\n * `Staff` table with `login` and `hash` should not have to migrate it to use\n * this.\n */\n readonly fields?: {\n readonly id?: string\n readonly email?: string\n readonly name?: string\n readonly passwordHash?: string\n readonly disabled?: string\n /** Written on a successful sign-in, when the column exists. */\n readonly lastLoginAt?: string\n }\n}\n\nconst DEFAULTS = {\n id: 'id',\n email: 'email',\n name: 'name',\n passwordHash: 'passwordHash',\n disabled: 'disabled',\n lastLoginAt: 'lastLoginAt',\n} as const\n\nexport function prismaAccountStore(options: PrismaAccountStoreOptions): AdminAccountStore {\n const model = options.model ?? 'AdminAccount'\n const column = { ...DEFAULTS, ...options.fields }\n\n /*\n * The allowlist is the one configured name.\n *\n * `resolveDelegate` takes a list because the adapter resolves a model named\n * by a *request*, where an allowlist is the whole defence. Here the name\n * comes from the application's own configuration and there is nothing to\n * defend against - but passing it anyway keeps the property-name guard\n * inside `resolveDelegate`, which is the part that still matters, and gives\n * a clear error rather than `undefined.findMany is not a function` when the\n * model does not exist.\n */\n const delegate = () => resolveDelegate(options.client, model, [model])\n\n /**\n * A row as the contract describes it.\n *\n * Returns `null` for a row with no usable hash rather than an account that\n * can never sign in. The difference matters at the point of use: a `null`\n * takes the same path as an unknown email, and an account object with an\n * empty hash would be compared against and fail in a way that takes a\n * measurably different amount of time.\n */\n const toAccount = (row: unknown): AdminAccount | null => {\n if (typeof row !== 'object' || row === null) return null\n const record = row as Record<string, unknown>\n\n const id = record[column.id]\n const email = record[column.email]\n const hash = record[column.passwordHash]\n\n if (typeof id !== 'string' && typeof id !== 'number') return null\n if (typeof email !== 'string') return null\n if (typeof hash !== 'string' || hash === '') return null\n\n const name = record[column.name]\n const disabled = record[column.disabled]\n\n return {\n id: String(id),\n email,\n passwordHash: hash,\n ...(typeof name === 'string' && name !== '' ? { name } : {}),\n ...(typeof disabled === 'boolean' ? { disabled } : {}),\n }\n }\n\n return {\n describes: model,\n\n async findByEmail(email) {\n /*\n * `findFirst`, not `findUnique`.\n *\n * The email column is very likely unique, and this store cannot know\n * that - a consumer mapping it onto an existing table may have it\n * indexed and not constrained. `findUnique` throws on a column Prisma\n * does not consider unique, which would turn a schema difference into a\n * 500 on the login route.\n */\n const rows = await delegate().findMany({\n where: { [column.email]: email },\n take: 1,\n })\n return toAccount(rows[0])\n },\n\n async findById(id) {\n const rows = await delegate().findMany({ where: { [column.id]: id }, take: 1 })\n return toAccount(rows[0])\n },\n\n async count() {\n return delegate().count()\n },\n\n async recordLogin(id) {\n // Best effort. A store mapped onto a table without this column should\n // not turn a successful sign-in into a failure, and the caller already\n // treats a rejection here as something to log rather than to surface.\n await delegate().update({\n where: { [column.id]: id },\n data: { [column.lastLoginAt]: new Date() },\n })\n },\n }\n}\n"],"mappings":"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","names":["NestAdminError","AdapterError","FieldNotFoundError","InvalidQueryError","ModelNotFoundError","isNestAdminError"]}
package/dist/prisma.js CHANGED
@@ -368,6 +368,16 @@ function toConstraintError(cause, model) {
368
368
  return new ConstraintError(constraint, model, fieldsFrom(cause.meta));
369
369
  }
370
370
  __name(toConstraintError, "toConstraintError");
371
+ function coerceId(model, fieldName, id) {
372
+ const field = model.fields.find((candidate) => candidate.name === fieldName);
373
+ if (field?.kind !== "number" || typeof id === "number") return id;
374
+ const numeric = Number(id);
375
+ if (!Number.isFinite(numeric)) {
376
+ throw new InvalidQueryError(`Invalid id ${JSON.stringify(id)} for numeric primary key "${model.name}.${fieldName}".`);
377
+ }
378
+ return numeric;
379
+ }
380
+ __name(coerceId, "coerceId");
371
381
  function toRelatedWhere(parent, relationFieldName, parentId, models) {
372
382
  const field = parent.fields.find((candidate) => candidate.name === relationFieldName);
373
383
  if (!field?.relation) {
@@ -389,7 +399,7 @@ function toRelatedWhere(parent, relationFieldName, parentId, models) {
389
399
  throw new FieldNotFoundError(parent.name, relationFieldName, `${parent.name} has no primary key.`);
390
400
  }
391
401
  const match = {
392
- [parentKey]: parentId
402
+ [parentKey]: coerceId(parent, parentKey, parentId)
393
403
  };
394
404
  return {
395
405
  target,
@@ -772,8 +782,10 @@ var PrismaAdapter = class {
772
782
  where: this.#whereById(metadata, id),
773
783
  data: {
774
784
  [relationField]: {
785
+ // Against the *target's* key, not this model's - the two ends of
786
+ // a relation can be typed differently.
775
787
  [operation]: {
776
- [targetKey]: targetId
788
+ [targetKey]: coerceId(target, targetKey, targetId)
777
789
  }
778
790
  }
779
791
  }
@@ -815,25 +827,10 @@ var PrismaAdapter = class {
815
827
  throw new InvalidQueryError(`Model "${model.name}" has a composite primary key (${model.primaryKey.join(", ")}), which is not supported in this version.`);
816
828
  }
817
829
  return {
818
- [primaryKeyField]: this.#coerceId(model, primaryKeyField, id)
830
+ [primaryKeyField]: coerceId(model, primaryKeyField, id)
819
831
  };
820
832
  }
821
833
  /**
822
- * Coerce an id to the type the schema declares.
823
- *
824
- * Ids arriving from a URL are always strings, but a Prisma `Int @id` column
825
- * must be queried with a number or Prisma rejects the argument.
826
- */
827
- #coerceId(model, fieldName, id) {
828
- const field = model.fields.find((candidate) => candidate.name === fieldName);
829
- if (field?.kind !== "number" || typeof id === "number") return id;
830
- const numeric = Number(id);
831
- if (!Number.isFinite(numeric)) {
832
- throw new InvalidQueryError(`Invalid id ${JSON.stringify(id)} for numeric primary key "${model.name}.${fieldName}".`);
833
- }
834
- return numeric;
835
- }
836
- /**
837
834
  * Reject anything the caller has no business writing.
838
835
  *
839
836
  * Unknown keys are an error rather than silently dropped: quietly discarding
@@ -1 +1 @@
1
- {"version":3,"sources":["../../prisma/src/adapter.ts","../../prisma/src/client/delegate.ts","../../prisma/src/client/version-gate.ts","../../prisma/src/metadata/read-dmmf.ts","../../prisma/src/metadata/to-metadata.ts","../../prisma/src/query/to-include.ts","../../prisma/src/errors/constraints.ts","../../prisma/src/query/to-related-where.ts","../../prisma/src/query/to-prisma-args.ts","../../prisma/src/auth/store.ts"],"sourcesContent":["/**\n * `PrismaAdapter` - the Prisma implementation of Core's `OrmAdapter`.\n *\n * The adapter never constructs a Prisma Client. Prisma 7 builds clients from\n * driver adapters, so only the consuming application knows the provider, the\n * credentials and the connection strategy. We receive a constructed client and\n * use it.\n */\nimport {\n AdapterError,\n FieldNotFoundError,\n InvalidQueryError,\n ModelNotFoundError,\n isNestAdminError,\n RecordNotFoundError,\n type ListQuery,\n type ModelMetadata,\n type OrmAdapter,\n type Page,\n type RecordData,\n type RecordId,\n} from '@nest-admin/core'\n\nimport { resolveDelegate, type PrismaModelDelegate } from './client/delegate.js'\nimport { assertSupportedPrismaVersion } from './client/version-gate.js'\nimport { readDatasourceProvider, readPrismaDmmf } from './metadata/read-dmmf.js'\nimport { toModelMetadata } from './metadata/to-metadata.js'\nimport { toIncludeClause } from './query/to-include.js'\nimport { toConstraintError } from './errors/constraints.js'\nimport { toRelatedWhere } from './query/to-related-where.js'\nimport { resolvePagination, toFindManyArgs } from './query/to-prisma-args.js'\n\n/** Prisma's error code for \"record required but not found\". */\nconst PRISMA_RECORD_NOT_FOUND = 'P2025'\n\nexport interface PrismaAdapterOptions {\n /**\n * A constructed Prisma Client. Owned entirely by the consuming application:\n * the adapter never calls `new PrismaClient()`, because under Prisma 7 the\n * client is built from a driver adapter that only the application can supply.\n */\n readonly client: unknown\n /**\n * Path to `schema.prisma`, or to a directory of `.prisma` files. When\n * omitted, `prisma/schema.prisma`, `prisma/schema` and `schema.prisma` are\n * tried in that order, relative to `cwd`.\n */\n readonly schemaPath?: string\n /** Base directory for schema resolution. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\nexport class PrismaAdapter implements OrmAdapter {\n readonly name = 'prisma'\n\n readonly #client: unknown\n readonly #schemaPath: string | undefined\n readonly #cwd: string | undefined\n\n /**\n * Metadata is derived from a static schema, so it is read once and reused.\n * Every operation validates against it, which would otherwise re-parse the\n * schema on each call.\n */\n #models: readonly ModelMetadata[] | undefined\n\n /**\n * Which database this is, so a search can ignore capitalisation the way that\n * database allows. Read alongside the metadata, and `undefined` when the\n * schema does not say - see `insensitively` in `to-prisma-args.ts`.\n */\n #provider: string | undefined\n\n constructor(options: PrismaAdapterOptions) {\n if (options.client === null || options.client === undefined) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client. ' +\n 'Pass one via `new PrismaAdapter({ client })`.',\n )\n }\n this.#client = options.client\n this.#schemaPath = options.schemaPath\n this.#cwd = options.cwd\n }\n\n async getModels(): Promise<readonly ModelMetadata[]> {\n if (this.#models) return this.#models\n // Checked before parsing: a version mismatch would otherwise surface as\n // \"Prisma rejected the schema\", pointing at the user's valid schema.\n assertSupportedPrismaVersion(this.#client)\n const dmmf = readPrismaDmmf({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n this.#models = toModelMetadata(dmmf)\n this.#provider = readDatasourceProvider({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n return this.#models\n }\n\n async list(model: string, query: ListQuery): Promise<Page<RecordData>> {\n const declared = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n\n // Narrowed first: everything below reads the model, so restricting it once\n // restricts field lookup, free-text search and relation loading together.\n const metadata = narrowFields(declared, query.fields)\n\n const args = toFindManyArgs(metadata, query, this.#provider)\n const include = toIncludeClause(metadata, await this.getModels())\n const omit = omitClause(declared, query.fields)\n const withRelations = { ...args, ...(include ? { include } : {}), ...(omit ? { omit } : {}) }\n const { page, perPage } = resolvePagination(query)\n\n const [rows, total] = await this.#run(model, () =>\n Promise.all([\n delegate.findMany(withRelations),\n delegate.count(args.where ? { where: args.where } : {}),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async findOne(model: string, id: RecordId): Promise<RecordData | null> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n const include = toIncludeClause(metadata, await this.getModels())\n const record = await this.#run(model, () =>\n delegate.findUnique(include ? { where, include } : { where }),\n )\n return (record as RecordData | null) ?? null\n }\n\n async create(model: string, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const writable = this.#validateWritableData(metadata, data)\n\n const created = await this.#run(model, () => delegate.create({ data: writable }))\n return created as RecordData\n }\n\n async update(model: string, id: RecordId, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n const writable = this.#validateWritableData(metadata, data)\n\n const updated = await this.#run(model, () => delegate.update({ where, data: writable }), id)\n return updated as RecordData\n }\n\n async delete(model: string, id: RecordId): Promise<void> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n await this.#run(model, () => delegate.delete({ where }), id)\n }\n\n /**\n * A page of the records on the far side of a to-many relation.\n *\n * Implemented as an ordinary list of the *target* model with one extra\n * condition, so pagination, sorting, filtering and relation loading all\n * behave exactly as they do on a top-level list. See `to-related-where.ts`.\n */\n async listRelated(\n model: string,\n id: RecordId,\n relationField: string,\n query: ListQuery,\n ): Promise<Page<RecordData>> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n\n // The relation is validated first: a bad field name is wrong whether or\n // not the record exists, and rejecting it here costs no query.\n const { target, where } = toRelatedWhere(metadata, relationField, id, models)\n\n // A missing parent is a 404, not an empty page. The condition below would\n // simply match nothing, which reads as \"this record has no children\".\n await this.#requireRecord(model, metadata, id)\n const delegate = await this.#delegate(target.name)\n\n const narrowed = narrowFields(target, query.fields)\n const args = toFindManyArgs(narrowed, query, this.#provider)\n const combined = args.where ? { AND: [args.where, where] } : where\n const include = toIncludeClause(narrowed, models)\n const omit = omitClause(target, query.fields)\n\n const { page, perPage } = resolvePagination(query)\n const [rows, total] = await this.#run(target.name, () =>\n Promise.all([\n delegate.findMany({\n ...args,\n where: combined,\n ...(include ? { include } : {}),\n ...(omit ? { omit } : {}),\n }),\n delegate.count({ where: combined }),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async attachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'connect')\n }\n\n async detachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'disconnect')\n }\n\n // ---------------------------------------------------------------- internals\n\n /**\n * Add or remove one link, from the parent's side.\n *\n * Prisma expresses both the same way and works out where the link is stored -\n * a join-table row for a many-to-many, the child's foreign key for a\n * one-to-many. Whether the operation is allowed is the caller's decision;\n * this performs it.\n */\n async #link(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n operation: 'connect' | 'disconnect',\n ): Promise<void> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n const { target } = toRelatedWhere(metadata, relationField, id, models)\n\n const [targetKey] = target.primaryKey\n if (targetKey === undefined) {\n throw new FieldNotFoundError(target.name, relationField, 'The target has no primary key.')\n }\n\n const delegate = await this.#delegate(model)\n await this.#run(\n model,\n () =>\n delegate.update({\n where: this.#whereById(metadata, id),\n data: { [relationField]: { [operation]: { [targetKey]: targetId } } },\n }),\n id,\n )\n }\n\n /** Throw `RecordNotFoundError` unless the record exists. */\n async #requireRecord(model: string, metadata: ModelMetadata, id: RecordId): Promise<void> {\n const delegate = await this.#delegate(model)\n const found = await this.#run(\n model,\n () => delegate.findUnique({ where: this.#whereById(metadata, id) }),\n id,\n )\n if (found === null || found === undefined) throw new RecordNotFoundError(model, id)\n }\n\n async #requireModel(model: string): Promise<ModelMetadata> {\n const models = await this.getModels()\n const found = models.find((candidate) => candidate.name === model)\n if (!found) {\n throw new ModelNotFoundError(\n model,\n models.map((candidate) => candidate.name),\n )\n }\n return found\n }\n\n async #delegate(model: string): Promise<PrismaModelDelegate> {\n const models = await this.getModels()\n return resolveDelegate(\n this.#client,\n model,\n models.map((candidate) => candidate.name),\n )\n }\n\n /**\n * Build a `where` clause addressing a single record by primary key.\n *\n * Composite keys are represented in metadata but not supported here: a\n * `RecordId` is a single scalar, so there is nothing to map the second\n * column from. Rejected explicitly rather than silently mis-querying.\n */\n #whereById(model: ModelMetadata, id: RecordId): Record<string, unknown> {\n const [primaryKeyField, ...rest] = model.primaryKey\n\n if (primaryKeyField === undefined) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has no primary key, so records cannot be addressed by id.`,\n )\n }\n if (rest.length > 0) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has a composite primary key ` +\n `(${model.primaryKey.join(', ')}), which is not supported in this version.`,\n )\n }\n\n return { [primaryKeyField]: this.#coerceId(model, primaryKeyField, id) }\n }\n\n /**\n * Coerce an id to the type the schema declares.\n *\n * Ids arriving from a URL are always strings, but a Prisma `Int @id` column\n * must be queried with a number or Prisma rejects the argument.\n */\n #coerceId(model: ModelMetadata, fieldName: string, id: RecordId): RecordId {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (field?.kind !== 'number' || typeof id === 'number') return id\n\n const numeric = Number(id)\n if (!Number.isFinite(numeric)) {\n throw new InvalidQueryError(\n `Invalid id ${JSON.stringify(id)} for numeric primary key ` +\n `\"${model.name}.${fieldName}\".`,\n )\n }\n return numeric\n }\n\n /**\n * Reject anything the caller has no business writing.\n *\n * Unknown keys are an error rather than silently dropped: quietly discarding\n * a field the user filled in is worse than telling them it does not exist.\n * Relation and list fields are rejected because nested writes are not\n * implemented - see the Phase 2 report.\n */\n #validateWritableData(model: ModelMetadata, data: RecordData): RecordData {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new InvalidQueryError(`Write payload for \"${model.name}\" must be an object.`)\n }\n\n const writable: RecordData = {}\n for (const [key, value] of Object.entries(data)) {\n const field = model.fields.find((candidate) => candidate.name === key)\n if (!field) {\n throw new FieldNotFoundError(model.name, key)\n }\n if (field.kind === 'relation') {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing relation fields is not supported in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing list fields is not supported in this version.',\n )\n }\n writable[key] = value\n }\n return writable\n }\n\n /**\n * Run a client call, translating Prisma failures into Core errors.\n *\n * Prisma error types are identified by their `code` property rather than\n * `instanceof`. Importing `@prisma/client` to get the error classes would\n * mean loading a second copy of a package the consumer owns, and would tie\n * us to their Prisma version.\n */\n async #run<T>(model: string, operation: () => Promise<T>, id?: RecordId): Promise<T> {\n try {\n return await operation()\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n\n if (isPrismaError(cause) && cause.code === PRISMA_RECORD_NOT_FOUND && id !== undefined) {\n throw new RecordNotFoundError(model, id)\n }\n\n // A refused write is a fact about the request, not a failure of the\n // database. Reporting it as an internal error is what made a duplicate\n // email indistinguishable from a dead connection.\n const constraint = toConstraintError(cause, model)\n if (constraint) throw constraint\n\n const detail = cause instanceof Error ? cause.message : String(cause)\n throw new AdapterError(`Prisma operation failed for model \"${model}\": ${detail}`, { cause })\n }\n }\n}\n\nfunction isPrismaError(value: unknown): value is { code: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The model as this query is allowed to see it.\n *\n * Narrowing once, at the top, is what keeps the rest of the adapter honest:\n * field lookup, free-text search and relation loading all read the model, so\n * they inherit the restriction without knowing it exists. Doing it per-concern\n * would mean three places to forget.\n */\nfunction narrowFields(model: ModelMetadata, fields: readonly string[] | undefined): ModelMetadata {\n if (!fields) return model\n\n const allowed = new Set(fields)\n return { ...model, fields: model.fields.filter((field) => allowed.has(field.name)) }\n}\n\n/**\n * Columns to leave out of the result.\n *\n * `omit` rather than `select` because it composes with `include`: a `select`\n * would have to enumerate the relations too, and would silently drop any the\n * caller forgot. This way a hidden column is never read at all, which is a\n * stronger guarantee than removing it from the response afterwards.\n */\nfunction omitClause(\n model: ModelMetadata,\n fields: readonly string[] | undefined,\n): Record<string, true> | undefined {\n if (!fields) return undefined\n\n const allowed = new Set(fields)\n const omitted: Record<string, true> = {}\n\n for (const field of model.fields) {\n // Relations are excluded through `include`, not `omit`; Prisma rejects\n // naming them here.\n if (!allowed.has(field.name) && field.kind !== 'relation') omitted[field.name] = true\n }\n\n return Object.keys(omitted).length > 0 ? omitted : undefined\n}\n","/**\n * Dynamic model resolution.\n *\n * The admin addresses models by name at runtime (`\"User\"`), so the Prisma\n * Client's statically-typed delegates cannot be reached through their types.\n * This module is the single, deliberately narrow place where that type escape\n * happens. Nothing else in the package casts the client.\n */\nimport { AdapterError, ModelNotFoundError } from '@nest-admin/core'\n\n/**\n * The subset of a Prisma model delegate the adapter uses.\n *\n * Declared structurally rather than imported from `@prisma/client`: the client\n * is generated in the consumer's project against their schema, so there is no\n * meaningful shared type to import, and depending on one would couple us to a\n * Prisma version we do not control.\n */\nexport interface PrismaModelDelegate {\n findMany(args?: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown>\n count(args?: unknown): Promise<number>\n create(args: unknown): Promise<unknown>\n update(args: unknown): Promise<unknown>\n delete(args: unknown): Promise<unknown>\n}\n\nconst REQUIRED_METHODS = [\n 'findMany',\n 'findUnique',\n 'count',\n 'create',\n 'update',\n 'delete',\n] as const satisfies readonly (keyof PrismaModelDelegate)[]\n\n/**\n * Property names that must never be used as a delegate lookup key, regardless\n * of what the caller passes. Model names are validated against known metadata\n * before we get here, so this is defence in depth rather than the only guard.\n */\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype'])\n\n/**\n * Prisma exposes `model User` as `prisma.user` - the model name with only its\n * first character lower-cased. Note this is not general camelCase conversion:\n * `UserProfile` becomes `userProfile`, and `HTTPLog` becomes `hTTPLog`.\n */\nexport function toDelegateKey(modelName: string): string {\n if (modelName.length === 0) return modelName\n return modelName.charAt(0).toLowerCase() + modelName.slice(1)\n}\n\n/**\n * Resolve a model name to its Prisma Client delegate.\n *\n * `knownModels` is the metadata-derived allowlist. A name outside it is\n * rejected before the client is touched at all, so an attacker-controlled\n * model name can never reach arbitrary client properties.\n */\nexport function resolveDelegate(\n client: unknown,\n modelName: string,\n knownModels: readonly string[],\n): PrismaModelDelegate {\n if (!knownModels.includes(modelName)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n const key = toDelegateKey(modelName)\n if (FORBIDDEN_KEYS.has(key)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n if (typeof client !== 'object' || client === null) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client instance. ' +\n `Received ${client === null ? 'null' : typeof client}.`,\n )\n }\n\n // The one type escape. Guarded above by the metadata allowlist and below by\n // a shape check, so the cast is asserted rather than assumed.\n const candidate = (client as Record<string, unknown>)[key]\n\n if (typeof candidate !== 'object' || candidate === null) {\n throw new AdapterError(\n `The Prisma Client has no delegate \"${key}\" for model \"${modelName}\". ` +\n 'This usually means the client was generated from a different schema ' +\n 'than the one Nest Admin read - re-run `prisma generate`.',\n )\n }\n\n const delegate = candidate as Record<string, unknown>\n const missing = REQUIRED_METHODS.filter((method) => typeof delegate[method] !== 'function')\n if (missing.length > 0) {\n throw new AdapterError(\n `Prisma Client delegate \"${key}\" is missing expected methods: ${missing.join(', ')}.`,\n )\n }\n\n return candidate as PrismaModelDelegate\n}\n","/**\n * Prisma version gate.\n *\n * Phase 1 established that `@prisma/get-dmmf` is pinned exactly and enforces\n * *its own* Prisma version's schema rules: given a Prisma 6 schema, the 7.x\n * parser rejects `url` inside `datasource` even though the schema is perfectly\n * valid for that consumer. Without a gate, that surfaces as a confusing\n * \"Prisma rejected the schema\" error pointing at the user's own valid file.\n *\n * The gate turns that into a statement about versions.\n *\n * ## Two deliberate design choices\n *\n * **It fails open on detection.** The client version is read from\n * `client._clientVersion`, an underscore-prefixed internal. If Prisma renames\n * or removes it, the gate silently does nothing rather than breaking every\n * consumer on an otherwise-fine upgrade. A version check that itself becomes\n * the outage is worse than no version check.\n *\n * **It compares majors only.** Minor and patch releases have not changed the\n * schema language; majors have. Pinning tighter would produce false alarms on\n * every routine bump.\n *\n * This lives in `packages/prisma`, not Core - Core must never learn what\n * Prisma is.\n */\nimport { NestAdminError } from '@nest-admin/core'\n\n/**\n * Prisma majors whose schema language this adapter's pinned parser handles.\n *\n * Derived from the parser we ship (`@prisma/get-dmmf`, pinned in\n * package.json), not from what we wish were true. Widen this only after\n * testing against the new major.\n */\nexport const SUPPORTED_PRISMA_MAJORS: readonly number[] = [7]\n\n/** Raised when the consumer's Prisma Client major is outside the tested range. */\nexport class PrismaVersionUnsupportedError extends NestAdminError {\n constructor(\n readonly clientVersion: string,\n readonly supportedMajors: readonly number[],\n ) {\n super(\n `Nest Admin ships a Prisma ${supportedMajors.join('/')} schema parser, ` +\n `but this application uses Prisma Client ${clientVersion}. ` +\n 'Schema parsing would likely fail with a misleading error, so it was ' +\n 'stopped here instead. Align the versions, or open an issue if ' +\n `Prisma ${clientVersion.split('.')[0]} should be supported.`,\n )\n }\n}\n\n/**\n * Read the Prisma Client version from an instance.\n *\n * Returns `undefined` when it cannot be determined - see \"fails open\" above.\n */\nexport function readClientVersion(client: unknown): string | undefined {\n if (typeof client !== 'object' || client === null) return undefined\n const version = (client as Record<string, unknown>)['_clientVersion']\n return typeof version === 'string' && version !== '' ? version : undefined\n}\n\nfunction majorOf(version: string): number | undefined {\n const major = Number(version.split('.')[0])\n return Number.isInteger(major) ? major : undefined\n}\n\n/**\n * Throw when the client's major is known and unsupported.\n *\n * Silent when the version is unreadable or unparseable.\n */\nexport function assertSupportedPrismaVersion(\n client: unknown,\n supportedMajors: readonly number[] = SUPPORTED_PRISMA_MAJORS,\n): void {\n const version = readClientVersion(client)\n if (version === undefined) return\n\n const major = majorOf(version)\n if (major === undefined) return\n\n if (!supportedMajors.includes(major)) {\n throw new PrismaVersionUnsupportedError(version, supportedMajors)\n }\n}\n","/**\n * Prisma schema acquisition.\n *\n * This is the ONLY module in the repository permitted to import\n * `@prisma/get-dmmf`. Everything downstream consumes the returned\n * `DMMF.Document` and nothing else, which is what keeps the eventual switch to\n * a build-time Prisma generator a change to this file alone.\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport { AdapterError, isNestAdminError, NestAdminError } from '@nest-admin/core'\nimport { getDMMF } from '@prisma/get-dmmf'\nimport type * as DMMF from '@prisma/dmmf'\n\n/** Paths tried, in order, when no explicit schema location is configured. */\nconst DEFAULT_SCHEMA_CANDIDATES = ['prisma/schema.prisma', 'prisma/schema', 'schema.prisma']\n\n/** Raised when the Prisma schema cannot be located or read. */\nexport class PrismaSchemaNotFoundError extends NestAdminError {\n constructor(\n readonly triedPaths: readonly string[],\n explicit: boolean,\n ) {\n super(\n explicit\n ? `Prisma schema not found at \"${triedPaths[0]}\".`\n : `Could not locate a Prisma schema. Tried: ${triedPaths.join(', ')}. ` +\n 'Pass `schemaPath` to PrismaAdapter if your schema lives elsewhere.',\n )\n }\n}\n\n/** Raised when Prisma rejects the schema. Carries Prisma's own validation text. */\nexport class PrismaSchemaInvalidError extends NestAdminError {\n constructor(\n readonly prismaMessage: string,\n options?: { cause?: unknown },\n ) {\n super(`Prisma rejected the schema:\\n${prismaMessage}`, options)\n }\n}\n\n/**\n * Resolve the schema location to an absolute path.\n *\n * `schemaPath` may point at a single `.prisma` file or, since Prisma 7, at a\n * directory of `.prisma` files. Both are supported.\n */\nfunction locateSchema(schemaPath: string | undefined, cwd: string): string {\n if (schemaPath !== undefined) {\n const absolute = resolve(cwd, schemaPath)\n if (!existsSync(absolute)) throw new PrismaSchemaNotFoundError([absolute], true)\n return absolute\n }\n\n const tried: string[] = []\n for (const candidate of DEFAULT_SCHEMA_CANDIDATES) {\n const absolute = resolve(cwd, candidate)\n tried.push(absolute)\n if (existsSync(absolute)) return absolute\n }\n throw new PrismaSchemaNotFoundError(tried, false)\n}\n\n/**\n * Read the schema as `[filename, content]` tuples.\n *\n * `getDMMF` accepts this shape natively (`SchemaFileInput = string |\n * Array<[filename, content]>`), so multi-file schemas need no concatenation\n * and no parsing on our side. Passing real filenames also means Prisma's\n * validation errors point at the right file.\n */\nfunction readSchemaFiles(absolutePath: string): Array<[string, string]> {\n if (statSync(absolutePath).isDirectory()) {\n const files = readdirSync(absolutePath)\n .filter((name) => name.endsWith('.prisma'))\n .sort()\n if (files.length === 0) {\n throw new PrismaSchemaNotFoundError([join(absolutePath, '*.prisma')], true)\n }\n return files.map((name) => {\n const file = join(absolutePath, name)\n return [file, readFileSync(file, 'utf8')] as [string, string]\n })\n }\n\n return [[absolutePath, readFileSync(absolutePath, 'utf8')]]\n}\n\nexport interface ReadDmmfOptions {\n /** Path to a `.prisma` file or a directory of them. Auto-detected if absent. */\n readonly schemaPath?: string\n /** Base directory for relative paths and auto-detection. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\n/**\n * Load and parse the Prisma schema into a DMMF document.\n *\n * Note the two traps this function exists to absorb:\n *\n * 1. `getDMMF` is **synchronous** and returns `DMMF.Document | GetDMMFError` -\n * it does not throw and does not reject. Reading `.datamodel` off an error\n * result yields a bare `TypeError` with none of Prisma's diagnostics.\n * 2. Returning empty metadata on failure would surface as an admin panel with\n * no resources, which reads as a configuration mistake and costs hours.\n * Every failure here is loud.\n */\nexport function readPrismaDmmf(options: ReadDmmfOptions = {}): DMMF.Document {\n const cwd = options.cwd ?? process.cwd()\n const absolutePath = locateSchema(options.schemaPath, cwd)\n\n let files: Array<[string, string]>\n try {\n files = readSchemaFiles(absolutePath)\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n throw new AdapterError(`Failed to read the Prisma schema at \"${absolutePath}\".`, { cause })\n }\n\n const result = getDMMF({ datamodel: files })\n\n if (!isDmmfDocument(result)) {\n throw new PrismaSchemaInvalidError(extractPrismaMessage(result), { cause: result.error })\n }\n return result\n}\n\n/**\n * The datasource provider the schema declares - `postgresql`, `sqlite`, and so\n * on - or `undefined` when it cannot be read.\n *\n * Needed because Prisma accepts `mode: 'insensitive'` on some providers and\n * *throws* on the rest, so a search that ignores capitalisation has to know\n * which database it is talking to. See `to-prisma-args.ts`.\n *\n * ## Why this is read from the text\n *\n * The provider is not in the DMMF: `getDMMF` returns the datamodel, and the\n * datasource block is not part of it. Nor can it be asked of the client -\n * Prisma 7 builds clients from driver adapters, and what the application passed\n * is not something this package is allowed to introspect. The declaration is a\n * fixed one-line form in a file we are already reading, so it is read from\n * there, and every failure is answered with `undefined` rather than a throw:\n * an unreadable provider must degrade to the case-sensitive search that was the\n * behaviour before this existed, never to a broken panel.\n *\n * It reads the schema a second time. That happens once, at startup, on a file\n * of a few kilobytes - cheaper than threading a second return value through\n * every caller of `readPrismaDmmf`.\n */\nexport function readDatasourceProvider(options: ReadDmmfOptions = {}): string | undefined {\n try {\n const files = readSchemaFiles(locateSchema(options.schemaPath, options.cwd ?? process.cwd()))\n for (const [, content] of files) {\n const declared = /datasources+w+s*{[^}]*?providers*=s*\"([a-z]+)\"/i.exec(content)\n if (declared?.[1] !== undefined) return declared[1].toLowerCase()\n }\n } catch {\n // Unreadable schema. The DMMF read reports that properly; this one is an\n // optimisation and has nothing useful to add.\n }\n return undefined\n}\n\nfunction isDmmfDocument(value: DMMF.Document | { error: Error }): value is DMMF.Document {\n return 'datamodel' in value\n}\n\n/**\n * Prisma reports validation failures as a JSON string inside `error.message`,\n * carrying an ANSI-coloured `P1012` report. Unwrap it where possible so the\n * message we surface is the one a developer would see from the Prisma CLI.\n */\nfunction extractPrismaMessage(result: { reason: string; error: Error }): string {\n const raw = result.error?.message ?? result.reason\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed === 'object' && parsed !== null && 'message' in parsed) {\n const message = (parsed as { message: unknown }).message\n if (typeof message === 'string') return stripAnsi(message)\n }\n } catch {\n // Not JSON - fall through and use the raw text.\n }\n return stripAnsi(raw)\n}\n\nconst ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;]*m`, 'g')\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_PATTERN, '')\n}\n","/**\n * DMMF -> Core `ModelMetadata`.\n *\n * The one place Prisma's vocabulary is translated into ours. No DMMF type\n * escapes this module: everything downstream (the adapter, the future HTTP\n * layer, the admin UI) sees only Core shapes.\n *\n * This mapper is deliberately independent of *how* the DMMF was obtained, so\n * it is unaffected by a later switch to a build-time Prisma generator.\n */\nimport type { FieldKind, FieldMetadata, ModelMetadata } from '@nest-admin/core'\nimport type * as DMMF from '@prisma/dmmf'\n\n/**\n * Prisma scalar type -> Core field kind.\n *\n * `BigInt`, `Decimal` and `Bytes` are intentionally mapped to `'unknown'`\n * rather than squeezed into `'number'` or `'string'`. They do not round-trip\n * through JSON without losing precision or fidelity, and the MVP has not\n * tested editing them - claiming support we have not verified would be worse\n * than declaring them unhandled. They are still listed, so the admin can show\n * them read-only.\n */\nconst SCALAR_KINDS: Readonly<Record<string, FieldKind>> = {\n String: 'string',\n Int: 'number',\n Float: 'number',\n Boolean: 'boolean',\n DateTime: 'datetime',\n Json: 'json',\n}\n\nfunction toFieldKind(field: DMMF.Field): FieldKind {\n if (field.kind === 'object') return 'relation'\n if (field.kind === 'enum') return 'enum'\n if (field.kind === 'scalar') return SCALAR_KINDS[field.type] ?? 'unknown'\n return 'unknown'\n}\n\n/**\n * Is this default produced by the database or the ORM, rather than supplied by\n * the user?\n *\n * Measured against Prisma 7.10.0, DMMF distinguishes the two by *shape*:\n *\n * @default(cuid()) -> { name: 'cuid', args: [1] } (object)\n * @default(now()) -> { name: 'now', args: [] } (object)\n * @default(autoincrement()) -> { name: 'autoincrement' } (object)\n * @default(dbgenerated(..)) -> { name: 'dbgenerated', ... } (object)\n * @default(true) -> true (primitive)\n * @default(0) -> 0 (primitive)\n * @default(\"USER\") -> \"USER\" (primitive)\n *\n * So a function default is an object carrying `name`; a literal default is a\n * primitive. Treating \"has a default\" as \"generated\" would wrongly lock\n * `active Boolean @default(true)` out of every create form.\n */\nfunction isFunctionDefault(value: unknown): value is { name: string; args?: unknown[] } {\n return typeof value === 'object' && value !== null && !Array.isArray(value) && 'name' in value\n}\n\nfunction toFieldMetadata(\n field: DMMF.Field,\n enums: ReadonlyMap<string, readonly string[]>,\n): FieldMetadata {\n const kind = toFieldKind(field)\n\n // A value the database or ORM supplies: a function default, or @updatedAt.\n const isGenerated = field.isUpdatedAt === true || isFunctionDefault(field.default)\n\n // A literal default is a pre-fill for the create form, not a generated value.\n const hasLiteralDefault = field.hasDefaultValue === true && !isFunctionDefault(field.default)\n\n const base = {\n name: field.name,\n kind,\n isId: field.isId === true,\n isRequired: field.isRequired === true,\n isUnique: field.isUnique === true,\n isList: field.isList === true,\n isGenerated,\n } satisfies Omit<FieldMetadata, 'defaultValue' | 'enumValues' | 'relation'>\n\n return {\n ...base,\n ...(hasLiteralDefault ? { defaultValue: field.default } : {}),\n ...(kind === 'enum' ? { enumValues: enums.get(field.type) ?? [] } : {}),\n ...(kind === 'relation'\n ? {\n relation: {\n targetModel: field.type,\n // Cardinality follows directly from isList - the single attribute\n // the generated Prisma Client does not expose at runtime, which is\n // why metadata comes from the schema rather than the client.\n cardinality: field.isList === true ? ('many' as const) : ('one' as const),\n // Present only on the owning side of a to-one relation. Prisma\n // gives both sides a relation field but only one of them a column,\n // and these arrays are empty on the side that has none - so an\n // empty array means \"no foreign key here\", not \"unknown\".\n ...(field.relationFromFields?.[0] !== undefined\n ? { from: field.relationFromFields[0] }\n : {}),\n ...(field.relationToFields?.[0] !== undefined ? { to: field.relationToFields[0] } : {}),\n // Shared by both halves, so the other side can be found. Prisma\n // generates one when the schema does not name it.\n ...(field.relationName !== undefined ? { name: field.relationName } : {}),\n },\n }\n : {}),\n }\n}\n\n/**\n * Field names forming the model's primary key.\n *\n * Prisma expresses a single-column key as `@id` on the field and a composite\n * key as a model-level `@@id`, which DMMF surfaces as `primaryKey.fields`.\n * Both are represented here; the adapter is what limits the MVP to\n * single-column keys.\n */\nfunction toPrimaryKey(model: DMMF.Model): readonly string[] {\n const compositeFields = model.primaryKey?.fields\n if (compositeFields && compositeFields.length > 0) return [...compositeFields]\n return model.fields.filter((field) => field.isId === true).map((field) => field.name)\n}\n\n/** Translate a whole DMMF document into Core model metadata. */\nexport function toModelMetadata(dmmf: DMMF.Document): readonly ModelMetadata[] {\n const enums = new Map<string, readonly string[]>(\n dmmf.datamodel.enums.map((enumType) => [\n enumType.name,\n enumType.values.map((value) => value.name),\n ]),\n )\n\n return dmmf.datamodel.models.map((model) => ({\n name: model.name,\n primaryKey: toPrimaryKey(model),\n fields: model.fields.map((field) => toFieldMetadata(field, enums)),\n }))\n}\n","/**\n * Loading the readable side of a to-one relation.\n *\n * A record stores `authorId`. A person needs \"Ada Lovelace\". Resolving that in\n * the caller would mean one query per row - the classic N+1 - so it is done in\n * the same query, with an `include`.\n *\n * ## Only two columns are ever selected\n *\n * The `include` carries an explicit `select` of the target's primary key and\n * its display field, and nothing else. That is a security boundary, not an\n * optimisation: `include: { author: true }` would attach the *whole* related\n * record to every row, so a `User.passwordHash` would be published by the act\n * of listing `Post`. Naming the two columns means a relation can never widen\n * what a response contains.\n *\n * To-many relations are not loaded. They have no column on this side, they can\n * be unbounded, and one `include` per row would turn a list page into an\n * unpredictable amount of work. They arrive in 0.4.0, paginated and asked for\n * explicitly.\n */\nimport { displayFieldFor, type ModelMetadata } from '@nest-admin/core'\n\n/** A Prisma `include` clause, or `undefined` when the model has no to-one relations. */\nexport type IncludeClause = Record<string, { select: Record<string, true> }>\n\n/**\n * Build the `include` for every to-one relation the model owns.\n *\n * `models` is the full set, because the display field belongs to the *target*\n * model and can only be resolved by looking it up. A relation whose target is\n * missing from that set is skipped rather than guessed at: the target may have\n * been excluded from the admin by configuration, and inventing a column name\n * would produce a Prisma error blaming the schema.\n */\nexport function toIncludeClause(\n model: ModelMetadata,\n models: readonly ModelMetadata[],\n): IncludeClause | undefined {\n const include: IncludeClause = {}\n\n for (const field of model.fields) {\n const relation = field.relation\n // `from` is what distinguishes the owning side from the other one. Without\n // it there is no column here, so there is nothing to resolve.\n if (!relation || relation.cardinality !== 'one' || relation.from === undefined) continue\n\n const target = models.find((candidate) => candidate.name === relation.targetModel)\n if (!target) continue\n\n const select: Record<string, true> = {}\n for (const key of target.primaryKey) select[key] = true\n select[displayFieldFor(target)] = true\n\n include[field.name] = { select }\n }\n\n return Object.keys(include).length > 0 ? include : undefined\n}\n","/**\n * Prisma error codes -> Core constraint errors.\n *\n * Everything here exists so that an ordinary mistake in a form stops being\n * reported as an internal error. Before it, a duplicate email, a foreign key\n * pointing at nothing and a missing required value all came back as\n * \"an internal error occurred\" - the correct treatment for a broken database\n * and the wrong one for a person who typed the same address twice.\n *\n * ## Codes, not classes\n *\n * Matched by `code` rather than `instanceof PrismaClientKnownRequestError`, for\n * the reason the adapter already gives: importing `@prisma/client` here would\n * load a second copy of a package the consumer owns and tie this package to\n * their Prisma version.\n *\n * ## Field names come from `meta`, and may not be there\n *\n * Prisma reports the columns involved differently per code and per connector,\n * and sometimes not at all - a SQLite unique violation on a composite index\n * names the index rather than the columns. Where a name is missing the error\n * says so in general terms rather than inventing one, because a message that\n * blames the wrong field is worse than one that blames none.\n */\nimport { ConstraintError, type ConstraintKind } from '@nest-admin/core'\n\n/**\n * Measured against Prisma 7.10.0.\n *\n * `P2014` is the one worth naming: it fires when a *delete* would orphan a\n * required relation, so it is a foreign-key problem arriving from the opposite\n * direction to `P2003`.\n */\nconst CONSTRAINT_CODES: Readonly<Record<string, ConstraintKind>> = {\n P2002: 'unique',\n P2003: 'foreign-key',\n P2014: 'foreign-key',\n P2011: 'required',\n P2012: 'required',\n P2013: 'required',\n}\n\ninterface PrismaKnownError {\n readonly code: string\n readonly meta?: Readonly<Record<string, unknown>>\n}\n\nfunction isPrismaKnownError(value: unknown): value is PrismaKnownError {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The columns Prisma named, if it named any.\n *\n * The shape differs by code: `target` for a unique violation (a string or an\n * array, depending on the connector), `field_name` for a foreign key,\n * `constraint` for a null violation. Anything unrecognised yields nothing,\n * which the message handles.\n */\nfunction fieldsFrom(meta: Readonly<Record<string, unknown>> | undefined): readonly string[] {\n if (!meta) return []\n\n // Prisma 7 with a driver adapter nests the connector's own report, and that\n // is the only place the column names appear - `meta.target` is the older,\n // flatter shape and is still what a client without a driver adapter reports.\n // Both are read, because which one arrives depends on how the consumer built\n // their client rather than on anything this package controls.\n const nested = (meta['driverAdapterError'] as { cause?: { constraint?: unknown } } | undefined)\n ?.cause?.constraint\n\n const candidate =\n (nested as { fields?: unknown } | undefined)?.fields ??\n meta['target'] ??\n meta['field_name'] ??\n meta['constraint']\n\n if (Array.isArray(candidate)) {\n return candidate.filter((entry): entry is string => typeof entry === 'string')\n }\n\n if (typeof candidate !== 'string') return []\n\n // Some connectors report the index name rather than the columns -\n // `User_email_key` for `@unique` on `email`. The column is recoverable from\n // the convention, and a wrong guess here would name a field that does not\n // exist, so it is only trusted when the shape matches exactly.\n const index = /^(.+?)_(.+)_key$/.exec(candidate)\n if (index?.[2] !== undefined) return index[2].split('_')\n\n return [candidate]\n}\n\n/**\n * A missing required argument, which Prisma refuses before the database sees it.\n *\n * It arrives as `PrismaClientValidationError`, which carries **no code** - so\n * it cannot be matched the way every other case here is, and without special\n * handling a form submitted without a required field answers with a generic\n * 500.\n *\n * The message names the arguments in a fixed phrase, and that phrase is all\n * that is read from it. The rest of the text is a rendering of the call site\n * and of the data that was submitted - absolute paths and field values - so\n * forwarding any of it is out of the question.\n */\nfunction missingArguments(cause: unknown): readonly string[] {\n if (!(cause instanceof Error) || cause.constructor.name !== 'PrismaClientValidationError') {\n return []\n }\n\n const names: string[] = []\n for (const match of cause.message.matchAll(/Argument `([A-Za-z0-9_]+)` is missing/g)) {\n if (match[1] !== undefined) names.push(match[1])\n }\n\n return names\n}\n\n/**\n * A `ConstraintError` when Prisma refused the write for a reason a caller can\n * act on, or `undefined` when it did not.\n */\nexport function toConstraintError(cause: unknown, model: string): ConstraintError | undefined {\n const missing = missingArguments(cause)\n if (missing.length > 0) return new ConstraintError('required', model, missing)\n\n if (!isPrismaKnownError(cause)) return undefined\n\n const constraint = CONSTRAINT_CODES[cause.code]\n if (!constraint) return undefined\n\n return new ConstraintError(constraint, model, fieldsFrom(cause.meta))\n}\n","/**\n * Asking the target model for the records linked to one parent.\n *\n * A related list could be fetched from the parent - `user.posts()` - but then\n * pagination, sorting, filtering and relation loading would all have to be\n * reimplemented for that path. Asking the *target* model with an extra `where`\n * instead means a related list is an ordinary list that happens to be\n * constrained, and everything already built for lists applies to it unchanged.\n *\n * The constraint is expressed through the relation's other half, which is why\n * relation names matter:\n *\n * User.posts -> inverse is Post.author (to-one) -> { author: { id: <parent> } }\n * Post.tags -> inverse is Tag.posts (to-many) -> { posts: { some: { id: <parent> } } }\n *\n * Both are Prisma relation filters on the target, so neither needs to know\n * whether a foreign key exists or where it lives.\n */\nimport {\n FieldNotFoundError,\n inverseRelationField,\n type ModelMetadata,\n type RecordId,\n} from '@nest-admin/core'\n\n/**\n * A `where` clause selecting the target records linked to `parentId`.\n *\n * `parentKey` is the parent's primary-key field, which the filter matches on.\n */\nexport function toRelatedWhere(\n parent: ModelMetadata,\n relationFieldName: string,\n parentId: RecordId,\n models: readonly ModelMetadata[],\n): { target: ModelMetadata; where: Record<string, unknown> } {\n const field = parent.fields.find((candidate) => candidate.name === relationFieldName)\n\n if (!field?.relation) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'Only a relation field can be listed this way.',\n )\n }\n\n if (field.relation.cardinality !== 'many') {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'This is a to-one relation. It arrives with the record itself.',\n )\n }\n\n const target = models.find((candidate) => candidate.name === field.relation?.targetModel)\n if (!target) {\n // The target is not part of this admin - excluded by configuration, or\n // hidden from this principal. Either way there is nothing to list.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${field.relation.targetModel} is not available.`,\n )\n }\n\n const inverse = inverseRelationField(field, models)\n if (!inverse) {\n // Without the other half there is no way to express the constraint, and\n // returning every record of the target would be catastrophically wrong.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'The other half of this relation could not be resolved.',\n )\n }\n\n const [parentKey] = parent.primaryKey\n if (parentKey === undefined) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${parent.name} has no primary key.`,\n )\n }\n\n const match = { [parentKey]: parentId }\n\n return {\n target,\n where: {\n [inverse.name]: inverse.relation?.cardinality === 'many' ? { some: match } : { is: match },\n },\n }\n}\n","/**\n * Core `ListQuery` -> Prisma `findMany` arguments.\n *\n * Everything here is validated against model metadata before it reaches the\n * client. Field names arriving from an HTTP request eventually flow into this\n * module, so an unvalidated name would become an injection surface into the\n * query object. There is no raw SQL anywhere; all queries go through Prisma's\n * structured API.\n */\nimport {\n FieldNotFoundError,\n InvalidQueryError,\n type FieldMetadata,\n type FilterRule,\n type ListQuery,\n type ModelMetadata,\n} from '@nest-admin/core'\n\nexport const DEFAULT_PER_PAGE = 25\nexport const MAX_PER_PAGE = 100\n\n/** Operators that only make sense on string fields. */\nconst STRING_ONLY_OPERATORS = new Set(['contains', 'startsWith', 'endsWith'])\n\n/** Operators that require an ordered (numeric, date, or string) field. */\nconst COMPARISON_OPERATORS = new Set(['gt', 'gte', 'lt', 'lte'])\n\nexport interface PrismaFindManyArgs {\n where?: Record<string, unknown>\n orderBy?: Array<Record<string, 'asc' | 'desc'>>\n skip?: number\n take?: number\n}\n\n/**\n * What the field is being resolved for.\n *\n * Only relations care, and they care because the two cases are not symmetric.\n * See {@link findQueryableField}.\n */\ntype QueryPurpose = 'filter' | 'sort'\n\n/**\n * A field usable in a filter or a sort.\n *\n * A to-one relation the model owns is stored in a scalar column, so a **filter**\n * on `author` is answerable: it means exactly a filter on `authorId`, and the\n * caller gets to use whichever name they think in.\n *\n * **Sorting** by it is refused, even though it would run. `authorId` holds a\n * cuid, so ordering by it is ordering by a random-looking string - a result\n * that looks sorted, is stable, and means nothing. What someone asking to sort\n * by `author` wants is the author's *name*, which is sorting by a field on\n * another model and is not this version. A refusal that says so is better than\n * a page of rows in an order nobody can explain.\n *\n * List fields are excluded outright: there is no column on this side at all.\n */\nfunction findQueryableField(\n model: ModelMetadata,\n fieldName: string,\n purpose: QueryPurpose,\n): FieldMetadata {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (!field) {\n throw new FieldNotFoundError(model.name, fieldName)\n }\n if (field.kind === 'relation') {\n const owned = field.relation?.from\n if (owned !== undefined && field.relation?.cardinality === 'one') {\n if (purpose === 'filter') return findQueryableField(model, owned, purpose)\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n `Sorting by a relation is not supported in this version. ` +\n `Sorting by \"${owned}\" would order by an opaque key rather than by ` +\n `anything readable.`,\n )\n }\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'Relation fields cannot be filtered or sorted in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'List fields cannot be filtered or sorted in this version.',\n )\n }\n return field\n}\n\nfunction toPrismaCondition(model: ModelMetadata, rule: FilterRule): Record<string, unknown> {\n const field = findQueryableField(model, rule.field, 'filter')\n\n if (STRING_ONLY_OPERATORS.has(rule.operator) && field.kind !== 'string') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" requires a string field, but ` +\n `\"${model.name}.${field.name}\" is of kind \"${field.kind}\".`,\n )\n }\n\n if (COMPARISON_OPERATORS.has(rule.operator) && field.kind === 'boolean') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" cannot be applied to boolean field ` +\n `\"${model.name}.${field.name}\".`,\n )\n }\n\n if (rule.operator === 'in') {\n if (!Array.isArray(rule.value)) {\n throw new InvalidQueryError(\n `Operator \"in\" requires an array value for \"${model.name}.${field.name}\".`,\n )\n }\n return { [field.name]: { in: rule.value } }\n }\n\n if (rule.operator === 'eq') return { [field.name]: { equals: rule.value } }\n if (rule.operator === 'ne') return { [field.name]: { not: rule.value } }\n\n return { [field.name]: { [rule.operator]: rule.value } }\n}\n\n/**\n * Providers where Prisma accepts `mode: 'insensitive'`.\n *\n * The list is short because Prisma *throws* on the others rather than ignoring\n * the option, so being wrong here breaks every search rather than degrading it.\n *\n * The omissions are deliberate, not oversights:\n *\n * | Provider | Why nothing is sent |\n * | ---------- | ---------------------------------------------------------- |\n * | mysql | Its default collations end in `_ci`; `LIKE` already ignores case. |\n * | sqlite | `LIKE` is case-insensitive for ASCII by default. |\n * | sqlserver | Its default collation is case-insensitive. |\n * | cockroachdb | Prisma documents `mode` for PostgreSQL and MongoDB only. |\n *\n * So on the four below, the option is unnecessary; on CockroachDB it is\n * unproven, and this is not the place to guess.\n */\nconst INSENSITIVE_MODE_PROVIDERS: ReadonlySet<string> = new Set([\n 'postgresql',\n 'postgres',\n 'mongodb',\n])\n\n/**\n * The case-insensitivity option for this provider, if it takes one.\n *\n * Spread into every string comparison. Returning an object to spread rather\n * than a boolean to branch on keeps the option out of the query entirely where\n * it is not supported - Prisma rejects `mode: undefined` as readily as it\n * rejects `mode: 'insensitive'` on SQLite.\n */\nexport function insensitively(provider: string | undefined): { mode?: 'insensitive' } {\n return provider !== undefined && INSENSITIVE_MODE_PROVIDERS.has(provider)\n ? { mode: 'insensitive' }\n : {}\n}\n\n/** String comparisons, which are the ones capitalisation applies to. */\nconst TEXTUAL_OPERATORS: ReadonlySet<string> = new Set(['contains', 'startsWith', 'endsWith'])\n\n/**\n * Free-text search: `contains` across the model's meaningful string fields.\n *\n * Generated string fields are excluded. A `cuid()` or `uuid()` primary key is\n * an opaque machine value, and including it makes single-letter searches match\n * essentially at random - searching \"e\" returns any record whose id happens to\n * contain an \"e\". Looking a record up by its id is an exact-match concern, so\n * it belongs in a filter (`{ field: 'id', operator: 'eq' }`), not in free text.\n *\n * Capitalisation is ignored, which needed the provider to say so. Searching\n * \"ada\" and getting nothing because the record says \"Ada\" is the kind of defect\n * people conclude the search is broken from, and they are not wrong. What it\n * takes to ignore case differs per database, and on some of them the option\n * that does it is an error - hence `insensitively`.\n */\nfunction toSearchCondition(\n model: ModelMetadata,\n term: string,\n provider: string | undefined,\n): Record<string, unknown> | undefined {\n // Foreign keys are string columns holding a cuid, so they match the same\n // rule the generated-id exclusion exists for - and they are not generated,\n // so that rule misses them. Left in, a search for \"e\" matches almost every\n // row of any model that references another, because most cuids contain an e.\n const foreignKeys = new Set(\n model.fields.map((field) => field.relation?.from).filter((name) => name !== undefined),\n )\n\n const stringFields = model.fields.filter(\n (field) =>\n field.kind === 'string' &&\n !field.isList &&\n !field.isGenerated &&\n !foreignKeys.has(field.name),\n )\n if (stringFields.length === 0) return undefined\n\n return {\n OR: stringFields.map((field) => ({\n [field.name]: { contains: term, ...insensitively(provider) },\n })),\n }\n}\n\nexport function buildWhere(\n model: ModelMetadata,\n query: Pick<ListQuery, 'filters' | 'search'>,\n provider?: string,\n): Record<string, unknown> | undefined {\n const conditions: Array<Record<string, unknown>> = []\n\n for (const rule of query.filters ?? []) {\n const condition = toPrismaCondition(model, rule)\n // A \"contains\" filter is the same promise the search box makes, typed into\n // a different box. It would be strange for one to ignore case and not the\n // other, and stranger still to have to know which.\n conditions.push(\n TEXTUAL_OPERATORS.has(rule.operator) ? insensitive(condition, provider) : condition,\n )\n }\n\n const search = query.search?.trim()\n if (search) {\n const searchCondition = toSearchCondition(model, search, provider)\n if (searchCondition) conditions.push(searchCondition)\n }\n\n if (conditions.length === 0) return undefined\n if (conditions.length === 1) return conditions[0]\n return { AND: conditions }\n}\n\nfunction buildOrderBy(\n model: ModelMetadata,\n query: Pick<ListQuery, 'sort'>,\n): Array<Record<string, 'asc' | 'desc'>> | undefined {\n const rules = query.sort ?? []\n if (rules.length === 0) return undefined\n\n return rules.map((rule) => {\n const field = findQueryableField(model, rule.field, 'sort')\n return { [field.name]: rule.direction }\n })\n}\n\n/** Normalised, clamped pagination. Page numbers are 1-based. */\nexport function resolvePagination(query: Pick<ListQuery, 'page' | 'perPage'>): {\n page: number\n perPage: number\n skip: number\n take: number\n} {\n const rawPage = query.page ?? 1\n if (!Number.isInteger(rawPage) || rawPage < 1) {\n throw new InvalidQueryError(\n `\"page\" must be an integer >= 1, received ${JSON.stringify(query.page)}.`,\n )\n }\n\n const rawPerPage = query.perPage ?? DEFAULT_PER_PAGE\n if (!Number.isInteger(rawPerPage) || rawPerPage < 1) {\n throw new InvalidQueryError(\n `\"perPage\" must be an integer >= 1, received ${JSON.stringify(query.perPage)}.`,\n )\n }\n\n // Clamped rather than rejected: a UI asking for too much should get a\n // capped page, not an error.\n const perPage = Math.min(rawPerPage, MAX_PER_PAGE)\n return { page: rawPage, perPage, skip: (rawPage - 1) * perPage, take: perPage }\n}\n\n/**\n * The same condition, told to ignore case.\n *\n * A condition is `{ field: { operator: value } }`, and the option belongs\n * beside the operator rather than beside the field, so it cannot simply be\n * spread at the top level.\n */\nfunction insensitive(\n condition: Record<string, unknown>,\n provider: string | undefined,\n): Record<string, unknown> {\n const mode = insensitively(provider)\n if (mode.mode === undefined) return condition\n\n const entries = Object.entries(condition).map(([field, comparison]) => [\n field,\n typeof comparison === 'object' && comparison !== null\n ? { ...(comparison as Record<string, unknown>), ...mode }\n : comparison,\n ])\n return Object.fromEntries(entries) as Record<string, unknown>\n}\n\nexport function toFindManyArgs(\n model: ModelMetadata,\n query: ListQuery,\n provider?: string,\n): PrismaFindManyArgs {\n const { skip, take } = resolvePagination(query)\n const where = buildWhere(model, query, provider)\n const orderBy = buildOrderBy(model, query)\n\n return {\n ...(where ? { where } : {}),\n ...(orderBy ? { orderBy } : {}),\n skip,\n take,\n }\n}\n","/**\n * Admin accounts, in Prisma.\n *\n * ## A model of its own\n *\n * The default is `AdminAccount`, and that default is the design rather than a\n * placeholder. The people who administer a system are usually not rows in the\n * table they administer, and pointing this at the application's `User` would\n * mean every customer record carries a password that opens the admin - which is\n * a decision nobody makes on purpose and several people make by accident.\n *\n * The model name is configurable because some applications already have a\n * `Staff` or an `Operator`. Pointing it at `User` is possible and is a choice,\n * not a default.\n *\n * ## What it does not do\n *\n * Create, update, delete. The store contract is read-only, and this implements\n * only what it declares: an admin that could mint its own administrators is an\n * escalation waiting for its first mistake in a policy. Seeding the first\n * account is the application's job, with `hashAdminPassword`.\n *\n * ## The account model should not be a resource\n *\n * Nothing here can arrange that - which models the admin exposes is the\n * module's business - so it is the one thing a consumer has to remember:\n *\n * ```ts\n * resources: { exclude: ['AdminAccount'] }\n * ```\n *\n * Without it, anyone who may edit that model can grant themselves whatever the\n * admin can do. `builtInAuth` warns at startup when it sees the account model\n * among the exposed resources.\n */\nimport type { AdminAccount, AdminAccountStore } from '@nest-admin/core'\n\nimport { resolveDelegate } from '../client/delegate.js'\n\nexport interface PrismaAccountStoreOptions {\n /** A constructed Prisma Client - the same one the adapter is given. */\n readonly client: unknown\n\n /** The model holding admin accounts. `AdminAccount` by default. */\n readonly model?: string\n\n /**\n * Column names, where they differ from the defaults.\n *\n * A mapping rather than a required schema: an application that already has a\n * `Staff` table with `login` and `hash` should not have to migrate it to use\n * this.\n */\n readonly fields?: {\n readonly id?: string\n readonly email?: string\n readonly name?: string\n readonly passwordHash?: string\n readonly disabled?: string\n /** Written on a successful sign-in, when the column exists. */\n readonly lastLoginAt?: string\n }\n}\n\nconst DEFAULTS = {\n id: 'id',\n email: 'email',\n name: 'name',\n passwordHash: 'passwordHash',\n disabled: 'disabled',\n lastLoginAt: 'lastLoginAt',\n} as const\n\nexport function prismaAccountStore(options: PrismaAccountStoreOptions): AdminAccountStore {\n const model = options.model ?? 'AdminAccount'\n const column = { ...DEFAULTS, ...options.fields }\n\n /*\n * The allowlist is the one configured name.\n *\n * `resolveDelegate` takes a list because the adapter resolves a model named\n * by a *request*, where an allowlist is the whole defence. Here the name\n * comes from the application's own configuration and there is nothing to\n * defend against - but passing it anyway keeps the property-name guard\n * inside `resolveDelegate`, which is the part that still matters, and gives\n * a clear error rather than `undefined.findMany is not a function` when the\n * model does not exist.\n */\n const delegate = () => resolveDelegate(options.client, model, [model])\n\n /**\n * A row as the contract describes it.\n *\n * Returns `null` for a row with no usable hash rather than an account that\n * can never sign in. The difference matters at the point of use: a `null`\n * takes the same path as an unknown email, and an account object with an\n * empty hash would be compared against and fail in a way that takes a\n * measurably different amount of time.\n */\n const toAccount = (row: unknown): AdminAccount | null => {\n if (typeof row !== 'object' || row === null) return null\n const record = row as Record<string, unknown>\n\n const id = record[column.id]\n const email = record[column.email]\n const hash = record[column.passwordHash]\n\n if (typeof id !== 'string' && typeof id !== 'number') return null\n if (typeof email !== 'string') return null\n if (typeof hash !== 'string' || hash === '') return null\n\n const name = record[column.name]\n const disabled = record[column.disabled]\n\n return {\n id: String(id),\n email,\n passwordHash: hash,\n ...(typeof name === 'string' && name !== '' ? { name } : {}),\n ...(typeof disabled === 'boolean' ? { disabled } : {}),\n }\n }\n\n return {\n describes: model,\n\n async findByEmail(email) {\n /*\n * `findFirst`, not `findUnique`.\n *\n * The email column is very likely unique, and this store cannot know\n * that - a consumer mapping it onto an existing table may have it\n * indexed and not constrained. `findUnique` throws on a column Prisma\n * does not consider unique, which would turn a schema difference into a\n * 500 on the login route.\n */\n const rows = await delegate().findMany({\n where: { [column.email]: email },\n take: 1,\n })\n return toAccount(rows[0])\n },\n\n async findById(id) {\n const rows = await delegate().findMany({ where: { [column.id]: id }, take: 1 })\n return toAccount(rows[0])\n },\n\n async count() {\n return delegate().count()\n },\n\n async recordLogin(id) {\n // Best effort. A store mapped onto a table without this column should\n // not turn a successful sign-in into a failure, and the caller already\n // treats a rejection here as something to log rather than to surface.\n await delegate().update({\n where: { [column.id]: id },\n data: { [column.lastLoginAt]: new Date() },\n })\n },\n }\n}\n"],"mappings":"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","names":["NestAdminError","AdapterError","FieldNotFoundError","ModelNotFoundError","InvalidQueryError","isNestAdminError"]}
1
+ {"version":3,"sources":["../../prisma/src/adapter.ts","../../prisma/src/client/delegate.ts","../../prisma/src/client/version-gate.ts","../../prisma/src/metadata/read-dmmf.ts","../../prisma/src/metadata/to-metadata.ts","../../prisma/src/query/to-include.ts","../../prisma/src/errors/constraints.ts","../../prisma/src/query/coerce-id.ts","../../prisma/src/query/to-related-where.ts","../../prisma/src/query/to-prisma-args.ts","../../prisma/src/auth/store.ts"],"sourcesContent":["/**\n * `PrismaAdapter` - the Prisma implementation of Core's `OrmAdapter`.\n *\n * The adapter never constructs a Prisma Client. Prisma 7 builds clients from\n * driver adapters, so only the consuming application knows the provider, the\n * credentials and the connection strategy. We receive a constructed client and\n * use it.\n */\nimport {\n AdapterError,\n FieldNotFoundError,\n InvalidQueryError,\n ModelNotFoundError,\n isNestAdminError,\n RecordNotFoundError,\n type ListQuery,\n type ModelMetadata,\n type OrmAdapter,\n type Page,\n type RecordData,\n type RecordId,\n} from '@nest-admin/core'\n\nimport { resolveDelegate, type PrismaModelDelegate } from './client/delegate.js'\nimport { assertSupportedPrismaVersion } from './client/version-gate.js'\nimport { readDatasourceProvider, readPrismaDmmf } from './metadata/read-dmmf.js'\nimport { toModelMetadata } from './metadata/to-metadata.js'\nimport { toIncludeClause } from './query/to-include.js'\nimport { toConstraintError } from './errors/constraints.js'\nimport { coerceId } from './query/coerce-id.js'\nimport { toRelatedWhere } from './query/to-related-where.js'\nimport { resolvePagination, toFindManyArgs } from './query/to-prisma-args.js'\n\n/** Prisma's error code for \"record required but not found\". */\nconst PRISMA_RECORD_NOT_FOUND = 'P2025'\n\nexport interface PrismaAdapterOptions {\n /**\n * A constructed Prisma Client. Owned entirely by the consuming application:\n * the adapter never calls `new PrismaClient()`, because under Prisma 7 the\n * client is built from a driver adapter that only the application can supply.\n */\n readonly client: unknown\n /**\n * Path to `schema.prisma`, or to a directory of `.prisma` files. When\n * omitted, `prisma/schema.prisma`, `prisma/schema` and `schema.prisma` are\n * tried in that order, relative to `cwd`.\n */\n readonly schemaPath?: string\n /** Base directory for schema resolution. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\nexport class PrismaAdapter implements OrmAdapter {\n readonly name = 'prisma'\n\n readonly #client: unknown\n readonly #schemaPath: string | undefined\n readonly #cwd: string | undefined\n\n /**\n * Metadata is derived from a static schema, so it is read once and reused.\n * Every operation validates against it, which would otherwise re-parse the\n * schema on each call.\n */\n #models: readonly ModelMetadata[] | undefined\n\n /**\n * Which database this is, so a search can ignore capitalisation the way that\n * database allows. Read alongside the metadata, and `undefined` when the\n * schema does not say - see `insensitively` in `to-prisma-args.ts`.\n */\n #provider: string | undefined\n\n constructor(options: PrismaAdapterOptions) {\n if (options.client === null || options.client === undefined) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client. ' +\n 'Pass one via `new PrismaAdapter({ client })`.',\n )\n }\n this.#client = options.client\n this.#schemaPath = options.schemaPath\n this.#cwd = options.cwd\n }\n\n async getModels(): Promise<readonly ModelMetadata[]> {\n if (this.#models) return this.#models\n // Checked before parsing: a version mismatch would otherwise surface as\n // \"Prisma rejected the schema\", pointing at the user's valid schema.\n assertSupportedPrismaVersion(this.#client)\n const dmmf = readPrismaDmmf({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n this.#models = toModelMetadata(dmmf)\n this.#provider = readDatasourceProvider({\n ...(this.#schemaPath !== undefined ? { schemaPath: this.#schemaPath } : {}),\n ...(this.#cwd !== undefined ? { cwd: this.#cwd } : {}),\n })\n return this.#models\n }\n\n async list(model: string, query: ListQuery): Promise<Page<RecordData>> {\n const declared = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n\n // Narrowed first: everything below reads the model, so restricting it once\n // restricts field lookup, free-text search and relation loading together.\n const metadata = narrowFields(declared, query.fields)\n\n const args = toFindManyArgs(metadata, query, this.#provider)\n const include = toIncludeClause(metadata, await this.getModels())\n const omit = omitClause(declared, query.fields)\n const withRelations = { ...args, ...(include ? { include } : {}), ...(omit ? { omit } : {}) }\n const { page, perPage } = resolvePagination(query)\n\n const [rows, total] = await this.#run(model, () =>\n Promise.all([\n delegate.findMany(withRelations),\n delegate.count(args.where ? { where: args.where } : {}),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async findOne(model: string, id: RecordId): Promise<RecordData | null> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n const include = toIncludeClause(metadata, await this.getModels())\n const record = await this.#run(model, () =>\n delegate.findUnique(include ? { where, include } : { where }),\n )\n return (record as RecordData | null) ?? null\n }\n\n async create(model: string, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const writable = this.#validateWritableData(metadata, data)\n\n const created = await this.#run(model, () => delegate.create({ data: writable }))\n return created as RecordData\n }\n\n async update(model: string, id: RecordId, data: RecordData): Promise<RecordData> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n const writable = this.#validateWritableData(metadata, data)\n\n const updated = await this.#run(model, () => delegate.update({ where, data: writable }), id)\n return updated as RecordData\n }\n\n async delete(model: string, id: RecordId): Promise<void> {\n const metadata = await this.#requireModel(model)\n const delegate = await this.#delegate(model)\n const where = this.#whereById(metadata, id)\n\n await this.#run(model, () => delegate.delete({ where }), id)\n }\n\n /**\n * A page of the records on the far side of a to-many relation.\n *\n * Implemented as an ordinary list of the *target* model with one extra\n * condition, so pagination, sorting, filtering and relation loading all\n * behave exactly as they do on a top-level list. See `to-related-where.ts`.\n */\n async listRelated(\n model: string,\n id: RecordId,\n relationField: string,\n query: ListQuery,\n ): Promise<Page<RecordData>> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n\n // The relation is validated first: a bad field name is wrong whether or\n // not the record exists, and rejecting it here costs no query.\n const { target, where } = toRelatedWhere(metadata, relationField, id, models)\n\n // A missing parent is a 404, not an empty page. The condition below would\n // simply match nothing, which reads as \"this record has no children\".\n await this.#requireRecord(model, metadata, id)\n const delegate = await this.#delegate(target.name)\n\n const narrowed = narrowFields(target, query.fields)\n const args = toFindManyArgs(narrowed, query, this.#provider)\n const combined = args.where ? { AND: [args.where, where] } : where\n const include = toIncludeClause(narrowed, models)\n const omit = omitClause(target, query.fields)\n\n const { page, perPage } = resolvePagination(query)\n const [rows, total] = await this.#run(target.name, () =>\n Promise.all([\n delegate.findMany({\n ...args,\n where: combined,\n ...(include ? { include } : {}),\n ...(omit ? { omit } : {}),\n }),\n delegate.count({ where: combined }),\n ]),\n )\n\n return { data: rows as RecordData[], total, page, perPage }\n }\n\n async attachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'connect')\n }\n\n async detachRelated(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n ): Promise<void> {\n await this.#link(model, id, relationField, targetId, 'disconnect')\n }\n\n // ---------------------------------------------------------------- internals\n\n /**\n * Add or remove one link, from the parent's side.\n *\n * Prisma expresses both the same way and works out where the link is stored -\n * a join-table row for a many-to-many, the child's foreign key for a\n * one-to-many. Whether the operation is allowed is the caller's decision;\n * this performs it.\n */\n async #link(\n model: string,\n id: RecordId,\n relationField: string,\n targetId: RecordId,\n operation: 'connect' | 'disconnect',\n ): Promise<void> {\n const metadata = await this.#requireModel(model)\n const models = await this.getModels()\n const { target } = toRelatedWhere(metadata, relationField, id, models)\n\n const [targetKey] = target.primaryKey\n if (targetKey === undefined) {\n throw new FieldNotFoundError(target.name, relationField, 'The target has no primary key.')\n }\n\n const delegate = await this.#delegate(model)\n await this.#run(\n model,\n () =>\n delegate.update({\n where: this.#whereById(metadata, id),\n data: {\n [relationField]: {\n // Against the *target's* key, not this model's - the two ends of\n // a relation can be typed differently.\n [operation]: { [targetKey]: coerceId(target, targetKey, targetId) },\n },\n },\n }),\n id,\n )\n }\n\n /** Throw `RecordNotFoundError` unless the record exists. */\n async #requireRecord(model: string, metadata: ModelMetadata, id: RecordId): Promise<void> {\n const delegate = await this.#delegate(model)\n const found = await this.#run(\n model,\n () => delegate.findUnique({ where: this.#whereById(metadata, id) }),\n id,\n )\n if (found === null || found === undefined) throw new RecordNotFoundError(model, id)\n }\n\n async #requireModel(model: string): Promise<ModelMetadata> {\n const models = await this.getModels()\n const found = models.find((candidate) => candidate.name === model)\n if (!found) {\n throw new ModelNotFoundError(\n model,\n models.map((candidate) => candidate.name),\n )\n }\n return found\n }\n\n async #delegate(model: string): Promise<PrismaModelDelegate> {\n const models = await this.getModels()\n return resolveDelegate(\n this.#client,\n model,\n models.map((candidate) => candidate.name),\n )\n }\n\n /**\n * Build a `where` clause addressing a single record by primary key.\n *\n * Composite keys are represented in metadata but not supported here: a\n * `RecordId` is a single scalar, so there is nothing to map the second\n * column from. Rejected explicitly rather than silently mis-querying.\n */\n #whereById(model: ModelMetadata, id: RecordId): Record<string, unknown> {\n const [primaryKeyField, ...rest] = model.primaryKey\n\n if (primaryKeyField === undefined) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has no primary key, so records cannot be addressed by id.`,\n )\n }\n if (rest.length > 0) {\n throw new InvalidQueryError(\n `Model \"${model.name}\" has a composite primary key ` +\n `(${model.primaryKey.join(', ')}), which is not supported in this version.`,\n )\n }\n\n return { [primaryKeyField]: coerceId(model, primaryKeyField, id) }\n }\n\n /**\n * Reject anything the caller has no business writing.\n *\n * Unknown keys are an error rather than silently dropped: quietly discarding\n * a field the user filled in is worse than telling them it does not exist.\n * Relation and list fields are rejected because nested writes are not\n * implemented - see the Phase 2 report.\n */\n #validateWritableData(model: ModelMetadata, data: RecordData): RecordData {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new InvalidQueryError(`Write payload for \"${model.name}\" must be an object.`)\n }\n\n const writable: RecordData = {}\n for (const [key, value] of Object.entries(data)) {\n const field = model.fields.find((candidate) => candidate.name === key)\n if (!field) {\n throw new FieldNotFoundError(model.name, key)\n }\n if (field.kind === 'relation') {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing relation fields is not supported in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n key,\n 'Writing list fields is not supported in this version.',\n )\n }\n writable[key] = value\n }\n return writable\n }\n\n /**\n * Run a client call, translating Prisma failures into Core errors.\n *\n * Prisma error types are identified by their `code` property rather than\n * `instanceof`. Importing `@prisma/client` to get the error classes would\n * mean loading a second copy of a package the consumer owns, and would tie\n * us to their Prisma version.\n */\n async #run<T>(model: string, operation: () => Promise<T>, id?: RecordId): Promise<T> {\n try {\n return await operation()\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n\n if (isPrismaError(cause) && cause.code === PRISMA_RECORD_NOT_FOUND && id !== undefined) {\n throw new RecordNotFoundError(model, id)\n }\n\n // A refused write is a fact about the request, not a failure of the\n // database. Reporting it as an internal error is what made a duplicate\n // email indistinguishable from a dead connection.\n const constraint = toConstraintError(cause, model)\n if (constraint) throw constraint\n\n const detail = cause instanceof Error ? cause.message : String(cause)\n throw new AdapterError(`Prisma operation failed for model \"${model}\": ${detail}`, { cause })\n }\n }\n}\n\nfunction isPrismaError(value: unknown): value is { code: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The model as this query is allowed to see it.\n *\n * Narrowing once, at the top, is what keeps the rest of the adapter honest:\n * field lookup, free-text search and relation loading all read the model, so\n * they inherit the restriction without knowing it exists. Doing it per-concern\n * would mean three places to forget.\n */\nfunction narrowFields(model: ModelMetadata, fields: readonly string[] | undefined): ModelMetadata {\n if (!fields) return model\n\n const allowed = new Set(fields)\n return { ...model, fields: model.fields.filter((field) => allowed.has(field.name)) }\n}\n\n/**\n * Columns to leave out of the result.\n *\n * `omit` rather than `select` because it composes with `include`: a `select`\n * would have to enumerate the relations too, and would silently drop any the\n * caller forgot. This way a hidden column is never read at all, which is a\n * stronger guarantee than removing it from the response afterwards.\n */\nfunction omitClause(\n model: ModelMetadata,\n fields: readonly string[] | undefined,\n): Record<string, true> | undefined {\n if (!fields) return undefined\n\n const allowed = new Set(fields)\n const omitted: Record<string, true> = {}\n\n for (const field of model.fields) {\n // Relations are excluded through `include`, not `omit`; Prisma rejects\n // naming them here.\n if (!allowed.has(field.name) && field.kind !== 'relation') omitted[field.name] = true\n }\n\n return Object.keys(omitted).length > 0 ? omitted : undefined\n}\n","/**\n * Dynamic model resolution.\n *\n * The admin addresses models by name at runtime (`\"User\"`), so the Prisma\n * Client's statically-typed delegates cannot be reached through their types.\n * This module is the single, deliberately narrow place where that type escape\n * happens. Nothing else in the package casts the client.\n */\nimport { AdapterError, ModelNotFoundError } from '@nest-admin/core'\n\n/**\n * The subset of a Prisma model delegate the adapter uses.\n *\n * Declared structurally rather than imported from `@prisma/client`: the client\n * is generated in the consumer's project against their schema, so there is no\n * meaningful shared type to import, and depending on one would couple us to a\n * Prisma version we do not control.\n */\nexport interface PrismaModelDelegate {\n findMany(args?: unknown): Promise<unknown[]>\n findUnique(args: unknown): Promise<unknown>\n count(args?: unknown): Promise<number>\n create(args: unknown): Promise<unknown>\n update(args: unknown): Promise<unknown>\n delete(args: unknown): Promise<unknown>\n}\n\nconst REQUIRED_METHODS = [\n 'findMany',\n 'findUnique',\n 'count',\n 'create',\n 'update',\n 'delete',\n] as const satisfies readonly (keyof PrismaModelDelegate)[]\n\n/**\n * Property names that must never be used as a delegate lookup key, regardless\n * of what the caller passes. Model names are validated against known metadata\n * before we get here, so this is defence in depth rather than the only guard.\n */\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype'])\n\n/**\n * Prisma exposes `model User` as `prisma.user` - the model name with only its\n * first character lower-cased. Note this is not general camelCase conversion:\n * `UserProfile` becomes `userProfile`, and `HTTPLog` becomes `hTTPLog`.\n */\nexport function toDelegateKey(modelName: string): string {\n if (modelName.length === 0) return modelName\n return modelName.charAt(0).toLowerCase() + modelName.slice(1)\n}\n\n/**\n * Resolve a model name to its Prisma Client delegate.\n *\n * `knownModels` is the metadata-derived allowlist. A name outside it is\n * rejected before the client is touched at all, so an attacker-controlled\n * model name can never reach arbitrary client properties.\n */\nexport function resolveDelegate(\n client: unknown,\n modelName: string,\n knownModels: readonly string[],\n): PrismaModelDelegate {\n if (!knownModels.includes(modelName)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n const key = toDelegateKey(modelName)\n if (FORBIDDEN_KEYS.has(key)) {\n throw new ModelNotFoundError(modelName, knownModels)\n }\n\n if (typeof client !== 'object' || client === null) {\n throw new AdapterError(\n 'PrismaAdapter requires a constructed Prisma Client instance. ' +\n `Received ${client === null ? 'null' : typeof client}.`,\n )\n }\n\n // The one type escape. Guarded above by the metadata allowlist and below by\n // a shape check, so the cast is asserted rather than assumed.\n const candidate = (client as Record<string, unknown>)[key]\n\n if (typeof candidate !== 'object' || candidate === null) {\n throw new AdapterError(\n `The Prisma Client has no delegate \"${key}\" for model \"${modelName}\". ` +\n 'This usually means the client was generated from a different schema ' +\n 'than the one Nest Admin read - re-run `prisma generate`.',\n )\n }\n\n const delegate = candidate as Record<string, unknown>\n const missing = REQUIRED_METHODS.filter((method) => typeof delegate[method] !== 'function')\n if (missing.length > 0) {\n throw new AdapterError(\n `Prisma Client delegate \"${key}\" is missing expected methods: ${missing.join(', ')}.`,\n )\n }\n\n return candidate as PrismaModelDelegate\n}\n","/**\n * Prisma version gate.\n *\n * Phase 1 established that `@prisma/get-dmmf` is pinned exactly and enforces\n * *its own* Prisma version's schema rules: given a Prisma 6 schema, the 7.x\n * parser rejects `url` inside `datasource` even though the schema is perfectly\n * valid for that consumer. Without a gate, that surfaces as a confusing\n * \"Prisma rejected the schema\" error pointing at the user's own valid file.\n *\n * The gate turns that into a statement about versions.\n *\n * ## Two deliberate design choices\n *\n * **It fails open on detection.** The client version is read from\n * `client._clientVersion`, an underscore-prefixed internal. If Prisma renames\n * or removes it, the gate silently does nothing rather than breaking every\n * consumer on an otherwise-fine upgrade. A version check that itself becomes\n * the outage is worse than no version check.\n *\n * **It compares majors only.** Minor and patch releases have not changed the\n * schema language; majors have. Pinning tighter would produce false alarms on\n * every routine bump.\n *\n * This lives in `packages/prisma`, not Core - Core must never learn what\n * Prisma is.\n */\nimport { NestAdminError } from '@nest-admin/core'\n\n/**\n * Prisma majors whose schema language this adapter's pinned parser handles.\n *\n * Derived from the parser we ship (`@prisma/get-dmmf`, pinned in\n * package.json), not from what we wish were true. Widen this only after\n * testing against the new major.\n */\nexport const SUPPORTED_PRISMA_MAJORS: readonly number[] = [7]\n\n/** Raised when the consumer's Prisma Client major is outside the tested range. */\nexport class PrismaVersionUnsupportedError extends NestAdminError {\n constructor(\n readonly clientVersion: string,\n readonly supportedMajors: readonly number[],\n ) {\n super(\n `Nest Admin ships a Prisma ${supportedMajors.join('/')} schema parser, ` +\n `but this application uses Prisma Client ${clientVersion}. ` +\n 'Schema parsing would likely fail with a misleading error, so it was ' +\n 'stopped here instead. Align the versions, or open an issue if ' +\n `Prisma ${clientVersion.split('.')[0]} should be supported.`,\n )\n }\n}\n\n/**\n * Read the Prisma Client version from an instance.\n *\n * Returns `undefined` when it cannot be determined - see \"fails open\" above.\n */\nexport function readClientVersion(client: unknown): string | undefined {\n if (typeof client !== 'object' || client === null) return undefined\n const version = (client as Record<string, unknown>)['_clientVersion']\n return typeof version === 'string' && version !== '' ? version : undefined\n}\n\nfunction majorOf(version: string): number | undefined {\n const major = Number(version.split('.')[0])\n return Number.isInteger(major) ? major : undefined\n}\n\n/**\n * Throw when the client's major is known and unsupported.\n *\n * Silent when the version is unreadable or unparseable.\n */\nexport function assertSupportedPrismaVersion(\n client: unknown,\n supportedMajors: readonly number[] = SUPPORTED_PRISMA_MAJORS,\n): void {\n const version = readClientVersion(client)\n if (version === undefined) return\n\n const major = majorOf(version)\n if (major === undefined) return\n\n if (!supportedMajors.includes(major)) {\n throw new PrismaVersionUnsupportedError(version, supportedMajors)\n }\n}\n","/**\n * Prisma schema acquisition.\n *\n * This is the ONLY module in the repository permitted to import\n * `@prisma/get-dmmf`. Everything downstream consumes the returned\n * `DMMF.Document` and nothing else, which is what keeps the eventual switch to\n * a build-time Prisma generator a change to this file alone.\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport { AdapterError, isNestAdminError, NestAdminError } from '@nest-admin/core'\nimport { getDMMF } from '@prisma/get-dmmf'\nimport type * as DMMF from '@prisma/dmmf'\n\n/** Paths tried, in order, when no explicit schema location is configured. */\nconst DEFAULT_SCHEMA_CANDIDATES = ['prisma/schema.prisma', 'prisma/schema', 'schema.prisma']\n\n/** Raised when the Prisma schema cannot be located or read. */\nexport class PrismaSchemaNotFoundError extends NestAdminError {\n constructor(\n readonly triedPaths: readonly string[],\n explicit: boolean,\n ) {\n super(\n explicit\n ? `Prisma schema not found at \"${triedPaths[0]}\".`\n : `Could not locate a Prisma schema. Tried: ${triedPaths.join(', ')}. ` +\n 'Pass `schemaPath` to PrismaAdapter if your schema lives elsewhere.',\n )\n }\n}\n\n/** Raised when Prisma rejects the schema. Carries Prisma's own validation text. */\nexport class PrismaSchemaInvalidError extends NestAdminError {\n constructor(\n readonly prismaMessage: string,\n options?: { cause?: unknown },\n ) {\n super(`Prisma rejected the schema:\\n${prismaMessage}`, options)\n }\n}\n\n/**\n * Resolve the schema location to an absolute path.\n *\n * `schemaPath` may point at a single `.prisma` file or, since Prisma 7, at a\n * directory of `.prisma` files. Both are supported.\n */\nfunction locateSchema(schemaPath: string | undefined, cwd: string): string {\n if (schemaPath !== undefined) {\n const absolute = resolve(cwd, schemaPath)\n if (!existsSync(absolute)) throw new PrismaSchemaNotFoundError([absolute], true)\n return absolute\n }\n\n const tried: string[] = []\n for (const candidate of DEFAULT_SCHEMA_CANDIDATES) {\n const absolute = resolve(cwd, candidate)\n tried.push(absolute)\n if (existsSync(absolute)) return absolute\n }\n throw new PrismaSchemaNotFoundError(tried, false)\n}\n\n/**\n * Read the schema as `[filename, content]` tuples.\n *\n * `getDMMF` accepts this shape natively (`SchemaFileInput = string |\n * Array<[filename, content]>`), so multi-file schemas need no concatenation\n * and no parsing on our side. Passing real filenames also means Prisma's\n * validation errors point at the right file.\n */\nfunction readSchemaFiles(absolutePath: string): Array<[string, string]> {\n if (statSync(absolutePath).isDirectory()) {\n const files = readdirSync(absolutePath)\n .filter((name) => name.endsWith('.prisma'))\n .sort()\n if (files.length === 0) {\n throw new PrismaSchemaNotFoundError([join(absolutePath, '*.prisma')], true)\n }\n return files.map((name) => {\n const file = join(absolutePath, name)\n return [file, readFileSync(file, 'utf8')] as [string, string]\n })\n }\n\n return [[absolutePath, readFileSync(absolutePath, 'utf8')]]\n}\n\nexport interface ReadDmmfOptions {\n /** Path to a `.prisma` file or a directory of them. Auto-detected if absent. */\n readonly schemaPath?: string\n /** Base directory for relative paths and auto-detection. Defaults to `process.cwd()`. */\n readonly cwd?: string\n}\n\n/**\n * Load and parse the Prisma schema into a DMMF document.\n *\n * Note the two traps this function exists to absorb:\n *\n * 1. `getDMMF` is **synchronous** and returns `DMMF.Document | GetDMMFError` -\n * it does not throw and does not reject. Reading `.datamodel` off an error\n * result yields a bare `TypeError` with none of Prisma's diagnostics.\n * 2. Returning empty metadata on failure would surface as an admin panel with\n * no resources, which reads as a configuration mistake and costs hours.\n * Every failure here is loud.\n */\nexport function readPrismaDmmf(options: ReadDmmfOptions = {}): DMMF.Document {\n const cwd = options.cwd ?? process.cwd()\n const absolutePath = locateSchema(options.schemaPath, cwd)\n\n let files: Array<[string, string]>\n try {\n files = readSchemaFiles(absolutePath)\n } catch (cause) {\n if (isNestAdminError(cause)) throw cause\n throw new AdapterError(`Failed to read the Prisma schema at \"${absolutePath}\".`, { cause })\n }\n\n const result = getDMMF({ datamodel: files })\n\n if (!isDmmfDocument(result)) {\n throw new PrismaSchemaInvalidError(extractPrismaMessage(result), { cause: result.error })\n }\n return result\n}\n\n/**\n * The datasource provider the schema declares - `postgresql`, `sqlite`, and so\n * on - or `undefined` when it cannot be read.\n *\n * Needed because Prisma accepts `mode: 'insensitive'` on some providers and\n * *throws* on the rest, so a search that ignores capitalisation has to know\n * which database it is talking to. See `to-prisma-args.ts`.\n *\n * ## Why this is read from the text\n *\n * The provider is not in the DMMF: `getDMMF` returns the datamodel, and the\n * datasource block is not part of it. Nor can it be asked of the client -\n * Prisma 7 builds clients from driver adapters, and what the application passed\n * is not something this package is allowed to introspect. The declaration is a\n * fixed one-line form in a file we are already reading, so it is read from\n * there, and every failure is answered with `undefined` rather than a throw:\n * an unreadable provider must degrade to the case-sensitive search that was the\n * behaviour before this existed, never to a broken panel.\n *\n * It reads the schema a second time. That happens once, at startup, on a file\n * of a few kilobytes - cheaper than threading a second return value through\n * every caller of `readPrismaDmmf`.\n */\nexport function readDatasourceProvider(options: ReadDmmfOptions = {}): string | undefined {\n try {\n const files = readSchemaFiles(locateSchema(options.schemaPath, options.cwd ?? process.cwd()))\n for (const [, content] of files) {\n const declared = /datasources+w+s*{[^}]*?providers*=s*\"([a-z]+)\"/i.exec(content)\n if (declared?.[1] !== undefined) return declared[1].toLowerCase()\n }\n } catch {\n // Unreadable schema. The DMMF read reports that properly; this one is an\n // optimisation and has nothing useful to add.\n }\n return undefined\n}\n\nfunction isDmmfDocument(value: DMMF.Document | { error: Error }): value is DMMF.Document {\n return 'datamodel' in value\n}\n\n/**\n * Prisma reports validation failures as a JSON string inside `error.message`,\n * carrying an ANSI-coloured `P1012` report. Unwrap it where possible so the\n * message we surface is the one a developer would see from the Prisma CLI.\n */\nfunction extractPrismaMessage(result: { reason: string; error: Error }): string {\n const raw = result.error?.message ?? result.reason\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed === 'object' && parsed !== null && 'message' in parsed) {\n const message = (parsed as { message: unknown }).message\n if (typeof message === 'string') return stripAnsi(message)\n }\n } catch {\n // Not JSON - fall through and use the raw text.\n }\n return stripAnsi(raw)\n}\n\nconst ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;]*m`, 'g')\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_PATTERN, '')\n}\n","/**\n * DMMF -> Core `ModelMetadata`.\n *\n * The one place Prisma's vocabulary is translated into ours. No DMMF type\n * escapes this module: everything downstream (the adapter, the future HTTP\n * layer, the admin UI) sees only Core shapes.\n *\n * This mapper is deliberately independent of *how* the DMMF was obtained, so\n * it is unaffected by a later switch to a build-time Prisma generator.\n */\nimport type { FieldKind, FieldMetadata, ModelMetadata } from '@nest-admin/core'\nimport type * as DMMF from '@prisma/dmmf'\n\n/**\n * Prisma scalar type -> Core field kind.\n *\n * `BigInt`, `Decimal` and `Bytes` are intentionally mapped to `'unknown'`\n * rather than squeezed into `'number'` or `'string'`. They do not round-trip\n * through JSON without losing precision or fidelity, and the MVP has not\n * tested editing them - claiming support we have not verified would be worse\n * than declaring them unhandled. They are still listed, so the admin can show\n * them read-only.\n */\nconst SCALAR_KINDS: Readonly<Record<string, FieldKind>> = {\n String: 'string',\n Int: 'number',\n Float: 'number',\n Boolean: 'boolean',\n DateTime: 'datetime',\n Json: 'json',\n}\n\nfunction toFieldKind(field: DMMF.Field): FieldKind {\n if (field.kind === 'object') return 'relation'\n if (field.kind === 'enum') return 'enum'\n if (field.kind === 'scalar') return SCALAR_KINDS[field.type] ?? 'unknown'\n return 'unknown'\n}\n\n/**\n * Is this default produced by the database or the ORM, rather than supplied by\n * the user?\n *\n * Measured against Prisma 7.10.0, DMMF distinguishes the two by *shape*:\n *\n * @default(cuid()) -> { name: 'cuid', args: [1] } (object)\n * @default(now()) -> { name: 'now', args: [] } (object)\n * @default(autoincrement()) -> { name: 'autoincrement' } (object)\n * @default(dbgenerated(..)) -> { name: 'dbgenerated', ... } (object)\n * @default(true) -> true (primitive)\n * @default(0) -> 0 (primitive)\n * @default(\"USER\") -> \"USER\" (primitive)\n *\n * So a function default is an object carrying `name`; a literal default is a\n * primitive. Treating \"has a default\" as \"generated\" would wrongly lock\n * `active Boolean @default(true)` out of every create form.\n */\nfunction isFunctionDefault(value: unknown): value is { name: string; args?: unknown[] } {\n return typeof value === 'object' && value !== null && !Array.isArray(value) && 'name' in value\n}\n\nfunction toFieldMetadata(\n field: DMMF.Field,\n enums: ReadonlyMap<string, readonly string[]>,\n): FieldMetadata {\n const kind = toFieldKind(field)\n\n // A value the database or ORM supplies: a function default, or @updatedAt.\n const isGenerated = field.isUpdatedAt === true || isFunctionDefault(field.default)\n\n // A literal default is a pre-fill for the create form, not a generated value.\n const hasLiteralDefault = field.hasDefaultValue === true && !isFunctionDefault(field.default)\n\n const base = {\n name: field.name,\n kind,\n isId: field.isId === true,\n isRequired: field.isRequired === true,\n isUnique: field.isUnique === true,\n isList: field.isList === true,\n isGenerated,\n } satisfies Omit<FieldMetadata, 'defaultValue' | 'enumValues' | 'relation'>\n\n return {\n ...base,\n ...(hasLiteralDefault ? { defaultValue: field.default } : {}),\n ...(kind === 'enum' ? { enumValues: enums.get(field.type) ?? [] } : {}),\n ...(kind === 'relation'\n ? {\n relation: {\n targetModel: field.type,\n // Cardinality follows directly from isList - the single attribute\n // the generated Prisma Client does not expose at runtime, which is\n // why metadata comes from the schema rather than the client.\n cardinality: field.isList === true ? ('many' as const) : ('one' as const),\n // Present only on the owning side of a to-one relation. Prisma\n // gives both sides a relation field but only one of them a column,\n // and these arrays are empty on the side that has none - so an\n // empty array means \"no foreign key here\", not \"unknown\".\n ...(field.relationFromFields?.[0] !== undefined\n ? { from: field.relationFromFields[0] }\n : {}),\n ...(field.relationToFields?.[0] !== undefined ? { to: field.relationToFields[0] } : {}),\n // Shared by both halves, so the other side can be found. Prisma\n // generates one when the schema does not name it.\n ...(field.relationName !== undefined ? { name: field.relationName } : {}),\n },\n }\n : {}),\n }\n}\n\n/**\n * Field names forming the model's primary key.\n *\n * Prisma expresses a single-column key as `@id` on the field and a composite\n * key as a model-level `@@id`, which DMMF surfaces as `primaryKey.fields`.\n * Both are represented here; the adapter is what limits the MVP to\n * single-column keys.\n */\nfunction toPrimaryKey(model: DMMF.Model): readonly string[] {\n const compositeFields = model.primaryKey?.fields\n if (compositeFields && compositeFields.length > 0) return [...compositeFields]\n return model.fields.filter((field) => field.isId === true).map((field) => field.name)\n}\n\n/** Translate a whole DMMF document into Core model metadata. */\nexport function toModelMetadata(dmmf: DMMF.Document): readonly ModelMetadata[] {\n const enums = new Map<string, readonly string[]>(\n dmmf.datamodel.enums.map((enumType) => [\n enumType.name,\n enumType.values.map((value) => value.name),\n ]),\n )\n\n return dmmf.datamodel.models.map((model) => ({\n name: model.name,\n primaryKey: toPrimaryKey(model),\n fields: model.fields.map((field) => toFieldMetadata(field, enums)),\n }))\n}\n","/**\n * Loading the readable side of a to-one relation.\n *\n * A record stores `authorId`. A person needs \"Ada Lovelace\". Resolving that in\n * the caller would mean one query per row - the classic N+1 - so it is done in\n * the same query, with an `include`.\n *\n * ## Only two columns are ever selected\n *\n * The `include` carries an explicit `select` of the target's primary key and\n * its display field, and nothing else. That is a security boundary, not an\n * optimisation: `include: { author: true }` would attach the *whole* related\n * record to every row, so a `User.passwordHash` would be published by the act\n * of listing `Post`. Naming the two columns means a relation can never widen\n * what a response contains.\n *\n * To-many relations are not loaded. They have no column on this side, they can\n * be unbounded, and one `include` per row would turn a list page into an\n * unpredictable amount of work. They arrive in 0.4.0, paginated and asked for\n * explicitly.\n */\nimport { displayFieldFor, type ModelMetadata } from '@nest-admin/core'\n\n/** A Prisma `include` clause, or `undefined` when the model has no to-one relations. */\nexport type IncludeClause = Record<string, { select: Record<string, true> }>\n\n/**\n * Build the `include` for every to-one relation the model owns.\n *\n * `models` is the full set, because the display field belongs to the *target*\n * model and can only be resolved by looking it up. A relation whose target is\n * missing from that set is skipped rather than guessed at: the target may have\n * been excluded from the admin by configuration, and inventing a column name\n * would produce a Prisma error blaming the schema.\n */\nexport function toIncludeClause(\n model: ModelMetadata,\n models: readonly ModelMetadata[],\n): IncludeClause | undefined {\n const include: IncludeClause = {}\n\n for (const field of model.fields) {\n const relation = field.relation\n // `from` is what distinguishes the owning side from the other one. Without\n // it there is no column here, so there is nothing to resolve.\n if (!relation || relation.cardinality !== 'one' || relation.from === undefined) continue\n\n const target = models.find((candidate) => candidate.name === relation.targetModel)\n if (!target) continue\n\n const select: Record<string, true> = {}\n for (const key of target.primaryKey) select[key] = true\n select[displayFieldFor(target)] = true\n\n include[field.name] = { select }\n }\n\n return Object.keys(include).length > 0 ? include : undefined\n}\n","/**\n * Prisma error codes -> Core constraint errors.\n *\n * Everything here exists so that an ordinary mistake in a form stops being\n * reported as an internal error. Before it, a duplicate email, a foreign key\n * pointing at nothing and a missing required value all came back as\n * \"an internal error occurred\" - the correct treatment for a broken database\n * and the wrong one for a person who typed the same address twice.\n *\n * ## Codes, not classes\n *\n * Matched by `code` rather than `instanceof PrismaClientKnownRequestError`, for\n * the reason the adapter already gives: importing `@prisma/client` here would\n * load a second copy of a package the consumer owns and tie this package to\n * their Prisma version.\n *\n * ## Field names come from `meta`, and may not be there\n *\n * Prisma reports the columns involved differently per code and per connector,\n * and sometimes not at all - a SQLite unique violation on a composite index\n * names the index rather than the columns. Where a name is missing the error\n * says so in general terms rather than inventing one, because a message that\n * blames the wrong field is worse than one that blames none.\n */\nimport { ConstraintError, type ConstraintKind } from '@nest-admin/core'\n\n/**\n * Measured against Prisma 7.10.0.\n *\n * `P2014` is the one worth naming: it fires when a *delete* would orphan a\n * required relation, so it is a foreign-key problem arriving from the opposite\n * direction to `P2003`.\n */\nconst CONSTRAINT_CODES: Readonly<Record<string, ConstraintKind>> = {\n P2002: 'unique',\n P2003: 'foreign-key',\n P2014: 'foreign-key',\n P2011: 'required',\n P2012: 'required',\n P2013: 'required',\n}\n\ninterface PrismaKnownError {\n readonly code: string\n readonly meta?: Readonly<Record<string, unknown>>\n}\n\nfunction isPrismaKnownError(value: unknown): value is PrismaKnownError {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'code' in value &&\n typeof (value as { code: unknown }).code === 'string'\n )\n}\n\n/**\n * The columns Prisma named, if it named any.\n *\n * The shape differs by code: `target` for a unique violation (a string or an\n * array, depending on the connector), `field_name` for a foreign key,\n * `constraint` for a null violation. Anything unrecognised yields nothing,\n * which the message handles.\n */\nfunction fieldsFrom(meta: Readonly<Record<string, unknown>> | undefined): readonly string[] {\n if (!meta) return []\n\n // Prisma 7 with a driver adapter nests the connector's own report, and that\n // is the only place the column names appear - `meta.target` is the older,\n // flatter shape and is still what a client without a driver adapter reports.\n // Both are read, because which one arrives depends on how the consumer built\n // their client rather than on anything this package controls.\n const nested = (meta['driverAdapterError'] as { cause?: { constraint?: unknown } } | undefined)\n ?.cause?.constraint\n\n const candidate =\n (nested as { fields?: unknown } | undefined)?.fields ??\n meta['target'] ??\n meta['field_name'] ??\n meta['constraint']\n\n if (Array.isArray(candidate)) {\n return candidate.filter((entry): entry is string => typeof entry === 'string')\n }\n\n if (typeof candidate !== 'string') return []\n\n // Some connectors report the index name rather than the columns -\n // `User_email_key` for `@unique` on `email`. The column is recoverable from\n // the convention, and a wrong guess here would name a field that does not\n // exist, so it is only trusted when the shape matches exactly.\n const index = /^(.+?)_(.+)_key$/.exec(candidate)\n if (index?.[2] !== undefined) return index[2].split('_')\n\n return [candidate]\n}\n\n/**\n * A missing required argument, which Prisma refuses before the database sees it.\n *\n * It arrives as `PrismaClientValidationError`, which carries **no code** - so\n * it cannot be matched the way every other case here is, and without special\n * handling a form submitted without a required field answers with a generic\n * 500.\n *\n * The message names the arguments in a fixed phrase, and that phrase is all\n * that is read from it. The rest of the text is a rendering of the call site\n * and of the data that was submitted - absolute paths and field values - so\n * forwarding any of it is out of the question.\n */\nfunction missingArguments(cause: unknown): readonly string[] {\n if (!(cause instanceof Error) || cause.constructor.name !== 'PrismaClientValidationError') {\n return []\n }\n\n const names: string[] = []\n for (const match of cause.message.matchAll(/Argument `([A-Za-z0-9_]+)` is missing/g)) {\n if (match[1] !== undefined) names.push(match[1])\n }\n\n return names\n}\n\n/**\n * A `ConstraintError` when Prisma refused the write for a reason a caller can\n * act on, or `undefined` when it did not.\n */\nexport function toConstraintError(cause: unknown, model: string): ConstraintError | undefined {\n const missing = missingArguments(cause)\n if (missing.length > 0) return new ConstraintError('required', model, missing)\n\n if (!isPrismaKnownError(cause)) return undefined\n\n const constraint = CONSTRAINT_CODES[cause.code]\n if (!constraint) return undefined\n\n return new ConstraintError(constraint, model, fieldsFrom(cause.meta))\n}\n","/**\n * An id, in the type the schema declares.\n *\n * Ids reach the adapter from a URL, so they are always strings. Prisma refuses\n * a string for an `Int @id` - `Expected IntFilter or Int, provided String` -\n * rather than coercing it, which is the right call for a query builder and\n * leaves the conversion to whoever knows the schema. That is this package.\n *\n * ## Why this is its own module\n *\n * It used to be a private method on the adapter, called from the one place that\n * built a `where` clause by primary key. Two other places also turn an id into\n * a Prisma argument - the parent id in a related-list filter, and the target id\n * in a connect/disconnect - and neither of them could reach a private method,\n * so neither of them converted anything. Every relation route worked against a\n * string-keyed model and failed against an integer-keyed one.\n *\n * Being a module makes it reachable from all three, and makes the rule\n * testable on its own. Being called at each point where a value becomes a\n * Prisma argument - rather than once at the entrance - is deliberate: that is\n * where the mistake was made, so that is where the guard belongs.\n */\nimport { InvalidQueryError, type ModelMetadata, type RecordId } from '@nest-admin/core'\n\n/**\n * Convert `id` to the type `model.fieldName` is declared as.\n *\n * Only numeric keys need anything done. A value that is already a number is\n * returned unchanged, so calling this twice is harmless - which matters,\n * because the paths below overlap.\n */\nexport function coerceId(model: ModelMetadata, fieldName: string, id: RecordId): RecordId {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (field?.kind !== 'number' || typeof id === 'number') return id\n\n const numeric = Number(id)\n if (!Number.isFinite(numeric)) {\n // Refused rather than passed through. Prisma would refuse it too, but with\n // a message about its own argument types rather than about the id someone\n // put in a URL.\n throw new InvalidQueryError(\n `Invalid id ${JSON.stringify(id)} for numeric primary key \"${model.name}.${fieldName}\".`,\n )\n }\n\n return numeric\n}\n\n/**\n * The same, against whatever `model` uses as its primary key.\n *\n * Returns the id untouched when the model has no single primary key: the\n * callers that care raise their own, better-worded error for that, and this\n * one should not pre-empt them.\n */\nexport function coercePrimaryKey(model: ModelMetadata, id: RecordId): RecordId {\n const [primaryKey, ...rest] = model.primaryKey\n if (primaryKey === undefined || rest.length > 0) return id\n return coerceId(model, primaryKey, id)\n}\n","/**\n * Asking the target model for the records linked to one parent.\n *\n * A related list could be fetched from the parent - `user.posts()` - but then\n * pagination, sorting, filtering and relation loading would all have to be\n * reimplemented for that path. Asking the *target* model with an extra `where`\n * instead means a related list is an ordinary list that happens to be\n * constrained, and everything already built for lists applies to it unchanged.\n *\n * The constraint is expressed through the relation's other half, which is why\n * relation names matter:\n *\n * User.posts -> inverse is Post.author (to-one) -> { author: { id: <parent> } }\n * Post.tags -> inverse is Tag.posts (to-many) -> { posts: { some: { id: <parent> } } }\n *\n * Both are Prisma relation filters on the target, so neither needs to know\n * whether a foreign key exists or where it lives.\n */\nimport {\n FieldNotFoundError,\n inverseRelationField,\n type ModelMetadata,\n type RecordId,\n} from '@nest-admin/core'\n\nimport { coerceId } from './coerce-id.js'\n\n/**\n * A `where` clause selecting the target records linked to `parentId`.\n *\n * `parentKey` is the parent's primary-key field, which the filter matches on.\n */\nexport function toRelatedWhere(\n parent: ModelMetadata,\n relationFieldName: string,\n parentId: RecordId,\n models: readonly ModelMetadata[],\n): { target: ModelMetadata; where: Record<string, unknown> } {\n const field = parent.fields.find((candidate) => candidate.name === relationFieldName)\n\n if (!field?.relation) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'Only a relation field can be listed this way.',\n )\n }\n\n if (field.relation.cardinality !== 'many') {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'This is a to-one relation. It arrives with the record itself.',\n )\n }\n\n const target = models.find((candidate) => candidate.name === field.relation?.targetModel)\n if (!target) {\n // The target is not part of this admin - excluded by configuration, or\n // hidden from this principal. Either way there is nothing to list.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${field.relation.targetModel} is not available.`,\n )\n }\n\n const inverse = inverseRelationField(field, models)\n if (!inverse) {\n // Without the other half there is no way to express the constraint, and\n // returning every record of the target would be catastrophically wrong.\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n 'The other half of this relation could not be resolved.',\n )\n }\n\n const [parentKey] = parent.primaryKey\n if (parentKey === undefined) {\n throw new FieldNotFoundError(\n parent.name,\n relationFieldName,\n `${parent.name} has no primary key.`,\n )\n }\n\n // Coerced here rather than by the caller, because this is the line that\n // turns an id into a Prisma argument. A string against an `Int @id` is\n // refused by Prisma with a message about its own argument types.\n const match = { [parentKey]: coerceId(parent, parentKey, parentId) }\n\n return {\n target,\n where: {\n [inverse.name]: inverse.relation?.cardinality === 'many' ? { some: match } : { is: match },\n },\n }\n}\n","/**\n * Core `ListQuery` -> Prisma `findMany` arguments.\n *\n * Everything here is validated against model metadata before it reaches the\n * client. Field names arriving from an HTTP request eventually flow into this\n * module, so an unvalidated name would become an injection surface into the\n * query object. There is no raw SQL anywhere; all queries go through Prisma's\n * structured API.\n */\nimport {\n FieldNotFoundError,\n InvalidQueryError,\n type FieldMetadata,\n type FilterRule,\n type ListQuery,\n type ModelMetadata,\n} from '@nest-admin/core'\n\nexport const DEFAULT_PER_PAGE = 25\nexport const MAX_PER_PAGE = 100\n\n/** Operators that only make sense on string fields. */\nconst STRING_ONLY_OPERATORS = new Set(['contains', 'startsWith', 'endsWith'])\n\n/** Operators that require an ordered (numeric, date, or string) field. */\nconst COMPARISON_OPERATORS = new Set(['gt', 'gte', 'lt', 'lte'])\n\nexport interface PrismaFindManyArgs {\n where?: Record<string, unknown>\n orderBy?: Array<Record<string, 'asc' | 'desc'>>\n skip?: number\n take?: number\n}\n\n/**\n * What the field is being resolved for.\n *\n * Only relations care, and they care because the two cases are not symmetric.\n * See {@link findQueryableField}.\n */\ntype QueryPurpose = 'filter' | 'sort'\n\n/**\n * A field usable in a filter or a sort.\n *\n * A to-one relation the model owns is stored in a scalar column, so a **filter**\n * on `author` is answerable: it means exactly a filter on `authorId`, and the\n * caller gets to use whichever name they think in.\n *\n * **Sorting** by it is refused, even though it would run. `authorId` holds a\n * cuid, so ordering by it is ordering by a random-looking string - a result\n * that looks sorted, is stable, and means nothing. What someone asking to sort\n * by `author` wants is the author's *name*, which is sorting by a field on\n * another model and is not this version. A refusal that says so is better than\n * a page of rows in an order nobody can explain.\n *\n * List fields are excluded outright: there is no column on this side at all.\n */\nfunction findQueryableField(\n model: ModelMetadata,\n fieldName: string,\n purpose: QueryPurpose,\n): FieldMetadata {\n const field = model.fields.find((candidate) => candidate.name === fieldName)\n if (!field) {\n throw new FieldNotFoundError(model.name, fieldName)\n }\n if (field.kind === 'relation') {\n const owned = field.relation?.from\n if (owned !== undefined && field.relation?.cardinality === 'one') {\n if (purpose === 'filter') return findQueryableField(model, owned, purpose)\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n `Sorting by a relation is not supported in this version. ` +\n `Sorting by \"${owned}\" would order by an opaque key rather than by ` +\n `anything readable.`,\n )\n }\n\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'Relation fields cannot be filtered or sorted in this version.',\n )\n }\n if (field.isList) {\n throw new FieldNotFoundError(\n model.name,\n fieldName,\n 'List fields cannot be filtered or sorted in this version.',\n )\n }\n return field\n}\n\nfunction toPrismaCondition(model: ModelMetadata, rule: FilterRule): Record<string, unknown> {\n const field = findQueryableField(model, rule.field, 'filter')\n\n if (STRING_ONLY_OPERATORS.has(rule.operator) && field.kind !== 'string') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" requires a string field, but ` +\n `\"${model.name}.${field.name}\" is of kind \"${field.kind}\".`,\n )\n }\n\n if (COMPARISON_OPERATORS.has(rule.operator) && field.kind === 'boolean') {\n throw new InvalidQueryError(\n `Operator \"${rule.operator}\" cannot be applied to boolean field ` +\n `\"${model.name}.${field.name}\".`,\n )\n }\n\n if (rule.operator === 'in') {\n if (!Array.isArray(rule.value)) {\n throw new InvalidQueryError(\n `Operator \"in\" requires an array value for \"${model.name}.${field.name}\".`,\n )\n }\n return { [field.name]: { in: rule.value } }\n }\n\n if (rule.operator === 'eq') return { [field.name]: { equals: rule.value } }\n if (rule.operator === 'ne') return { [field.name]: { not: rule.value } }\n\n return { [field.name]: { [rule.operator]: rule.value } }\n}\n\n/**\n * Providers where Prisma accepts `mode: 'insensitive'`.\n *\n * The list is short because Prisma *throws* on the others rather than ignoring\n * the option, so being wrong here breaks every search rather than degrading it.\n *\n * The omissions are deliberate, not oversights:\n *\n * | Provider | Why nothing is sent |\n * | ---------- | ---------------------------------------------------------- |\n * | mysql | Its default collations end in `_ci`; `LIKE` already ignores case. |\n * | sqlite | `LIKE` is case-insensitive for ASCII by default. |\n * | sqlserver | Its default collation is case-insensitive. |\n * | cockroachdb | Prisma documents `mode` for PostgreSQL and MongoDB only. |\n *\n * So on the four below, the option is unnecessary; on CockroachDB it is\n * unproven, and this is not the place to guess.\n */\nconst INSENSITIVE_MODE_PROVIDERS: ReadonlySet<string> = new Set([\n 'postgresql',\n 'postgres',\n 'mongodb',\n])\n\n/**\n * The case-insensitivity option for this provider, if it takes one.\n *\n * Spread into every string comparison. Returning an object to spread rather\n * than a boolean to branch on keeps the option out of the query entirely where\n * it is not supported - Prisma rejects `mode: undefined` as readily as it\n * rejects `mode: 'insensitive'` on SQLite.\n */\nexport function insensitively(provider: string | undefined): { mode?: 'insensitive' } {\n return provider !== undefined && INSENSITIVE_MODE_PROVIDERS.has(provider)\n ? { mode: 'insensitive' }\n : {}\n}\n\n/** String comparisons, which are the ones capitalisation applies to. */\nconst TEXTUAL_OPERATORS: ReadonlySet<string> = new Set(['contains', 'startsWith', 'endsWith'])\n\n/**\n * Free-text search: `contains` across the model's meaningful string fields.\n *\n * Generated string fields are excluded. A `cuid()` or `uuid()` primary key is\n * an opaque machine value, and including it makes single-letter searches match\n * essentially at random - searching \"e\" returns any record whose id happens to\n * contain an \"e\". Looking a record up by its id is an exact-match concern, so\n * it belongs in a filter (`{ field: 'id', operator: 'eq' }`), not in free text.\n *\n * Capitalisation is ignored, which needed the provider to say so. Searching\n * \"ada\" and getting nothing because the record says \"Ada\" is the kind of defect\n * people conclude the search is broken from, and they are not wrong. What it\n * takes to ignore case differs per database, and on some of them the option\n * that does it is an error - hence `insensitively`.\n */\nfunction toSearchCondition(\n model: ModelMetadata,\n term: string,\n provider: string | undefined,\n): Record<string, unknown> | undefined {\n // Foreign keys are string columns holding a cuid, so they match the same\n // rule the generated-id exclusion exists for - and they are not generated,\n // so that rule misses them. Left in, a search for \"e\" matches almost every\n // row of any model that references another, because most cuids contain an e.\n const foreignKeys = new Set(\n model.fields.map((field) => field.relation?.from).filter((name) => name !== undefined),\n )\n\n const stringFields = model.fields.filter(\n (field) =>\n field.kind === 'string' &&\n !field.isList &&\n !field.isGenerated &&\n !foreignKeys.has(field.name),\n )\n if (stringFields.length === 0) return undefined\n\n return {\n OR: stringFields.map((field) => ({\n [field.name]: { contains: term, ...insensitively(provider) },\n })),\n }\n}\n\nexport function buildWhere(\n model: ModelMetadata,\n query: Pick<ListQuery, 'filters' | 'search'>,\n provider?: string,\n): Record<string, unknown> | undefined {\n const conditions: Array<Record<string, unknown>> = []\n\n for (const rule of query.filters ?? []) {\n const condition = toPrismaCondition(model, rule)\n // A \"contains\" filter is the same promise the search box makes, typed into\n // a different box. It would be strange for one to ignore case and not the\n // other, and stranger still to have to know which.\n conditions.push(\n TEXTUAL_OPERATORS.has(rule.operator) ? insensitive(condition, provider) : condition,\n )\n }\n\n const search = query.search?.trim()\n if (search) {\n const searchCondition = toSearchCondition(model, search, provider)\n if (searchCondition) conditions.push(searchCondition)\n }\n\n if (conditions.length === 0) return undefined\n if (conditions.length === 1) return conditions[0]\n return { AND: conditions }\n}\n\nfunction buildOrderBy(\n model: ModelMetadata,\n query: Pick<ListQuery, 'sort'>,\n): Array<Record<string, 'asc' | 'desc'>> | undefined {\n const rules = query.sort ?? []\n if (rules.length === 0) return undefined\n\n return rules.map((rule) => {\n const field = findQueryableField(model, rule.field, 'sort')\n return { [field.name]: rule.direction }\n })\n}\n\n/** Normalised, clamped pagination. Page numbers are 1-based. */\nexport function resolvePagination(query: Pick<ListQuery, 'page' | 'perPage'>): {\n page: number\n perPage: number\n skip: number\n take: number\n} {\n const rawPage = query.page ?? 1\n if (!Number.isInteger(rawPage) || rawPage < 1) {\n throw new InvalidQueryError(\n `\"page\" must be an integer >= 1, received ${JSON.stringify(query.page)}.`,\n )\n }\n\n const rawPerPage = query.perPage ?? DEFAULT_PER_PAGE\n if (!Number.isInteger(rawPerPage) || rawPerPage < 1) {\n throw new InvalidQueryError(\n `\"perPage\" must be an integer >= 1, received ${JSON.stringify(query.perPage)}.`,\n )\n }\n\n // Clamped rather than rejected: a UI asking for too much should get a\n // capped page, not an error.\n const perPage = Math.min(rawPerPage, MAX_PER_PAGE)\n return { page: rawPage, perPage, skip: (rawPage - 1) * perPage, take: perPage }\n}\n\n/**\n * The same condition, told to ignore case.\n *\n * A condition is `{ field: { operator: value } }`, and the option belongs\n * beside the operator rather than beside the field, so it cannot simply be\n * spread at the top level.\n */\nfunction insensitive(\n condition: Record<string, unknown>,\n provider: string | undefined,\n): Record<string, unknown> {\n const mode = insensitively(provider)\n if (mode.mode === undefined) return condition\n\n const entries = Object.entries(condition).map(([field, comparison]) => [\n field,\n typeof comparison === 'object' && comparison !== null\n ? { ...(comparison as Record<string, unknown>), ...mode }\n : comparison,\n ])\n return Object.fromEntries(entries) as Record<string, unknown>\n}\n\nexport function toFindManyArgs(\n model: ModelMetadata,\n query: ListQuery,\n provider?: string,\n): PrismaFindManyArgs {\n const { skip, take } = resolvePagination(query)\n const where = buildWhere(model, query, provider)\n const orderBy = buildOrderBy(model, query)\n\n return {\n ...(where ? { where } : {}),\n ...(orderBy ? { orderBy } : {}),\n skip,\n take,\n }\n}\n","/**\n * Admin accounts, in Prisma.\n *\n * ## A model of its own\n *\n * The default is `AdminAccount`, and that default is the design rather than a\n * placeholder. The people who administer a system are usually not rows in the\n * table they administer, and pointing this at the application's `User` would\n * mean every customer record carries a password that opens the admin - which is\n * a decision nobody makes on purpose and several people make by accident.\n *\n * The model name is configurable because some applications already have a\n * `Staff` or an `Operator`. Pointing it at `User` is possible and is a choice,\n * not a default.\n *\n * ## What it does not do\n *\n * Create, update, delete. The store contract is read-only, and this implements\n * only what it declares: an admin that could mint its own administrators is an\n * escalation waiting for its first mistake in a policy. Seeding the first\n * account is the application's job, with `hashAdminPassword`.\n *\n * ## The account model should not be a resource\n *\n * Nothing here can arrange that - which models the admin exposes is the\n * module's business - so it is the one thing a consumer has to remember:\n *\n * ```ts\n * resources: { exclude: ['AdminAccount'] }\n * ```\n *\n * Without it, anyone who may edit that model can grant themselves whatever the\n * admin can do. `builtInAuth` warns at startup when it sees the account model\n * among the exposed resources.\n */\nimport type { AdminAccount, AdminAccountStore } from '@nest-admin/core'\n\nimport { resolveDelegate } from '../client/delegate.js'\n\nexport interface PrismaAccountStoreOptions {\n /** A constructed Prisma Client - the same one the adapter is given. */\n readonly client: unknown\n\n /** The model holding admin accounts. `AdminAccount` by default. */\n readonly model?: string\n\n /**\n * Column names, where they differ from the defaults.\n *\n * A mapping rather than a required schema: an application that already has a\n * `Staff` table with `login` and `hash` should not have to migrate it to use\n * this.\n */\n readonly fields?: {\n readonly id?: string\n readonly email?: string\n readonly name?: string\n readonly passwordHash?: string\n readonly disabled?: string\n /** Written on a successful sign-in, when the column exists. */\n readonly lastLoginAt?: string\n }\n}\n\nconst DEFAULTS = {\n id: 'id',\n email: 'email',\n name: 'name',\n passwordHash: 'passwordHash',\n disabled: 'disabled',\n lastLoginAt: 'lastLoginAt',\n} as const\n\nexport function prismaAccountStore(options: PrismaAccountStoreOptions): AdminAccountStore {\n const model = options.model ?? 'AdminAccount'\n const column = { ...DEFAULTS, ...options.fields }\n\n /*\n * The allowlist is the one configured name.\n *\n * `resolveDelegate` takes a list because the adapter resolves a model named\n * by a *request*, where an allowlist is the whole defence. Here the name\n * comes from the application's own configuration and there is nothing to\n * defend against - but passing it anyway keeps the property-name guard\n * inside `resolveDelegate`, which is the part that still matters, and gives\n * a clear error rather than `undefined.findMany is not a function` when the\n * model does not exist.\n */\n const delegate = () => resolveDelegate(options.client, model, [model])\n\n /**\n * A row as the contract describes it.\n *\n * Returns `null` for a row with no usable hash rather than an account that\n * can never sign in. The difference matters at the point of use: a `null`\n * takes the same path as an unknown email, and an account object with an\n * empty hash would be compared against and fail in a way that takes a\n * measurably different amount of time.\n */\n const toAccount = (row: unknown): AdminAccount | null => {\n if (typeof row !== 'object' || row === null) return null\n const record = row as Record<string, unknown>\n\n const id = record[column.id]\n const email = record[column.email]\n const hash = record[column.passwordHash]\n\n if (typeof id !== 'string' && typeof id !== 'number') return null\n if (typeof email !== 'string') return null\n if (typeof hash !== 'string' || hash === '') return null\n\n const name = record[column.name]\n const disabled = record[column.disabled]\n\n return {\n id: String(id),\n email,\n passwordHash: hash,\n ...(typeof name === 'string' && name !== '' ? { name } : {}),\n ...(typeof disabled === 'boolean' ? { disabled } : {}),\n }\n }\n\n return {\n describes: model,\n\n async findByEmail(email) {\n /*\n * `findFirst`, not `findUnique`.\n *\n * The email column is very likely unique, and this store cannot know\n * that - a consumer mapping it onto an existing table may have it\n * indexed and not constrained. `findUnique` throws on a column Prisma\n * does not consider unique, which would turn a schema difference into a\n * 500 on the login route.\n */\n const rows = await delegate().findMany({\n where: { [column.email]: email },\n take: 1,\n })\n return toAccount(rows[0])\n },\n\n async findById(id) {\n const rows = await delegate().findMany({ where: { [column.id]: id }, take: 1 })\n return toAccount(rows[0])\n },\n\n async count() {\n return delegate().count()\n },\n\n async recordLogin(id) {\n // Best effort. A store mapped onto a table without this column should\n // not turn a successful sign-in into a failure, and the caller already\n // treats a rejection here as something to log rather than to surface.\n await delegate().update({\n where: { [column.id]: id },\n data: { [column.lastLoginAt]: new Date() },\n })\n },\n }\n}\n"],"mappings":"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","names":["NestAdminError","AdapterError","FieldNotFoundError","InvalidQueryError","ModelNotFoundError","isNestAdminError"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-admin/nestjs",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "NestJS integration for Nest Admin. This is the single package published to npm.",
5
5
  "keywords": [
6
6
  "nestjs",