Skip to content

Commit 9cb10a8

Browse files
update method publish
1 parent 59d77f9 commit 9cb10a8

File tree

10 files changed

+426
-117
lines changed

10 files changed

+426
-117
lines changed

apps/web/client/public/onlook-preload-script.js

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/web/client/src/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const env = createEnv({
1010
NODE_ENV: z.enum(['development', 'test', 'production']),
1111
CSB_API_KEY: z.string(),
1212
SUPABASE_DATABASE_URL: z.string().url(),
13+
SUPABASE_SERVICE_ROLE_KEY: z.string().optional(),
1314
RESEND_API_KEY: z.string().optional(),
1415
FREESTYLE_API_KEY: z.string().optional(),
1516

@@ -74,6 +75,7 @@ export const env = createEnv({
7475

7576
// Supabase
7677
SUPABASE_DATABASE_URL: process.env.SUPABASE_DATABASE_URL,
78+
SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY,
7779
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
7880
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
7981
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FreestyleDeployWebSuccessResponseV2 } from 'freestyle-sandboxes';
1+
import type { DeploymentSource, FreestyleDeployWebSuccessResponseV2 } from 'freestyle-sandboxes';
22
import { initializeFreestyleSdk } from '../freestyle';
33
import type {
44
HostingProviderAdapter,
@@ -9,34 +9,62 @@ import type {
99
export class FreestyleAdapter implements HostingProviderAdapter {
1010
async deploy(request: DeploymentRequest): Promise<DeploymentResponse> {
1111
const sdk = initializeFreestyleSdk();
12-
12+
if (request.sourceUrl) {
13+
// Many SDKs accept a generic URL-based source. Use a loose cast to avoid type mismatch.
14+
15+
const res = await sdk.deployWeb(
16+
{ kind: 'tar', url: request.sourceUrl } as unknown as DeploymentSource,
17+
request.config,
18+
);
19+
20+
const freestyleResponse = res as {
21+
message?: string;
22+
error?: { message: string };
23+
data?: FreestyleDeployWebSuccessResponseV2;
24+
};
25+
26+
if (freestyleResponse.error) {
27+
throw new Error(
28+
freestyleResponse.error.message ||
29+
freestyleResponse.message ??
30+
'Unknown error',
31+
);
32+
}
33+
34+
return {
35+
deploymentId: freestyleResponse.data?.deploymentId ?? '',
36+
success: true,
37+
message: freestyleResponse.message,
38+
};
39+
}
40+
1341
const res = await sdk.deployWeb(
1442
{
1543
files: request.files,
1644
kind: 'files',
1745
},
18-
request.config
46+
request.config,
1947
);
20-
48+
2149
const freestyleResponse = res as {
2250
message?: string;
2351
error?: {
2452
message: string;
2553
};
2654
data?: FreestyleDeployWebSuccessResponseV2;
2755
};
28-
56+
2957
if (freestyleResponse.error) {
3058
throw new Error(
31-
freestyleResponse.error.message ||
32-
freestyleResponse.message ||
33-
'Unknown error'
59+
freestyleResponse.error.message ||
60+
freestyleResponse.message ||
61+
'Unknown error',
3462
);
3563
}
36-
64+
3765
return {
3866
deploymentId: freestyleResponse.data?.deploymentId ?? '',
39-
success: true
67+
success: true,
4068
};
4169
}
4270
}

apps/web/client/src/server/api/routers/publish/deployment.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { z } from "zod";
99
import { createTRPCRouter, protectedProcedure } from "../../trpc";
1010
import { updateDeployment } from './helpers';
1111
import { createDeployment, publish } from './helpers/index.ts';
12+
import { getDeploymentLogs } from './helpers/logs';
1213

1314
export const deploymentRouter = createTRPCRouter({
1415
getByType: protectedProcedure.input(z.object({
@@ -121,6 +122,11 @@ export const deploymentRouter = createTRPCRouter({
121122
throw error;
122123
}
123124
}),
125+
getLogs: protectedProcedure.input(z.object({
126+
deploymentId: z.string(),
127+
})).query(async ({ input }) => {
128+
return getDeploymentLogs(input.deploymentId);
129+
}),
124130
cancel: protectedProcedure.input(z.object({
125131
deploymentId: z.string(),
126132
})).mutation(async ({ ctx, input }) => {

apps/web/client/src/server/api/routers/publish/helpers/deploy.ts

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,39 @@ import {
1414
import { HostingProviderFactory } from '../../domain/hosting-factory.ts';
1515

1616
export const deployFreestyle = async (
17-
{
18-
files,
19-
urls,
20-
envVars,
21-
}: {
22-
files: Record<string, FreestyleFile>,
23-
urls: string[],
24-
envVars?: Record<string, string>,
17+
args: (
18+
{ files: Record<string, FreestyleFile>; sourceUrl?: undefined } |
19+
{ files?: undefined; sourceUrl: string }
20+
) & {
21+
urls: string[];
22+
envVars?: Record<string, string>;
2523
}
2624
): Promise<{
2725
success: boolean;
2826
message?: string;
2927
}> => {
3028
const entrypoint = 'server.js';
3129
const adapter = HostingProviderFactory.create(HostingProvider.FREESTYLE);
32-
const deploymentFiles: Record<string, { content: string; encoding?: 'utf-8' | 'base64' }> = {};
33-
for (const [path, file] of Object.entries(files)) {
34-
deploymentFiles[path] = {
35-
content: file.content,
36-
encoding: (file.encoding === 'base64' ? 'base64' : 'utf-8')
37-
};
38-
}
3930

4031
const result = await adapter.deploy({
41-
files: deploymentFiles,
32+
...(('sourceUrl' in args && typeof args.sourceUrl === 'string')
33+
? { sourceUrl: args.sourceUrl }
34+
: {
35+
files: Object.fromEntries(
36+
Object.entries(args.files ?? {}).map(([path, file]) => [
37+
path,
38+
{
39+
content: file.content,
40+
encoding: (file.encoding === 'base64' ? 'base64' : 'utf-8'),
41+
} as const,
42+
]),
43+
),
44+
}
45+
),
4246
config: {
43-
domains: urls,
47+
domains: args.urls,
4448
entrypoint,
45-
envVars,
49+
envVars: args.envVars,
4650
},
4751
});
4852

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
export type DeploymentLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'success';
2+
3+
export type DeploymentLogEntry = {
4+
timestamp: number;
5+
level: DeploymentLogLevel;
6+
message: string;
7+
};
8+
9+
const MAX_ENTRIES_PER_DEPLOYMENT = 500;
10+
11+
const deploymentLogs = new Map<string, DeploymentLogEntry[]>();
12+
13+
export const addDeploymentLog = (
14+
deploymentId: string,
15+
message: string,
16+
level: DeploymentLogLevel = 'info',
17+
): void => {
18+
if (!deploymentId) return;
19+
const entry: DeploymentLogEntry = {
20+
timestamp: Date.now(),
21+
level,
22+
message,
23+
};
24+
const list = deploymentLogs.get(deploymentId) ?? [];
25+
list.push(entry);
26+
// Trim to max
27+
if (list.length > MAX_ENTRIES_PER_DEPLOYMENT) {
28+
const excess = list.length - MAX_ENTRIES_PER_DEPLOYMENT;
29+
list.splice(0, excess);
30+
}
31+
deploymentLogs.set(deploymentId, list);
32+
};
33+
34+
export const getDeploymentLogs = (deploymentId: string): DeploymentLogEntry[] => {
35+
if (!deploymentId) return [];
36+
return deploymentLogs.get(deploymentId) ?? [];
37+
};
38+
39+
export const clearDeploymentLogs = (deploymentId: string): void => {
40+
if (!deploymentId) return;
41+
deploymentLogs.delete(deploymentId);
42+
};
43+
44+

apps/web/client/src/server/api/routers/publish/helpers/publish.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { deployFreestyle } from './deploy';
88
import { extractEnvVarsFromSandbox } from './env';
99
import { forkBuildSandbox } from './fork';
1010
import { getProjectUrls, getSandboxId, updateDeployment } from './helpers';
11+
import { addDeploymentLog, clearDeploymentLogs } from './logs';
1112

1213
export async function publish({ db, deployment }: { db: DrizzleDb; deployment: Deployment }) {
1314
const {
@@ -20,8 +21,12 @@ export async function publish({ db, deployment }: { db: DrizzleDb; deployment: D
2021
requestedBy: userId,
2122
} = deployment;
2223
try {
24+
clearDeploymentLogs(deploymentId);
25+
addDeploymentLog(deploymentId, 'Starting deployment...', 'info');
2326
const deploymentUrls = await getProjectUrls(db, projectId, type);
27+
addDeploymentLog(deploymentId, `Resolved deployment URLs: ${deploymentUrls.join(', ')}`, 'debug');
2428
const sandboxId = await getSandboxId(db, projectId);
29+
addDeploymentLog(deploymentId, `Using sandbox ${sandboxId} for build`, 'debug');
2530

2631
const updateDeploymentResult1 = await updateDeployment(db, deploymentId, {
2732
status: DeploymentStatus.IN_PROGRESS,
@@ -35,11 +40,8 @@ export async function publish({ db, deployment }: { db: DrizzleDb; deployment: D
3540
});
3641
}
3742

38-
const { provider, sandboxId: forkedSandboxId } = await forkBuildSandbox(
39-
sandboxId,
40-
userId,
41-
deploymentId,
42-
);
43+
const { provider, sandboxId: forkedSandboxId } = await forkBuildSandbox(sandboxId, userId, deploymentId);
44+
addDeploymentLog(deploymentId, `Forked build sandbox: ${forkedSandboxId}`, 'info');
4345

4446
try {
4547
const updateDeploymentResult2 = await updateDeployment(db, deploymentId, {
@@ -55,13 +57,17 @@ export async function publish({ db, deployment }: { db: DrizzleDb; deployment: D
5557
});
5658
}
5759

60+
5861
const publishManager = new PublishManager(provider);
59-
const files = await publishManager.publish({
62+
addDeploymentLog(deploymentId, 'Building project inside sandbox...', 'info');
63+
const artifactUrl = await publishManager.buildAndUploadArtifact({
6064
skipBadge: type === DeploymentType.CUSTOM,
6165
buildScript: buildScript ?? DefaultSettings.COMMANDS.build,
6266
buildFlags: buildFlags ?? DefaultSettings.EDITOR_SETTINGS.buildFlags,
67+
deploymentId,
6368
updateDeployment: (deployment) => updateDeployment(db, deploymentId, deployment),
6469
});
70+
addDeploymentLog(deploymentId, `Build artifact uploaded. Signed URL generated.`, 'success');
6571

6672
const updateDeploymentResult3 = await updateDeployment(db, deploymentId, {
6773
status: DeploymentStatus.IN_PROGRESS,
@@ -77,13 +83,16 @@ export async function publish({ db, deployment }: { db: DrizzleDb; deployment: D
7783

7884
// Note: Prefer user provided env vars over sandbox env vars
7985
const sandboxEnvVars = await extractEnvVarsFromSandbox(provider);
86+
addDeploymentLog(deploymentId, `Extracted ${Object.keys(sandboxEnvVars).length} env vars from sandbox`, 'debug');
8087
const mergedEnvVars = { ...sandboxEnvVars, ...(envVars ?? {}) };
88+
addDeploymentLog(deploymentId, 'Starting deployment to hosting provider...', 'info');
8189

8290
await deployFreestyle({
83-
files,
91+
sourceUrl: artifactUrl,
8492
urls: deploymentUrls,
8593
envVars: mergedEnvVars,
8694
});
95+
addDeploymentLog(deploymentId, 'Deployment finalized by hosting provider', 'success');
8796
} finally {
8897
await provider.destroy();
8998
}
@@ -94,6 +103,11 @@ export async function publish({ db, deployment }: { db: DrizzleDb; deployment: D
94103
error: error instanceof Error ? error.message : 'Unknown error',
95104
progress: 100,
96105
});
106+
addDeploymentLog(
107+
deploymentId,
108+
error instanceof Error ? error.message : 'Unknown error during deployment',
109+
'error',
110+
);
97111
throw error;
98112
}
99113
}

0 commit comments

Comments
 (0)