Skip to content

Commit f2cb8f8

Browse files
committed
added auth requirement, with echo.config.json for referral code
1 parent ce56d03 commit f2cb8f8

3 files changed

Lines changed: 80 additions & 265 deletions

File tree

packages/app/control/src/app/api/v1/referrals/register-template/route.ts

Lines changed: 0 additions & 76 deletions
This file was deleted.

packages/app/control/src/services/db/apps/template-referral.ts

Lines changed: 0 additions & 138 deletions
This file was deleted.

packages/sdk/echo-start/src/index.ts

Lines changed: 80 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
outro,
66
select,
77
text,
8+
confirm,
89
spinner,
910
log,
1011
isCancel,
@@ -14,6 +15,7 @@ import chalk from 'chalk';
1415
import { Command } from 'commander';
1516
import degit from 'degit';
1617
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs';
18+
import { readFile } from 'fs/promises';
1719
import path from 'path';
1820
import { spawn } from 'child_process';
1921

@@ -185,65 +187,67 @@ function isExternalTemplate(template: string): boolean {
185187
);
186188
}
187189

188-
function extractGithubUsername(templateUrl: string): string | null {
189-
const match = templateUrl.match(
190-
/github\.com\/([^\/]+)/
191-
);
192-
return match?.[1] ?? null;
190+
async function extractReferralCodeFromTemplate(
191+
templatePath: string
192+
): Promise<string | null> {
193+
const configFile = path.join(templatePath, 'echo.config.json');
194+
195+
if (!existsSync(configFile)) {
196+
return null;
197+
}
198+
199+
try {
200+
const content = await readFile(configFile, 'utf-8');
201+
const config = JSON.parse(content);
202+
return config.referralCode || config.echo?.referralCode || null;
203+
} catch {
204+
return null;
205+
}
193206
}
194207

195208
async function registerTemplateReferral(
196209
appId: string,
197-
templateUrl: string
210+
templatePath: string,
211+
apiKey: string
198212
): Promise<void> {
199-
const githubUsername = extractGithubUsername(templateUrl);
200-
201-
if (!githubUsername) {
202-
log.warn('Could not extract GitHub username from template URL');
203-
return;
204-
}
205-
206213
try {
207-
log.step(`Registering template referral for ${githubUsername}...`);
208-
209-
const response = await fetch(
210-
`${ECHO_BASE_URL}/api/v1/referrals/register-template`,
211-
{
212-
method: 'POST',
213-
headers: {
214-
'Content-Type': 'application/json',
215-
},
216-
body: JSON.stringify({
217-
appId,
218-
githubUsername,
219-
templateUrl,
220-
}),
221-
}
222-
);
214+
const referralCode = await extractReferralCodeFromTemplate(templatePath);
223215

224-
if (!response.ok) {
225-
const errorText = await response.text();
226-
log.warn(`Referral registration failed: ${response.status} - ${errorText}`);
216+
if (!referralCode) {
217+
log.info('No referral code found in template echo.config.json');
227218
return;
228219
}
229220

230-
const result = (await response.json()) as {
231-
status?: string;
232-
referrerUsername?: string;
233-
message?: string;
234-
};
235-
236-
if (result.status === 'registered' && result.referrerUsername) {
237-
log.success(
238-
`Template creator ${result.referrerUsername} registered as referrer`
221+
log.step(`Found template referral code, applying...`);
222+
223+
const response = await fetch(`${ECHO_BASE_URL}/api/v1/user/referral`, {
224+
method: 'POST',
225+
headers: {
226+
'Content-Type': 'application/json',
227+
Authorization: `Bearer ${apiKey}`,
228+
},
229+
body: JSON.stringify({
230+
echoAppId: appId,
231+
code: referralCode,
232+
}),
233+
});
234+
235+
if (!response.ok) {
236+
const errorData = (await response.json()) as { message?: string };
237+
log.warn(
238+
`Referral code could not be applied: ${errorData.message || 'Unknown error'}`
239239
);
240-
} else if (result.status === 'skipped') {
241-
log.info(`Referral skipped: ${result.message || 'Unknown reason'}`);
242-
} else if (result.status === 'not_found') {
243-
log.info(`Template creator ${githubUsername} not found on Echo`);
240+
return;
241+
}
242+
243+
const result = (await response.json()) as { success?: boolean };
244+
if (result.success) {
245+
log.success('Template referral code applied successfully');
244246
}
245247
} catch (error) {
246-
log.warn(`Referral registration error: ${error instanceof Error ? error.message : 'Unknown error'}`);
248+
log.warn(
249+
`Referral registration error: ${error instanceof Error ? error.message : 'Unknown error'}`
250+
);
247251
}
248252
}
249253

@@ -372,10 +376,6 @@ async function createApp(projectDir: string, options: CreateAppOptions) {
372376

373377
log.step(`Using App ID: ${appId}`);
374378

375-
if (isExternal) {
376-
await registerTemplateReferral(appId, template);
377-
}
378-
379379
const absoluteProjectPath = path.resolve(projectDir);
380380

381381
// Check if directory already exists
@@ -436,7 +436,36 @@ async function createApp(projectDir: string, options: CreateAppOptions) {
436436

437437
log.step('Configuring project files');
438438

439-
// Update package.json with the name of the project
439+
if (isExternal) {
440+
const referralCode = await extractReferralCodeFromTemplate(
441+
absoluteProjectPath
442+
);
443+
444+
if (referralCode) {
445+
const shouldApplyReferral = await confirm({
446+
message: 'This template includes a referral code. Apply it?',
447+
initialValue: true,
448+
});
449+
450+
if (!isCancel(shouldApplyReferral) && shouldApplyReferral) {
451+
const apiKey = await text({
452+
message: 'Enter your Echo API key:',
453+
placeholder: 'Your API key from https://echo.merit.systems/keys',
454+
validate: (value: string) => {
455+
if (!value.trim()) {
456+
return 'API key is required to apply referral code';
457+
}
458+
return;
459+
},
460+
});
461+
462+
if (!isCancel(apiKey)) {
463+
await registerTemplateReferral(appId, absoluteProjectPath, apiKey);
464+
}
465+
}
466+
}
467+
}
468+
440469
const packageJsonPath = path.join(absoluteProjectPath, 'package.json');
441470
// Technically this is checked above, but good practice to check again
442471
if (existsSync(packageJsonPath)) {

0 commit comments

Comments
 (0)