Skip to content

Commit cee7ad8

Browse files
authored
Add types to ErrorFactory message parameters (#1720)
* Add types to ErrorFactory message parameters * Add ErrorParams to packages that use ErrorFactory
1 parent 6dc1533 commit cee7ad8

File tree

10 files changed

+75
-27
lines changed

10 files changed

+75
-27
lines changed

packages/app/src/errors.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ const ERRORS: ErrorMap<AppError> = {
4040
'Firebase App instance.'
4141
};
4242

43-
const appErrors = new ErrorFactory<AppError>('app', 'Firebase', ERRORS);
43+
type ErrorParams = { [key in AppError]: { name: string } };
4444

45-
export function error(code: AppError, args?: { [name: string]: any }) {
46-
throw appErrors.create(code, args);
47-
}
45+
export const ERROR_FACTORY = new ErrorFactory<AppError, ErrorParams>(
46+
'app',
47+
'Firebase',
48+
ERRORS
49+
);

packages/app/src/firebaseApp.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
FirebaseAppInternals
2828
} from '@firebase/app-types/private';
2929
import { deepCopy, deepExtend } from '@firebase/util';
30-
import { error, AppError } from './errors';
30+
import { AppError, ERROR_FACTORY } from './errors';
3131
import { DEFAULT_ENTRY_NAME } from './constants';
3232

