launchbase 1.2.1 → 1.2.3

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.1';
10
+ const VERSION = '1.2.3';
11
11
  const program = new Command();
12
12
 
13
13
  function findAvailablePort(startPort = 5432, maxAttempts = 100) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "launchbase",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Generate production-ready NestJS backends with authentication, multi-tenancy, billing, and deployment in minutes",
5
5
  "author": "LaunchBase",
6
6
  "keywords": [
@@ -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
 
@@ -111,6 +111,7 @@ model EdgeFunction {
111
111
  projectId String
112
112
  name String
113
113
  slug String
114
+ description String?
114
115
  runtime String @default("nodejs18")
115
116
  sourceCode String
116
117
  environment Json?
@@ -118,6 +119,7 @@ model EdgeFunction {
118
119
  status String @default("draft")
119
120
  deployedAt DateTime?
120
121
  deploymentUrl String?
122
+ deploymentId String?
121
123
  createdAt DateTime @default(now())
122
124
  updatedAt DateTime @updatedAt
123
125
  logs EdgeFunctionLog[]
@@ -152,6 +154,7 @@ model VectorCollection {
152
154
  id String @id @default(cuid())
153
155
  projectId String
154
156
  name String
157
+ description String?
155
158
  provider String @default("local")
156
159
  dimension Int @default(1536)
157
160
  embeddingModel String @default("text-embedding-3-small")
@@ -169,7 +172,9 @@ model Deployment {
169
172
  id String @id @default(cuid())
170
173
  projectId String
171
174
  status String @default("pending")
172
- version String?
175
+ version String
176
+ description String?
177
+ error String?
173
178
  deployedAt DateTime?
174
179
  platform String?
175
180
  url String?
@@ -1,38 +1,11 @@
1
- import { PrismaClient, Role } from '@prisma/client';
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
- const email = 'admin@example.com';
8
- const password = 'password123';
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 slug = dto.orgName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
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: { organizationMemberships: { include: { organization: true } } }
119
+ include: {
120
+ memberships: {
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
117
- const firstMembership = user.organizationMemberships[0];
136
+ // Get first org and project for the user
137
+ const firstMembership = user.memberships[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: firstMembership ? { id: firstMembership.organization.id, name: firstMembership.organization.name, slug: firstMembership.organization.slug } : null,
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
  }
@@ -191,7 +191,7 @@ export class BillingService {
191
191
  if (type === 'members' && limits.members === -1) return true;
192
192
 
193
193
  if (type === 'projects') {
194
- const count = await this.prisma.project.count({ where: { orgId } });
194
+ const count = await this.prisma.project.count({ where: { organizationId: orgId } });
195
195
  return count < limits.projects;
196
196
  }
197
197
 
@@ -3,7 +3,7 @@ import { IsString, IsOptional, MaxLength } from 'class-validator';
3
3
  export class CreateDeploymentDto {
4
4
  @IsString()
5
5
  @MaxLength(50)
6
- version: string;
6
+ version!: string;
7
7
 
8
8
  @IsString()
9
9
  @IsOptional()
@@ -12,18 +12,19 @@ export class EdgeFunctionsService {
12
12
  // Validate the function code
13
13
  this.validateCode(dto.code);
14
14
 
15
+ // Generate slug from name
16
+ const slug = dto.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
17
+
15
18
  const func = await this.prisma.edgeFunction.create({
16
19
  data: {
17
20
  name: dto.name,
21
+ slug,
18
22
  description: dto.description,
19
- code: dto.code,
23
+ sourceCode: dto.code,
20
24
  runtime: dto.runtime || 'nodejs18',
21
- timeout: dto.timeout || 30000,
22
- memory: dto.memory || 128,
23
25
  environment: dto.environment || {},
24
26
  triggers: dto.triggers || [],
25
27
  projectId,
26
- createdBy: userId,
27
28
  },
28
29
  });
29
30
 
@@ -90,7 +91,7 @@ export class EdgeFunctionsService {
90
91
 
91
92
  try {
92
93
  // Execute in sandboxed VM
93
- result = await this.runInSandbox(func.code, {
94
+ result = await this.runInSandbox(func.sourceCode, {
94
95
  ...dto.payload,
95
96
  user: { id: user.id, email: user.email },
96
97
  projectId,