@reliverse/rse-sdk
Version:
@reliverse/rse-sdk allows you to create new plugins for @reliverse/rse CLI, interact with reliverse.org, and even extend your own CLI functionality (you may also try @reliverse/dler-sdk for this case).
493 lines (492 loc) • 13.7 kB
JavaScript
import { relinka } from "@reliverse/relinka";
import { selectPrompt } from "@reliverse/rempts";
import { decide } from "../../../../utils/decideHelper.js";
import {
initGithubSDK
} from "../../../../utils/instanceGithub.js";
import { initVercelSDK } from "../../../../utils/instanceVercel.js";
import { getOrCreateReliverseMemory } from "../../../../utils/reliverseMemory.js";
import { deployProject } from "./deploy.js";
import { handleGithubRepo, initGitDir } from "./git.js";
import { isSpecialDomain } from "./helpers/domainHelpers.js";
import { ensureDbInitialized } from "./helpers/handlePkgJsonScripts.js";
import { promptForDomain } from "./helpers/promptForDomain.js";
import { checkVercelDeployment } from "./vercel/vercel-check.js";
import { getVercelProjectDomain } from "./vercel/vercel-domain.js";
export async function handleGitInit(cwd, isDev, projectName, projectPath, config, isTemplateDownload) {
relinka("verbose", "[B] initGitDir");
const gitInitialized = await initGitDir({
cwd,
isDev,
projectName,
projectPath,
allowReInit: true,
createCommit: true,
config,
isTemplateDownload
});
if (!gitInitialized) {
relinka("error", "Failed to initialize git. Stopping git/deploy process.");
return false;
}
return true;
}
export async function configureGithubRepo(githubInstance, githubToken, skipPrompts, cwd, isDev, memory, config, projectName, projectPath, maskInput, selectedTemplate, isTemplateDownload, githubUsername) {
if (!memory) {
relinka("error", "Failed to read rsey");
return { success: false };
}
const repoCreated = await handleGithubRepo({
skipPrompts,
cwd,
isDev,
memory,
config,
projectName,
projectPath,
maskInput,
selectedTemplate,
isTemplateDownload,
githubInstance,
githubToken,
githubUsername
});
if (!repoCreated) {
relinka(
"error",
"Failed to create GitHub repository. Stopping deploy process."
);
return { success: false };
}
const updatedMemory = await getOrCreateReliverseMemory();
if (!updatedMemory?.githubKey) {
relinka("error", "GitHub token still not found after setup");
return { success: false };
}
return { success: true };
}
export async function promptGitDeploy({
isLib,
projectName,
config,
projectPath,
primaryDomain: initialPrimaryDomain,
hasDbPush,
shouldRunDbPush,
shouldInstallDeps,
isDev,
memory,
cwd,
maskInput,
skipPrompts,
selectedTemplate,
isTemplateDownload,
frontendUsername
}) {
let allDomains = [];
let primaryDomain = initialPrimaryDomain;
try {
const useGithubRepo = await decide(
config,
"gitBehavior",
"Do you want to create/connect a GitHub repository for this project?",
"This will allow you to store your code on GitHub, collaborate with others, deploy, and track changes automatically.",
true,
skipPrompts
);
if (!useGithubRepo) {
const initLocalGit = await decide(
config,
"gitBehavior",
"Do you want to initialize git locally? (recommended)",
"This allows you to track changes, create commits, and work with branches.",
true,
skipPrompts
);
if (!initLocalGit) {
relinka("info", "Skipping git initialization entirely.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
if (!await handleGitInit(
cwd,
isDev,
projectName,
projectPath,
config,
isTemplateDownload
)) {
relinka("error", "Failed to initialize git locally.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
relinka("info", "Skipping GitHub repository creation step.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
const githubResult = await initGithubSDK(
memory,
frontendUsername,
maskInput
);
if (!githubResult) {
throw new Error(
"Failed to initialize Octokit SDK. Please notify CLI developers if the problem persists."
);
}
const [githubToken, githubInstance, githubUsername] = githubResult;
let githubRetryCount = 0;
let skipGithub = false;
let githubData = { success: false };
while (githubRetryCount < 3 && !skipGithub) {
try {
githubData = await configureGithubRepo(
githubInstance,
githubToken,
skipPrompts,
cwd,
isDev,
memory,
config,
projectName,
projectPath,
maskInput,
selectedTemplate,
isTemplateDownload,
githubUsername
);
if (githubData.success) break;
githubRetryCount++;
} catch (error) {
githubRetryCount++;
relinka(
"error",
"GitHub setup encountered an error:",
error instanceof Error ? error.message : String(error)
);
}
if (githubRetryCount < 3 && !skipPrompts) {
const userAction = await selectPrompt({
title: "GitHub setup failed. What would you like to do?",
options: [
{
label: "Try again",
value: "retry",
hint: "Attempt GitHub setup again"
},
{
label: "Continue without GitHub",
value: "skip",
hint: "Proceed without GitHub"
},
{
label: "Close the application",
value: "close",
hint: "Exit setup"
}
]
});
if (userAction === "retry") continue;
else if (userAction === "skip") {
skipGithub = true;
if (!await handleGitInit(
cwd,
isDev,
projectName,
projectPath,
config,
false
)) {
relinka(
"error",
"Failed to initialize local git after skipping GitHub."
);
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
} else {
relinka("info", "Setup cancelled by user.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
}
}
if (githubRetryCount === 3 && !skipGithub && !skipPrompts) {
const userAction = await selectPrompt({
title: "GitHub setup failed after 3 attempts. What do you want to do?",
options: [
{
label: "Continue without GitHub",
value: "skip",
hint: "Proceed using local git"
},
{
label: "Close the application",
value: "close",
hint: "Exit setup"
}
]
});
if (userAction === "skip") {
if (!await handleGitInit(
cwd,
isDev,
projectName,
projectPath,
config,
false
)) {
relinka("error", "Failed to initialize local git after final skip.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
skipGithub = true;
} else {
relinka("info", "Setup cancelled by user.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
}
if (skipGithub) {
relinka(
"success",
"Git initialized locally! GitHub & deployments can be set up later by running the CLI inside your project folder."
);
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
if (!githubData.success) {
relinka(
"error",
"GitHub setup did not complete successfully after multiple attempts."
);
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
if (isLib) {
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
let alreadyDeployed = false;
try {
alreadyDeployed = await checkVercelDeployment(
projectName,
githubUsername,
githubToken,
githubInstance
);
} catch (vercelError) {
relinka(
"warn",
"Could not check existing Vercel deployments. Assuming none:",
vercelError instanceof Error ? vercelError.message : String(vercelError)
);
}
if (alreadyDeployed) {
relinka(
"success",
"Project already has Vercel deployments configured on GitHub.",
"New deployments are triggered automatically on new commits."
);
return {
deployService: "vercel",
primaryDomain,
isDeployed: true,
allDomains
};
}
const shouldDeployProject = await decide(
config,
"deployBehavior",
"Do you want to deploy this project?",
"This will set up deployment configuration, environment variables, and deploy to your chosen platform.",
true,
skipPrompts
);
if (!shouldDeployProject) {
relinka("info", "Skipping project deployment.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
const dbStatus = await ensureDbInitialized(
hasDbPush,
shouldRunDbPush,
shouldInstallDeps,
projectPath
);
if (dbStatus === "cancel") {
relinka("info", "Deployment cancelled during database initialization.");
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
const vercelResult = await initVercelSDK(memory, maskInput);
if (!vercelResult) {
throw new Error(
"Failed to initialize Vercel SDK. Please notify CLI developers if the problem persists."
);
}
const [vercelToken, vercelInstance] = vercelResult;
if (!alreadyDeployed) {
if (skipPrompts && config.projectDomain && !isSpecialDomain(config.projectDomain)) {
primaryDomain = config.projectDomain.replace(/^https?:\/\//, "");
} else {
primaryDomain = await promptForDomain(projectName);
}
} else {
const domainResult = await getVercelProjectDomain(
vercelInstance,
vercelToken,
projectName
);
primaryDomain = domainResult.primary;
allDomains = domainResult.domains;
}
const deploymentCheck = await checkVercelDeployment(
projectName,
githubUsername,
githubToken,
githubInstance
);
if (deploymentCheck) {
relinka("info", `Project ${projectName} is already deployed to Vercel`);
return {
deployService: "vercel",
primaryDomain,
isDeployed: true,
allDomains: [primaryDomain]
};
}
let deployRetryCount = 0;
while (deployRetryCount < 3) {
try {
const deployResult = await deployProject(
githubInstance,
vercelInstance,
vercelToken,
githubToken,
skipPrompts,
projectName,
config,
projectPath,
primaryDomain,
memory,
"new",
githubUsername
);
if (deployResult.deployService !== "none") {
relinka(
"success",
"Git, GitHub, and deployment completed successfully! \u{1F389}"
);
return deployResult;
}
deployRetryCount++;
if (deployRetryCount < 3 && !skipPrompts) {
const retryChoice = await decide(
config,
"deployBehavior",
"Deployment failed. Retry?",
"This may help if the error was temporary.",
true,
skipPrompts
);
if (!retryChoice) break;
} else {
break;
}
} catch (error) {
deployRetryCount++;
relinka(
"error",
"Deployment failed:",
error instanceof Error ? error.message : String(error)
);
if (deployRetryCount < 3 && !skipPrompts) {
const retryChoice = await decide(
config,
"deployBehavior",
"Retry deployment?",
"This may help if the error was temporary.",
true,
skipPrompts
);
if (!retryChoice) break;
} else {
break;
}
}
}
if (deployRetryCount === 3) {
relinka("error", "Deployment failed after 3 attempts.");
}
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
} catch (globalError) {
if (globalError instanceof Error) {
relinka("error", `Process failed: ${globalError.message}`);
if (globalError.stack) {
relinka("verbose", "Stack trace:", globalError.stack);
}
} else {
relinka("error", "An unexpected error occurred:", String(globalError));
}
return {
deployService: "none",
primaryDomain,
isDeployed: false,
allDomains
};
}
}