diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 7f5e3363bb..29abdc9113 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -28,6 +28,13 @@ jobs: - run: npm run lint - run: npm run format:check - run: npx tsc --noEmit ably.d.ts modular.d.ts + # src/ is compiled by esbuild, which strips types without checking them, so this is + # the only step that typechecks the library itself. + - run: npx tsc --noEmit -p tsconfig.json + # The error-code union is generated from the ably-common submodule at its pinned + # commit; fail if the committed copy has drifted from the registry. + - run: npm run generate:errorcodes-ts + - run: git diff --exit-code -- src/common/lib/types/errorcodes.ts # for some reason, this doesn't work in CI using `npx attw --pack .` - run: npm pack - run: npx attw ably-$(node -e "console.log(require('./package.json').version)").tgz --summary --exclude-entrypoints 'ably/modular' diff --git a/package.json b/package.json index 68a4bc2ba9..f5916a6f58 100644 --- a/package.json +++ b/package.json @@ -206,6 +206,7 @@ "modulereport": "tsc --noEmit --esModuleInterop scripts/moduleReport.ts && esr scripts/moduleReport.ts", "speccoveragereport": "tsc --noEmit --esModuleInterop --target ES2017 --moduleResolution node scripts/specCoverageReport.ts && esr scripts/specCoverageReport.ts", "process-private-api-data": "tsc --noEmit --esModuleInterop --strictNullChecks scripts/processPrivateApiData/run.ts && esr scripts/processPrivateApiData/run.ts", - "docs": "typedoc" + "docs": "typedoc", + "generate:errorcodes-ts": "node test/common/ably-common/errors/scripts/generate-ts.js --format=type --out src/common/lib/types/errorcodes.ts" } } diff --git a/src/common/lib/client/auth.ts b/src/common/lib/client/auth.ts index f8f65c938e..dd668c33f0 100644 --- a/src/common/lib/client/auth.ts +++ b/src/common/lib/client/auth.ts @@ -2,6 +2,7 @@ import Logger from '../util/logger'; import * as Utils from '../util/utils'; import Multicaster, { MulticasterInstance } from '../util/multicaster'; import ErrorInfo, { IPartialErrorInfo } from '../types/errorinfo'; +import type { ErrorCode } from '../types/errorcodes'; import { RequestResultError, RequestParams, RequestResult } from '../../types/http'; import * as API from '../../../../ably'; import BaseClient from './baseclient'; @@ -28,17 +29,27 @@ function isRealtime(client: BaseClient): client is BaseRealtime { return !!(client as BaseRealtime).connection; } +/* Fallbacks this SDK supplies when the callback's error carries no code of its own. Annotated + * so they are checked against the registry; the `err.code` below cannot be, because it comes + * from the application's authCallback rather than from this repository. */ +const AUTH_CALLBACK_ERROR_CODE: ErrorCode = 40170; +const AUTH_CALLBACK_FORBIDDEN_CODE: ErrorCode = 40300; + /* A client auth callback may give errors in any number of formats; normalise to an ErrorInfo or PartialErrorInfo */ function normaliseAuthcallbackError(err: any) { if (!Utils.isErrorInfoOrPartialErrorInfo(err)) { - return new ErrorInfo(Utils.inspectError(err), err.code || 40170, err.statusCode || 401); + return new ErrorInfo( + Utils.inspectError(err), + (err.code as ErrorCode) || AUTH_CALLBACK_ERROR_CODE, + err.statusCode || 401, + ); } /* network errors will not have an inherent error code */ if (!err.code) { if (err.statusCode === 403) { - err.code = 40300; + err.code = AUTH_CALLBACK_FORBIDDEN_CODE; } else { - err.code = 40170; + err.code = AUTH_CALLBACK_ERROR_CODE; /* normalise statusCode to 401 per RSA4e */ err.statusCode = 401; } diff --git a/src/common/lib/client/realtimechannel.ts b/src/common/lib/client/realtimechannel.ts index b4c42c8e6c..dcb389c02b 100644 --- a/src/common/lib/client/realtimechannel.ts +++ b/src/common/lib/client/realtimechannel.ts @@ -697,7 +697,7 @@ class RealtimeChannel extends EventEmitter { case actions.DETACHED: { const detachErr = message.error - ? ErrorInfo.fromValues(message.error) + ? ErrorInfo.fromWireValues(message.error) : new ErrorInfo('Channel detached', 90001, 404); if (this.state === 'detaching') { this.notifyState('detached', detachErr); @@ -858,7 +858,7 @@ class RealtimeChannel extends EventEmitter { /* attach/detach operation attempted on superseded transport handle */ this.checkPendingState(); } else { - this.notifyState('failed', ErrorInfo.fromValues(err)); + this.notifyState('failed', ErrorInfo.fromWireValues(err)); } break; } diff --git a/src/common/lib/transport/connectionerrors.ts b/src/common/lib/transport/connectionerrors.ts index fcd7b3c8af..175a81145c 100644 --- a/src/common/lib/transport/connectionerrors.ts +++ b/src/common/lib/transport/connectionerrors.ts @@ -1,5 +1,8 @@ import ErrorInfo from '../types/errorinfo'; +import type { ErrorCode } from '../types/errorcodes'; +// `satisfies` checks every code against the registry while keeping the literal types, so +// that the members stay usable as ErrorCode at the call sites below. const ConnectionErrorCodes = { DISCONNECTED: 80003, SUSPENDED: 80002, @@ -8,7 +11,7 @@ const ConnectionErrorCodes = { CLOSED: 80017, UNKNOWN_CONNECTION_ERR: 50002, UNKNOWN_CHANNEL_ERR: 50001, -}; +} as const satisfies Record; const ConnectionErrors = { disconnected: () => @@ -50,7 +53,7 @@ const ConnectionErrors = { unknownChannelErr: () => ErrorInfo.fromValues({ statusCode: 500, - code: ConnectionErrorCodes.UNKNOWN_CONNECTION_ERR, + code: ConnectionErrorCodes.UNKNOWN_CHANNEL_ERR, message: 'Internal channel error', }), }; @@ -59,7 +62,9 @@ export function isRetriable(err: ErrorInfo) { if (!err.statusCode || !err.code || err.statusCode >= 500) { return true; } - return Object.values(ConnectionErrorCodes).includes(err.code); + // Widened because `as const` gives the values their own narrow literal union, which + // `includes` will not accept an arbitrary ErrorCode against. + return (Object.values(ConnectionErrorCodes) as ErrorCode[]).includes(err.code); } export default ConnectionErrors; diff --git a/src/common/lib/types/devicedetails.ts b/src/common/lib/types/devicedetails.ts index 25b099d3d9..5119a263bc 100644 --- a/src/common/lib/types/devicedetails.ts +++ b/src/common/lib/types/devicedetails.ts @@ -124,7 +124,7 @@ class DeviceDetails { } static fromValues(values: Record): DeviceDetails { - values.error = values.error && ErrorInfo.fromValues(values.error as IConvertibleToErrorInfo); + values.error = values.error && ErrorInfo.fromWireValues(values.error as IConvertibleToErrorInfo); return Object.assign(new DeviceDetails(), values); } diff --git a/src/common/lib/types/errorcodes.ts b/src/common/lib/types/errorcodes.ts new file mode 100644 index 0000000000..25fca02f0b --- /dev/null +++ b/src/common/lib/types/errorcodes.ts @@ -0,0 +1,266 @@ +// GENERATED FROM ably-common/errors/codes — DO NOT EDIT. +// Regenerate with: npm run generate:errorcodes-ts + +/** A registered Ably error code. */ +export type ErrorCode = + | 10000 + | 20000 + | 40000 + | 40001 + | 40002 + | 40003 + | 40004 + | 40005 + | 40006 + | 40007 + | 40008 + | 40009 + | 40010 + | 40011 + | 40012 + | 40013 + | 40014 + | 40015 + | 40016 + | 40017 + | 40018 + | 40019 + | 40020 + | 40021 + | 40022 + | 40023 + | 40024 + | 40025 + | 40030 + | 40031 + | 40032 + | 40033 + | 40034 + | 40035 + | 40099 + | 40100 + | 40101 + | 40102 + | 40103 + | 40104 + | 40105 + | 40106 + | 40110 + | 40111 + | 40112 + | 40113 + | 40114 + | 40115 + | 40120 + | 40121 + | 40125 + | 40126 + | 40127 + | 40128 + | 40130 + | 40131 + | 40132 + | 40133 + | 40140 + | 40141 + | 40142 + | 40143 + | 40144 + | 40145 + | 40150 + | 40151 + | 40160 + | 40161 + | 40162 + | 40163 + | 40164 + | 40165 + | 40166 + | 40167 + | 40170 + | 40171 + | 40172 + | 40180 + | 40181 + | 40182 + | 40300 + | 40310 + | 40311 + | 40320 + | 40330 + | 40331 + | 40332 + | 40400 + | 40500 + | 40900 + | 41001 + | 42200 + | 42210 + | 42211 + | 42212 + | 42213 + | 42910 + | 42911 + | 42912 + | 42913 + | 42914 + | 42915 + | 42916 + | 42917 + | 42918 + | 42920 + | 42921 + | 42922 + | 42923 + | 42924 + | 42925 + | 42926 + | 50000 + | 50001 + | 50002 + | 50003 + | 50004 + | 50005 + | 50006 + | 50010 + | 50205 + | 50210 + | 50305 + | 50306 + | 50310 + | 50320 + | 50330 + | 50405 + | 50410 + | 61002 + | 70000 + | 70001 + | 70002 + | 70003 + | 70004 + | 70005 + | 70006 + | 71000 + | 71001 + | 71100 + | 71101 + | 71102 + | 71200 + | 71201 + | 71202 + | 71203 + | 71204 + | 71300 + | 71301 + | 71302 + | 71303 + | 72000 + | 72001 + | 72002 + | 72003 + | 72004 + | 72005 + | 72006 + | 72007 + | 72008 + | 80000 + | 80001 + | 80002 + | 80003 + | 80004 + | 80005 + | 80006 + | 80007 + | 80008 + | 80009 + | 80010 + | 80011 + | 80012 + | 80013 + | 80014 + | 80015 + | 80016 + | 80017 + | 80018 + | 80019 + | 80020 + | 80021 + | 80022 + | 80023 + | 80024 + | 80030 + | 90000 + | 90001 + | 90002 + | 90003 + | 90004 + | 90005 + | 90006 + | 90007 + | 90008 + | 90009 + | 90010 + | 90021 + | 91000 + | 91001 + | 91002 + | 91003 + | 91004 + | 91005 + | 91006 + | 91007 + | 91008 + | 91100 + | 92000 + | 92001 + | 92002 + | 92003 + | 92004 + | 92005 + | 92006 + | 92007 + | 92008 + | 93001 + | 93002 + | 101000 + | 101001 + | 101002 + | 101003 + | 101004 + | 102000 + | 102001 + | 102002 + | 102003 + | 102004 + | 102005 + | 102050 + | 102051 + | 102052 + | 102053 + | 102054 + | 102100 + | 102101 + | 102102 + | 102103 + | 102104 + | 102105 + | 102106 + | 102107 + | 102108 + | 102109 + | 102110 + | 102111 + | 102112 + | 102113 + | 102200 + | 102201 + | 102202 + | 103000 + | 103001 + | 103002 + | 103003 + | 103004 + | 103005 + | 103006 + | 103007 + | 103008; diff --git a/src/common/lib/types/errorinfo.ts b/src/common/lib/types/errorinfo.ts index 64523921dd..3080f7d2ee 100644 --- a/src/common/lib/types/errorinfo.ts +++ b/src/common/lib/types/errorinfo.ts @@ -1,9 +1,10 @@ import Platform from 'common/platform'; import * as Utils from '../util/utils'; import * as API from '../../../../ably'; +import type { ErrorCode } from './errorcodes'; export interface IPartialErrorInfo extends Error { - code: number | null; + code: ErrorCode | null; statusCode?: number; cause?: ErrorInfo | PartialErrorInfo; href?: string; @@ -24,6 +25,13 @@ function toString(err: ErrorInfo | PartialErrorInfo) { return result; } +/** + * The values of an error decoded from a server response body or a ProtocolMessage. `code` is + * a plain `number` rather than an {@link ErrorCode} because the server chose it, and may use + * codes this version of the client does not know about, so it cannot be checked against the + * registry. Reached only via {@link ErrorInfo.fromWireValues}; errors this SDK raises itself + * use {@link ErrorInfoValues}. + */ export interface IConvertibleToErrorInfo { message: string; code: number; @@ -34,6 +42,7 @@ export interface IConvertibleToErrorInfo { href?: string; } +/** As {@link IConvertibleToErrorInfo}, for the partial case. */ export interface IConvertibleToPartialErrorInfo { message: string; code: number | null; @@ -44,19 +53,45 @@ export interface IConvertibleToPartialErrorInfo { href?: string; } +/** + * The values an error raised by this SDK is constructed from. Identical to + * {@link IConvertibleToErrorInfo} except that `code` must be a registered Ably error code, + * so that an unregistered code, or a `code`/`statusCode` transposition, fails to compile. + * This is the shape to use for any error written in this repository. + */ +export interface ErrorInfoValues extends Omit { + code: ErrorCode; +} + +/** As {@link ErrorInfoValues}, for the partial case. */ +export interface PartialErrorInfoValues extends Omit { + code: ErrorCode | null; +} + +/** + * Apply the help.ably.io href default shared by the `fromValues` factories. Errors built + * with `new ErrorInfo(...)` deliberately do not get it. + */ +function withHelpHref(err: T): T { + if (err.code && !err.href) { + err.href = 'https://help.ably.io/error/' + err.code; + } + return err; +} + export default class ErrorInfo extends Error implements IPartialErrorInfo, API.ErrorInfo { - code: number; + code: ErrorCode; statusCode: number; cause?: ErrorInfo; href?: string; detail?: Record; remediation?: string; - constructor(message: string, code: number, statusCode: number, cause?: ErrorInfo, detail?: Record); - constructor(values: IConvertibleToErrorInfo); + constructor(message: string, code: ErrorCode, statusCode: number, cause?: ErrorInfo, detail?: Record); + constructor(values: ErrorInfoValues); constructor( - messageOrValues: string | IConvertibleToErrorInfo, - code?: number, + messageOrValues: string | ErrorInfoValues, + code?: ErrorCode, statusCode?: number, cause?: ErrorInfo, detail?: Record, @@ -84,7 +119,7 @@ export default class ErrorInfo extends Error implements IPartialErrorInfo, API.E if (typeof Object.setPrototypeOf !== 'undefined') { Object.setPrototypeOf(this, ErrorInfo.prototype); } - this.code = code as number; + this.code = code as ErrorCode; this.statusCode = statusCode as number; this.cause = cause; this.detail = detail; @@ -95,21 +130,29 @@ export default class ErrorInfo extends Error implements IPartialErrorInfo, API.E return toString(this); } - static fromValues(values: IConvertibleToErrorInfo): ErrorInfo { - // Delegate shape validation and field assignment to the options-object constructor; - // fromValues only adds the help.ably.io href default for server-decoded errors that - // arrive without one. SDK-thrown errors that use `new ErrorInfo({...})` directly do - // not get this default, by design. - const result = new ErrorInfo(values); - if (result.code && !result.href) { - result.href = 'https://help.ably.io/error/' + result.code; - } - return result; + /** + * Build an error this SDK is raising itself, adding the help.ably.io href default. `code` + * is checked against the registry. To build an error out of a server response body or a + * ProtocolMessage, use {@link ErrorInfo.fromWireValues} instead. + */ + static fromValues(values: ErrorInfoValues): ErrorInfo { + // Shape validation and field assignment are delegated to the options-object constructor. + return withHelpHref(new ErrorInfo(values)); + } + + /** + * Build an error out of data received from the server — a response body, or the `error` + * field of a ProtocolMessage. The cast is deliberate: the server chose this `code`, so + * unlike {@link ErrorInfo.fromValues} it is not checked against the registry. Prefer + * `fromValues` unless the code really did come from the server. + */ + static fromWireValues(values: IConvertibleToErrorInfo): ErrorInfo { + return withHelpHref(new ErrorInfo(values as ErrorInfoValues)); } } export class PartialErrorInfo extends Error implements IPartialErrorInfo { - code: number | null; + code: ErrorCode | null; statusCode?: number; cause?: ErrorInfo | PartialErrorInfo; href?: string; @@ -118,15 +161,15 @@ export class PartialErrorInfo extends Error implements IPartialErrorInfo { constructor( message: string, - code: number | null, + code: ErrorCode | null, statusCode?: number, cause?: ErrorInfo | PartialErrorInfo, detail?: Record, ); - constructor(values: IConvertibleToPartialErrorInfo); + constructor(values: PartialErrorInfoValues); constructor( - messageOrValues: string | IConvertibleToPartialErrorInfo, - code?: number | null, + messageOrValues: string | PartialErrorInfoValues, + code?: ErrorCode | null, statusCode?: number, cause?: ErrorInfo | PartialErrorInfo, detail?: Record, @@ -154,7 +197,7 @@ export class PartialErrorInfo extends Error implements IPartialErrorInfo { if (typeof Object.setPrototypeOf !== 'undefined') { Object.setPrototypeOf(this, PartialErrorInfo.prototype); } - this.code = code as number | null; + this.code = code as ErrorCode | null; this.statusCode = statusCode; this.cause = cause; this.detail = detail; @@ -165,13 +208,13 @@ export class PartialErrorInfo extends Error implements IPartialErrorInfo { return toString(this); } - static fromValues(values: IConvertibleToPartialErrorInfo): PartialErrorInfo { - // Same shape as ErrorInfo.fromValues - delegate validation/assignment to the - // options-object constructor; href default applies only to the server-decoded path. - const result = new PartialErrorInfo(values); - if (result.code && !result.href) { - result.href = 'https://help.ably.io/error/' + result.code; - } - return result; + /** As {@link ErrorInfo.fromValues}, for the partial case. */ + static fromValues(values: PartialErrorInfoValues): PartialErrorInfo { + return withHelpHref(new PartialErrorInfo(values)); + } + + /** As {@link ErrorInfo.fromWireValues}, for the partial case. */ + static fromWireValues(values: IConvertibleToPartialErrorInfo): PartialErrorInfo { + return withHelpHref(new PartialErrorInfo(values as PartialErrorInfoValues)); } } diff --git a/src/common/lib/types/protocolmessage.ts b/src/common/lib/types/protocolmessage.ts index 14ab7c9288..ba1b9ba4cd 100644 --- a/src/common/lib/types/protocolmessage.ts +++ b/src/common/lib/types/protocolmessage.ts @@ -3,7 +3,7 @@ import * as API from '../../../../ably'; import { PresenceMessagePlugin } from '../client/modularplugins'; import { AnnotationsPlugin } from '../client/modularplugins'; import * as Utils from '../util/utils'; -import ErrorInfo from './errorinfo'; +import ErrorInfo, { type IConvertibleToErrorInfo } from './errorinfo'; import { WireMessage } from './message'; import PresenceMessage, { WirePresenceMessage } from './presencemessage'; import Annotation, { WireAnnotation } from './annotation'; @@ -46,7 +46,7 @@ export function fromDeserialized( ): ProtocolMessage { let error: ErrorInfo | undefined; if (deserialized.error) { - error = ErrorInfo.fromValues(deserialized.error as ErrorInfo); + error = ErrorInfo.fromWireValues(deserialized.error as IConvertibleToErrorInfo); } let messages: WireMessage[] | undefined; @@ -132,7 +132,7 @@ export function stringify( result += '; state=' + toStringArray(objectsPlugin.WireObjectMessage.fromValuesArray(msg.state, Utils, MessageEncoding)); } - if (msg.error) result += '; error=' + ErrorInfo.fromValues(msg.error).toString(); + if (msg.error) result += '; error=' + ErrorInfo.fromWireValues(msg.error).toString(); if (msg.auth && msg.auth.accessToken) result += '; token=' + msg.auth.accessToken; if (msg.flags) result += '; flags=' + flagNames.filter(msg.hasFlag).join(','); if (msg.params) { diff --git a/src/common/types/http.ts b/src/common/types/http.ts index b135404adf..3a03df145d 100644 --- a/src/common/types/http.ts +++ b/src/common/types/http.ts @@ -237,7 +237,7 @@ export class Http { return tryAHost(hosts); } catch (err) { // Handle any unexpected error, to ensure we always meet our contract of not throwing any errors - return { error: new ErrorInfo(`Unexpected error in Http.do: ${Utils.inspectError(err)}`, 500, 50000) }; + return { error: new ErrorInfo(`Unexpected error in Http.do: ${Utils.inspectError(err)}`, 50000, 500) }; } } @@ -263,7 +263,7 @@ export class Http { return result; } catch (err) { // Handle any unexpected error, to ensure we always meet our contract of not throwing any errors - return { error: new ErrorInfo(`Unexpected error in Http.doUri: ${Utils.inspectError(err)}`, 500, 50000) }; + return { error: new ErrorInfo(`Unexpected error in Http.doUri: ${Utils.inspectError(err)}`, 50000, 500) }; } } } diff --git a/src/platform/nodejs/lib/transport/nodecomettransport.js b/src/platform/nodejs/lib/transport/nodecomettransport.js index 045a2d9f39..cd5ba2e8a6 100644 --- a/src/platform/nodejs/lib/transport/nodecomettransport.js +++ b/src/platform/nodejs/lib/transport/nodecomettransport.js @@ -270,7 +270,7 @@ class Request extends EventEmitter { return; } - var err = body.error && ErrorInfo.fromValues(body.error); + var err = body.error && ErrorInfo.fromWireValues(body.error); if (!err) { err = new PartialErrorInfo( 'Error response received from server: ' + statusCode + ', body was: ' + util.inspect(body), diff --git a/src/platform/nodejs/lib/util/crypto.ts b/src/platform/nodejs/lib/util/crypto.ts index 69353a1fb8..4eac767221 100644 --- a/src/platform/nodejs/lib/util/crypto.ts +++ b/src/platform/nodejs/lib/util/crypto.ts @@ -180,7 +180,7 @@ var createCryptoClass = function (bufferUtils: typeof BufferUtils) { try { return generateRandom((keyLength || DEFAULT_KEYLENGTH) / 8); } catch (err) { - throw new ErrorInfo('Failed to generate random key: ' + (err as Error).message, 500, 50000); + throw new ErrorInfo('Failed to generate random key: ' + (err as Error).message, 50000, 500); } } diff --git a/src/platform/nodejs/lib/util/http.ts b/src/platform/nodejs/lib/util/http.ts index b78f89c286..b0b8b70d1d 100644 --- a/src/platform/nodejs/lib/util/http.ts +++ b/src/platform/nodejs/lib/util/http.ts @@ -1,6 +1,7 @@ import Platform from 'common/platform'; import Defaults from 'common/lib/util/defaults'; import ErrorInfo from 'common/lib/types/errorinfo'; +import type { ErrorCode } from 'common/lib/types/errorcodes'; import { ErrnoException, RequestBody, @@ -164,11 +165,13 @@ const Http: IPlatformHttpStatic = class { } const error = (body as { error: ErrorInfo }).error - ? ErrorInfo.fromValues((body as { error: ErrorInfo }).error) + ? ErrorInfo.fromWireValues((body as { error: ErrorInfo }).error) : new ErrorInfo( (headers['x-ably-errormessage'] as string) || 'Error response received from server: ' + statusCode + ' body was: ' + Platform.Config.inspect(body), - Number(headers['x-ably-errorcode']), + // Read off a response header, so the server chose it and it can't be checked + // against the registry. + Number(headers['x-ably-errorcode']) as ErrorCode, statusCode, ); diff --git a/src/platform/web/lib/http/http.ts b/src/platform/web/lib/http/http.ts index 387ad2830d..12a89c02c8 100644 --- a/src/platform/web/lib/http/http.ts +++ b/src/platform/web/lib/http/http.ts @@ -15,8 +15,8 @@ export type HTTPRequestImplementations = Pick): re function getAblyError(responseBody: unknown, headers: Record) { if (isAblyError(responseBody, headers)) { - return responseBody.error && ErrorInfo.fromValues(responseBody.error); + return responseBody.error && ErrorInfo.fromWireValues(responseBody.error); } } @@ -175,7 +176,7 @@ class XHRRequest extends EventEmitter implements IXHRRequest { const errorHandler = ( errorEvent: ProgressEvent, message: string, - code: number | null, + code: ErrorCode | null, statusCode: number, ) => { let errorMessage = message + ' (event type: ' + errorEvent.type + ')'; diff --git a/src/platform/web/lib/util/crypto.ts b/src/platform/web/lib/util/crypto.ts index 6139cb19fc..6981e56a8f 100644 --- a/src/platform/web/lib/util/crypto.ts +++ b/src/platform/web/lib/util/crypto.ts @@ -143,7 +143,7 @@ var createCryptoClass = function (config: IPlatformConfig, bufferUtils: typeof B try { return config.getRandomArrayBuffer((keyLength || DEFAULT_KEYLENGTH) / 8); } catch (err) { - throw new ErrorInfo('Failed to generate random key: ' + (err as Error).message, 400, 50000); + throw new ErrorInfo('Failed to generate random key: ' + (err as Error).message, 50000, 500); } } diff --git a/test/common/ably-common b/test/common/ably-common index 496da5ead0..1c86dab126 160000 --- a/test/common/ably-common +++ b/test/common/ably-common @@ -1 +1 @@ -Subproject commit 496da5ead0fa9d6667be0422b5a7ffa62fa7366c +Subproject commit 1c86dab1261df7e9afc155d2fe23f55d51394937 diff --git a/test/uts/rest/unit/types/error_types.test.ts b/test/uts/rest/unit/types/error_types.test.ts index 8e415504ba..37ef3f03b5 100644 --- a/test/uts/rest/unit/types/error_types.test.ts +++ b/test/uts/rest/unit/types/error_types.test.ts @@ -106,7 +106,7 @@ describe('uts/rest/unit/types/error_types', function () { { code: 40400, status: 404, meaning: 'Not found' }, { code: 50000, status: 500, meaning: 'Internal server error' }, { code: 50003, status: 500, meaning: 'Timeout' }, - ]; + ] as const; for (const tc of cases) { const error = new Ably.ErrorInfo(tc.meaning, tc.code, tc.status);