fix(appstore): handle App Store backend failures and empty RPC responses
This commit is contained in:
@@ -84,13 +84,53 @@ export class CloudlyAppStoreManager {
|
||||
public async start() {}
|
||||
public async stop() {}
|
||||
|
||||
private getErrorMessage(errorArg: unknown): string {
|
||||
if (errorArg instanceof Error) return errorArg.message;
|
||||
return String(errorArg);
|
||||
}
|
||||
|
||||
private getSafeAppStoreErrorMessage(errorArg: unknown): string {
|
||||
const message = this.getErrorMessage(errorArg);
|
||||
const lowerMessage = message.toLowerCase();
|
||||
if (
|
||||
lowerMessage.includes('fetch') ||
|
||||
lowerMessage.includes('connect') ||
|
||||
lowerMessage.includes('connection refused') ||
|
||||
lowerMessage.includes('network') ||
|
||||
/http \d+/.test(lowerMessage)
|
||||
) {
|
||||
return 'The App Store backend is currently unreachable. Please retry later.';
|
||||
}
|
||||
if (
|
||||
lowerMessage.includes('domain is required') ||
|
||||
lowerMessage.includes('missing required app env var') ||
|
||||
lowerMessage.includes('unsupported platform requirement') ||
|
||||
lowerMessage.includes('published port') ||
|
||||
lowerMessage.includes('app requires cloudly')
|
||||
) {
|
||||
return message;
|
||||
}
|
||||
return 'The App Store request failed. Please retry later.';
|
||||
}
|
||||
|
||||
private createSafeAppStoreTypedError(actionArg: string, errorArg: unknown): plugins.typedrequest.TypedResponseError {
|
||||
console.warn(`${actionArg}: ${this.getErrorMessage(errorArg)}`);
|
||||
return new plugins.typedrequest.TypedResponseError(
|
||||
`${actionArg}: ${this.getSafeAppStoreErrorMessage(errorArg)}`,
|
||||
);
|
||||
}
|
||||
|
||||
private registerHandlers() {
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.appstore.IReq_Any_GetAppStoreTemplates>(
|
||||
'getAppStoreTemplates',
|
||||
async (dataArg) => {
|
||||
await this.passAdminIdentity(dataArg);
|
||||
return { apps: await this.getApps() };
|
||||
try {
|
||||
return { apps: await this.getApps() };
|
||||
} catch (error) {
|
||||
throw this.createSafeAppStoreTypedError('Could not load App Store templates', error);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -100,10 +140,17 @@ export class CloudlyAppStoreManager {
|
||||
'getAppStoreConfig',
|
||||
async (dataArg) => {
|
||||
await this.passAdminIdentity(dataArg);
|
||||
return {
|
||||
config: await this.getAppVersionConfig(dataArg.appId, dataArg.version),
|
||||
appMeta: await this.getAppMeta(dataArg.appId),
|
||||
};
|
||||
try {
|
||||
return {
|
||||
config: await this.getAppVersionConfig(dataArg.appId, dataArg.version),
|
||||
appMeta: await this.getAppMeta(dataArg.appId),
|
||||
};
|
||||
} catch (error) {
|
||||
throw this.createSafeAppStoreTypedError(
|
||||
`Could not load App Store details for ${dataArg.appId}@${dataArg.version || 'latest'}`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -113,8 +160,15 @@ export class CloudlyAppStoreManager {
|
||||
'installAppStoreApp',
|
||||
async (dataArg) => {
|
||||
await this.passAdminIdentity(dataArg);
|
||||
const service = await this.installApp(dataArg.install);
|
||||
return { service: await service.createSavableObject() };
|
||||
try {
|
||||
const service = await this.installApp(dataArg.install);
|
||||
return { service: await service.createSavableObject() };
|
||||
} catch (error) {
|
||||
throw this.createSafeAppStoreTypedError(
|
||||
`Could not install App Store app ${dataArg.install?.appId || 'unknown'}`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user