diff --git a/frontend/openchat-agent/src/services/candidService.ts b/frontend/openchat-agent/src/services/candidService.ts index 67f40c2e39..e65abdb579 100644 --- a/frontend/openchat-agent/src/services/candidService.ts +++ b/frontend/openchat-agent/src/services/candidService.ts @@ -1,10 +1,9 @@ import { Actor, HttpAgent, type Identity } from "@dfinity/agent"; import type { IDL } from "@dfinity/candid"; import type { Principal } from "@dfinity/principal"; -import { AuthError, DestinationInvalidError, SessionExpiryError, offline } from "openchat-shared"; +import { AuthError, DestinationInvalidError, SessionExpiryError } from "openchat-shared"; import { ReplicaNotUpToDateError, toCanisterResponseError } from "./error"; import { ResponseTooLargeError } from "openchat-shared"; -import { isMainnet } from "../utils/network"; const MAX_RETRIES = process.env.NODE_ENV === "production" ? 7 : 3; const RETRY_DELAY = 100; @@ -14,18 +13,9 @@ function debug(msg: string): void { } export abstract class CandidService { - protected createServiceClient( - factory: IDL.InterfaceFactory, - canisterId: string, - config: { icUrl: string }, - ): T { - const host = config.icUrl; - const agent = HttpAgent.createSync({ identity: this.identity, host, retryTimes: 5 }); - if (!isMainnet(config.icUrl) && !offline()) { - agent.fetchRootKey(); - } + protected createServiceClient(factory: IDL.InterfaceFactory, canisterId: string): T { return Actor.createActor(factory, { - agent, + agent: this.agent, canisterId, }); } @@ -94,5 +84,8 @@ export abstract class CandidService { }); } - constructor(protected identity: Identity) {} + constructor( + protected identity: Identity, + protected agent: HttpAgent, + ) {} } diff --git a/frontend/openchat-agent/src/services/ckbtcMinter/ckbtcMinter.ts b/frontend/openchat-agent/src/services/ckbtcMinter/ckbtcMinter.ts index d017992c0c..59e68d3251 100644 --- a/frontend/openchat-agent/src/services/ckbtcMinter/ckbtcMinter.ts +++ b/frontend/openchat-agent/src/services/ckbtcMinter/ckbtcMinter.ts @@ -1,10 +1,9 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import type { UpdateBtcBalanceResponse } from "openchat-shared"; import { idlFactory, type CkbtcMinterService } from "./candid/idl"; import { CandidService } from "../candidService"; import { updateBtcBalanceResponse } from "./mappers"; -import type { AgentConfig } from "../../config"; import { apiOptional } from "../common/chatMappers"; const CKBTC_MINTER_CANISTER_ID = "mqygn-kiaaa-aaaar-qaadq-cai"; @@ -12,20 +11,15 @@ const CKBTC_MINTER_CANISTER_ID = "mqygn-kiaaa-aaaar-qaadq-cai"; export class CkbtcMinterClient extends CandidService { private service: CkbtcMinterService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, CKBTC_MINTER_CANISTER_ID, - config, ); } - static create(identity: Identity, config: AgentConfig): CkbtcMinterClient { - return new CkbtcMinterClient(identity, config); - } - updateBalance(userId: string): Promise { return this.handleResponse( this.service.update_balance({ diff --git a/frontend/openchat-agent/src/services/community/community.client.ts b/frontend/openchat-agent/src/services/community/community.client.ts index 51f5d7a30c..273528e885 100644 --- a/frontend/openchat-agent/src/services/community/community.client.ts +++ b/frontend/openchat-agent/src/services/community/community.client.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type CommunityService } from "./candid/idl"; import { CandidService } from "../candidService"; import { apiOptionUpdate, identity } from "../../utils/mapping"; @@ -182,26 +182,17 @@ import { export class CommunityClient extends CandidService { private service: CommunityService; - private constructor( - private communityId: string, + constructor( identity: Identity, + agent: HttpAgent, private config: AgentConfig, + private communityId: string, private db: Database, private inviteCode: string | undefined, ) { - super(identity); + super(identity, agent); - this.service = this.createServiceClient(idlFactory, communityId, config); - } - - static create( - communityId: string, - identity: Identity, - config: AgentConfig, - db: Database, - inviteCode: string | undefined, - ): CommunityClient { - return new CommunityClient(communityId, identity, config, db, inviteCode); + this.service = this.createServiceClient(idlFactory, communityId); } claimPrize(channelId: string, messageId: bigint): Promise { @@ -382,7 +373,7 @@ export class CommunityClient extends CandidService { blockLevelMarkdown: boolean | undefined, newAchievement: boolean, ): Promise { - return DataClient.create(this.identity, this.config) + return new DataClient(this.identity, this.agent, this.config) .uploadData(message.content, [chatId.communityId]) .then((content) => { return this.handleResponse( @@ -982,7 +973,7 @@ export class CommunityClient extends CandidService { // pre-emtively remove the failed message from indexeddb - it will get re-added if anything goes wrong removeFailedMessage(this.db, chatId, event.event.messageId, threadRootMessageIndex); - const dataClient = DataClient.create(this.identity, this.config); + const dataClient = new DataClient(this.identity, this.agent, this.config); const uploadContentPromise = event.event.forwarded ? dataClient.forwardData(event.event.content, [chatId.communityId]) : dataClient.uploadData(event.event.content, [chatId.communityId]); diff --git a/frontend/openchat-agent/src/services/data/data.client.ts b/frontend/openchat-agent/src/services/data/data.client.ts index 99cc441bbd..35c68301a2 100644 --- a/frontend/openchat-agent/src/services/data/data.client.ts +++ b/frontend/openchat-agent/src/services/data/data.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import { v1 as uuidv1 } from "uuid"; import { sha3_256 } from "js-sha3"; @@ -19,17 +19,15 @@ import { StorageIndexClient } from "../storageIndex/storageIndex.client"; import { StorageBucketClient } from "../storageBucket/storageBucket.client"; export class DataClient extends EventTarget { - static create(identity: Identity, config: AgentConfig): DataClient { - const storageIndexClient = StorageIndexClient.create(identity, config); - return new DataClient(identity, config, storageIndexClient); - } + private storageIndexClient: StorageIndexClient; - private constructor( + constructor( private identity: Identity, + private agent: HttpAgent, private config: AgentConfig, - private storageIndexClient: StorageIndexClient ) { super(); + this.storageIndexClient = new StorageIndexClient(identity, agent, config); } static newBlobId(): bigint { @@ -54,7 +52,7 @@ export class DataClient extends EventTarget { async uploadData( content: MessageContent, - accessorCanisterIds: string[] + accessorCanisterIds: string[], ): Promise { let byteLimit: number | undefined = undefined; let bytesUsed: number | undefined = undefined; @@ -71,7 +69,7 @@ export class DataClient extends EventTarget { const response = await this.uploadFile( content.mimeType, accessorIds, - content.blobData + content.blobData, ); const ref = this.extractBlobReference(response); @@ -83,7 +81,7 @@ export class DataClient extends EventTarget { this.config.blobUrlPattern, ref.canisterId, ref.blobId, - "blobs" + "blobs", ), }; byteLimit = Number(response.projectedAllowance.byteLimit); @@ -113,7 +111,7 @@ export class DataClient extends EventTarget { this.config.blobUrlPattern, videoRef.canisterId, videoRef.blobId, - "blobs" + "blobs", ), }, imageData: { @@ -123,7 +121,7 @@ export class DataClient extends EventTarget { this.config.blobUrlPattern, imageRef.canisterId, imageRef.blobId, - "blobs" + "blobs", ), }, }; @@ -131,7 +129,7 @@ export class DataClient extends EventTarget { bytesUsed = Number( video.projectedAllowance.bytesUsedAfterOperation + image.projectedAllowance.bytesUsedAfterOperation - - image.projectedAllowance.bytesUsed + image.projectedAllowance.bytesUsed, ); }); } @@ -142,7 +140,7 @@ export class DataClient extends EventTarget { new StorageUpdated({ byteLimit, bytesUsed, - }) + }), ); } @@ -151,7 +149,7 @@ export class DataClient extends EventTarget { async forwardData( content: MessageContent, - accessorCanisterIds: string[] + accessorCanisterIds: string[], ): Promise { let byteLimit: number | undefined = undefined; let bytesUsed: number | undefined = undefined; @@ -169,7 +167,7 @@ export class DataClient extends EventTarget { const response = await this.forwardFile( content.blobReference.canisterId, content.blobReference.blobId, - accessorIds + accessorIds, ); if (response.kind === "success") { byteLimit = Number(response.projectedAllowance.byteLimit); @@ -184,7 +182,7 @@ export class DataClient extends EventTarget { this.config.blobUrlPattern, content.blobReference.canisterId, content.blobReference.blobId, - "blobs" + "blobs", ), }; } else { @@ -208,12 +206,12 @@ export class DataClient extends EventTarget { this.forwardFile( videoCanisterId, content.videoData.blobReference.blobId, - accessorIds + accessorIds, ), this.forwardFile( imageCanisterId, content.imageData.blobReference.blobId, - accessorIds + accessorIds, ), ]).then(([video, image]) => { if (video.kind === "success" && image.kind === "success") { @@ -221,7 +219,7 @@ export class DataClient extends EventTarget { bytesUsed = Number( video.projectedAllowance.bytesUsedAfterOperation + image.projectedAllowance.bytesUsedAfterOperation - - image.projectedAllowance.bytesUsed + image.projectedAllowance.bytesUsed, ); updatedContent = { ...content, @@ -235,7 +233,7 @@ export class DataClient extends EventTarget { this.config.blobUrlPattern, videoCanisterId, video.newFileId, - "blobs" + "blobs", ), }, imageData: { @@ -248,7 +246,7 @@ export class DataClient extends EventTarget { this.config.blobUrlPattern, imageCanisterId, image.newFileId, - "blobs" + "blobs", ), }, }; @@ -272,7 +270,7 @@ export class DataClient extends EventTarget { new StorageUpdated({ byteLimit, bytesUsed, - }) + }), ); } @@ -295,7 +293,7 @@ export class DataClient extends EventTarget { accessors: Array, bytes: ArrayBuffer, expiryTimestampMillis?: bigint, - onProgress?: (percentComplete: number) => void + onProgress?: (percentComplete: number) => void, ): Promise { const hash = new Uint8Array(hashBytes(bytes)); const fileSize = bytes.byteLength; @@ -303,7 +301,7 @@ export class DataClient extends EventTarget { const allocatedBucketResponse = await this.storageIndexClient.allocatedBucket( hash, BigInt(fileSize), - random128() + random128(), ); if (allocatedBucketResponse.kind !== "success") { @@ -316,11 +314,7 @@ export class DataClient extends EventTarget { const chunkSize = allocatedBucketResponse.chunkSize; const chunkCount = Math.ceil(fileSize / chunkSize); const chunkIndexes = [...Array(chunkCount).keys()]; - const bucketClient = StorageBucketClient.create( - this.identity, - this.config, - bucketCanisterId - ); + const bucketClient = new StorageBucketClient(this.identity, this.agent, bucketCanisterId); let chunksCompleted = 0; @@ -342,7 +336,7 @@ export class DataClient extends EventTarget { chunkSize, chunkIndex, chunkBytes, - expiryTimestampMillis + expiryTimestampMillis, ); if (chunkResponse === "success") { @@ -370,13 +364,9 @@ export class DataClient extends EventTarget { private async forwardFile( bucketCanisterId: string, fileId: bigint, - accessors: Array + accessors: Array, ): Promise { - const bucketClient = StorageBucketClient.create( - this.identity, - this.config, - bucketCanisterId - ); + const bucketClient = new StorageBucketClient(this.identity, this.agent, bucketCanisterId); const fileInfoResponse = await bucketClient.fileInfo(fileId); if (fileInfoResponse.kind === "file_not_found") { @@ -385,7 +375,7 @@ export class DataClient extends EventTarget { const canForwardResponse = await this.storageIndexClient.canForward( fileInfoResponse.fileHash, - fileInfoResponse.fileSize + fileInfoResponse.fileSize, ); switch (canForwardResponse.kind) { case "user_not_found": diff --git a/frontend/openchat-agent/src/services/dexes/icpSwap/index/icpSwap.index.client.ts b/frontend/openchat-agent/src/services/dexes/icpSwap/index/icpSwap.index.client.ts index 11ef120232..543a26a40e 100644 --- a/frontend/openchat-agent/src/services/dexes/icpSwap/index/icpSwap.index.client.ts +++ b/frontend/openchat-agent/src/services/dexes/icpSwap/index/icpSwap.index.client.ts @@ -1,7 +1,6 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type IcpSwapIndexService } from "./candid/idl"; import { CandidService } from "../../../candidService"; -import type { AgentConfig } from "../../../../config"; import type { TokenSwapPool } from "openchat-shared"; import { getPoolsResponse } from "./mappers"; @@ -13,20 +12,15 @@ export class IcpSwapIndexClient extends CandidService { private pools: TokenSwapPool[] = []; // Cache the pools for 10 minutes private poolsLastUpdated: number = 0; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, ICPSWAP_INDEX_CANISTER_ID, - config, ); } - static create(identity: Identity, config: AgentConfig): IcpSwapIndexClient { - return new IcpSwapIndexClient(identity, config); - } - async getPools(): Promise { const now = Date.now(); if (this.pools.length > 0 && now - this.poolsLastUpdated < TEN_MINUTES) diff --git a/frontend/openchat-agent/src/services/dexes/icpSwap/pool/icpSwap.pool.client.ts b/frontend/openchat-agent/src/services/dexes/icpSwap/pool/icpSwap.pool.client.ts index 424ef89e3a..51fb15d9aa 100644 --- a/frontend/openchat-agent/src/services/dexes/icpSwap/pool/icpSwap.pool.client.ts +++ b/frontend/openchat-agent/src/services/dexes/icpSwap/pool/icpSwap.pool.client.ts @@ -1,32 +1,21 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type IcpSwapPoolService } from "./candid/idl"; import { CandidService } from "../../../candidService"; -import type { AgentConfig } from "../../../../config"; import { quoteResponse } from "./mappers"; export class IcpSwapPoolClient extends CandidService { private service: IcpSwapPoolService; - private constructor( + constructor( identity: Identity, - config: AgentConfig, + agent: HttpAgent, canisterId: string, private token0: string, private token1: string, ) { - super(identity); + super(identity, agent); - this.service = this.createServiceClient(idlFactory, canisterId, config); - } - - static create( - identity: Identity, - config: AgentConfig, - canisterId: string, - token0: string, - token1: string, - ): IcpSwapPoolClient { - return new IcpSwapPoolClient(identity, config, canisterId, token0, token1); + this.service = this.createServiceClient(idlFactory, canisterId); } quote(inputToken: string, outputToken: string, amountIn: bigint): Promise { diff --git a/frontend/openchat-agent/src/services/dexes/index.ts b/frontend/openchat-agent/src/services/dexes/index.ts index 8ccaa8375c..251b47760a 100644 --- a/frontend/openchat-agent/src/services/dexes/index.ts +++ b/frontend/openchat-agent/src/services/dexes/index.ts @@ -1,6 +1,5 @@ -import { AnonymousIdentity, type Identity } from "@dfinity/agent"; +import { AnonymousIdentity, type HttpAgent, type Identity } from "@dfinity/agent"; import type { DexId, TokenSwapPool } from "openchat-shared"; -import type { AgentConfig } from "../../config"; import { IcpSwapIndexClient } from "./icpSwap/index/icpSwap.index.client"; import { IcpSwapPoolClient } from "./icpSwap/pool/icpSwap.pool.client"; import { SonicSwapsClient } from "./sonic/swaps/sonic.swaps.client"; @@ -10,10 +9,10 @@ export class DexesAgent { private _icpSwapIndexClient: IcpSwapIndexClient; private _sonicSwapsClient: SonicSwapsClient; - constructor(private config: AgentConfig) { + constructor(private agent: HttpAgent) { this._identity = new AnonymousIdentity(); - this._icpSwapIndexClient = IcpSwapIndexClient.create(this._identity, config); - this._sonicSwapsClient = SonicSwapsClient.create(this._identity, config); + this._icpSwapIndexClient = new IcpSwapIndexClient(this._identity, this.agent); + this._sonicSwapsClient = new SonicSwapsClient(this._identity, this.agent); } async getSwapPools(inputToken: string, outputTokens: Set): Promise { @@ -73,16 +72,16 @@ export class DexesAgent { amountIn: bigint, ): Promise { if (pool.dex === "icpswap") { - const client = IcpSwapPoolClient.create( + const client = new IcpSwapPoolClient( this._identity, - this.config, + this.agent, pool.canisterId, pool.token0, pool.token1, ); return client.quote(inputToken, outputToken, amountIn); } else if (pool.dex === "sonic") { - const client = SonicSwapsClient.create(this._identity, this.config); + const client = new SonicSwapsClient(this._identity, this.agent); return client.quote(inputToken, outputToken, amountIn); } else { return Promise.resolve(BigInt(0)); diff --git a/frontend/openchat-agent/src/services/dexes/sonic/swaps/sonic.swaps.client.ts b/frontend/openchat-agent/src/services/dexes/sonic/swaps/sonic.swaps.client.ts index d8cb351163..5360348d17 100644 --- a/frontend/openchat-agent/src/services/dexes/sonic/swaps/sonic.swaps.client.ts +++ b/frontend/openchat-agent/src/services/dexes/sonic/swaps/sonic.swaps.client.ts @@ -1,7 +1,6 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type SonicSwapsService } from "./candid/idl"; import { CandidService } from "../../../candidService"; -import type { AgentConfig } from "../../../../config"; import type { TokenSwapPool } from "openchat-shared"; import { getAllPairsResponse, getPairResponse } from "./mappers"; import { Principal } from "@dfinity/principal"; @@ -15,20 +14,15 @@ export class SonicSwapsClient extends CandidService { private pools: TokenSwapPool[] = []; // Cache the pools for 10 minutes private poolsLastUpdated: number = 0; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, SONIC_INDEX_CANISTER_ID, - config, ); } - static create(identity: Identity, config: AgentConfig): SonicSwapsClient { - return new SonicSwapsClient(identity, config); - } - async getPools(): Promise { if (!ENABLED) return Promise.resolve([]); diff --git a/frontend/openchat-agent/src/services/group/group.client.ts b/frontend/openchat-agent/src/services/group/group.client.ts index 2e60862fcb..2e6e73f288 100644 --- a/frontend/openchat-agent/src/services/group/group.client.ts +++ b/frontend/openchat-agent/src/services/group/group.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type GroupService } from "./candid/idl"; import type { EventsResponse, @@ -145,27 +145,14 @@ export class GroupClient extends CandidService { constructor( identity: Identity, + agent: HttpAgent, private config: AgentConfig, private chatId: GroupChatIdentifier, private db: Database, private inviteCode: string | undefined, ) { - super(identity); - this.groupService = this.createServiceClient( - idlFactory, - chatId.groupId, - config, - ); - } - - static create( - chatId: GroupChatIdentifier, - identity: Identity, - config: AgentConfig, - db: Database, - inviteCode: string | undefined, - ): GroupClient { - return new GroupClient(identity, config, chatId, db, inviteCode); + super(identity, agent); + this.groupService = this.createServiceClient(idlFactory, chatId.groupId); } summary(): Promise { @@ -452,7 +439,7 @@ export class GroupClient extends CandidService { blockLevelMarkdown: boolean | undefined, newAchievement: boolean, ): Promise { - return DataClient.create(this.identity, this.config) + return new DataClient(this.identity, this.agent, this.config) .uploadData(message.content, [this.chatId.groupId]) .then((content) => { const args: EditMessageV2Args = { @@ -494,7 +481,7 @@ export class GroupClient extends CandidService { // pre-emtively remove the failed message from indexeddb - it will get re-added if anything goes wrong removeFailedMessage(this.db, this.chatId, event.event.messageId, threadRootMessageIndex); - const dataClient = DataClient.create(this.identity, this.config); + const dataClient = new DataClient(this.identity, this.agent, this.config); const uploadContentPromise = event.event.forwarded ? dataClient.forwardData(event.event.content, [this.chatId.groupId]) : dataClient.uploadData(event.event.content, [this.chatId.groupId]); diff --git a/frontend/openchat-agent/src/services/groupIndex/groupIndex.client.ts b/frontend/openchat-agent/src/services/groupIndex/groupIndex.client.ts index 914ba500c7..969f2b9523 100644 --- a/frontend/openchat-agent/src/services/groupIndex/groupIndex.client.ts +++ b/frontend/openchat-agent/src/services/groupIndex/groupIndex.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import type { AgentConfig } from "../../config"; import type { @@ -39,20 +39,15 @@ import { identity } from "../../utils/mapping"; export class GroupIndexClient extends CandidService { private groupIndexService: GroupIndexService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.groupIndexService = this.createServiceClient( idlFactory, config.groupIndexCanister, - config, ); } - static create(identity: Identity, config: AgentConfig): GroupIndexClient { - return new GroupIndexClient(identity, config); - } - activeGroups( communityIds: CommunityIdentifier[], groupIds: GroupChatIdentifier[], diff --git a/frontend/openchat-agent/src/services/icpcoins/icpcoins.client.ts b/frontend/openchat-agent/src/services/icpcoins/icpcoins.client.ts index ebaa7691b1..f70dc4db13 100644 --- a/frontend/openchat-agent/src/services/icpcoins/icpcoins.client.ts +++ b/frontend/openchat-agent/src/services/icpcoins/icpcoins.client.ts @@ -1,27 +1,18 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import type { TokenExchangeRates } from "openchat-shared"; import { idlFactory, type ICPCoinsService } from "./candid/idl"; import { CandidService } from "../candidService"; import { getLatestResponse } from "./mappers"; -import type { AgentConfig } from "../../config"; const ICPCOINS_CANISTER_ID = "u45jl-liaaa-aaaam-abppa-cai"; export class ICPCoinsClient extends CandidService { private service: ICPCoinsService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent) { + super(identity, agent); - this.service = this.createServiceClient( - idlFactory, - ICPCOINS_CANISTER_ID, - config - ); - } - - static create(identity: Identity, config: AgentConfig): ICPCoinsClient { - return new ICPCoinsClient(identity, config); + this.service = this.createServiceClient(idlFactory, ICPCOINS_CANISTER_ID); } exchangeRates(): Promise> { diff --git a/frontend/openchat-agent/src/services/identity/identity.client.ts b/frontend/openchat-agent/src/services/identity/identity.client.ts index b426366afa..00d7123779 100644 --- a/frontend/openchat-agent/src/services/identity/identity.client.ts +++ b/frontend/openchat-agent/src/services/identity/identity.client.ts @@ -1,4 +1,4 @@ -import type { Identity, SignIdentity } from "@dfinity/agent"; +import type { HttpAgent, Identity, SignIdentity } from "@dfinity/agent"; import { idlFactory, type IdentityService } from "./candid/idl"; import { CandidService } from "../candidService"; import type { @@ -31,16 +31,10 @@ import type { DelegationIdentity } from "@dfinity/identity"; export class IdentityClient extends CandidService { private service: IdentityService; - private constructor(identity: Identity, identityCanister: string, icUrl: string) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, identityCanister: string) { + super(identity, agent); - this.service = this.createServiceClient(idlFactory, identityCanister, { - icUrl, - }); - } - - static create(identity: Identity, identityCanister: string, icUrl: string): IdentityClient { - return new IdentityClient(identity, identityCanister, icUrl); + this.service = this.createServiceClient(idlFactory, identityCanister); } createIdentity( diff --git a/frontend/openchat-agent/src/services/identityAgent.ts b/frontend/openchat-agent/src/services/identityAgent.ts index 73167ff809..5480294d3d 100644 --- a/frontend/openchat-agent/src/services/identityAgent.ts +++ b/frontend/openchat-agent/src/services/identityAgent.ts @@ -1,5 +1,5 @@ import { IdentityClient } from "./identity/identity.client"; -import type { Identity, SignIdentity } from "@dfinity/agent"; +import { HttpAgent, type Identity, type SignIdentity } from "@dfinity/agent"; import { DelegationIdentity } from "@dfinity/identity"; import type { ApproveIdentityLinkResponse, @@ -10,12 +10,22 @@ import type { InitiateIdentityLinkResponse, } from "openchat-shared"; import { buildDelegationIdentity, toDer } from "openchat-shared"; +import { createHttpAgent } from "../utils/httpAgent"; export class IdentityAgent { private _identityClient: IdentityClient; - constructor(identity: Identity, identityCanister: string, icUrl: string) { - this._identityClient = IdentityClient.create(identity, identityCanister, icUrl); + private constructor(identity: Identity, agent: HttpAgent, identityCanister: string) { + this._identityClient = new IdentityClient(identity, agent, identityCanister); + } + + static async create( + identity: Identity, + identityCanister: string, + icUrl: string, + ): Promise { + const agent = await createHttpAgent(identity, icUrl); + return new IdentityAgent(identity, agent, identityCanister); } checkOpenChatIdentityExists(): Promise { diff --git a/frontend/openchat-agent/src/services/ledger/ledger.client.ts b/frontend/openchat-agent/src/services/ledger/ledger.client.ts index 628ebed52e..5751ebdc01 100644 --- a/frontend/openchat-agent/src/services/ledger/ledger.client.ts +++ b/frontend/openchat-agent/src/services/ledger/ledger.client.ts @@ -1,20 +1,15 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type LedgerService } from "./candid/idl"; import { CandidService } from "../candidService"; -import type { AgentConfig } from "../../config"; import { Principal } from "@dfinity/principal"; export class LedgerClient extends CandidService { private service: LedgerService; - private constructor(identity: Identity, config: AgentConfig, canisterId: string) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, canisterId: string) { + super(identity, agent); - this.service = this.createServiceClient(idlFactory, canisterId, config); - } - - static create(identity: Identity, config: AgentConfig, canisterId: string): LedgerClient { - return new LedgerClient(identity, config, canisterId); + this.service = this.createServiceClient(idlFactory, canisterId); } accountBalance(principal: string): Promise { @@ -22,7 +17,7 @@ export class LedgerClient extends CandidService { this.service.icrc1_balance_of({ owner: Principal.fromText(principal), subaccount: [] }), (balance) => { return balance; - } + }, ); } } diff --git a/frontend/openchat-agent/src/services/ledgerIndex/ledgerIndex.client.ts b/frontend/openchat-agent/src/services/ledgerIndex/ledgerIndex.client.ts index a1ad5feb6a..a4b1d949e4 100644 --- a/frontend/openchat-agent/src/services/ledgerIndex/ledgerIndex.client.ts +++ b/frontend/openchat-agent/src/services/ledgerIndex/ledgerIndex.client.ts @@ -1,7 +1,6 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type LedgerIndexService } from "./candid/idl"; import { CandidService } from "../candidService"; -import type { AgentConfig } from "../../config"; import { Principal } from "@dfinity/principal"; import { accountTransactions } from "./mappers"; import type { AccountTransactionResult } from "openchat-shared"; @@ -11,14 +10,10 @@ import { identity } from "../../utils/mapping"; export class LedgerIndexClient extends CandidService { private service: LedgerIndexService; - private constructor(identity: Identity, config: AgentConfig, canisterId: string) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, canisterId: string) { + super(identity, agent); - this.service = this.createServiceClient(idlFactory, canisterId, config); - } - - static create(identity: Identity, config: AgentConfig, canisterId: string): LedgerIndexClient { - return new LedgerIndexClient(identity, config, canisterId); + this.service = this.createServiceClient(idlFactory, canisterId); } getAccountTransactions(principal: string, fromId?: bigint): Promise { diff --git a/frontend/openchat-agent/src/services/localUserIndex/localUserIndex.client.ts b/frontend/openchat-agent/src/services/localUserIndex/localUserIndex.client.ts index 6becfb5d64..ef2930a01b 100644 --- a/frontend/openchat-agent/src/services/localUserIndex/localUserIndex.client.ts +++ b/frontend/openchat-agent/src/services/localUserIndex/localUserIndex.client.ts @@ -1,4 +1,4 @@ -import type { Identity, SignIdentity } from "@dfinity/agent"; +import type { HttpAgent, Identity, SignIdentity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import { idlFactory, type LocalUserIndexService } from "./candid/idl"; import type { @@ -34,7 +34,6 @@ import { joinCommunityResponse, registerUserResponse, } from "./mappers"; -import type { AgentConfig } from "../../config"; import { joinGroupResponse, apiOptional, apiChatIdentifier } from "../common/chatMappers"; import { MAX_MISSING, textToCode, UnsupportedValueError } from "openchat-shared"; import { identity } from "../../utils/mapping"; @@ -50,30 +49,20 @@ import { export class LocalUserIndexClient extends CandidService { private localUserIndexService: LocalUserIndexService; - private constructor( + constructor( identity: Identity, - config: AgentConfig, + agent: HttpAgent, canisterId: string, private db: Database, ) { - super(identity); + super(identity, agent); this.localUserIndexService = this.createServiceClient( idlFactory, canisterId, - config, ); } - static create( - identity: Identity, - config: AgentConfig, - canisterId: string, - db: Database, - ): LocalUserIndexClient { - return new LocalUserIndexClient(identity, config, canisterId, db); - } - groupAndCommunitySummaryUpdates( requests: GroupAndCommunitySummaryUpdatesArgs[], ): Promise { diff --git a/frontend/openchat-agent/src/services/marketMaker/marketMaker.client.ts b/frontend/openchat-agent/src/services/marketMaker/marketMaker.client.ts index 09b74b48bb..7a6513a1a0 100644 --- a/frontend/openchat-agent/src/services/marketMaker/marketMaker.client.ts +++ b/frontend/openchat-agent/src/services/marketMaker/marketMaker.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import type { UpdateMarketMakerConfigArgs, UpdateMarketMakerConfigResponse } from "openchat-shared"; import { idlFactory, type MarketMakerService } from "./candid/idl"; import { CandidService } from "../candidService"; @@ -10,20 +10,15 @@ import { identity } from "../../utils/mapping"; export class MarketMakerClient extends CandidService { private service: MarketMakerService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.marketMakerCanister, - config ); } - static create(identity: Identity, config: AgentConfig): MarketMakerClient { - return new MarketMakerClient(identity, config); - } - updateConfig(config: UpdateMarketMakerConfigArgs): Promise { const args = { exchange_id: config.exchangeId, @@ -38,11 +33,11 @@ export class MarketMakerClient extends CandidService { max_orders_per_direction: apiOptional(identity, config.maxOrdersPerDirection), max_orders_to_make_per_iteration: apiOptional( identity, - config.maxOrdersToMakePerIteration + config.maxOrdersToMakePerIteration, ), max_orders_to_cancel_per_iteration: apiOptional( identity, - config.maxOrdersToCancelPerIteration + config.maxOrdersToCancelPerIteration, ), }; return this.handleResponse(this.service.update_config(args), updateConfigResponse); diff --git a/frontend/openchat-agent/src/services/nnsGovernance/nns.governance.client.ts b/frontend/openchat-agent/src/services/nnsGovernance/nns.governance.client.ts index 28ae2d4074..a6fa5628de 100644 --- a/frontend/openchat-agent/src/services/nnsGovernance/nns.governance.client.ts +++ b/frontend/openchat-agent/src/services/nnsGovernance/nns.governance.client.ts @@ -1,37 +1,24 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import type { ManageNeuronResponse, ProposalVoteDetails } from "openchat-shared"; import { idlFactory, type NnsGovernanceService } from "./candid/idl"; import { CandidService } from "../candidService"; import { getProposalVoteDetails, manageNeuronResponse } from "./mappers"; -import type { AgentConfig } from "../../config"; import { apiOptional, apiProposalVote } from "../common/chatMappers"; import { identity } from "../../utils/mapping"; export class NnsGovernanceClient extends CandidService { private service: NnsGovernanceService; - private constructor(identity: Identity, config: AgentConfig, canisterId: string) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, canisterId: string) { + super(identity, agent); - this.service = this.createServiceClient( - idlFactory, - canisterId, - config - ); - } - - static create( - identity: Identity, - config: AgentConfig, - canisterId: string - ): NnsGovernanceClient { - return new NnsGovernanceClient(identity, config, canisterId); + this.service = this.createServiceClient(idlFactory, canisterId); } registerVote( neuronId: string, proposalId: bigint, - vote: boolean + vote: boolean, ): Promise { const args = { id: apiOptional(identity, { id: BigInt(neuronId) }), @@ -55,7 +42,7 @@ export class NnsGovernanceClient extends CandidService { }; return this.handleQueryResponse( () => this.service.list_proposals(args), - getProposalVoteDetails + getProposalVoteDetails, ); } } diff --git a/frontend/openchat-agent/src/services/notifications/notifications.client.ts b/frontend/openchat-agent/src/services/notifications/notifications.client.ts index 78b5e2d8ae..b94d841025 100644 --- a/frontend/openchat-agent/src/services/notifications/notifications.client.ts +++ b/frontend/openchat-agent/src/services/notifications/notifications.client.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type NotificationsService } from "./candid/idl"; import { CandidService } from "../candidService"; import { subscriptionExistsResponse } from "./mappers"; @@ -9,26 +9,21 @@ import type { AgentConfig } from "../../config"; export class NotificationsClient extends CandidService { private service: NotificationsService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.notificationsCanister, - config ); } - static create(identity: Identity, config: AgentConfig): NotificationsClient { - return new NotificationsClient(identity, config); - } - subscriptionExists(p256dh_key: string): Promise { return this.handleResponse( this.service.subscription_exists({ p256dh_key, }), - subscriptionExistsResponse + subscriptionExistsResponse, ); } @@ -50,7 +45,7 @@ export class NotificationsClient extends CandidService { this.service.remove_subscription({ p256dh_key: subscription.keys!["p256dh"], }), - toVoid + toVoid, ); } } diff --git a/frontend/openchat-agent/src/services/online/online.client.ts b/frontend/openchat-agent/src/services/online/online.client.ts index c85ae5cdad..535e9fe7a4 100644 --- a/frontend/openchat-agent/src/services/online/online.client.ts +++ b/frontend/openchat-agent/src/services/online/online.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import { idlFactory, type OnlineService } from "./candid/idl"; import { CandidService } from "../candidService"; @@ -9,18 +9,10 @@ import { lastOnlineResponse } from "./mappers"; export class OnlineClient extends CandidService { private service: OnlineService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); - this.service = this.createServiceClient( - idlFactory, - config.onlineCanister, - config - ); - } - - static create(identity: Identity, config: AgentConfig): OnlineClient { - return new OnlineClient(identity, config); + this.service = this.createServiceClient(idlFactory, config.onlineCanister); } lastOnline(userIds: string[]): Promise> { diff --git a/frontend/openchat-agent/src/services/openchatAgent.ts b/frontend/openchat-agent/src/services/openchatAgent.ts index b0e29d2f9b..786c5ca605 100644 --- a/frontend/openchat-agent/src/services/openchatAgent.ts +++ b/frontend/openchat-agent/src/services/openchatAgent.ts @@ -1,5 +1,5 @@ /* eslint-disable no-case-declarations */ -import type { Identity } from "@dfinity/agent"; +import { HttpAgent, type Identity } from "@dfinity/agent"; import { type Database, getCachedChats, @@ -244,8 +244,10 @@ import type { SetPinNumberResponse } from "openchat-shared"; import type { PinNumberSettings } from "openchat-shared"; import type { ClaimDailyChitResponse } from "openchat-shared"; import type { ChitUserBalance } from "openchat-shared"; +import { createHttpAgentSync } from "../utils/httpAgent"; export class OpenChatAgent extends EventTarget { + private _agent: HttpAgent; private _userIndexClient: UserIndexClient; private _onlineClient: OnlineClient; private _groupIndexClient: GroupIndexClient; @@ -254,6 +256,7 @@ export class OpenChatAgent extends EventTarget { private _proposalsBotClient: ProposalsBotClient; private _marketMakerClient: MarketMakerClient; private _registryClient: RegistryClient; + private _dataClient: DataClient; private _localUserIndexClients: Record; private _ledgerClients: Record; private _ledgerIndexClients: Record; @@ -276,25 +279,31 @@ export class OpenChatAgent extends EventTarget { ) { super(); this._logger = config.logger; + this._agent = createHttpAgentSync(identity, config.icUrl); this.db = initDb(this.principal); - this._onlineClient = OnlineClient.create(identity, config); - this._userIndexClient = new UserIndexClient(identity, config); - this._groupIndexClient = GroupIndexClient.create(identity, config); - this._notificationClient = NotificationsClient.create(identity, config); - this._proposalsBotClient = ProposalsBotClient.create(identity, config); - this._marketMakerClient = MarketMakerClient.create(identity, config); - this._registryClient = RegistryClient.create(identity, config); - this._icpcoinsClient = ICPCoinsClient.create(identity, config); - this.translationsClient = new TranslationsClient(identity, config); - this._signInWithEmailClient = SignInWithEmailClient.create(identity, config); - this._signInWithEthereumClient = SignInWithEthereumClient.create(identity, config); - this._signInWithSolanaClient = SignInWithSolanaClient.create(identity, config); + this._onlineClient = new OnlineClient(identity, this._agent, config); + this._userIndexClient = new UserIndexClient(identity, this._agent, config); + this._groupIndexClient = new GroupIndexClient(identity, this._agent, config); + this._notificationClient = new NotificationsClient(identity, this._agent, config); + this._proposalsBotClient = new ProposalsBotClient(identity, this._agent, config); + this._marketMakerClient = new MarketMakerClient(identity, this._agent, config); + this._registryClient = new RegistryClient(identity, this._agent, config); + this._dataClient = new DataClient(identity, this._agent, config); + this._icpcoinsClient = new ICPCoinsClient(identity, this._agent); + this.translationsClient = new TranslationsClient(identity, this._agent, config); + this._signInWithEmailClient = new SignInWithEmailClient(identity, this._agent, config); + this._signInWithEthereumClient = new SignInWithEthereumClient( + identity, + this._agent, + config, + ); + this._signInWithSolanaClient = new SignInWithSolanaClient(identity, this._agent, config); this._localUserIndexClients = {}; this._ledgerClients = {}; this._ledgerIndexClients = {}; this._groupClients = {}; this._communityClients = {}; - this._dexesAgent = new DexesAgent(config); + this._dexesAgent = new DexesAgent(this._agent); this._groupInvite = config.groupInvite; } @@ -324,7 +333,13 @@ export class OpenChatAgent extends EventTarget { if (userId === ANON_USER_ID) { this._userClient = AnonUserClient.create(); } else { - this._userClient = UserClient.create(userId, this.identity, this.config, this.db); + this._userClient = new UserClient( + userId, + this.identity, + this._agent, + this.config, + this.db, + ); } return this; } @@ -332,10 +347,11 @@ export class OpenChatAgent extends EventTarget { communityClient(communityId: string): CommunityClient { if (!this._communityClients[communityId]) { const inviteCode = this.getProvidedCommunityInviteCode(communityId); - this._communityClients[communityId] = CommunityClient.create( - communityId, + this._communityClients[communityId] = new CommunityClient( this.identity, + this._agent, this.config, + communityId, this.db, inviteCode, ); @@ -349,10 +365,11 @@ export class OpenChatAgent extends EventTarget { kind: "group_chat", groupId: chatId, }); - this._groupClients[chatId] = GroupClient.create( - { kind: "group_chat", groupId: chatId }, + this._groupClients[chatId] = new GroupClient( this.identity, + this._agent, this.config, + { kind: "group_chat", groupId: chatId }, this.db, inviteCode, ); @@ -369,16 +386,16 @@ export class OpenChatAgent extends EventTarget { getLedgerClient(ledger: string): LedgerClient { if (!this._ledgerClients[ledger]) { - this._ledgerClients[ledger] = LedgerClient.create(this.identity, this.config, ledger); + this._ledgerClients[ledger] = new LedgerClient(this.identity, this._agent, ledger); } return this._ledgerClients[ledger]; } getLedgerIndexClient(ledgerIndex: string): LedgerIndexClient { if (!this._ledgerIndexClients[ledgerIndex]) { - this._ledgerIndexClients[ledgerIndex] = LedgerIndexClient.create( + this._ledgerIndexClients[ledgerIndex] = new LedgerIndexClient( this.identity, - this.config, + this._agent, ledgerIndex, ); } @@ -387,9 +404,9 @@ export class OpenChatAgent extends EventTarget { private getLocalUserIndexClient(canisterId: string): LocalUserIndexClient { if (!this._localUserIndexClients[canisterId]) { - this._localUserIndexClients[canisterId] = LocalUserIndexClient.create( + this._localUserIndexClients[canisterId] = new LocalUserIndexClient( this.identity, - this.config, + this._agent, canisterId, this.db, ); @@ -2410,14 +2427,14 @@ export class OpenChatAgent extends EventTarget { if (offline()) return Promise.resolve(""); const userClient = userId - ? UserClient.create(userId, this.identity, this.config, this.db) + ? new UserClient(userId, this.identity, this._agent, this.config, this.db) : this.userClient; return userClient.getBio(); } getPublicProfile(userId?: string): Promise { const userClient = userId - ? UserClient.create(userId, this.identity, this.config, this.db) + ? new UserClient(userId, this.identity, this._agent, this.config, this.db) : this.userClient; return userClient.getPublicProfile(); } @@ -2439,7 +2456,7 @@ export class OpenChatAgent extends EventTarget { } getUserStorageLimits(): Promise { - return DataClient.create(this.identity, this.config).storageStatus(); + return this._dataClient.storageStatus(); } refreshAccountBalance(ledger: string, principal: string): Promise { @@ -2652,15 +2669,15 @@ export class OpenChatAgent extends EventTarget { isNns: boolean, ): Promise { if (isNns) { - return NnsGovernanceClient.create( + return new NnsGovernanceClient( this.identity, - this.config, + this._agent, governanceCanisterId, ).getProposalVoteDetails(proposalId); } else { - return SnsGovernanceClient.create( + return new SnsGovernanceClient( this.identity, - this.config, + this._agent, governanceCanisterId, ).getProposalVoteDetails(proposalId); } @@ -2669,9 +2686,9 @@ export class OpenChatAgent extends EventTarget { listNervousSystemFunctions( snsGovernanceCanisterId: string, ): Promise { - return SnsGovernanceClient.create( + return new SnsGovernanceClient( this.identity, - this.config, + this._agent, snsGovernanceCanisterId, ).listNervousSystemFunctions(); } @@ -3423,7 +3440,7 @@ export class OpenChatAgent extends EventTarget { if (localUserIndex !== undefined) { return localUserIndex; } - return UserClient.create(userId, this.identity, this.config, this.db) + return new UserClient(userId, this.identity, this._agent, this.config, this.db) .localUserIndex() .then((localUserIndex) => { return cacheLocalUserIndexForUser(userId, localUserIndex); @@ -3431,7 +3448,7 @@ export class OpenChatAgent extends EventTarget { } updateBtcBalance(userId: string): Promise { - return CkbtcMinterClient.create(this.identity, this.config).updateBalance(userId); + return new CkbtcMinterClient(this.identity, this._agent).updateBalance(userId); } generateMagicLink(email: string, sessionKey: Uint8Array): Promise { diff --git a/frontend/openchat-agent/src/services/proposalsBot/proposalsBot.client.ts b/frontend/openchat-agent/src/services/proposalsBot/proposalsBot.client.ts index 371a733fa8..28ab0e2c43 100644 --- a/frontend/openchat-agent/src/services/proposalsBot/proposalsBot.client.ts +++ b/frontend/openchat-agent/src/services/proposalsBot/proposalsBot.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import { idlFactory, type ProposalsBotService } from "./candid/idl"; import { CandidService } from "../candidService"; @@ -12,20 +12,15 @@ import { stakeNeuronForSubmittingProposalsResponse, topUpNeuronResponse } from " export class ProposalsBotClient extends CandidService { private service: ProposalsBotService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.proposalBotCanister, - config, ); } - static create(identity: Identity, config: AgentConfig): ProposalsBotClient { - return new ProposalsBotClient(identity, config); - } - stakeNeuronForSubmittingProposals( governanceCanisterId: string, stake: bigint, diff --git a/frontend/openchat-agent/src/services/registry/registry.client.ts b/frontend/openchat-agent/src/services/registry/registry.client.ts index 63c1e2ecf3..f57f0ce48c 100644 --- a/frontend/openchat-agent/src/services/registry/registry.client.ts +++ b/frontend/openchat-agent/src/services/registry/registry.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import type { RegistryUpdatesResponse } from "openchat-shared"; import { idlFactory, type RegistryService } from "./candid/idl"; @@ -13,22 +13,17 @@ export class RegistryClient extends CandidService { private readonly blobUrlPattern: string; private readonly canisterId: string; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.registryCanister, - config, ); this.blobUrlPattern = config.blobUrlPattern; this.canisterId = config.registryCanister; } - static create(identity: Identity, config: AgentConfig): RegistryClient { - return new RegistryClient(identity, config); - } - updates(since?: bigint): Promise { const args = { since: apiOptional(identity, since), diff --git a/frontend/openchat-agent/src/services/signInWithEmail/signInWithEmail.client.ts b/frontend/openchat-agent/src/services/signInWithEmail/signInWithEmail.client.ts index bb64f48058..7e78289600 100644 --- a/frontend/openchat-agent/src/services/signInWithEmail/signInWithEmail.client.ts +++ b/frontend/openchat-agent/src/services/signInWithEmail/signInWithEmail.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type SignInWithEmailService } from "./candid/idl"; import { CandidService } from "../candidService"; import type { GenerateMagicLinkResponse, GetDelegationResponse } from "openchat-shared"; @@ -9,22 +9,15 @@ import type { AgentConfig } from "../../config"; export class SignInWithEmailClient extends CandidService { private service: SignInWithEmailService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.signInWithEmailCanister, - { - icUrl: config.icUrl, - }, ); } - static create(identity: Identity, config: AgentConfig): SignInWithEmailClient { - return new SignInWithEmailClient(identity, config); - } - generateMagicLink(email: string, sessionKey: Uint8Array): Promise { const args = { email, session_key: sessionKey, max_time_to_live: [] as [] | [bigint] }; return this.handleResponse( diff --git a/frontend/openchat-agent/src/services/signInWithEthereum/signInWithEthereum.client.ts b/frontend/openchat-agent/src/services/signInWithEthereum/signInWithEthereum.client.ts index 67ed3c78b5..15376172a1 100644 --- a/frontend/openchat-agent/src/services/signInWithEthereum/signInWithEthereum.client.ts +++ b/frontend/openchat-agent/src/services/signInWithEthereum/signInWithEthereum.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type SignInWithEthereumService } from "./candid/idl"; import { CandidService } from "../candidService"; import type { @@ -12,22 +12,15 @@ import type { AgentConfig } from "../../config"; export class SignInWithEthereumClient extends CandidService { private service: SignInWithEthereumService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.signInWithEthereumCanister, - { - icUrl: config.icUrl, - }, ); } - static create(identity: Identity, config: AgentConfig): SignInWithEthereumClient { - return new SignInWithEthereumClient(identity, config); - } - prepareLogin(address: string): Promise { return this.handleResponse( this.service.siwe_prepare_login(address), diff --git a/frontend/openchat-agent/src/services/signInWithSolana/signInWithSolana.client.ts b/frontend/openchat-agent/src/services/signInWithSolana/signInWithSolana.client.ts index 3585062350..7caa80a873 100644 --- a/frontend/openchat-agent/src/services/signInWithSolana/signInWithSolana.client.ts +++ b/frontend/openchat-agent/src/services/signInWithSolana/signInWithSolana.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type SignInWithSolanaService } from "./candid/idl"; import { CandidService } from "../candidService"; import type { @@ -13,22 +13,15 @@ import type { AgentConfig } from "../../config"; export class SignInWithSolanaClient extends CandidService { private service: SignInWithSolanaService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.signInWithSolanaCanister, - { - icUrl: config.icUrl, - }, ); } - static create(identity: Identity, config: AgentConfig): SignInWithSolanaClient { - return new SignInWithSolanaClient(identity, config); - } - prepareLogin(address: string): Promise { return this.handleResponse( this.service.siws_prepare_login(address), diff --git a/frontend/openchat-agent/src/services/snsGovernance/sns.governance.client.ts b/frontend/openchat-agent/src/services/snsGovernance/sns.governance.client.ts index 7dcea25ba5..aa0ee6a658 100644 --- a/frontend/openchat-agent/src/services/snsGovernance/sns.governance.client.ts +++ b/frontend/openchat-agent/src/services/snsGovernance/sns.governance.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import type { ListNervousSystemFunctionsResponse, ManageNeuronResponse, @@ -7,7 +7,6 @@ import type { import { idlFactory, type SnsGovernanceService } from "./candid/idl"; import { CandidService } from "../candidService"; import { getProposalVoteDetails, manageNeuronResponse, nervousSystemFunctions } from "./mappers"; -import type { AgentConfig } from "../../config"; import { apiOptional, apiProposalVote } from "../common/chatMappers"; import { identity } from "../../utils/mapping"; import { toUint8Array } from "../../utils/base64"; @@ -15,28 +14,16 @@ import { toUint8Array } from "../../utils/base64"; export class SnsGovernanceClient extends CandidService { private service: SnsGovernanceService; - private constructor(identity: Identity, config: AgentConfig, canisterId: string) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, canisterId: string) { + super(identity, agent); - this.service = this.createServiceClient( - idlFactory, - canisterId, - config - ); - } - - static create( - identity: Identity, - config: AgentConfig, - canisterId: string - ): SnsGovernanceClient { - return new SnsGovernanceClient(identity, config, canisterId); + this.service = this.createServiceClient(idlFactory, canisterId); } registerVote( neuronId: string, proposalId: bigint, - vote: boolean + vote: boolean, ): Promise { const args = { subaccount: toUint8Array(neuronId), @@ -60,14 +47,14 @@ export class SnsGovernanceClient extends CandidService { }; return this.handleQueryResponse( () => this.service.list_proposals(args), - getProposalVoteDetails + getProposalVoteDetails, ); } listNervousSystemFunctions(): Promise { return this.handleQueryResponse( () => this.service.list_nervous_system_functions(), - nervousSystemFunctions + nervousSystemFunctions, ); } } diff --git a/frontend/openchat-agent/src/services/storageBucket/storageBucket.client.ts b/frontend/openchat-agent/src/services/storageBucket/storageBucket.client.ts index ea1cd6734a..05e5754247 100644 --- a/frontend/openchat-agent/src/services/storageBucket/storageBucket.client.ts +++ b/frontend/openchat-agent/src/services/storageBucket/storageBucket.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import type { Principal } from "@dfinity/principal"; import { idlFactory, type StorageBucketService } from "./candid/idl"; import { CandidService } from "../candidService"; @@ -14,27 +14,14 @@ import type { ForwardFileResponse, UploadChunkResponse, } from "openchat-shared"; -import type { AgentConfig } from "../../config"; export class StorageBucketClient extends CandidService { private service: StorageBucketService; - private constructor(identity: Identity, config: AgentConfig, canisterId: string) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, canisterId: string) { + super(identity, agent); - this.service = this.createServiceClient( - idlFactory, - canisterId, - config - ); - } - - static create( - identity: Identity, - config: AgentConfig, - canisterId: string - ): StorageBucketClient { - return new StorageBucketClient(identity, config, canisterId); + this.service = this.createServiceClient(idlFactory, canisterId); } uploadChunk( @@ -46,7 +33,7 @@ export class StorageBucketClient extends CandidService { chunkSize: number, chunkIndex: number, bytes: Uint8Array, - expiryTimestampMillis: bigint | undefined + expiryTimestampMillis: bigint | undefined, ): Promise { return this.handleResponse( this.service.upload_chunk_v2({ @@ -60,21 +47,21 @@ export class StorageBucketClient extends CandidService { chunk_size: chunkSize, expiry: expiryTimestampMillis !== undefined ? [expiryTimestampMillis] : [], }), - uploadChunkResponse + uploadChunkResponse, ); } forwardFile(fileId: bigint, accessors: Array): Promise { return this.handleResponse( this.service.forward_file({ file_id: fileId, accessors }), - forwardFileResponse + forwardFileResponse, ); } deleteFile(fileId: bigint): Promise { return this.handleResponse( this.service.delete_file({ file_id: fileId }), - deleteFileResponse + deleteFileResponse, ); } diff --git a/frontend/openchat-agent/src/services/storageIndex/storageIndex.client.ts b/frontend/openchat-agent/src/services/storageIndex/storageIndex.client.ts index 0734e80bba..c4ecbda672 100644 --- a/frontend/openchat-agent/src/services/storageIndex/storageIndex.client.ts +++ b/frontend/openchat-agent/src/services/storageIndex/storageIndex.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type StorageIndexService } from "./candid/idl"; import { CandidService } from "../candidService"; import { allocatedBucketResponse, canForwardResponse, userResponse } from "./mappers"; @@ -12,20 +12,15 @@ import type { AgentConfig } from "../../config"; export class StorageIndexClient extends CandidService { private service: StorageIndexService; - private constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.service = this.createServiceClient( idlFactory, config.openStorageIndexCanister, - config ); } - static create(identity: Identity, config: AgentConfig): StorageIndexClient { - return new StorageIndexClient(identity, config); - } - user(): Promise { return this.handleResponse(this.service.user({}), userResponse); } @@ -33,7 +28,7 @@ export class StorageIndexClient extends CandidService { allocatedBucket( fileHash: Uint8Array, fileSize: bigint, - fileIdSeed: bigint | undefined + fileIdSeed: bigint | undefined, ): Promise { return this.handleResponse( this.service.allocated_bucket_v2({ @@ -41,14 +36,14 @@ export class StorageIndexClient extends CandidService { file_size: fileSize, file_id_seed: fileIdSeed === undefined ? [] : [fileIdSeed], }), - allocatedBucketResponse + allocatedBucketResponse, ); } canForward(fileHash: Uint8Array, fileSize: bigint): Promise { return this.handleResponse( this.service.can_forward({ file_hash: fileHash, file_size: fileSize }), - canForwardResponse + canForwardResponse, ); } } diff --git a/frontend/openchat-agent/src/services/translations/translations.client.ts b/frontend/openchat-agent/src/services/translations/translations.client.ts index f064c88f67..8c3d3ed32b 100644 --- a/frontend/openchat-agent/src/services/translations/translations.client.ts +++ b/frontend/openchat-agent/src/services/translations/translations.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { idlFactory, type TranslationsService } from "./candid/idl"; import { CandidService } from "../candidService"; import type { AgentConfig } from "../../config"; @@ -24,13 +24,12 @@ import { export class TranslationsClient extends CandidService { private translationService: TranslationsService; - constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.translationService = this.createServiceClient( idlFactory, config.translationsCanister, - config, ); } diff --git a/frontend/openchat-agent/src/services/user/user.client.ts b/frontend/openchat-agent/src/services/user/user.client.ts index 1a6620d83f..b17c430a54 100644 --- a/frontend/openchat-agent/src/services/user/user.client.ts +++ b/frontend/openchat-agent/src/services/user/user.client.ts @@ -1,4 +1,4 @@ -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import type { ApiChannelMessagesRead, @@ -168,24 +168,16 @@ export class UserClient extends CandidService { private chatId: DirectChatIdentifier; constructor( - identity: Identity, userId: string, + identity: Identity, + agent: HttpAgent, private config: AgentConfig, private db: Database, ) { - super(identity); + super(identity, agent); this.userId = userId; this.chatId = { kind: "direct_chat", userId: userId }; - this.userService = this.createServiceClient(idlFactory, userId, config); - } - - static create( - userId: string, - identity: Identity, - config: AgentConfig, - db: Database, - ): UserClient { - return new UserClient(identity, userId, config, db); + this.userService = this.createServiceClient(idlFactory, userId); } private setCachedEvents( @@ -591,7 +583,7 @@ export class UserClient extends CandidService { threadRootMessageIndex?: number, blockLevelMarkdown?: boolean, ): Promise { - return DataClient.create(this.identity, this.config) + return new DataClient(this.identity, this.agent, this.config) .uploadData(message.content, [this.userId, recipientId]) .then((content) => { const req: EditMessageV2Args = { @@ -646,7 +638,7 @@ export class UserClient extends CandidService { threadRootMessageIndex: number | undefined, pin: string | undefined, ): Promise<[SendMessageResponse, Message]> { - const dataClient = DataClient.create(this.identity, this.config); + const dataClient = new DataClient(this.identity, this.agent, this.config); const uploadContentPromise = event.event.forwarded ? dataClient.forwardData(event.event.content, [this.userId, chatId.userId]) : dataClient.uploadData(event.event.content, [this.userId, chatId.userId]); diff --git a/frontend/openchat-agent/src/services/userIndex/userIndex.client.ts b/frontend/openchat-agent/src/services/userIndex/userIndex.client.ts index 743a0475b2..cd3bc15ab7 100644 --- a/frontend/openchat-agent/src/services/userIndex/userIndex.client.ts +++ b/frontend/openchat-agent/src/services/userIndex/userIndex.client.ts @@ -1,5 +1,5 @@ import { groupBy } from "../../utils/list"; -import type { Identity } from "@dfinity/agent"; +import type { HttpAgent, Identity } from "@dfinity/agent"; import { Principal } from "@dfinity/principal"; import { idlFactory, type UserIndexService } from "./candid/idl"; import type { @@ -72,13 +72,12 @@ import { export class UserIndexClient extends CandidService { private userIndexService: UserIndexService; - constructor(identity: Identity, config: AgentConfig) { - super(identity); + constructor(identity: Identity, agent: HttpAgent, config: AgentConfig) { + super(identity, agent); this.userIndexService = this.createServiceClient( idlFactory, config.userIndexCanister, - config, ); } diff --git a/frontend/openchat-agent/src/utils/httpAgent.ts b/frontend/openchat-agent/src/utils/httpAgent.ts new file mode 100644 index 0000000000..d94a54447b --- /dev/null +++ b/frontend/openchat-agent/src/utils/httpAgent.ts @@ -0,0 +1,28 @@ +import { HttpAgent, type Identity } from "@dfinity/agent"; +import { isMainnet } from "./network"; +import { offline } from "openchat-shared"; + +export function createHttpAgentSync(identity: Identity, icUrl: string): HttpAgent { + const [agent] = createHttpAgentInternal(identity, icUrl); + return agent; +} + +export async function createHttpAgent(identity: Identity, icUrl: string): Promise { + const [agent, fetchRootKeyPromise] = createHttpAgentInternal(identity, icUrl); + await fetchRootKeyPromise; + return agent; +} + +function createHttpAgentInternal(identity: Identity, icUrl: string): [HttpAgent, Promise] { + const agent = HttpAgent.createSync({ + identity, + host: icUrl, + verifyQuerySignatures: false, + }); + const fetchRootKey = !isMainnet(icUrl) && !offline(); + const fetchRootKeyPromise = fetchRootKey + ? agent.fetchRootKey().then((_) => {}) + : Promise.resolve(); + + return [agent, fetchRootKeyPromise]; +} diff --git a/frontend/openchat-worker/src/worker.ts b/frontend/openchat-worker/src/worker.ts index d9b3006fd7..e62aebf9a5 100644 --- a/frontend/openchat-worker/src/worker.ts +++ b/frontend/openchat-worker/src/worker.ts @@ -62,7 +62,7 @@ async function initialize( return { kind: "auth_identity_not_found" }; } - identityAgent = new IdentityAgent( + identityAgent = await IdentityAgent.create( authProviderIdentity as SignIdentity, identityCanister, icUrl, @@ -1831,14 +1831,14 @@ async function linkIdentities( DelegationChain.fromJSON(initiatorDelegation), ); const initiator = initiatorIdentity.getPrincipal().toString(); - const initiatorAgent = new IdentityAgent(initiatorIdentity, identityCanister, icUrl); + const initiatorAgent = await IdentityAgent.create(initiatorIdentity, identityCanister, icUrl); const approverIdentity = DelegationIdentity.fromDelegation( await ECDSAKeyIdentity.fromKeyPair(approverKey), DelegationChain.fromJSON(approverDelegation), ); const approver = approverIdentity.getPrincipal().toString(); - const approverAgent = new IdentityAgent(approverIdentity, identityCanister, icUrl); + const approverAgent = await IdentityAgent.create(approverIdentity, identityCanister, icUrl); if (approver != authPrincipalString) { return "principal_mismatch";