AppForge: migrate off Supabase to external Postgres + Better Auth + local storage
- New Express + TypeScript backend (server/) with pg, Better Auth, local file storage - De-Supabased Postgres schema (server/db) and TS reimplementations of DB functions - Frontend data layer rewired to REST (rest-client + backend-client compat shim) - Removed all Supabase references (code, config, deps, docs) - New brand assets: gradient favicon/app icons + dark/white wordmark logos Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { query, one } from '../db.js';
|
||||
import { env } from '../env.js';
|
||||
|
||||
interface TriggerArgs {
|
||||
buildId: string;
|
||||
websiteUrl: string;
|
||||
appName: string;
|
||||
platform: string;
|
||||
packageName: string;
|
||||
config: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a cloud build.
|
||||
*
|
||||
* If CODEMAGIC_API_TOKEN + CODEMAGIC_APP_ID are configured, this calls the
|
||||
* Codemagic API for real. Otherwise it runs a local SIMULATION so the build
|
||||
* flow is demonstrable in development (progress + placeholder artifact).
|
||||
*/
|
||||
export async function triggerCloudBuild(args: TriggerArgs): Promise<{ cloudBuildId?: string; message: string }> {
|
||||
if (env.CODEMAGIC_API_TOKEN && env.CODEMAGIC_APP_ID) {
|
||||
const res = await fetch('https://api.codemagic.io/builds', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'x-auth-token': env.CODEMAGIC_API_TOKEN },
|
||||
body: JSON.stringify({
|
||||
appId: env.CODEMAGIC_APP_ID,
|
||||
workflowId: args.platform === 'ios' ? 'ios-workflow' : 'android-workflow',
|
||||
branch: 'main',
|
||||
environment: {
|
||||
variables: {
|
||||
APP_NAME: args.appName,
|
||||
WEBSITE_URL: args.websiteUrl,
|
||||
PACKAGE_NAME: args.packageName,
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
const json: any = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(json?.error || json?.message || 'Codemagic build trigger failed');
|
||||
const cloudBuildId = json?.buildId || json?._id;
|
||||
await query(`UPDATE public.app_builds SET status = 'building', progress = 5 WHERE id = $1`, [args.buildId]);
|
||||
return { cloudBuildId, message: 'Cloud build started (Codemagic)' };
|
||||
}
|
||||
|
||||
// ---- Simulation (no Codemagic configured) ----
|
||||
await query(`UPDATE public.app_builds SET status = 'building', progress = 10 WHERE id = $1`, [args.buildId]);
|
||||
simulateBuild(args.buildId).catch((e) => console.error('[cloud-build sim]', e.message));
|
||||
return { message: 'Cloud build simulated (Codemagic not configured)' };
|
||||
}
|
||||
|
||||
async function simulateBuild(buildId: string) {
|
||||
const steps = [25, 45, 65, 85];
|
||||
for (const p of steps) {
|
||||
await delay(2000);
|
||||
await query(`UPDATE public.app_builds SET progress = $2 WHERE id = $1 AND status = 'building'`, [buildId, p]);
|
||||
}
|
||||
await delay(2000);
|
||||
const build = await one<any>(`SELECT package_name FROM public.app_builds WHERE id = $1`, [buildId]);
|
||||
const fileName = `${(build?.package_name || 'app').replace(/\./g, '-')}.apk`;
|
||||
await query(
|
||||
`UPDATE public.app_builds
|
||||
SET status = 'complete', progress = 100,
|
||||
download_url = $2, file_size_bytes = $3
|
||||
WHERE id = $1 AND status = 'building'`,
|
||||
[buildId, `/storage/apk-builds/simulated/${fileName}`, 12 * 1024 * 1024]
|
||||
);
|
||||
}
|
||||
|
||||
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
/** Returns the current build row (used by the status endpoint). */
|
||||
export async function getCloudBuildStatus(buildId: string) {
|
||||
return one(`SELECT * FROM public.app_builds WHERE id = $1`, [buildId]);
|
||||
}
|
||||
Reference in New Issue
Block a user