3333
interface ServicesCache {
@@ -202,7 +202,7 @@ export class FirebaseAppImpl implements FirebaseApp {
202202
*/
203203
private checkDestroyed_(): void {
204204
if (this.isDeleted_) {
205-
error(AppError.APP_DELETED, { name: this.name_ });
205+
throw ERROR_FACTORY.create(AppError.APP_DELETED, { name: this.name_ });
206206
}
207207
}
208208
}

packages/app/src/firebaseNamespaceCore.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
} from '@firebase/app-types/private';
3232
import { deepExtend, patchProperty } from '@firebase/util';
3333
import { FirebaseAppImpl } from './firebaseApp';
34-
import { error, AppError } from './errors';
34+
import { ERROR_FACTORY, AppError } from './errors';
3535
import { FirebaseAppLiteImpl } from './lite/firebaseAppLite';
3636
import { DEFAULT_ENTRY_NAME } from './constants';
3737
import { version } from '../../firebase/package.json';
@@ -105,7 +105,7 @@ export function createFirebaseNamespaceCore(
105105
function app(name?: string): FirebaseApp {
106106
name = name || DEFAULT_ENTRY_NAME;
107107
if (!contains(apps, name)) {
108-
error(AppError.NO_APP, { name: name });
108+
throw ERROR_FACTORY.create(AppError.NO_APP, { name: name });
109109
}
110110
return apps[name];
111111
}
@@ -134,11 +134,11 @@ export function createFirebaseNamespaceCore(
134134
const { name } = config;
135135

136136
if (typeof name !== 'string' || !name) {
137-
error(AppError.BAD_APP_NAME, { name: String(name) });
137+
throw ERROR_FACTORY.create(AppError.BAD_APP_NAME, { name: String(name) });
138138
}
139139

140140
if (contains(apps, name)) {
141-
error(AppError.DUPLICATE_APP, { name: name });
141+
throw ERROR_FACTORY.create(AppError.DUPLICATE_APP, { name: name });
142142
}
143143

144144
const app = new firebaseAppImpl(
@@ -177,7 +177,7 @@ export function createFirebaseNamespaceCore(
177177
): FirebaseServiceNamespace<FirebaseService> {
178178
// Cannot re-register a service that already exists
179179
if (factories[name]) {
180-
error(AppError.DUPLICATE_SERVICE, { name: name });
180+
throw ERROR_FACTORY.create(AppError.DUPLICATE_SERVICE, { name: name });
181181
}
182182

183183
// Capture the service factory for later service instantiation
@@ -198,7 +198,9 @@ export function createFirebaseNamespaceCore(
198198
if (typeof appArg[name] !== 'function') {
199199
// Invalid argument.
200200
// This happens in the following case: firebase.storage('gs:/')
201-
error(AppError.INVALID_APP_ARGUMENT, { name: name });
201+
throw ERROR_FACTORY.create(AppError.INVALID_APP_ARGUMENT, {
202+
name: name
203+
});
202204
}
203205

204206
// Forward service instance lookup to the FirebaseApp.

packages/app/src/lite/firebaseAppLite.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
FirebaseService
2727
} from '@firebase/app-types/private';
2828
import { deepCopy, deepExtend } from '@firebase/util';
29-
import { error, AppError } from '../errors';
29+
import { ERROR_FACTORY, AppError } from '../errors';
3030
import { DEFAULT_ENTRY_NAME } from '../constants';
3131

3232
interface ServicesCache {
@@ -168,7 +168,7 @@ export class FirebaseAppLiteImpl implements FirebaseApp {
168168
*/
169169
private checkDestroyed_(): void {
170170
if (this.isDeleted_) {
171-
error(AppError.APP_DELETED, { name: this.name_ });
171+
throw ERROR_FACTORY.create(AppError.APP_DELETED, { name: this.name_ });
172172
}
173173
}
174174
}

packages/installations/src/util/errors.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ const ERROR_DESCRIPTION_MAP: { readonly [key in ErrorCode]: string } = {
4343
"Can't delete installation while there is a pending registration request."
4444
};
4545

46-
export const ERROR_FACTORY = new ErrorFactory(
46+
interface ErrorParams {
47+
[ErrorCode.REQUEST_FAILED]: {
48+
requestName: string;
49+
} & ServerErrorData;
50+
}
51+
52+
export const ERROR_FACTORY = new ErrorFactory<ErrorCode, ErrorParams>(
4753
SERVICE,
4854
SERVICE_NAME,
4955
ERROR_DESCRIPTION_MAP

packages/messaging/src/models/errors.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,15 @@ export const ERROR_MAP: ErrorMap<ErrorCode> = {
157157
'The public VAPID key did not equal 65 bytes when decrypted.'
158158
};
159159

160-
export const errorFactory = new ErrorFactory(
160+
interface ErrorParams {
161+
[ErrorCode.FAILED_DEFAULT_REGISTRATION]: { browserErrorMessage: string };
162+
[ErrorCode.TOKEN_SUBSCRIBE_FAILED]: { errorInfo: string };
163+
[ErrorCode.TOKEN_UNSUBSCRIBE_FAILED]: { errorInfo: string };
164+
[ErrorCode.TOKEN_UPDATE_FAILED]: { errorInfo: string };
165+
[ErrorCode.UNABLE_TO_RESUBSCRIBE]: { errorInfo: string };
166+
}
167+
168+
export const errorFactory = new ErrorFactory<ErrorCode, ErrorParams>(
161169
'messaging',
162170
'Messaging',
163171
ERROR_MAP

packages/messaging/src/models/iid-model.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ export class IidModel {
7272

7373
responseData = await response.json();
7474
} catch (err) {
75-
throw errorFactory.create(ErrorCode.TOKEN_SUBSCRIBE_FAILED);
75+
throw errorFactory.create(ErrorCode.TOKEN_SUBSCRIBE_FAILED, {
76+
errorInfo: err
77+
});
7678
}
7779

7880
if (responseData.error) {
@@ -144,7 +146,9 @@ export class IidModel {
144146
);
145147
responseData = await response.json();
146148
} catch (err) {
147-
throw errorFactory.create(ErrorCode.TOKEN_UPDATE_FAILED);
149+
throw errorFactory.create(ErrorCode.TOKEN_UPDATE_FAILED, {
150+
errorInfo: err
151+
});
148152
}
149153

150154
if (responseData.error) {
@@ -196,7 +200,9 @@ export class IidModel {
196200
});
197201
}
198202
} catch (err) {
199-
throw errorFactory.create(ErrorCode.TOKEN_UNSUBSCRIBE_FAILED);
203+
throw errorFactory.create(ErrorCode.TOKEN_UNSUBSCRIBE_FAILED, {
204+
errorInfo: err
205+
});
200206
}
201207
}
202208
}

packages/performance/src/utils/errors.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ const ERROR_DESCRIPTION_MAP: { readonly [key in ErrorCode]: string } = {
4343
[ErrorCode.RC_NOT_OK]: 'RC response is not ok'
4444
};
4545

46-
export const ERROR_FACTORY = new ErrorFactory(
46+
interface ErrorParams {
47+
[ErrorCode.TRACE_STARTED_BEFORE]: { traceName: string };
48+
[ErrorCode.TRACE_STOPPED_BEFORE]: { traceName: string };
49+
}
50+
51+
export const ERROR_FACTORY = new ErrorFactory<ErrorCode, ErrorParams>(
4752
SERVICE,
4853
SERVICE_NAME,
4954
ERROR_DESCRIPTION_MAP

packages/util/src/errors.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,25 @@ export class FirebaseError extends Error {
103103
}
104104
}
105105

106-
export class ErrorFactory<ErrorCode extends string> {
106+
export class ErrorFactory<
107+
ErrorCode extends string,
108+
ErrorParams extends { readonly [K in ErrorCode]?: ErrorData } = {}
109+
> {
107110
constructor(
108111
private readonly service: string,
109112
private readonly serviceName: string,
110113
private readonly errors: ErrorMap<ErrorCode>
111114
) {}
112115

113-
create(code: ErrorCode, data: ErrorData = {}): FirebaseError {
116+
create<K extends ErrorCode>(
117+
code: K,
118+
...data: K extends keyof ErrorParams ? [ErrorParams[K]] : []
119+
): FirebaseError {
120+
const customData = data[0] || {};
114121
const fullCode = `${this.service}/${code}`;
115122
const template = this.errors[code];
116123

117-
const message = template ? replaceTemplate(template, data) : 'Error';
124+
const message = template ? replaceTemplate(template, customData) : 'Error';
118125
// Service Name: Error message (service/code).
119126
const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`;
120127

@@ -123,14 +130,14 @@ export class ErrorFactory<ErrorCode extends string> {
123130
// Keys with an underscore at the end of their name are not included in
124131
// error.data for some reason.
125132
// TODO: Replace with Object.entries when lib is updated to es2017.
126-
for (const key of Object.keys(data)) {
133+
for (const key of Object.keys(customData)) {
127134
if (key.slice(-1) !== '_') {
128135
if (key in error) {
129136
console.warn(
130137
`Overwriting FirebaseError base field "${key}" can cause unexpected behavior.`
131138
);
132139
}
133-
error[key] = data[key];
140+
error[key] = customData[key];
134141
}
135142
}
136143

packages/util/test/errors.test.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@ const ERROR_MAP: ErrorMap<ErrorCode> = {
3232
'I decided to use {$code} to represent the error code from my server.'
3333
};
3434

35-
const ERROR_FACTORY = new ErrorFactory<ErrorCode>('fake', 'Fake', ERROR_MAP);
35+
interface ErrorParams {
36+
'file-not-found': { file: string };
37+
'anon-replace': { repl_: string };
38+
'overwrite-field': { code: string };
39+
}
40+
41+
const ERROR_FACTORY = new ErrorFactory<ErrorCode, ErrorParams>(
42+
'fake',
43+
'Fake',
44+
ERROR_MAP
45+
);
3646

3747
describe('FirebaseError', () => {
3848
it('creates an Error', () => {
@@ -68,7 +78,9 @@ describe('FirebaseError', () => {
6878
});
6979

7080
it('uses the key in the template if the replacement is missing', () => {
71-
const e = ERROR_FACTORY.create('file-not-found', { fileX: 'foo.txt' });
81+
const e = ERROR_FACTORY.create('file-not-found', {
82+
fileX: 'foo.txt'
83+
} as any);
7284
assert.equal(e.code, 'fake/file-not-found');
7385
assert.equal(
7486
e.message,

0 commit comments

Comments
 (0)