@prismakit/cli 3.1.0 → 3.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismakit/cli",
3
- "version": "3.1.0",
3
+ "version": "3.2.1",
4
4
  "description": "CLI for PrismaKit — generate modules, validate compose, install agent skills",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {
@@ -28,11 +28,18 @@
28
28
  "LICENSE",
29
29
  "README.md"
30
30
  ],
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "test": "vitest run",
34
+ "typecheck": "tsc -p tsconfig.json --noEmit",
35
+ "lint": "tsc -p tsconfig.json --noEmit",
36
+ "clean": "rm -rf dist"
37
+ },
31
38
  "dependencies": {
32
- "@prismakit/core": "3.1.0"
39
+ "@prismakit/core": "workspace:*"
33
40
  },
34
41
  "peerDependencies": {
35
- "@prismakit/core": ">=3.1.0 <4"
42
+ "@prismakit/core": ">=3.2.0 <4"
36
43
  },
37
44
  "devDependencies": {
38
45
  "typescript": "^5.9.2",
@@ -56,12 +63,5 @@
56
63
  "prismakit",
57
64
  "cursor",
58
65
  "skills"
59
- ],
60
- "scripts": {
61
- "build": "tsup",
62
- "test": "vitest run",
63
- "typecheck": "tsc -p tsconfig.json --noEmit",
64
- "lint": "tsc -p tsconfig.json --noEmit",
65
- "clean": "rm -rf dist"
66
- }
67
- }
66
+ ]
67
+ }
@@ -52,8 +52,9 @@ Helpers may inject repositories — never the Prisma client.
52
52
  | Existence / uniqueness / auth | `getFirst` — **no** `setCache` |
53
53
  | List | `getMany` + `setCache: true` + optional `cacheTags` |
54
54
  | Paginated list | `getManyPaginate` |
55
- | Large / infinite list | `getManyCursor` |
55
+ | Large / infinite list | `getManyCursor` (with `cursor` → default `skip: 1`) |
56
56
  | Count / exists check | `count` / `exists` (no `setCache` on auth paths) |
57
+ | Composite PK row | `id: { a, b }` object — kit maps to Prisma `a_b: { a, b }` |
57
58
  | Aggregations | `aggregate` / `groupBy` |
58
59
  | Create / update / delete | matching mutation; default invalidation is enough outside tx |
59
60
  | Multi-step write | one transaction; pass `tx` into every repo call |
@@ -63,7 +64,7 @@ Helpers may inject repositories — never the Prisma client.
63
64
  ## Create a repository (core)
64
65
 
