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.
- package/CHANGELOG.md +45 -0
- package/README.md +41 -1
- package/RELEASE.md +4 -0
- package/dist/adapter-prisma.d.ts +1 -1
- package/dist/adapter-prisma.js +1 -1
- package/dist/adapters/prisma.d.ts +5 -0
- package/dist/adapters/prisma.js +125 -0
- package/dist/auth.d.ts +3 -3
- package/dist/auth.js +1 -1
- package/dist/core/ports/user.repo.d.ts +2 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/modules/auth/auth.controller.js +73 -1
- package/dist/modules/auth/auth.schemas.d.ts +35 -0
- package/dist/modules/auth/auth.schemas.js +13 -0
- package/dist/modules/auth/auth.service.d.ts +19 -1
- package/dist/modules/auth/auth.service.js +219 -8
- package/dist/modules/auth/auth.types.d.ts +130 -1
- package/dist/modules/user/user.types.d.ts +1 -0
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +1 -1
- package/dist/utils/jwt.d.ts +2 -0
- package/docs/auth-extensions.md +120 -0
- package/docs/github-self-hosted-runner.md +76 -0
- package/docs/migration-v2.md +131 -0
- package/examples/express-prisma/prisma/schema.prisma +69 -8
- package/package.json +5 -5
- package/prisma/schema.prisma +69 -8
- package/prisma.config.ts +6 -0
|
@@ -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
|
|
12
|
-
email
|
|
13
|
-
passwordHash
|
|
14
|
-
name
|
|
15
|
-
role
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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.
|
|
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",
|
package/prisma/schema.prisma
CHANGED
|
@@ -8,14 +8,19 @@ datasource db {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
model User {
|
|
11
|
-
id
|
|
12
|
-
email
|
|
13
|
-
passwordHash
|
|
14
|
-
name
|
|
15
|
-
role
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|