-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.ts
More file actions
191 lines (173 loc) · 6.32 KB
/
Copy patherrors.ts
File metadata and controls
191 lines (173 loc) · 6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/** Exception hierarchy for AudD API errors. */
export interface AudDApiErrorFields {
errorCode: number;
message: string;
httpStatus: number;
requestId: string | null;
requestedParams: Record<string, unknown>;
requestMethod: string | null;
brandedMessage: string | null;
rawResponse: unknown;
}
export type AudDApiErrorInit = Partial<AudDApiErrorFields> &
Pick<AudDApiErrorFields, "errorCode" | "message" | "httpStatus">;
/** Base for everything thrown by this SDK. */
export class AudDError extends Error {
override name = "AudDError";
}
/** Server returned `status: error`. Carries the AudD error code + the full echo. */
export class AudDAPIError extends AudDError {
override name = "AudDAPIError";
errorCode: number;
httpStatus: number;
requestId: string | null;
requestedParams: Record<string, unknown>;
requestMethod: string | null;
brandedMessage: string | null;
rawResponse: unknown;
/** Original `error_message` from the server. (`Error.message` may be overridden by subclasses.) */
serverMessage: string;
constructor(init: AudDApiErrorInit) {
super(`[#${init.errorCode}] ${init.message}`);
this.errorCode = init.errorCode;
this.serverMessage = init.message;
this.httpStatus = init.httpStatus;
this.requestId = init.requestId ?? null;
this.requestedParams = init.requestedParams ?? {};
this.requestMethod = init.requestMethod ?? null;
this.brandedMessage = init.brandedMessage ?? null;
this.rawResponse = init.rawResponse ?? null;
}
}
export class AudDAuthenticationError extends AudDAPIError {
override name = "AudDAuthenticationError";
}
export class AudDQuotaError extends AudDAPIError {
override name = "AudDQuotaError";
}
export class AudDSubscriptionError extends AudDAPIError {
override name = "AudDSubscriptionError";
}
export class AudDCustomCatalogAccessError extends AudDSubscriptionError {
override name = "AudDCustomCatalogAccessError";
}
export class AudDInvalidRequestError extends AudDAPIError {
override name = "AudDInvalidRequestError";
}
export class AudDInvalidAudioError extends AudDAPIError {
override name = "AudDInvalidAudioError";
}
export class AudDRateLimitError extends AudDAPIError {
override name = "AudDRateLimitError";
}
export class AudDStreamLimitError extends AudDAPIError {
override name = "AudDStreamLimitError";
}
export class AudDNotReleasedError extends AudDAPIError {
override name = "AudDNotReleasedError";
}
export class AudDBlockedError extends AudDAPIError {
override name = "AudDBlockedError";
}
export class AudDNeedsUpdateError extends AudDAPIError {
override name = "AudDNeedsUpdateError";
}
export class AudDServerError extends AudDAPIError {
override name = "AudDServerError";
}
export class AudDConnectionError extends AudDError {
override name = "AudDConnectionError";
override cause?: unknown;
constructor(message: string, cause?: unknown) {
super(message);
this.cause = cause;
}
}
export class AudDSerializationError extends AudDError {
override name = "AudDSerializationError";
rawText: string;
constructor(message: string, rawText = "") {
super(message);
this.rawText = rawText;
}
}
export type AudDAPIErrorCtor = new (init: AudDApiErrorInit) => AudDAPIError;
const CODE_MAP: Record<number, AudDAPIErrorCtor> = {
900: AudDAuthenticationError,
901: AudDAuthenticationError,
903: AudDAuthenticationError,
902: AudDQuotaError,
904: AudDSubscriptionError,
905: AudDSubscriptionError,
50: AudDInvalidRequestError,
51: AudDInvalidRequestError,
600: AudDInvalidRequestError,
601: AudDInvalidRequestError,
602: AudDInvalidRequestError,
700: AudDInvalidRequestError,
701: AudDInvalidRequestError,
702: AudDInvalidRequestError,
906: AudDInvalidRequestError,
300: AudDInvalidAudioError,
400: AudDInvalidAudioError,
500: AudDInvalidAudioError,
610: AudDStreamLimitError,
611: AudDRateLimitError,
907: AudDNotReleasedError,
19: AudDBlockedError,
31337: AudDBlockedError,
20: AudDNeedsUpdateError,
100: AudDServerError,
1000: AudDServerError,
};
export function errorClassForCode(code: number): AudDAPIErrorCtor {
return CODE_MAP[code] ?? AudDServerError;
}
function brandedMessageOf(result: unknown): string | null {
if (typeof result !== "object" || result === null) return null;
const r = result as { artist?: unknown; title?: unknown };
const parts: string[] = [];
if (typeof r.artist === "string" && r.artist.length > 0) parts.push(r.artist);
if (typeof r.title === "string" && r.title.length > 0) parts.push(r.title);
return parts.length === 0 ? null : parts.join(" — ");
}
export interface ServerErrorBody {
error?: { error_code?: number | undefined; error_message?: string | undefined } | undefined;
result?: unknown;
request_params?: Record<string, unknown> | undefined;
requested_params?: Record<string, unknown> | undefined;
request_api_method?: string | undefined;
}
export interface RaiseFromErrorOpts {
httpStatus: number;
requestId: string | null;
customCatalogContext?: boolean;
}
const CUSTOM_CATALOG_PREFIX =
"Adding songs to your custom catalog requires enterprise access that isn't enabled on your account.\n\n" +
"Note: the custom-catalog endpoint is for adding songs to your private fingerprint database, not for music recognition. " +
"If you intended to identify music, use recognize(...) (or recognizeEnterprise(...) for files longer than 25 seconds) instead.\n\n" +
"To request custom-catalog access, contact api@audd.io.\n\n";
export function raiseFromErrorResponse(body: ServerErrorBody, opts: RaiseFromErrorOpts): never {
const code = body.error?.error_code ?? 0;
const message = body.error?.error_message ?? "";
const requestedParams = body.request_params ?? body.requested_params ?? {};
const requestMethod = body.request_api_method ?? null;
const branded = brandedMessageOf(body.result);
const fields: AudDApiErrorFields = {
errorCode: code,
message,
httpStatus: opts.httpStatus,
requestId: opts.requestId,
requestedParams,
requestMethod,
brandedMessage: branded,
rawResponse: body,
};
const Cls = errorClassForCode(code);
if (opts.customCatalogContext === true && Cls === AudDSubscriptionError) {
const overridden = `${CUSTOM_CATALOG_PREFIX}[Server message: ${message}]`;
throw new AudDCustomCatalogAccessError({ ...fields, message: overridden });
}
throw new Cls(fields);
}