refactor(core): standardize frontend error handling (#10667)
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import type { GetWorkspacePageMetaByIdQuery } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -9,12 +8,12 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, mergeMap } from 'rxjs';
|
||||
|
||||
import type { DocService } from '../../doc';
|
||||
import type { GlobalCache } from '../../storage';
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { CloudDocMetaStore } from '../stores/cloud-doc-meta';
|
||||
|
||||
export type CloudDocMetaType =
|
||||
@@ -47,13 +46,7 @@ export class CloudDocMeta extends Entity {
|
||||
return fromPromise(
|
||||
this.store.fetchCloudDocMeta(this.workspaceId, this.docId)
|
||||
).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(meta => {
|
||||
this.cache.set<CloudDocMetaType>(this.cacheKey, meta);
|
||||
return EMPTY;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { InvoicesQuery } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -9,10 +8,10 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, map, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { InvoicesStore } from '../stores/invoices';
|
||||
|
||||
export type Invoice = NonNullable<
|
||||
@@ -50,13 +49,7 @@ export class Invoices extends Entity {
|
||||
this.pageInvoices$.setValue(data.invoices);
|
||||
return EMPTY;
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
catchErrorInto(this.error$),
|
||||
onStart(() => {
|
||||
this.pageInvoices$.setValue(undefined);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { UserFriendlyError } from '@affine/error';
|
||||
import {
|
||||
backoffRetry,
|
||||
effect,
|
||||
@@ -12,7 +13,6 @@ import { isEqual } from 'lodash-es';
|
||||
import { EMPTY, mergeMap } from 'rxjs';
|
||||
|
||||
import { validateAndReduceImage } from '../../../utils/reduce-image';
|
||||
import { BackendError } from '../error';
|
||||
import type { AccountProfile, AuthStore } from '../stores/auth';
|
||||
|
||||
export interface AuthSessionInfo {
|
||||
@@ -114,10 +114,7 @@ export class AuthSession extends Entity {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
if (
|
||||
e instanceof BackendError &&
|
||||
e.originError.name === 'UNSUPPORTED_CLIENT_VERSION'
|
||||
) {
|
||||
if (UserFriendlyError.fromAny(e).is('UNSUPPORTED_CLIENT_VERSION')) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { PricesQuery } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -9,10 +8,10 @@ import {
|
||||
mapInto,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { exhaustMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { ServerService } from '../services/server';
|
||||
import type { SubscriptionStore } from '../stores/subscription';
|
||||
|
||||
@@ -55,13 +54,7 @@ export class SubscriptionPrices extends Entity {
|
||||
}
|
||||
return this.store.fetchSubscriptionPrices(signal);
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mapInto(this.prices$),
|
||||
catchErrorInto(this.error$),
|
||||
onStart(() => this.isRevalidating$.next(true)),
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
SubscriptionVariant,
|
||||
} from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -14,10 +13,10 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, map, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { AuthService } from '../services/auth';
|
||||
import type { ServerService } from '../services/server';
|
||||
import type { SubscriptionStore } from '../stores/subscription';
|
||||
@@ -122,13 +121,7 @@ export class Subscription extends Entity {
|
||||
subscriptions: subscriptions,
|
||||
};
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(data => {
|
||||
if (data) {
|
||||
this.store.setCachedSubscriptions(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -8,10 +7,10 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, map, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { AuthService } from '../services/auth';
|
||||
import type { ServerService } from '../services/server';
|
||||
import type { UserCopilotQuotaStore } from '../stores/user-copilot-quota';
|
||||
@@ -54,13 +53,7 @@ export class UserCopilotQuota extends Entity {
|
||||
|
||||
return aiQuota;
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(data => {
|
||||
if (data) {
|
||||
const { limit, used } = data;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { FeatureType } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -9,10 +8,10 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, map, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { AuthService } from '../services/auth';
|
||||
import type { UserFeatureStore } from '../stores/user-feature';
|
||||
|
||||
@@ -59,13 +58,7 @@ export class UserFeature extends Entity {
|
||||
features: features,
|
||||
};
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(data => {
|
||||
if (data) {
|
||||
this.features$.next(data.features);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { QuotaQuery } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -9,12 +8,12 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import bytes from 'bytes';
|
||||
import { EMPTY, map, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { AuthService } from '../services/auth';
|
||||
import type { UserQuotaStore } from '../stores/user-quota';
|
||||
|
||||
@@ -79,13 +78,7 @@ export class UserQuota extends Entity {
|
||||
|
||||
return { quota, used };
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(data => {
|
||||
if (data) {
|
||||
const { quota, used } = data;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { InvoicesQuery } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -9,11 +8,11 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, map, mergeMap } from 'rxjs';
|
||||
|
||||
import type { WorkspaceService } from '../../workspace';
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { WorkspaceServerService } from '../services/workspace-server';
|
||||
import { InvoicesStore } from '../stores/invoices';
|
||||
|
||||
@@ -61,13 +60,7 @@ export class WorkspaceInvoices extends Entity {
|
||||
this.pageInvoices$.setValue(data.invoices);
|
||||
return EMPTY;
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
catchErrorInto(this.error$),
|
||||
onStart(() => {
|
||||
this.pageInvoices$.setValue(undefined);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { SubscriptionQuery, SubscriptionRecurring } from '@affine/graphql';
|
||||
import { SubscriptionPlan } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
Entity,
|
||||
@@ -10,11 +9,11 @@ import {
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, mergeMap } from 'rxjs';
|
||||
|
||||
import type { WorkspaceService } from '../../workspace';
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { WorkspaceServerService } from '../services/workspace-server';
|
||||
import { SubscriptionStore } from '../stores/subscription';
|
||||
export type SubscriptionType = NonNullable<
|
||||
@@ -123,13 +122,7 @@ export class WorkspaceSubscription extends Entity {
|
||||
subscription: subscription,
|
||||
};
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(data => {
|
||||
if (data && data.subscription && data.workspaceId && this.store) {
|
||||
this.store.setCachedWorkspaceSubscription(
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { UserFriendlyError } from '@affine/graphql';
|
||||
|
||||
export class NetworkError extends Error {
|
||||
constructor(
|
||||
public readonly originError: Error,
|
||||
public readonly status?: number
|
||||
) {
|
||||
super(`Network error: ${originError.message}`);
|
||||
this.stack = originError.stack;
|
||||
}
|
||||
}
|
||||
|
||||
export function isNetworkError(error: Error): error is NetworkError {
|
||||
return error instanceof NetworkError;
|
||||
}
|
||||
|
||||
export class BackendError extends Error {
|
||||
get status() {
|
||||
return this.originError.status;
|
||||
}
|
||||
|
||||
constructor(public readonly originError: UserFriendlyError) {
|
||||
super(`Server error: ${originError.message}`);
|
||||
this.stack = originError.stack;
|
||||
}
|
||||
}
|
||||
|
||||
export function isBackendError(error: Error): error is BackendError {
|
||||
return error instanceof BackendError;
|
||||
}
|
||||
@@ -1,12 +1,6 @@
|
||||
export type { Invoice } from './entities/invoices';
|
||||
export { Server } from './entities/server';
|
||||
export type { AuthAccountInfo } from './entities/session';
|
||||
export {
|
||||
BackendError,
|
||||
isBackendError,
|
||||
isNetworkError,
|
||||
NetworkError,
|
||||
} from './error';
|
||||
export { AccountChanged } from './events/account-changed';
|
||||
export { AccountLoggedIn } from './events/account-logged-in';
|
||||
export { AccountLoggedOut } from './events/account-logged-out';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { GetInviteInfoQuery } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
fromPromise,
|
||||
@@ -8,10 +7,10 @@ import {
|
||||
onComplete,
|
||||
onStart,
|
||||
Service,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, exhaustMap, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { AcceptInviteStore } from '../stores/accept-invite';
|
||||
import type { InviteInfoStore } from '../stores/invite-info';
|
||||
|
||||
@@ -52,14 +51,7 @@ export class AcceptInviteService extends Service {
|
||||
this.accepted$.next(res);
|
||||
return EMPTY;
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
count: 3,
|
||||
}),
|
||||
smartRetry(),
|
||||
catchErrorInto(this.error$),
|
||||
onStart(() => {
|
||||
this.inviteId$.setValue(inviteId);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AIProvider } from '@affine/core/blocksuite/ai';
|
||||
import { UserFriendlyError } from '@affine/error';
|
||||
import type { OAuthProviderType } from '@affine/graphql';
|
||||
import { track } from '@affine/track';
|
||||
import { OnEvent, Service } from '@toeverything/infra';
|
||||
@@ -7,7 +8,6 @@ import { distinctUntilChanged, map, skip } from 'rxjs';
|
||||
import { ApplicationFocused } from '../../lifecycle';
|
||||
import type { UrlService } from '../../url';
|
||||
import { type AuthAccountInfo, AuthSession } from '../entities/session';
|
||||
import { BackendError } from '../error';
|
||||
import { AccountChanged } from '../events/account-changed';
|
||||
import { AccountLoggedIn } from '../events/account-logged-in';
|
||||
import { AccountLoggedOut } from '../events/account-logged-out';
|
||||
@@ -103,7 +103,7 @@ export class AuthService extends Service {
|
||||
} catch (e) {
|
||||
track.$.$.auth.signInFail({
|
||||
method: 'magic-link',
|
||||
reason: e instanceof BackendError ? e.originError.name : 'unknown',
|
||||
reason: UserFriendlyError.fromAny(e).name,
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ export class AuthService extends Service {
|
||||
} catch (e) {
|
||||
track.$.$.auth.signInFail({
|
||||
method,
|
||||
reason: e instanceof BackendError ? e.originError.name : 'unknown',
|
||||
reason: UserFriendlyError.fromAny(e).name,
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ export class AuthService extends Service {
|
||||
track.$.$.auth.signInFail({
|
||||
method: 'oauth',
|
||||
provider,
|
||||
reason: e instanceof BackendError ? e.originError.name : 'unknown',
|
||||
reason: UserFriendlyError.fromAny(e).name,
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
@@ -181,7 +181,7 @@ export class AuthService extends Service {
|
||||
track.$.$.auth.signInFail({
|
||||
method: 'oauth',
|
||||
provider,
|
||||
reason: e instanceof BackendError ? e.originError.name : 'unknown',
|
||||
reason: UserFriendlyError.fromAny(e).name,
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
@@ -201,7 +201,7 @@ export class AuthService extends Service {
|
||||
} catch (e) {
|
||||
track.$.$.auth.signInFail({
|
||||
method: 'password',
|
||||
reason: e instanceof BackendError ? e.originError.name : 'unknown',
|
||||
reason: UserFriendlyError.fromAny(e).name,
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { UserFriendlyError } from '@affine/graphql';
|
||||
import { UserFriendlyError } from '@affine/error';
|
||||
import { fromPromise, Service } from '@toeverything/infra';
|
||||
|
||||
import { BackendError, NetworkError } from '../error';
|
||||
import type { ServerService } from './server';
|
||||
|
||||
const logger = new DebugLogger('affine:fetch');
|
||||
@@ -46,40 +45,54 @@ export class FetchService extends Service {
|
||||
abortController.abort('timeout');
|
||||
}, timeout);
|
||||
|
||||
const res = await globalThis
|
||||
.fetch(new URL(input, this.serverService.server.serverMetadata.baseUrl), {
|
||||
...init,
|
||||
signal: abortController.signal,
|
||||
headers: {
|
||||
...init?.headers,
|
||||
'x-affine-version': BUILD_CONFIG.appVersion,
|
||||
},
|
||||
})
|
||||
.catch(err => {
|
||||
logger.debug('network error', err);
|
||||
throw new NetworkError(err);
|
||||
});
|
||||
clearTimeout(timeoutId);
|
||||
if (res.status === 504) {
|
||||
const error = new Error('Gateway Timeout');
|
||||
logger.debug('network error', error);
|
||||
throw new NetworkError(error, res.status);
|
||||
}
|
||||
if (!res.ok) {
|
||||
logger.warn(
|
||||
'backend error',
|
||||
new Error(`${res.status} ${res.statusText}`)
|
||||
let res: Response;
|
||||
|
||||
try {
|
||||
res = await globalThis.fetch(
|
||||
new URL(input, this.serverService.server.serverMetadata.baseUrl),
|
||||
{
|
||||
...init,
|
||||
signal: abortController.signal,
|
||||
headers: {
|
||||
...init?.headers,
|
||||
'x-affine-version': BUILD_CONFIG.appVersion,
|
||||
},
|
||||
}
|
||||
);
|
||||
let reason: string | any = '';
|
||||
if (res.headers.get('Content-Type')?.includes('application/json')) {
|
||||
try {
|
||||
reason = await res.json();
|
||||
} catch {
|
||||
// ignore
|
||||
} catch (err: any) {
|
||||
throw new UserFriendlyError({
|
||||
status: 504,
|
||||
code: 'NETWORK_ERROR',
|
||||
type: 'NETWORK_ERROR',
|
||||
name: 'NETWORK_ERROR',
|
||||
message: `Network error: ${err.message}`,
|
||||
stacktrace: err.stack,
|
||||
});
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
if (res.status === 504) {
|
||||
const error = new Error('Gateway Timeout');
|
||||
logger.debug('network error', error);
|
||||
throw new UserFriendlyError({
|
||||
status: 504,
|
||||
code: 'NETWORK_ERROR',
|
||||
type: 'NETWORK_ERROR',
|
||||
name: 'NETWORK_ERROR',
|
||||
message: 'Gateway Timeout',
|
||||
stacktrace: error.stack,
|
||||
});
|
||||
} else {
|
||||
if (res.headers.get('Content-Type') === 'application/json') {
|
||||
throw UserFriendlyError.fromAny(await res.json());
|
||||
} else {
|
||||
throw UserFriendlyError.fromAny(await res.text());
|
||||
}
|
||||
}
|
||||
throw new BackendError(UserFriendlyError.fromAnyError(reason));
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { UserFriendlyError } from '@affine/error';
|
||||
import {
|
||||
gqlFetcherFactory,
|
||||
GraphQLError,
|
||||
type GraphQLQuery,
|
||||
type QueryOptions,
|
||||
type QueryResponse,
|
||||
UserFriendlyError,
|
||||
} from '@affine/graphql';
|
||||
import { fromPromise, Service } from '@toeverything/infra';
|
||||
import type { Observable } from 'rxjs';
|
||||
|
||||
import { BackendError } from '../error';
|
||||
import { AuthService } from './auth';
|
||||
import type { FetchService } from './fetch';
|
||||
|
||||
@@ -40,16 +38,9 @@ export class GraphQLService extends Service {
|
||||
try {
|
||||
return await this.rawGql(options);
|
||||
} catch (anyError) {
|
||||
let error = anyError;
|
||||
const error = UserFriendlyError.fromAny(anyError);
|
||||
|
||||
// NOTE(@forehalo):
|
||||
// GraphQL error is not present by non-200 status code, but by responding `errors` fields in the body
|
||||
// So it will never be `BackendError` originally.
|
||||
if (anyError instanceof GraphQLError) {
|
||||
error = new BackendError(UserFriendlyError.fromAnyError(anyError));
|
||||
}
|
||||
|
||||
if (error instanceof BackendError && error.status === 403) {
|
||||
if (error.isStatus(401)) {
|
||||
this.framework.get(AuthService).session.revalidate();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { UserFriendlyError } from '@affine/graphql';
|
||||
import { type UserFriendlyError } from '@affine/error';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
fromPromise,
|
||||
LiveData,
|
||||
onComplete,
|
||||
onStart,
|
||||
Service,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { catchError, EMPTY, exhaustMap, mergeMap } from 'rxjs';
|
||||
import { EMPTY, exhaustMap, mergeMap } from 'rxjs';
|
||||
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { SelfhostGenerateLicenseStore } from '../stores/selfhost-generate-license';
|
||||
|
||||
export class SelfhostGenerateLicenseService extends Service {
|
||||
@@ -26,22 +26,12 @@ export class SelfhostGenerateLicenseService extends Service {
|
||||
return fromPromise(async () => {
|
||||
return await this.store.generateKey(sessionId);
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(key => {
|
||||
this.licenseKey$.next(key);
|
||||
return EMPTY;
|
||||
}),
|
||||
catchError(err => {
|
||||
this.error$.next(UserFriendlyError.fromAnyError(err));
|
||||
console.error(err);
|
||||
return EMPTY;
|
||||
}),
|
||||
catchErrorInto(this.error$),
|
||||
onStart(() => {
|
||||
this.isLoading$.next(true);
|
||||
}),
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { License } from '@affine/graphql';
|
||||
import {
|
||||
backoffRetry,
|
||||
catchErrorInto,
|
||||
effect,
|
||||
exhaustMapWithTrailing,
|
||||
@@ -9,11 +8,11 @@ import {
|
||||
onComplete,
|
||||
onStart,
|
||||
Service,
|
||||
smartRetry,
|
||||
} from '@toeverything/infra';
|
||||
import { EMPTY, mergeMap } from 'rxjs';
|
||||
|
||||
import type { WorkspaceService } from '../../workspace';
|
||||
import { isBackendError, isNetworkError } from '../error';
|
||||
import type { SelfhostLicenseStore } from '../stores/selfhost-license';
|
||||
|
||||
export class SelfhostLicenseService extends Service {
|
||||
@@ -36,13 +35,7 @@ export class SelfhostLicenseService extends Service {
|
||||
}
|
||||
return await this.store.getLicense(currentWorkspaceId, signal);
|
||||
}).pipe(
|
||||
backoffRetry({
|
||||
when: isNetworkError,
|
||||
count: Infinity,
|
||||
}),
|
||||
backoffRetry({
|
||||
when: isBackendError,
|
||||
}),
|
||||
smartRetry(),
|
||||
mergeMap(data => {
|
||||
if (data) {
|
||||
this.license$.next(data);
|
||||
|
||||
Reference in New Issue
Block a user