Skip to content

Commit

Permalink
Add ESLint exceptions for JS SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
rygine committed Oct 16, 2024
1 parent be3205a commit 7fa6e14
Show file tree
Hide file tree
Showing 39 changed files with 180 additions and 43 deletions.
27 changes: 27 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,33 @@ export default tseslint.config(
],
},
},
{
files: ["sdks/js-sdk/test/**/*.ts"],
rules: {
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-confusing-void-expression": "off",
"@typescript-eslint/require-await": "off",
"@typescript-eslint/await-thenable": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/only-throw-error": "off",
"@typescript-eslint/unbound-method": "off",
"@typescript-eslint/no-misused-promises": "off",
"@typescript-eslint/no-unnecessary-type-arguments": "off",
"@typescript-eslint/no-unnecessary-type-assertion": "off",
"@typescript-eslint/no-deprecated": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"no-empty": "off",
},
},
{
files: ["sdks/**/*.ts"],
rules: {
Expand Down
1 change: 1 addition & 0 deletions sdks/js-sdk/bench/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ const main = async () => {
await decodeSuite();
};

// eslint-disable-next-line @typescript-eslint/no-floating-promises
main();
15 changes: 15 additions & 0 deletions sdks/js-sdk/src/ApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ const isAbortError = (err?: Error): boolean => {
};

const isAuthError = (err?: GrpcError | Error): boolean => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (err && "code" in err && err.code === ERR_CODE_UNAUTHENTICATED) {
return true;
}
Expand Down Expand Up @@ -189,6 +190,7 @@ export default class HttpApiClient implements ApiClient {
): ReturnType<typeof MessageApi.Query> {
try {
return await retry(
// eslint-disable-next-line @typescript-eslint/unbound-method
MessageApi.Query,
[
req,
Expand All @@ -203,6 +205,7 @@ export default class HttpApiClient implements ApiClient {
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
throw GrpcError.fromObject(e);
}
}
Expand All @@ -212,6 +215,7 @@ export default class HttpApiClient implements ApiClient {
req: messageApi.BatchQueryRequest,
): ReturnType<typeof MessageApi.BatchQuery> {
return retry(
// eslint-disable-next-line @typescript-eslint/unbound-method
MessageApi.BatchQuery,
[
req,
Expand All @@ -236,6 +240,7 @@ export default class HttpApiClient implements ApiClient {
headers.set("Authorization", `Bearer ${authToken}`);
try {
return await retry(
// eslint-disable-next-line @typescript-eslint/unbound-method
MessageApi.Publish,
[
req,
Expand All @@ -253,7 +258,9 @@ export default class HttpApiClient implements ApiClient {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
// Try at most 2X. If refreshing the auth token doesn't work the first time, it won't work the second time
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (isNotAuthError(e) || attemptNumber >= 1) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
throw GrpcError.fromObject(e);
}
await this.authCache?.refresh();
Expand All @@ -270,6 +277,7 @@ export default class HttpApiClient implements ApiClient {
const abortController = new AbortController();

const doSubscribe = async () => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while (true) {
const startTime = new Date().getTime();
try {
Expand All @@ -290,6 +298,7 @@ export default class HttpApiClient implements ApiClient {
onConnectionLost?.();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (isAbortError(err) || abortController.signal.aborted) {
return;
}
Expand All @@ -303,10 +312,13 @@ export default class HttpApiClient implements ApiClient {
}
}
};
// eslint-disable-next-line @typescript-eslint/no-floating-promises
doSubscribe();

return {
// eslint-disable-next-line @typescript-eslint/require-await
unsubscribe: async () => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
abortController?.abort();
},
};
Expand Down Expand Up @@ -369,6 +381,7 @@ export default class HttpApiClient implements ApiClient {
const endTimeNs = toNanoString(endTime);
let cursor: messageApi.Cursor | undefined;

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while (true) {
const pagingInfo: messageApi.PagingInfo = {
limit: pageSize,
Expand All @@ -390,6 +403,7 @@ export default class HttpApiClient implements ApiClient {
}

if (result.pagingInfo?.cursor) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
cursor = result.pagingInfo?.cursor;
} else {
return;
Expand Down Expand Up @@ -495,6 +509,7 @@ export default class HttpApiClient implements ApiClient {

return this._subscribe(
params,
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
(env) => callback(normalizeEnvelope(env)),
onConnectionLost,
);
Expand Down
25 changes: 20 additions & 5 deletions sdks/js-sdk/src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export type ContentOptions = {
/**
* Allow configuring codecs for additional content types
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-arguments
codecs: ContentCodec<any>[];

/**
Expand Down Expand Up @@ -267,7 +267,7 @@ export default class Client<ContentTypes = any> {

private _backupClient: BackupClient;
private readonly _conversations: Conversations<ContentTypes>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-arguments
private _codecs: Map<string, ContentCodec<any>>;
private _maxContentSize: number;

Expand Down Expand Up @@ -314,7 +314,7 @@ export default class Client<ContentTypes = any> {
* @param opts specify how to to connect to the network
*/

// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-arguments
static async create<ContentCodecs extends ContentCodec<any>[] = []>(
wallet: Signer | WalletClient | null,
opts?: Partial<ClientOptions> & { codecs?: ContentCodecs },
Expand Down Expand Up @@ -350,6 +350,7 @@ export default class Client<ContentTypes = any> {
* impersonate a user on the XMTP network and read the user's
* messages.
*/
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
static async getKeys<U>(
wallet: Signer | WalletClient | null,
opts?: Partial<ClientOptions> & { codecs?: U },
Expand Down Expand Up @@ -390,6 +391,7 @@ export default class Client<ContentTypes = any> {
}

// gracefully shut down the client
// eslint-disable-next-line @typescript-eslint/require-await
async close(): Promise<void> {
return undefined;
}
Expand Down Expand Up @@ -530,6 +532,7 @@ export default class Client<ContentTypes = any> {
// Else do the single address case
const keyBundle = await this.getUserContact(peerAddress);
return keyBundle !== undefined;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
// Instead of throwing, a bad address should just return false.
return false;
Expand Down Expand Up @@ -571,6 +574,7 @@ export default class Client<ContentTypes = any> {
}
try {
peerAddress = getAddress(peerAddress); // EIP55 normalize the address case.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
return false;
}
Expand All @@ -584,6 +588,7 @@ export default class Client<ContentTypes = any> {
throw new Error("Missing content topic");
}

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!bytes || !bytes.length) {
throw new Error("Cannot publish empty message");
}
Expand All @@ -608,9 +613,10 @@ export default class Client<ContentTypes = any> {
* Register a codec to be automatically used for encoding/decoding
* messages of the given Content Type
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-arguments
registerCodec<Codec extends ContentCodec<any>>(
codec: Codec,
// eslint-disable-next-line @typescript-eslint/prefer-return-this-type
): Client<ContentTypes | ExtractDecodedType<Codec>> {
const id = codec.contentType;
const key = `${id.authorityId}/${id.typeId}`;
Expand All @@ -622,7 +628,7 @@ export default class Client<ContentTypes = any> {
* Find a matching codec for a given `ContentTypeId` from the
* client's codec registry
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-arguments
codecFor(contentType: ContentTypeId): ContentCodec<any> | undefined {
const key = `${contentType.authorityId}/${contentType.typeId}`;
const codec = this._codecs.get(key);
Expand All @@ -649,6 +655,7 @@ export default class Client<ContentTypes = any> {
const contentType = options?.contentType || ContentTypeText;
const codec = this.codecFor(contentType);
if (!codec) {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
throw new Error("unknown content type " + contentType);
}
const encoded = codec.encode(content, this);
Expand Down Expand Up @@ -691,12 +698,15 @@ export default class Client<ContentTypes = any> {

const codec = this.codecFor(contentType);
if (codec) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
content = codec.decode(encodedContent as EncodedContent, this);
} else {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
error = new Error("unknown content type " + contentType);
}

return {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
content,
contentType,
error,
Expand All @@ -707,6 +717,7 @@ export default class Client<ContentTypes = any> {
listInvitations(opts?: ListMessagesOptions): Promise<messageApi.Envelope[]> {
return this.listEnvelopes(
buildUserInviteTopic(this.address),
// eslint-disable-next-line @typescript-eslint/require-await
async (env) => env,
opts,
);
Expand Down Expand Up @@ -795,7 +806,9 @@ async function getUserContactFromNetwork(
const keyBundle = decodeContactBundle(env.message);
let address: string | undefined;
try {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
address = await keyBundle?.walletSignatureAddress();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
address = undefined;
}
Expand Down Expand Up @@ -828,13 +841,15 @@ async function getUserContactsFromNetwork(
return Promise.all(
peerAddresses.map(async (address: string, index: number) => {
const envelopes = topicToEnvelopes[index];
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!envelopes) {
return undefined;
}
for (const env of envelopes) {
if (!env.message) continue;
try {
const keyBundle = decodeContactBundle(env.message);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const signingAddress = await keyBundle?.walletSignatureAddress();
if (address.toLowerCase() === signingAddress.toLowerCase()) {
return keyBundle;
Expand Down
1 change: 1 addition & 0 deletions sdks/js-sdk/src/Compression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export function readStreamFromBytes(
return new ReadableStream({
pull(controller) {
if (position >= bytes.length) {
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
return controller.close();
}
let end = position + chunkSize;
Expand Down
1 change: 1 addition & 0 deletions sdks/js-sdk/src/ContactBundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function decodeContactBundle(
let cb: contact.ContactBundle;
try {
cb = contact.ContactBundle.decode(bytes);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
const pb = publicKey.PublicKeyBundle.decode(bytes);
cb = { v1: { keyBundle: new PublicKeyBundle(pb) }, v2: undefined };
Expand Down
8 changes: 6 additions & 2 deletions sdks/js-sdk/src/Contacts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createConsentMessage } from "@xmtp/consent-proof-signature";
import { messageApi, privatePreferences, type invitation } from "@xmtp/proto";
// eslint-disable-next-line camelcase
import type { DecryptResponse_Response } from "@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb";
import { hashMessage, hexToBytes } from "viem";
import { ecdsaSignerKey } from "@/crypto/Signature";
Expand Down Expand Up @@ -140,7 +139,6 @@ export class ConsentList {

const decryptedMessageEntries = Array.from(messageMap.keys()).map(
(key, index) =>
// eslint-disable-next-line camelcase
[key, responses[index]] as [string, DecryptResponse_Response],
);

Expand Down Expand Up @@ -199,6 +197,7 @@ export class ConsentList {
await this.client.keystore.getPrivatePreferencesTopic();

return Stream.create<privatePreferences.PrivatePreferencesAction>(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.client,
[contentTopic],
async (envelope) => {
Expand Down Expand Up @@ -236,6 +235,7 @@ export class ConsentList {
const messageEntries = (
await this.client.listEnvelopes(
contentTopic,
// eslint-disable-next-line @typescript-eslint/require-await
async ({ message, timestampNs }: EnvelopeWithMessage) =>
[timestampNs, message] as [string | undefined, Uint8Array],
{
Expand Down Expand Up @@ -309,6 +309,7 @@ export class ConsentList {
[valueKey]: [...values, entry.value],
},
};
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
}, {} as PrivatePreferencesAction);

// get envelopes to publish (there should only be one)
Expand All @@ -319,7 +320,9 @@ export class ConsentList {
await this.client.publishEnvelopes(envelopes);

// persist newly published private preference to keystore
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.client.keystore.savePrivatePreferences(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
new Map([[envelopes[0].timestamp!.getTime().toString(), action]]),
);

Expand Down Expand Up @@ -397,6 +400,7 @@ export class Contacts {
return result;
}
},
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
[] as string[],
);
if (validConsentProofAddresses.length) {
Expand Down
5 changes: 4 additions & 1 deletion sdks/js-sdk/src/Invitation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type InvitationContext = {
export class InvitationV1 implements invitation.InvitationV1 {
topic: string;
context: InvitationContext | undefined;
aes256GcmHkdfSha256: invitation.InvitationV1_Aes256gcmHkdfsha256; // eslint-disable-line camelcase
aes256GcmHkdfSha256: invitation.InvitationV1_Aes256gcmHkdfsha256;
consentProof: invitation.ConsentProofPayload | undefined;

constructor({
Expand All @@ -31,6 +31,7 @@ export class InvitationV1 implements invitation.InvitationV1 {
}
if (
!aes256GcmHkdfSha256 ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
!aes256GcmHkdfSha256.keyMaterial ||
!aes256GcmHkdfSha256.keyMaterial.length
) {
Expand Down Expand Up @@ -117,6 +118,7 @@ export class SealedInvitationV1 implements invitation.SealedInvitationV1 {
private _invitation?: InvitationV1;

constructor({ headerBytes, ciphertext }: invitation.SealedInvitationV1) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!headerBytes || !headerBytes.length) {
throw new Error("Missing header bytes");
}
Expand Down Expand Up @@ -204,6 +206,7 @@ export class SealedInvitation implements invitation.SealedInvitation {
return new SealedInvitation(invitation.SealedInvitation.decode(bytes));
}

// eslint-disable-next-line @typescript-eslint/require-await
static async fromEnvelope(
env: messageApi.Envelope,
): Promise<SealedInvitation> {
Expand Down
Loading

0 comments on commit 7fa6e14

Please sign in to comment.