Enable storefront provision from Add Domain via optional git URL.
Persist deploy_slug on domains, call the websites agent /provision endpoint, and drop the hard-coded host map so Deploy appears from the UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
9ca6e2306f
commit
d933aef40b
@@ -37,6 +37,11 @@ import {
|
||||
DEFAULT_ENABLED_BUSINESS_MODULES,
|
||||
DEFAULT_HOME_CHARTS,
|
||||
} from '../business-settings/business-settings.types';
|
||||
import { WebsiteDeployAgentService } from '../website-deploy/website-deploy-agent.service';
|
||||
import {
|
||||
deploySlugFromHost,
|
||||
isValidGitRepoUrl,
|
||||
} from '../website-deploy/website-deploy.util';
|
||||
|
||||
type BusinessRow = {
|
||||
id: bigint;
|
||||
@@ -75,6 +80,7 @@ export class BusinessAdminService {
|
||||
private readonly permissions: PermissionsService,
|
||||
private readonly legacyMigrate: LegacyMigrateService,
|
||||
private readonly legacyPurge: LegacyPurgeService,
|
||||
private readonly websiteDeployAgent: WebsiteDeployAgentService,
|
||||
) {}
|
||||
|
||||
private async assertSuperAdmin(actor: AuthUser) {
|
||||
@@ -451,17 +457,29 @@ export class BusinessAdminService {
|
||||
await this.assertSuperAdmin(actor);
|
||||
|
||||
const businessId = BigInt(businessIdRaw);
|
||||
const host = dto.host.trim();
|
||||
const host = dto.host.trim().toLowerCase();
|
||||
const gitRepoUrl = dto.gitRepoUrl?.trim() || null;
|
||||
|
||||
if (!host) {
|
||||
throw new BadRequestException('host is required');
|
||||
}
|
||||
|
||||
if (gitRepoUrl && !isValidGitRepoUrl(gitRepoUrl)) {
|
||||
throw new BadRequestException(
|
||||
'gitRepoUrl must be an SSH git URL (e.g. git@git.meshkee.com:Meshkee-Websites/oaktasty.git)',
|
||||
);
|
||||
}
|
||||
|
||||
const business = await this.prisma.business.findUnique({ where: { id: businessId } });
|
||||
if (!business) {
|
||||
throw new NotFoundException('Business not found');
|
||||
}
|
||||
|
||||
const existingHost = await this.prisma.domain.findUnique({ where: { host } });
|
||||
if (existingHost) {
|
||||
throw new ConflictException('Domain host is already taken');
|
||||
}
|
||||
|
||||
const hasPrimary = await this.prisma.domain.findFirst({
|
||||
where: { businessId, isPrimary: true },
|
||||
select: { id: true },
|
||||
@@ -469,15 +487,55 @@ export class BusinessAdminService {
|
||||
|
||||
const isPrimary = dto.isPrimary ?? !hasPrimary;
|
||||
|
||||
return this.prisma.domain.create({
|
||||
let deploySlug: string | null = null;
|
||||
let provisionError: string | null = null;
|
||||
|
||||
if (gitRepoUrl) {
|
||||
deploySlug = deploySlugFromHost(host);
|
||||
if (!deploySlug) {
|
||||
throw new BadRequestException('Could not derive deploy slug from host');
|
||||
}
|
||||
|
||||
const slugTaken = await this.prisma.domain.findFirst({
|
||||
where: { deploySlug },
|
||||
select: { id: true },
|
||||
});
|
||||
if (slugTaken) {
|
||||
throw new ConflictException(`Deploy slug "${deploySlug}" is already in use`);
|
||||
}
|
||||
|
||||
try {
|
||||
await this.websiteDeployAgent.provision({
|
||||
slug: deploySlug,
|
||||
host,
|
||||
gitRepoUrl,
|
||||
});
|
||||
} catch (err) {
|
||||
if (err && typeof err === 'object' && 'message' in err && typeof err.message === 'string') {
|
||||
provisionError = err.message;
|
||||
} else {
|
||||
provisionError = 'Storefront provision failed on websites server';
|
||||
}
|
||||
deploySlug = null;
|
||||
}
|
||||
}
|
||||
|
||||
const domain = await this.prisma.domain.create({
|
||||
data: {
|
||||
businessId,
|
||||
host,
|
||||
isPrimary,
|
||||
isVerified: false,
|
||||
sslEnabled: false,
|
||||
deploySlug: provisionError ? null : deploySlug,
|
||||
gitRepoUrl: provisionError ? null : gitRepoUrl,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...domain,
|
||||
provisionError,
|
||||
};
|
||||
}
|
||||
|
||||
async updateDomain(
|
||||
|
||||
Reference in New Issue
Block a user