my-crud-lib 2.0.0 → 2.1.0

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.
@@ -0,0 +1,131 @@
1
+ # Migrating to v2
2
+
3
+ Version 2 changed the package from a Prisma-coupled helper into an adapter-driven library. Existing apps should update route setup and imports before upgrading.
4
+
5
+ ## What changed
6
+
7
+ - Auth no longer creates its own Prisma dependency. Pass a `userRepo` into auth or library factories.
8
+ - `createLibrary()` now separates route config from dependencies.
9
+ - Self-registration now creates `USER` accounts by default.
10
+ - Public imports should use documented package entry points only.
11
+
12
+ ## Auth router
13
+
14
+ Before v2, apps could mount auth without passing persistence explicitly:
15
+
16
+ ```ts
17
+ import { createAuthRouter } from "my-crud-lib";
18
+
19
+ app.use("/auth", createAuthRouter());
20
+ ```
21
+
22
+ In v2, create or import a repository adapter and pass it to the router:
23
+
24
+ ```ts
25
+ import { PrismaClient } from "@prisma/client";
26
+ import { createAuthRouter } from "my-crud-lib/auth";
27
+ import { makePrismaUserRepo } from "my-crud-lib/adapter-prisma";
28
+
29
+ const prisma = new PrismaClient();
30
+ const userRepo = makePrismaUserRepo(prisma);
31
+
32
+ app.use("/auth", createAuthRouter({ userRepo }));
33
+ ```
34
+
35
+ ## Full library mount
36
+
37
+ Before:
38
+
39
+ ```ts
40
+ import { createLibrary } from "my-crud-lib";
41
+
42
+ const lib = createLibrary({ routesPrefix: "/api" });
43
+ app.use(lib.router);
44
+ ```
45
+
46
+ After:
47
+
48
+ ```ts
49
+ import { PrismaClient } from "@prisma/client";
50
+ import { createLibrary } from "my-crud-lib";
51
+ import { makePrismaUserRepo } from "my-crud-lib/adapter-prisma";
52
+
53
+ const prisma = new PrismaClient();
54
+ const userRepo = makePrismaUserRepo(prisma);
55
+
56
+ const lib = createLibrary(
57
+ {
58
+ routesPrefix: "/api",
59
+ auth: {
60
+ passwordHashRounds: 10,
61
+ },
62
+ },
63
+ { userRepo }
64
+ );
65
+
66
+ app.use(lib.router);
67
+ ```
68
+
69
+ ## Custom adapters
70
+
71
+ Apps that do not use Prisma can implement `UserRepo` directly:
72
+
73
+ ```ts
74
+ import type { UserRepo } from "my-crud-lib/user";
75
+
76
+ const userRepo: UserRepo = {
77
+ async count() {
78
+ return 0;
79
+ },
80
+ async findMany() {
81
+ return [];
82
+ },
83
+ async findById(id) {
84
+ return null;
85
+ },
86
+ async findByEmail(email) {
87
+ return null;
88
+ },
89
+ async create(input) {
90
+ throw new Error("Implement user creation");
91
+ },
92
+ async update(id, input) {
93
+ throw new Error("Implement user update");
94
+ },
95
+ async delete(id) {},
96
+ async updateMe(userId, input) {
97
+ throw new Error("Implement profile update");
98
+ },
99
+ };
100
+ ```
101
+
102
+ ## Import paths
103
+
104
+ Use these public paths:
105
+
106
+ ```ts
107
+ import { createLibrary, createServer, mountDefaultRoutes } from "my-crud-lib";
108
+ import { createAuthRouter, makeAuthService } from "my-crud-lib/auth";
109
+ import { createUserRouter, type UserRepo } from "my-crud-lib/user";
110
+ import { registerSchema, listUsersQuerySchema } from "my-crud-lib/schemas";
111
+ import { isAuth, hasRole } from "my-crud-lib/middleware";
112
+ import { makePrismaUserRepo } from "my-crud-lib/adapter-prisma";
113
+ ```
114
+
115
+ Avoid importing from `dist` or internal `modules/*` paths. Those files are implementation details.
116
+
117
+ ## Role defaults
118
+
119
+ Self-registration now resolves to `USER` unless you explicitly configure a different role:
120
+
121
+ ```ts
122
+ app.use(
123
+ "/auth",
124
+ createAuthRouter({
125
+ userRepo,
126
+ defaultRegisterRole: "USER",
127
+ })
128
+ );
129
+ ```
130
+
131
+ Create admin users through your own seed script, internal admin workflow, or controlled provisioning path.
@@ -8,14 +8,19 @@ datasource db {
8
8
  }
9
9
 
10
10
  model User {
11
- id Int @id @default(autoincrement())
12
- email String @unique
13
- passwordHash String
14
- name String?
15
- role Role @default(USER)
16
- createdAt DateTime @default(now())
17
- updatedAt DateTime @updatedAt
18
- profile Profile?
11
+ id Int @id @default(autoincrement())
12
+ email String @unique
13
+ passwordHash String
14
+ name String?
15
+ role Role @default(USER)
16
+ emailVerifiedAt DateTime?
17
+ createdAt DateTime @default(now())
18
+ updatedAt DateTime @updatedAt
19
+ profile Profile?
20
+ refreshTokens RefreshToken[]
21
+ passwordResetTokens PasswordResetToken[]
22
+ emailVerificationTokens EmailVerificationToken[]
23
+ oauthAccounts OauthAccount[]
19
24
  }
20
25
 
