@agent-foundry/studio 1.0.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/README.md +96 -0
- package/dist/db/client.d.ts +59 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +51 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/deployments.d.ts +65 -0
- package/dist/db/deployments.d.ts.map +1 -0
- package/dist/db/deployments.js +249 -0
- package/dist/db/deployments.js.map +1 -0
- package/dist/db/index.d.ts +7 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +7 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/projects.d.ts +48 -0
- package/dist/db/projects.d.ts.map +1 -0
- package/dist/db/projects.js +192 -0
- package/dist/db/projects.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/oss/client.d.ts +65 -0
- package/dist/oss/client.d.ts.map +1 -0
- package/dist/oss/client.js +146 -0
- package/dist/oss/client.js.map +1 -0
- package/dist/oss/index.d.ts +7 -0
- package/dist/oss/index.d.ts.map +1 -0
- package/dist/oss/index.js +7 -0
- package/dist/oss/index.js.map +1 -0
- package/dist/oss/types.d.ts +96 -0
- package/dist/oss/types.d.ts.map +1 -0
- package/dist/oss/types.js +5 -0
- package/dist/oss/types.js.map +1 -0
- package/dist/oss/uploader.d.ts +72 -0
- package/dist/oss/uploader.d.ts.map +1 -0
- package/dist/oss/uploader.js +185 -0
- package/dist/oss/uploader.js.map +1 -0
- package/dist/types/deployment.d.ts +112 -0
- package/dist/types/deployment.d.ts.map +1 -0
- package/dist/types/deployment.js +7 -0
- package/dist/types/deployment.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/project.d.ts +90 -0
- package/dist/types/project.d.ts.map +1 -0
- package/dist/types/project.js +8 -0
- package/dist/types/project.js.map +1 -0
- package/dist/types/user.d.ts +71 -0
- package/dist/types/user.d.ts.map +1 -0
- package/dist/types/user.js +8 -0
- package/dist/types/user.js.map +1 -0
- package/dist/types/workspace.d.ts +88 -0
- package/dist/types/workspace.d.ts.map +1 -0
- package/dist/types/workspace.js +27 -0
- package/dist/types/workspace.js.map +1 -0
- package/dist/utils/build.d.ts +78 -0
- package/dist/utils/build.d.ts.map +1 -0
- package/dist/utils/build.js +148 -0
- package/dist/utils/build.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/manifest.d.ts +106 -0
- package/dist/utils/manifest.d.ts.map +1 -0
- package/dist/utils/manifest.js +109 -0
- package/dist/utils/manifest.js.map +1 -0
- package/package.json +62 -0
- package/src/db/client.ts +92 -0
- package/src/db/deployments.ts +316 -0
- package/src/db/index.ts +7 -0
- package/src/db/projects.ts +246 -0
- package/src/db/schema.sql +156 -0
- package/src/index.ts +18 -0
- package/src/oss/client.ts +183 -0
- package/src/oss/index.ts +7 -0
- package/src/oss/types.ts +126 -0
- package/src/oss/uploader.ts +254 -0
- package/src/types/deployment.ts +147 -0
- package/src/types/index.ts +8 -0
- package/src/types/project.ts +114 -0
- package/src/types/user.ts +91 -0
- package/src/types/workspace.ts +124 -0
- package/src/utils/build.ts +199 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/manifest.ts +224 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct Uploader
|
|
3
|
+
*
|
|
4
|
+
* High-level interface for uploading build artifacts to OSS.
|
|
5
|
+
* Handles STS credential fetching, multipart upload, and progress tracking.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { AliOSSClient } from './client';
|
|
9
|
+
import type {
|
|
10
|
+
UploadFile,
|
|
11
|
+
UploadProgress,
|
|
12
|
+
UploadResult,
|
|
13
|
+
UploadTokenResponse,
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Configuration for DirectUploader
|
|
18
|
+
*/
|
|
19
|
+
export interface DirectUploaderConfig {
|
|
20
|
+
/** BFF base URL (e.g., "http://localhost:11001") */
|
|
21
|
+
bffBaseUrl: string;
|
|
22
|
+
|
|
23
|
+
/** Supabase JWT token for authentication */
|
|
24
|
+
authToken: string;
|
|
25
|
+
|
|
26
|
+
/** Request timeout in milliseconds */
|
|
27
|
+
timeout?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Upload options
|
|
32
|
+
*/
|
|
33
|
+
export interface UploadOptions {
|
|
34
|
+
/** Project ID */
|
|
35
|
+
projectId: string;
|
|
36
|
+
|
|
37
|
+
/** Files to upload */
|
|
38
|
+
files: UploadFile[];
|
|
39
|
+
|
|
40
|
+
/** Optional: specific version string */
|
|
41
|
+
version?: string;
|
|
42
|
+
|
|
43
|
+
/** Progress callback */
|
|
44
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* DirectUploader - handles the complete upload flow
|
|
49
|
+
*
|
|
50
|
+
* 1. Requests STS credentials from BFF
|
|
51
|
+
* 2. Uploads files directly to OSS
|
|
52
|
+
* 3. Notifies BFF of completion
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const uploader = new DirectUploader({
|
|
57
|
+
* bffBaseUrl: 'http://localhost:11001',
|
|
58
|
+
* authToken: 'eyJ...',
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* const result = await uploader.upload({
|
|
62
|
+
* projectId: 'project-uuid',
|
|
63
|
+
* files: [
|
|
64
|
+
* { path: 'index.html', content: indexHtml, contentType: 'text/html' },
|
|
65
|
+
* { path: 'assets/main.js', content: mainJs, contentType: 'application/javascript' },
|
|
66
|
+
* ],
|
|
67
|
+
* onProgress: (p) => console.log(`${p.percent}%`),
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export class DirectUploader {
|
|
72
|
+
private config: DirectUploaderConfig;
|
|
73
|
+
|
|
74
|
+
constructor(config: DirectUploaderConfig) {
|
|
75
|
+
this.config = config;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Upload files to OSS
|
|
80
|
+
*/
|
|
81
|
+
async upload(options: UploadOptions): Promise<UploadResult> {
|
|
82
|
+
const { projectId, files, version, onProgress } = options;
|
|
83
|
+
|
|
84
|
+
// Report preparing stage
|
|
85
|
+
if (onProgress) {
|
|
86
|
+
onProgress({
|
|
87
|
+
currentFile: '',
|
|
88
|
+
uploadedCount: 0,
|
|
89
|
+
totalCount: files.length,
|
|
90
|
+
uploadedBytes: 0,
|
|
91
|
+
totalBytes: 0,
|
|
92
|
+
percent: 0,
|
|
93
|
+
stage: 'preparing',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
// Step 1: Get upload token from BFF
|
|
99
|
+
const tokenResponse = await this.getUploadToken(projectId, version);
|
|
100
|
+
|
|
101
|
+
// Step 2: Create OSS client with STS credentials
|
|
102
|
+
const ossClient = new AliOSSClient({
|
|
103
|
+
region: tokenResponse.region,
|
|
104
|
+
bucket: tokenResponse.bucket,
|
|
105
|
+
credentials: tokenResponse.credentials,
|
|
106
|
+
timeout: this.config.timeout,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Calculate total bytes
|
|
110
|
+
let totalBytes = 0;
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
if (file.content instanceof Blob) {
|
|
113
|
+
totalBytes += file.content.size;
|
|
114
|
+
} else if (file.content instanceof ArrayBuffer) {
|
|
115
|
+
totalBytes += file.content.byteLength;
|
|
116
|
+
} else if (typeof file.content === 'string') {
|
|
117
|
+
totalBytes += new Blob([file.content]).size;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Step 3: Upload files with progress tracking
|
|
122
|
+
let uploadedBytes = 0;
|
|
123
|
+
let uploadedCount = 0;
|
|
124
|
+
|
|
125
|
+
for (const file of files) {
|
|
126
|
+
// Get file size
|
|
127
|
+
let fileSize = 0;
|
|
128
|
+
if (file.content instanceof Blob) {
|
|
129
|
+
fileSize = file.content.size;
|
|
130
|
+
} else if (file.content instanceof ArrayBuffer) {
|
|
131
|
+
fileSize = file.content.byteLength;
|
|
132
|
+
} else if (typeof file.content === 'string') {
|
|
133
|
+
fileSize = new Blob([file.content]).size;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Report progress before upload
|
|
137
|
+
if (onProgress) {
|
|
138
|
+
onProgress({
|
|
139
|
+
currentFile: file.path,
|
|
140
|
+
uploadedCount,
|
|
141
|
+
totalCount: files.length,
|
|
142
|
+
uploadedBytes,
|
|
143
|
+
totalBytes,
|
|
144
|
+
percent: Math.round((uploadedBytes / totalBytes) * 100),
|
|
145
|
+
stage: 'uploading',
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Upload file
|
|
150
|
+
const key = `${tokenResponse.keyPrefix}/${file.path}`.replace(/\/+/g, '/');
|
|
151
|
+
await ossClient.uploadFile(key, file.content, file.contentType);
|
|
152
|
+
|
|
153
|
+
uploadedBytes += fileSize;
|
|
154
|
+
uploadedCount++;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Step 4: Notify BFF of completion
|
|
158
|
+
if (onProgress) {
|
|
159
|
+
onProgress({
|
|
160
|
+
currentFile: '',
|
|
161
|
+
uploadedCount: files.length,
|
|
162
|
+
totalCount: files.length,
|
|
163
|
+
uploadedBytes: totalBytes,
|
|
164
|
+
totalBytes,
|
|
165
|
+
percent: 100,
|
|
166
|
+
stage: 'finalizing',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const finalResult = await this.completeUpload(
|
|
171
|
+
tokenResponse.deploymentId,
|
|
172
|
+
tokenResponse.bucket,
|
|
173
|
+
tokenResponse.keyPrefix,
|
|
174
|
+
totalBytes,
|
|
175
|
+
files.length
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
success: true,
|
|
180
|
+
deploymentId: tokenResponse.deploymentId,
|
|
181
|
+
url: finalResult.url,
|
|
182
|
+
bucket: tokenResponse.bucket,
|
|
183
|
+
keyPrefix: tokenResponse.keyPrefix,
|
|
184
|
+
totalBytes,
|
|
185
|
+
fileCount: files.length,
|
|
186
|
+
};
|
|
187
|
+
} catch (error) {
|
|
188
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
deploymentId: '',
|
|
192
|
+
totalBytes: 0,
|
|
193
|
+
fileCount: 0,
|
|
194
|
+
error: errorMessage,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Request upload token from BFF
|
|
201
|
+
*/
|
|
202
|
+
private async getUploadToken(
|
|
203
|
+
projectId: string,
|
|
204
|
+
version?: string
|
|
205
|
+
): Promise<UploadTokenResponse> {
|
|
206
|
+
const response = await fetch(`${this.config.bffBaseUrl}/studio/oss/token`, {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: {
|
|
209
|
+
'Content-Type': 'application/json',
|
|
210
|
+
'Authorization': `Bearer ${this.config.authToken}`,
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({ projectId, version }),
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (!response.ok) {
|
|
216
|
+
const error = await response.text();
|
|
217
|
+
throw new Error(`Failed to get upload token: ${error}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return response.json();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Notify BFF that upload is complete
|
|
225
|
+
*/
|
|
226
|
+
private async completeUpload(
|
|
227
|
+
deploymentId: string,
|
|
228
|
+
bucket: string,
|
|
229
|
+
keyPrefix: string,
|
|
230
|
+
totalBytes: number,
|
|
231
|
+
fileCount: number
|
|
232
|
+
): Promise<{ url: string }> {
|
|
233
|
+
const response = await fetch(`${this.config.bffBaseUrl}/studio/deployments/${deploymentId}/complete`, {
|
|
234
|
+
method: 'POST',
|
|
235
|
+
headers: {
|
|
236
|
+
'Content-Type': 'application/json',
|
|
237
|
+
'Authorization': `Bearer ${this.config.authToken}`,
|
|
238
|
+
},
|
|
239
|
+
body: JSON.stringify({
|
|
240
|
+
bucket,
|
|
241
|
+
keyPrefix,
|
|
242
|
+
totalBytes,
|
|
243
|
+
fileCount,
|
|
244
|
+
}),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!response.ok) {
|
|
248
|
+
const error = await response.text();
|
|
249
|
+
throw new Error(`Failed to complete upload: ${error}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return response.json();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment types
|
|
3
|
+
*
|
|
4
|
+
* A Deployment represents a build and upload of a project to Alibaba Cloud OSS.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Deployment status enum
|
|
9
|
+
*/
|
|
10
|
+
export type DeploymentStatus =
|
|
11
|
+
| 'pending' // Deployment created, waiting to start
|
|
12
|
+
| 'building' // Running pnpm build
|
|
13
|
+
| 'uploading' // Uploading to OSS
|
|
14
|
+
| 'published' // Successfully deployed
|
|
15
|
+
| 'failed'; // Build or upload failed
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Deployment metadata stored as JSONB
|
|
19
|
+
*/
|
|
20
|
+
export interface DeploymentMetadata {
|
|
21
|
+
/** Git commit hash if available */
|
|
22
|
+
commitHash?: string;
|
|
23
|
+
|
|
24
|
+
/** Git branch name */
|
|
25
|
+
branch?: string;
|
|
26
|
+
|
|
27
|
+
/** Build duration in milliseconds */
|
|
28
|
+
buildDurationMs?: number;
|
|
29
|
+
|
|
30
|
+
/** Upload duration in milliseconds */
|
|
31
|
+
uploadDurationMs?: number;
|
|
32
|
+
|
|
33
|
+
/** Number of files uploaded */
|
|
34
|
+
fileCount?: number;
|
|
35
|
+
|
|
36
|
+
/** Node.js version used for build */
|
|
37
|
+
nodeVersion?: string;
|
|
38
|
+
|
|
39
|
+
/** Custom metadata from user */
|
|
40
|
+
custom?: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Deployment record
|
|
45
|
+
*/
|
|
46
|
+
export interface Deployment {
|
|
47
|
+
/** UUID primary key */
|
|
48
|
+
id: string;
|
|
49
|
+
|
|
50
|
+
/** Associated project ID */
|
|
51
|
+
projectId: string;
|
|
52
|
+
|
|
53
|
+
/** User who created the deployment */
|
|
54
|
+
userId: string;
|
|
55
|
+
|
|
56
|
+
/** Version string (semver or timestamp) */
|
|
57
|
+
version: string;
|
|
58
|
+
|
|
59
|
+
/** Current deployment status */
|
|
60
|
+
status: DeploymentStatus;
|
|
61
|
+
|
|
62
|
+
/** OSS bucket name */
|
|
63
|
+
ossBucket?: string;
|
|
64
|
+
|
|
65
|
+
/** Object key/path in OSS bucket */
|
|
66
|
+
ossKey?: string;
|
|
67
|
+
|
|
68
|
+
/** Public access URL for the deployed app */
|
|
69
|
+
ossUrl?: string;
|
|
70
|
+
|
|
71
|
+
/** Total bundle size in bytes */
|
|
72
|
+
bundleSizeBytes?: number;
|
|
73
|
+
|
|
74
|
+
/** Build output log */
|
|
75
|
+
buildLog?: string;
|
|
76
|
+
|
|
77
|
+
/** Error message if failed */
|
|
78
|
+
errorMessage?: string;
|
|
79
|
+
|
|
80
|
+
/** Additional metadata */
|
|
81
|
+
metadata: DeploymentMetadata;
|
|
82
|
+
|
|
83
|
+
/** ISO timestamp of creation */
|
|
84
|
+
createdAt: string;
|
|
85
|
+
|
|
86
|
+
/** ISO timestamp when published */
|
|
87
|
+
publishedAt?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Input for creating a new deployment
|
|
92
|
+
*/
|
|
93
|
+
export interface CreateDeploymentInput {
|
|
94
|
+
projectId: string;
|
|
95
|
+
version?: string; // Auto-generated if not provided
|
|
96
|
+
metadata?: Partial<DeploymentMetadata>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Input for updating deployment status
|
|
101
|
+
*/
|
|
102
|
+
export interface UpdateDeploymentInput {
|
|
103
|
+
status?: DeploymentStatus;
|
|
104
|
+
ossBucket?: string;
|
|
105
|
+
ossKey?: string;
|
|
106
|
+
ossUrl?: string;
|
|
107
|
+
bundleSizeBytes?: number;
|
|
108
|
+
buildLog?: string;
|
|
109
|
+
errorMessage?: string;
|
|
110
|
+
metadata?: Partial<DeploymentMetadata>;
|
|
111
|
+
publishedAt?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Deployment list filters
|
|
116
|
+
*/
|
|
117
|
+
export interface DeploymentListFilters {
|
|
118
|
+
/** Filter by project */
|
|
119
|
+
projectId?: string;
|
|
120
|
+
|
|
121
|
+
/** Filter by status */
|
|
122
|
+
status?: DeploymentStatus;
|
|
123
|
+
|
|
124
|
+
/** Limit number of results */
|
|
125
|
+
limit?: number;
|
|
126
|
+
|
|
127
|
+
/** Offset for pagination */
|
|
128
|
+
offset?: number;
|
|
129
|
+
|
|
130
|
+
/** Order by field */
|
|
131
|
+
orderBy?: 'createdAt' | 'publishedAt' | 'version';
|
|
132
|
+
|
|
133
|
+
/** Order direction */
|
|
134
|
+
orderDir?: 'asc' | 'desc';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Deployment progress event for real-time updates
|
|
139
|
+
*/
|
|
140
|
+
export interface DeploymentProgress {
|
|
141
|
+
deploymentId: string;
|
|
142
|
+
status: DeploymentStatus;
|
|
143
|
+
stage: 'init' | 'install' | 'build' | 'bundle' | 'upload' | 'finalize';
|
|
144
|
+
percent: number;
|
|
145
|
+
message?: string;
|
|
146
|
+
timestamp: string;
|
|
147
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Studio Project types
|
|
3
|
+
*
|
|
4
|
+
* A StudioProject represents a React/Vite project created and managed
|
|
5
|
+
* within the Build Studio desktop application.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supported frontend frameworks
|
|
10
|
+
*/
|
|
11
|
+
export type ProjectFramework = 'vite-react' | 'next' | 'remix' | 'vite-vue' | 'vite-svelte';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Project configuration stored as JSONB in database
|
|
15
|
+
*/
|
|
16
|
+
export interface ProjectConfig {
|
|
17
|
+
/** Build command to execute (default: "pnpm build") */
|
|
18
|
+
buildCommand?: string;
|
|
19
|
+
|
|
20
|
+
/** Output directory for build artifacts (default: "dist") */
|
|
21
|
+
outputDir?: string;
|
|
22
|
+
|
|
23
|
+
/** Environment variables to inject during build */
|
|
24
|
+
envVars?: Record<string, string>;
|
|
25
|
+
|
|
26
|
+
/** Base URL for the deployed app */
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
|
|
29
|
+
/** Custom Vite config overrides */
|
|
30
|
+
viteConfig?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Studio Project - a React/Vite project managed by Build Studio
|
|
35
|
+
*/
|
|
36
|
+
export interface StudioProject {
|
|
37
|
+
/** UUID primary key */
|
|
38
|
+
id: string;
|
|
39
|
+
|
|
40
|
+
/** Owner user ID (from Supabase Auth) */
|
|
41
|
+
userId: string;
|
|
42
|
+
|
|
43
|
+
/** Human-readable project name */
|
|
44
|
+
name: string;
|
|
45
|
+
|
|
46
|
+
/** URL-safe unique identifier (unique per user) */
|
|
47
|
+
slug: string;
|
|
48
|
+
|
|
49
|
+
/** Optional project description */
|
|
50
|
+
description?: string;
|
|
51
|
+
|
|
52
|
+
/** Local filesystem path to project root */
|
|
53
|
+
rootPath: string;
|
|
54
|
+
|
|
55
|
+
/** Frontend framework used */
|
|
56
|
+
framework: ProjectFramework;
|
|
57
|
+
|
|
58
|
+
/** Project configuration */
|
|
59
|
+
config: ProjectConfig;
|
|
60
|
+
|
|
61
|
+
/** Parent project ID if this is a fork/copy */
|
|
62
|
+
parentProjectId?: string;
|
|
63
|
+
|
|
64
|
+
/** ISO timestamp of creation */
|
|
65
|
+
createdAt: string;
|
|
66
|
+
|
|
67
|
+
/** ISO timestamp of last update */
|
|
68
|
+
updatedAt: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Input for creating a new project
|
|
73
|
+
*/
|
|
74
|
+
export interface CreateProjectInput {
|
|
75
|
+
name: string;
|
|
76
|
+
slug: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
rootPath: string;
|
|
79
|
+
framework?: ProjectFramework;
|
|
80
|
+
config?: ProjectConfig;
|
|
81
|
+
parentProjectId?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Input for updating a project
|
|
86
|
+
*/
|
|
87
|
+
export interface UpdateProjectInput {
|
|
88
|
+
name?: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
config?: Partial<ProjectConfig>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Project list filters
|
|
95
|
+
*/
|
|
96
|
+
export interface ProjectListFilters {
|
|
97
|
+
/** Filter by framework */
|
|
98
|
+
framework?: ProjectFramework;
|
|
99
|
+
|
|
100
|
+
/** Search by name (case-insensitive) */
|
|
101
|
+
search?: string;
|
|
102
|
+
|
|
103
|
+
/** Limit number of results */
|
|
104
|
+
limit?: number;
|
|
105
|
+
|
|
106
|
+
/** Offset for pagination */
|
|
107
|
+
offset?: number;
|
|
108
|
+
|
|
109
|
+
/** Order by field */
|
|
110
|
+
orderBy?: 'createdAt' | 'updatedAt' | 'name';
|
|
111
|
+
|
|
112
|
+
/** Order direction */
|
|
113
|
+
orderDir?: 'asc' | 'desc';
|
|
114
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User types
|
|
3
|
+
*
|
|
4
|
+
* StudioUser is linked to Supabase Auth user but may have
|
|
5
|
+
* additional Studio-specific metadata.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* User preferences for Studio
|
|
10
|
+
*/
|
|
11
|
+
export interface UserPreferences {
|
|
12
|
+
/** Default framework for new projects */
|
|
13
|
+
defaultFramework?: string;
|
|
14
|
+
|
|
15
|
+
/** Default build command */
|
|
16
|
+
defaultBuildCommand?: string;
|
|
17
|
+
|
|
18
|
+
/** Theme preference */
|
|
19
|
+
theme?: 'light' | 'dark' | 'system';
|
|
20
|
+
|
|
21
|
+
/** Editor font size */
|
|
22
|
+
editorFontSize?: number;
|
|
23
|
+
|
|
24
|
+
/** Show line numbers in editor */
|
|
25
|
+
showLineNumbers?: boolean;
|
|
26
|
+
|
|
27
|
+
/** Auto-save interval in seconds (0 = disabled) */
|
|
28
|
+
autoSaveInterval?: number;
|
|
29
|
+
|
|
30
|
+
/** Default chat panel width ratio (0.0 - 1.0) */
|
|
31
|
+
chatPanelRatio?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Studio user - extends Supabase Auth user with Studio-specific data
|
|
36
|
+
*/
|
|
37
|
+
export interface StudioUser {
|
|
38
|
+
/** User ID from Supabase Auth */
|
|
39
|
+
id: string;
|
|
40
|
+
|
|
41
|
+
/** Email address */
|
|
42
|
+
email: string;
|
|
43
|
+
|
|
44
|
+
/** Display name */
|
|
45
|
+
displayName?: string;
|
|
46
|
+
|
|
47
|
+
/** Avatar URL */
|
|
48
|
+
avatarUrl?: string;
|
|
49
|
+
|
|
50
|
+
/** User preferences */
|
|
51
|
+
preferences: UserPreferences;
|
|
52
|
+
|
|
53
|
+
/** ISO timestamp of account creation */
|
|
54
|
+
createdAt: string;
|
|
55
|
+
|
|
56
|
+
/** ISO timestamp of last login */
|
|
57
|
+
lastLoginAt?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Authentication state
|
|
62
|
+
*/
|
|
63
|
+
export interface AuthState {
|
|
64
|
+
/** Whether user is authenticated */
|
|
65
|
+
isAuthenticated: boolean;
|
|
66
|
+
|
|
67
|
+
/** Current user if authenticated */
|
|
68
|
+
user?: StudioUser;
|
|
69
|
+
|
|
70
|
+
/** Supabase access token */
|
|
71
|
+
accessToken?: string;
|
|
72
|
+
|
|
73
|
+
/** Token expiration timestamp */
|
|
74
|
+
expiresAt?: string;
|
|
75
|
+
|
|
76
|
+
/** Whether auth state is loading */
|
|
77
|
+
isLoading: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Login credentials
|
|
82
|
+
*/
|
|
83
|
+
export interface LoginCredentials {
|
|
84
|
+
email: string;
|
|
85
|
+
password: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* OAuth provider
|
|
90
|
+
*/
|
|
91
|
+
export type OAuthProvider = 'google' | 'github' | 'apple';
|