65
66
  ```typescript
66
- import { Prisma, PrismaClient } from '@prisma/client';
67
+ import { PrismaClient } from '@prisma/client';
67
68
  import { createRepository } from '@prismakit/core';
68
69
  import { RedisCacheAdapter } from '@prismakit/redis';
69
70
 
@@ -71,9 +72,8 @@ const DAY = 86_400;
71
72
 
72
73
  const UserRepoClass = createRepository({
73
74
  model: 'user',
74
- scalarFields: Prisma.UserScalarFieldEnum,
75
75
  cache: { ttl: DAY, nullTtl: 60, sensitiveFields: ['password'] },
76
- lock: true, // table + columns from Prisma meta
76
+ lock: true, // table + columns resolved from Prisma schema meta
77
77
  });
78
78
 
79
79
  const prisma = new PrismaClient();
@@ -83,14 +83,16 @@ export const users = new UserRepoClass({ prisma, cache });
83
83
 
84
84
  `defineRepository` and `createPrismaRepository` are aliases of `createRepository`.
85
85
 
86
+ **NestJS apps:** use `createDefineRepo` / `defineAppRepo` with app-wide cache defaults instead — see skill `prismakit-nestjs`.
87
+
86
88
  | Option | Description |
87
89
  |--------|-------------|
88
90
  | `model` | Prisma client key (`prisma.user` → `'user'`). Needed for cache + compose. |
89
- | `scalarFields` | Usually `Prisma.XScalarFieldEnum`. Enables select-split + compose. Optional if DMMF/schema meta is loaded. |
90
- | `cache` | `CacheOptions` or `true` `{ ttl: 86400, sensitiveFields: ['password'] }`. |
91
+ | `scalarFields` | Usually `Prisma.XScalarFieldEnum`. **Optional** when `schemaPath` / DMMF meta is loaded (default since 3.1). |
92
+ | `cache` | `CacheOptions` or `true` (uses app defaults when bound via `createDefineRepo`). |
91
93
  | `lock` | `true` / client key / `@@map` table / `{ tableName, columns }`. |
92
94
  | `primaryKey` | Override only. Defaults to schema `@id` / `@@id` (composite `string[]`) or `id`. |
93
- | `schemaPath` | Path to `schema.prisma` when meta is not loaded globally. |
95
+ | `schemaPath` | Path to `schema.prisma` when meta is not loaded globally. Default: `prisma/schema.prisma`. |
94
96
  | `getDelegate` | Optional. Defaults to `(c) => c[model]`. |
95
97
 
96
98
  Put files under `**/repositories/**`. Keep Prisma client construction under `**/infrastructure/prisma/**`.
@@ -124,7 +126,9 @@ await users.getFirst({
124
126
  | `count` / `exists` | `{ count }` / `{ exists }` |
125
127
  | `aggregate` / `groupBy` | Prisma delegate results |
126
128
 
127
- `id` is `string` or `Record<string, string>` for composite PKs.
129
+ `id` is `string` or `Record<string, string>` for composite PKs (object form for `@@id([a,b])`).
130
+
131
+ `getManyCursor`: when `cursor` is set, default `skip` is `1` so the cursor row is not repeated. Pass `skip: 0` only for inclusive semantics.
128
132
 
129
133
  ## Writes
130
134
 
@@ -234,6 +238,11 @@ export default [prismakit.configs.recommended];
234
238
 
235
239
  Allowed Prisma usage: `**/repositories/**`, `**/infrastructure/prisma/**`. Rules: `no-prisma-service-outside-repos`, `no-direct-prisma-delegate`, `require-transaction-service`, `require-cached-repo-provider`.
236
240
 
241
+ ## Observability
242
+
243
+ - Core: `setTelemetry({ enabled, onEvent })` or Nest `telemetry` / `queryLog.slowThreshold`.
244
+ - Optional: `@prismakit/opentelemetry` → `createPrismaKitTelemetry({ slowThreshold })`.
245
+
237
246
  ## Clean code
238
247
 
239
248
  - One repository per Prisma model, file `*.repository.ts` under `repositories/`.
@@ -241,6 +250,7 @@ Allowed Prisma usage: `**/repositories/**`, `**/infrastructure/prisma/**`. Rules
241
250
  - Named TTL constants (`const DAY = 86_400`), not magic numbers scattered in call sites.
242
251
  - Pass `tx` into **every** repo call in a unit of work. Do not mix cached reads with half-committed writes.
243
252
  - Tests: `@prismakit/memory` `MemoryCacheAdapter`. Production: `@prismakit/redis`.
253
+ - Library CI proves PG+Redis paths under `FORCE_INTEGRATION=1` (CRUD, compose, locks, stampede, fail-open).
244
254
 
245
255
  ## Anti-patterns (BAD → GOOD)
246
256
 
@@ -9,16 +9,18 @@ API surface for `@prismakit/core` 3.x. Read [SKILL.md](SKILL.md) first.
9
9
  | `@prismakit/core` | `createRepository`, AutoComposer, locks, pagination, `CacheAdapter` |
10
10
  | `@prismakit/redis` | `RedisCacheAdapter` |
11
11
  | `@prismakit/memory` | `MemoryCacheAdapter` (tests / local) |
12
+ | `@prismakit/opentelemetry` | Map telemetry → OTel metrics/spans |
12
13
  | `@prismakit/cli` | `prismakit generate / validate / skills` |
13
14
  | `@prismakit/eslint-plugin` | Repository-only data-access rules |
14
15
 
15
- Node ≥ 20. Install:
16
+ Node ≥ 20. Line **3.2.x**. Install:
16
17
 
17
18
  ```bash
18
19
  pnpm add @prismakit/core
19
20
  pnpm add @prismakit/redis ioredis # optional production cache
20
21
  pnpm add -D @prismakit/eslint-plugin @prismakit/cli
21
22
  # tests: pnpm add -D @prismakit/memory
23
+ # optional: pnpm add @prismakit/opentelemetry @opentelemetry/api
22
24
  ```
23
25
 
24
26
  ## Factory
@@ -40,7 +42,7 @@ Aliases: `defineRepository`, `createPrismaRepository`.
40
42
  | `cache` | `CacheOptions \| true` | `true` → `{ ttl: 86400, sensitiveFields: ['password'] }`. |
41
43
  | `lock` | `true \| string \| RepositoryLockConfig` | `true` / client key / Pascal name / `@@map` table. |
42
44
  | `schemaPath` | `string` | Lock/schema helpers when global meta is missing. |
43
- | `primaryKey` | `string \| string[]` | `*ById` + row locks. Default: meta PK or `id`. |
45
+ | `primaryKey` | `string \| string[]` | `*ById` + row locks. Default: meta PK or `id`. Composite → Prisma `a_b: { a, b }` where. |
44
46
  | `getDelegate` | `(client) => delegate` | Default `(c) => c[model]`. |
45
47
  | `toPayload` | `(data) => payload` | Default identity. Prefer typed factories over this. |
46
48
 
@@ -59,7 +61,7 @@ All methods accept optional `tx`. Cached repos also accept cache fields (see bel
59
61
  | `getFirst` | `where?`, `select?`, `lock?`, `setCache?`, `cacheTags?` | `T \| null` |
60
62
  | `getMany` | `where?`, `select?`, `orderBy?`, `take?`, `skip?`, `lock?`, `setCache?`, `cacheTags?` | `T[]` |
61
63
  | `getManyPaginate` | `where?`, `select?`, `orderBy?`, `page?`, `pageSize?`, `setCache?`, `cacheTags?` | `PaginatedResult<T>` |
62
- | `getManyCursor` | `where?`, `select?`, `orderBy?`, `cursor?`, `take?`, `skip?`, `setCache?`, `cacheTags?` | `CursorPage<T>` |
64
+ | `getManyCursor` | `where?`, `select?`, `orderBy?`, `cursor?`, `take?`, `skip?`, `setCache?`, `cacheTags?` | `CursorPage<T>`; with `cursor`, default `skip: 1` |
63
65
  | `count` | `where?`, `select?`, `setCache?`, `cacheTags?` | `{ count: number }` |
64
66
  | `exists` | `where?`, `setCache?`, `cacheTags?` | `{ exists: boolean }` |
65
67
  | `aggregate` | Prisma aggregate args + `setCache?`, `cacheTags?` | delegate result |
@@ -45,37 +45,65 @@ export class AppModule {}
45
45
 
46
46
  ## Factory (one default)
47
47
 
48
- Bind `Prisma.TypeMap` once, then define repos with runtime options only.
48
+ Bind `Prisma.TypeMap` once with app-wide cache defaults, then define repos with per-model overrides only.
49
49
 
50
50
  ```typescript
51
- // src/infrastructure/prisma/define-repo.ts
51
+ // src/infrastructure/prisma/define-app-repo.ts
52
52
  import { createDefineRepo } from '@prismakit/nestjs';
53
- import type { Prisma } from '@prisma/client';
53
+ import type { Prisma } from '@prisma/client'; // or generated client path
54
54
 
55
- export const defineRepo = createDefineRepo<Prisma.TypeMap>();
55
+ const DAY = 86_400;
56
+
57
+ export const defineAppRepo = createDefineRepo<Prisma.TypeMap>({
58
+ cache: {
59
+ ttl: DAY,
60
+ nullTtl: 60,
61
+ defaultSetCache: true,
62
+ },
63
+ });
56
64
  ```
57
65
 
58
66
  ```typescript
59
67
  // src/modules/users/repositories/user.repository.ts
60
- import { Prisma } from '@prisma/client';
61
- import { defineRepo } from '../../../infrastructure/prisma/define-repo';
62
-
63
- const DAY = 86_400;
68
+ import { defineAppRepo } from 'src/infrastructure/prisma/define-app-repo';
64
69
 
65
- export class UserRepository extends defineRepo({
70
+ export class UserRepository extends defineAppRepo({
66
71
  model: 'user',
67
- scalarFields: Prisma.UserScalarFieldEnum,
68
- cache: { ttl: DAY, nullTtl: 60, sensitiveFields: ['password'] },
69
- lock: true,
72
+ cache: {
73
+ defaultSetCache: false, // auth lookups pass setCache explicitly
74
+ sensitiveFields: ['password'],
75
+ methods: { getFirst: { enabled: false } },
76
+ },
70
77
  }) {}
71
78
  ```
72
79
 
80
+ ```typescript
81
+ // src/modules/category/repositories/category.repository.ts
82
+ import { defineAppRepo } from 'src/infrastructure/prisma/define-app-repo';
83
+
84
+ export class CategoryRepository extends defineAppRepo({
85
+ model: 'category',
86
+ cache: true, // inherits app-wide defaults (ttl, nullTtl, defaultSetCache)
87
+ }) {}
88
+ ```
89
+
90
+ ```typescript
91
+ // Uncached repo — TypeScript omits setCache / invalidateCache
92
+ import { defineAppRepo } from 'src/infrastructure/prisma/define-app-repo';
93
+
94
+ export class AuditLogRepository extends defineAppRepo({
95
+ model: 'auditLog',
96
+ }) {}
97
+ ```
98
+
99
+ `scalarFields` is **optional** when `schemaPath` or DMMF meta is loaded (default since 3.1). Omit it in new repos.
100
+
73
101
  Escape hatches (do not use as the app default):
74
102
 
75
103
  - `defineInjectableRepository` from `@prismakit/nestjs` (package alias `defineRepository`) — phantoms + payload HKT when TypeMap is unavailable.
76
104
  - `createInjectableRepository` without a types bag — thin, results are `unknown`. Alias: `createPrismaRepository`.
77
105
 
78
- Do not import `defineRepo` from `@prismakit/nestjs` in apps that already bind `createDefineRepo` as `defineRepo`.
106
+ Do not import `defineRepo` from `@prismakit/nestjs` in apps that already bind `createDefineRepo` as `defineAppRepo`.
79
107
 
80
108
  ## Register and inject
81
109
 
@@ -196,8 +224,8 @@ Repository `cache` is the source of truth. Omit `cacheModels` (fail-open). Pass
196
224
  | `validateCompose: true` | Assert compose-safe selects on boot |
197
225
  | `strictCachedRepos` | Fail boot if a `cache` repo class is not in Nest `providers` (default `true`) |
198
226
  | `compose` | `{ maxDepth, parallel, setCache }` |
199
- | `telemetry` | `{ enabled: true, onEvent }` |
200
- | `queryLog` | `{ slowThreshold, onSlowQuery }` — enables telemetry |
227
+ | `telemetry` | `{ enabled: true, onEvent }` or `createPrismaKitTelemetry()` from `@prismakit/opentelemetry` |
228
+ | `queryLog` | `{ slowThreshold, onSlowQuery }` — enables telemetry / `query.slow` |
201
229
  | `autoRegisterModels` | `true` or `string[]` — stub repos for compose-only models |
202
230
 
203
231
  ## Scaffolding
@@ -205,12 +233,15 @@ Repository `cache` is the source of truth. Omit `cacheModels` (fail-open). Pass
205
233
  ```bash
206
234
  npx prismakit generate product --cache
207
235
  npx prismakit generate product --cache --full --route products
236
+ npx prismakit skills # refresh .cursor/skills after upgrades
208
237
  ```
209
238
 
210
239
  Repo-only: add the class to feature `providers`. `--full`: import `*Module` in `AppModule`. Then `npx prismakit validate`.
211
240
 
212
241
  Enable ESLint `prismakit.configs.recommended` (see skill `prismakit`).
213
242
 
243
+ Reference app: [starter-prismakit-nestjs](https://github.com/fikiap23/starter-prismakit-nestjs) (Nest 11 + Prisma 7 + Redis).
244
+
214
245
  ## Clean code (Nest)
215
246
 
216
247
  - One `defineRepo` binder under `src/infrastructure/prisma/`. Do not call `createDefineRepo` per feature.