21
26
  model Profile {
@@ -26,6 +31,62 @@ model Profile {
26
31
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
27
32
  }
28
33
 
34
+ model RefreshToken {
35
+ id String @id
36
+ userId Int
37
+ tokenHash String
38
+ familyId String
39
+ expiresAt DateTime
40
+ revokedAt DateTime?
41
+ replacedByTokenId String?
42
+ createdAt DateTime @default(now())
43
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
44
+
45
+ @@index([userId])
46
+ @@index([familyId])
47
+ }
48
+
49
+ model PasswordResetToken {
50
+ id String @id
51
+ userId Int
52
+ tokenHash String
53
+ expiresAt DateTime
54
+ usedAt DateTime?
55
+ revokedAt DateTime?
56
+ createdAt DateTime @default(now())
57
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
58
+
59
+ @@index([userId])
60
+ }
61
+
62
+ model EmailVerificationToken {
63
+ id String @id
64
+ userId Int
65
+ tokenHash String
66
+ expiresAt DateTime
67
+ usedAt DateTime?
68
+ revokedAt DateTime?
69
+ createdAt DateTime @default(now())
70
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
71
+
72
+ @@index([userId])
73
+ }
74
+
75
+ model OauthAccount {
76
+ id Int @id @default(autoincrement())
77
+ provider String
78
+ providerAccountId String
79
+ userId Int
80
+ email String?
81
+ createdAt DateTime @default(now())
82
+ updatedAt DateTime @updatedAt
83
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
84
+
85
+ @@unique([provider, providerAccountId])
86
+ @@index([userId])
87
+ @@map("OAuthAccount")
88
+ }
89
+
29
90
  enum Role {
30
91
  USER
31
92
  ADMIN
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-crud-lib",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "TypeScript auth and user/profile CRUD helpers for Express with Prisma and custom repository adapters",
5
5
  "license": "MIT",
6
6
  "author": "Riccardo Sensi",
@@ -60,18 +60,18 @@
60
60
  },
61
61
  "files": [
62
62
  "dist",
63
+ "docs",
63
64
  "examples",
65
+ "CHANGELOG.md",
64
66
  "README.md",
65
67
  "RELEASE.md",
66
68
  "LICENSE",
67
- "prisma/schema.prisma"
69
+ "prisma/schema.prisma",
70
+ "prisma.config.ts"
68
71
  ],
69
72
  "engines": {
70
73
  "node": ">=18.17"
71
74
  },
72
- "prisma": {
73
- "schema": "prisma/schema.prisma"
74
- },
75
75
  "scripts": {
76
76
  "prebuild": "node scripts/prisma-generate.mjs",
77
77
  "build": "tsc",
@@ -8,14 +8,19 @@ datasource db {
8
8
  }
9
9
 
10
10
  model User {
11
- id Int @id @default(autoincrement())
12
- email String @unique
13
- passwordHash String
14
- name String?
15
- role Role @default(USER)
16
- createdAt DateTime @default(now())
17
- updatedAt DateTime @updatedAt
18
- profile Profile?
11
+ id Int @id @default(autoincrement())
12
+ email String @unique
13
+ passwordHash String
14
+ name String?
15
+ role Role @default(USER)
16
+ emailVerifiedAt DateTime?
17
+ createdAt DateTime @default(now())
18
+ updatedAt DateTime @updatedAt
19
+ profile Profile?
20
+ refreshTokens RefreshToken[]
21
+ passwordResetTokens PasswordResetToken[]
22
+ emailVerificationTokens EmailVerificationToken[]
23
+ oauthAccounts OauthAccount[]
19
24
  }
20
25
 
21
26
  model Profile {
@@ -26,6 +31,62 @@ model Profile {
26
31
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
27
32
  }
28
33
 
34
+ model RefreshToken {
35
+ id String @id
36
+ userId Int
37
+ tokenHash String
38
+ familyId String
39
+ expiresAt DateTime
40
+ revokedAt DateTime?
41
+ replacedByTokenId String?
42
+ createdAt DateTime @default(now())
43
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
44
+
45
+ @@index([userId])
46
+ @@index([familyId])
47
+ }
48
+
49
+ model PasswordResetToken {
50
+ id String @id
51
+ userId Int
52
+ tokenHash String
53
+ expiresAt DateTime
54
+ usedAt DateTime?
55
+ revokedAt DateTime?
56
+ createdAt DateTime @default(now())
57
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
58
+
59
+ @@index([userId])
60
+ }
61
+
62
+ model EmailVerificationToken {
63
+ id String @id
64
+ userId Int
65
+ tokenHash String
66
+ expiresAt DateTime
67
+ usedAt DateTime?
68
+ revokedAt DateTime?
69
+ createdAt DateTime @default(now())
70
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
71
+
72
+ @@index([userId])
73
+ }
74
+
75
+ model OauthAccount {
76
+ id Int @id @default(autoincrement())
77
+ provider String
78
+ providerAccountId String
79
+ userId Int
80
+ email String?
81
+ createdAt DateTime @default(now())
82
+ updatedAt DateTime @updatedAt
83
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
84
+
85
+ @@unique([provider, providerAccountId])
86
+ @@index([userId])
87
+ @@map("OAuthAccount")
88
+ }
89
+
29
90
  enum Role {
30
91
  USER
31
92
  ADMIN
@@ -0,0 +1,6 @@
1
+ import 'dotenv/config';
2
+ import { defineConfig } from 'prisma/config';
3
+
4
+ export default defineConfig({
5
+ schema: 'prisma/schema.prisma',
6
+ });