launchbase 1.2.1 → 1.2.2
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/bin/launchbase.js
CHANGED
|
@@ -7,7 +7,7 @@ const crypto = require('crypto');
|
|
|
7
7
|
const fs = require('fs-extra');
|
|
8
8
|
const { execSync, spawn } = require('child_process');
|
|
9
9
|
|
|
10
|
-
const VERSION = '1.2.
|
|
10
|
+
const VERSION = '1.2.2';
|
|
11
11
|
const program = new Command();
|
|
12
12
|
|
|
13
13
|
function findAvailablePort(startPort = 5432, maxAttempts = 100) {
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ export const api = axios.create({
|
|
|
14
14
|
api.interceptors.request.use((config) => {
|
|
15
15
|
const token = localStorage.getItem('accessToken')
|
|
16
16
|
const orgId = localStorage.getItem('currentOrgId')
|
|
17
|
+
const projectId = localStorage.getItem('currentProjectId')
|
|
17
18
|
|
|
18
19
|
if (token) {
|
|
19
20
|
config.headers.Authorization = `Bearer ${token}`
|
|
@@ -21,6 +22,9 @@ api.interceptors.request.use((config) => {
|
|
|
21
22
|
if (orgId) {
|
|
22
23
|
config.headers['X-Org-Id'] = orgId
|
|
23
24
|
}
|
|
25
|
+
if (projectId) {
|
|
26
|
+
config.headers['X-Project-Id'] = projectId
|
|
27
|
+
}
|
|
24
28
|
|
|
25
29
|
return config
|
|
26
30
|
})
|
|
@@ -35,23 +35,29 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
35
35
|
|
|
36
36
|
const login = async (email: string, password: string) => {
|
|
37
37
|
const res = await api.post('/api/auth/login', { email, password })
|
|
38
|
-
const { accessToken, refreshToken, user, org } = res.data
|
|
38
|
+
const { accessToken, refreshToken, user, org, project } = res.data
|
|
39
39
|
localStorage.setItem('accessToken', accessToken)
|
|
40
40
|
localStorage.setItem('refreshToken', refreshToken)
|
|
41
41
|
if (org) {
|
|
42
42
|
localStorage.setItem('currentOrgId', org.id)
|
|
43
43
|
}
|
|
44
|
+
if (project) {
|
|
45
|
+
localStorage.setItem('currentProjectId', project.id)
|
|
46
|
+
}
|
|
44
47
|
setUser(user)
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
const signup = async (email: string, password: string, orgName: string) => {
|
|
48
51
|
const res = await api.post('/api/auth/signup', { email, password, orgName })
|
|
49
|
-
const { accessToken, refreshToken, user, org } = res.data
|
|
52
|
+
const { accessToken, refreshToken, user, org, project } = res.data
|
|
50
53
|
localStorage.setItem('accessToken', accessToken)
|
|
51
54
|
localStorage.setItem('refreshToken', refreshToken)
|
|
52
55
|
if (org) {
|
|
53
56
|
localStorage.setItem('currentOrgId', org.id)
|
|
54
57
|
}
|
|
58
|
+
if (project) {
|
|
59
|
+
localStorage.setItem('currentProjectId', project.id)
|
|
60
|
+
}
|
|
55
61
|
setUser(user)
|
|
56
62
|
}
|
|
57
63
|
|
|
@@ -59,6 +65,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
59
65
|
localStorage.removeItem('accessToken')
|
|
60
66
|
localStorage.removeItem('refreshToken')
|
|
61
67
|
localStorage.removeItem('currentOrgId')
|
|
68
|
+
localStorage.removeItem('currentProjectId')
|
|
62
69
|
setUser(null)
|
|
63
70
|
}
|
|
64
71
|
|
package/template/prisma/seed.ts
CHANGED
|
@@ -1,38 +1,11 @@
|
|
|
1
|
-
import { PrismaClient
|
|
2
|
-
import * as bcrypt from 'bcrypt';
|
|
1
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
2
|
|
|
4
3
|
const prisma = new PrismaClient();
|
|
5
4
|
|
|
6
5
|
async function main() {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const existing = await prisma.user.findUnique({ where: { email } });
|
|
11
|
-
if (existing) return;
|
|
12
|
-
|
|
13
|
-
const saltRounds = Number(process.env.BCRYPT_SALT_ROUNDS ?? '10');
|
|
14
|
-
const passwordHash = await bcrypt.hash(password, saltRounds);
|
|
15
|
-
|
|
16
|
-
const user = await prisma.user.create({
|
|
17
|
-
data: { email, passwordHash }
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const org = await prisma.organization.create({
|
|
21
|
-
data: { name: 'My Organization', slug: 'my-org' }
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
await prisma.organizationMember.create({
|
|
25
|
-
data: { userId: user.id, organizationId: org.id, role: Role.OWNER }
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
await prisma.project.create({
|
|
29
|
-
data: {
|
|
30
|
-
organizationId: org.id,
|
|
31
|
-
name: 'Default Project',
|
|
32
|
-
slug: 'default-project',
|
|
33
|
-
description: 'Default project created during setup'
|
|
34
|
-
}
|
|
35
|
-
});
|
|
6
|
+
// Production-ready seed - no demo data
|
|
7
|
+
// Users, organizations, and projects are created through the API
|
|
8
|
+
console.log('Database seeded (production mode - no demo data)');
|
|
36
9
|
}
|
|
37
10
|
|
|
38
11
|
main()
|
|
@@ -66,7 +66,7 @@ export class AuthService {
|
|
|
66
66
|
const passwordHash = await this.hashPassword(dto.password);
|
|
67
67
|
|
|
68
68
|
// Generate slug from org name
|
|
69
|
-
const
|
|
69
|
+
const orgSlug = dto.orgName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
70
70
|
|
|
71
71
|
const user = await this.prisma.user.create({
|
|
72
72
|
data: {
|
|
@@ -79,7 +79,7 @@ export class AuthService {
|
|
|
79
79
|
const org = await this.prisma.organization.create({
|
|
80
80
|
data: {
|
|
81
81
|
name: dto.orgName,
|
|
82
|
-
slug,
|
|
82
|
+
slug: orgSlug,
|
|
83
83
|
ownerId: user.id
|
|
84
84
|
}
|
|
85
85
|
});
|
|
@@ -92,11 +92,23 @@ export class AuthService {
|
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
+
// Create default project for the organization
|
|
96
|
+
const projectSlug = 'default-project';
|
|
97
|
+
const project = await this.prisma.project.create({
|
|
98
|
+
data: {
|
|
99
|
+
organizationId: org.id,
|
|
100
|
+
name: 'Default Project',
|
|
101
|
+
slug: projectSlug,
|
|
102
|
+
description: 'Default project created during signup'
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
95
106
|
const tokens = await this.issueTokens(user);
|
|
96
107
|
|
|
97
108
|
return {
|
|
98
109
|
user: { id: user.id, email: user.email },
|
|
99
110
|
org: { id: org.id, name: org.name, slug: org.slug },
|
|
111
|
+
project: { id: project.id, name: project.name, slug: project.slug },
|
|
100
112
|
...tokens
|
|
101
113
|
};
|
|
102
114
|
}
|
|
@@ -104,7 +116,15 @@ export class AuthService {
|
|
|
104
116
|
async login(dto: LoginDto) {
|
|
105
117
|
const user = await this.prisma.user.findUnique({
|
|
106
118
|
where: { email: dto.email },
|
|
107
|
-
include: {
|
|
119
|
+
include: {
|
|
120
|
+
organizationMemberships: {
|
|
121
|
+
include: {
|
|
122
|
+
organization: {
|
|
123
|
+
include: { projects: { take: 1 } }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
108
128
|
});
|
|
109
129
|
if (!user || !user.passwordHash) throw new UnauthorizedException('Invalid credentials');
|
|
110
130
|
|
|
@@ -113,12 +133,15 @@ export class AuthService {
|
|
|
113
133
|
|
|
114
134
|
const tokens = await this.issueTokens({ id: user.id, email: user.email });
|
|
115
135
|
|
|
116
|
-
// Get first org for the user
|
|
136
|
+
// Get first org and project for the user
|
|
117
137
|
const firstMembership = user.organizationMemberships[0];
|
|
138
|
+
const firstOrg = firstMembership?.organization;
|
|
139
|
+
const firstProject = firstOrg?.projects[0];
|
|
118
140
|
|
|
119
141
|
return {
|
|
120
142
|
user: { id: user.id, email: user.email },
|
|
121
|
-
org:
|
|
143
|
+
org: firstOrg ? { id: firstOrg.id, name: firstOrg.name, slug: firstOrg.slug } : null,
|
|
144
|
+
project: firstProject ? { id: firstProject.id, name: firstProject.name, slug: firstProject.slug } : null,
|
|
122
145
|
...tokens
|
|
123
146
|
};
|
|
124
147
|
}
|