@crossmint/client-sdk-smart-wallet 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -70
- package/dist/index.d.ts +53 -70
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
- package/src/SmartWalletSDK.ts +10 -7
- package/src/api/CrossmintWalletService.test.ts +2 -1
- package/src/api/CrossmintWalletService.ts +21 -7
- package/src/blockchain/wallets/EVMSmartWallet.ts +7 -9
- package/src/blockchain/wallets/account/cache.test.ts +67 -0
- package/src/blockchain/wallets/account/cache.ts +43 -0
- package/src/blockchain/wallets/account/config.test.ts +103 -0
- package/src/blockchain/wallets/account/config.ts +71 -15
- package/src/blockchain/wallets/account/creator.ts +18 -14
- package/src/blockchain/wallets/account/eoa.ts +10 -9
- package/src/blockchain/wallets/account/passkey.ts +11 -12
- package/src/blockchain/wallets/account/strategy.ts +2 -2
- package/src/blockchain/wallets/clientDecorator.ts +4 -5
- package/src/blockchain/wallets/service.ts +20 -15
- package/src/error/processor.ts +4 -3
- package/src/services/index.ts +1 -0
- package/src/services/logger.ts +6 -0
- package/src/types/internal.ts +29 -23
- package/src/utils/constants.ts +0 -4
- package/src/utils/helpers.ts +0 -8
- package/src/utils/test.ts +24 -0
- package/src/api/APIErrorService.ts +0 -78
- package/src/api/BaseCrossmintService.ts +0 -81
- package/src/services/logging/BrowserLoggerInterface.ts +0 -5
- package/src/services/logging/ConsoleProvider.ts +0 -15
- package/src/services/logging/DatadogProvider.ts +0 -39
- package/src/services/logging/index.ts +0 -16
- package/src/utils/log.ts +0 -49
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AccountAndSigner,
|
|
1
|
+
import { AccountAndSigner, WalletCreationContext } from "../../../types/internal";
|
|
2
2
|
|
|
3
3
|
export interface AccountCreationStrategy {
|
|
4
|
-
create(params:
|
|
4
|
+
create(params: WalletCreationContext): Promise<AccountAndSigner>;
|
|
5
5
|
}
|
|
@@ -4,9 +4,8 @@ import { stringify } from "viem";
|
|
|
4
4
|
|
|
5
5
|
import { SmartWalletError } from "../../error";
|
|
6
6
|
import { ErrorProcessor } from "../../error/processor";
|
|
7
|
-
import {
|
|
7
|
+
import { scwLogger } from "../../services";
|
|
8
8
|
import { usesGelatoBundler } from "../../utils/blockchain";
|
|
9
|
-
import { logPerformance } from "../../utils/log";
|
|
10
9
|
import { SmartWalletChain } from "../chains";
|
|
11
10
|
|
|
12
11
|
const transactionMethods = [
|
|
@@ -38,7 +37,7 @@ function isSignMethod(method: string): method is SignMethod {
|
|
|
38
37
|
* - Automatic formatting of transactions for Gelato bundler compatibility.
|
|
39
38
|
* */
|
|
40
39
|
export class ClientDecorator {
|
|
41
|
-
constructor(private readonly errorProcessor: ErrorProcessor) {}
|
|
40
|
+
constructor(private readonly errorProcessor: ErrorProcessor, protected logger = scwLogger) {}
|
|
42
41
|
|
|
43
42
|
public decorate<Client extends SmartAccountClient<EntryPoint>>({
|
|
44
43
|
crossmintChain,
|
|
@@ -60,7 +59,7 @@ export class ClientDecorator {
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
return (...args: any[]) =>
|
|
63
|
-
logPerformance(`CrossmintSmartWallet.${prop}`, () =>
|
|
62
|
+
this.logger.logPerformance(`CrossmintSmartWallet.${prop}`, () =>
|
|
64
63
|
this.execute(target, prop, originalMethod, args, crossmintChain)
|
|
65
64
|
);
|
|
66
65
|
},
|
|
@@ -76,7 +75,7 @@ export class ClientDecorator {
|
|
|
76
75
|
crossmintChain: SmartWalletChain
|
|
77
76
|
) {
|
|
78
77
|
try {
|
|
79
|
-
|
|
78
|
+
this.logger.log(`[CrossmintSmartWallet.${prop}] - params: ${stringify(args)}`);
|
|
80
79
|
const processed = isTxnMethod(prop) ? this.processTxnArgs(prop, crossmintChain, args) : args;
|
|
81
80
|
return await originalMethod.call(target, ...processed);
|
|
82
81
|
} catch (error: any) {
|
|
@@ -12,7 +12,7 @@ import { CURRENT_VERSION, ZERO_DEV_TYPE } from "../../utils/constants";
|
|
|
12
12
|
import { equalsIgnoreCase } from "../../utils/helpers";
|
|
13
13
|
import { type SmartWalletChain, getBundlerRPC, viemNetworks } from "../chains";
|
|
14
14
|
import { EVMSmartWallet } from "./EVMSmartWallet";
|
|
15
|
-
import type {
|
|
15
|
+
import type { AccountConfigService } from "./account/config";
|
|
16
16
|
import type { AccountCreator } from "./account/creator";
|
|
17
17
|
import type { ClientDecorator } from "./clientDecorator";
|
|
18
18
|
import { paymasterMiddleware, usePaymaster } from "./paymaster";
|
|
@@ -20,7 +20,7 @@ import { paymasterMiddleware, usePaymaster } from "./paymaster";
|
|
|
20
20
|
export class SmartWalletService {
|
|
21
21
|
constructor(
|
|
22
22
|
private readonly crossmintService: CrossmintWalletService,
|
|
23
|
-
private readonly
|
|
23
|
+
private readonly accountConfigService: AccountConfigService,
|
|
24
24
|
private readonly accountCreator: AccountCreator,
|
|
25
25
|
private readonly clientDecorator: ClientDecorator
|
|
26
26
|
) {}
|
|
@@ -30,28 +30,24 @@ export class SmartWalletService {
|
|
|
30
30
|
chain: SmartWalletChain,
|
|
31
31
|
walletParams: WalletParams
|
|
32
32
|
): Promise<EVMSmartWallet> {
|
|
33
|
-
const {
|
|
34
|
-
|
|
33
|
+
const {
|
|
34
|
+
config: { entryPointVersion, kernelVersion, existing, userWithId },
|
|
35
|
+
cached,
|
|
36
|
+
} = await this.accountConfigService.get(user, chain);
|
|
37
|
+
|
|
35
38
|
const publicClient = createPublicClient({ transport: http(getBundlerRPC(chain)) });
|
|
36
39
|
|
|
37
40
|
const { account, signerConfig } = await this.accountCreator.get({
|
|
38
41
|
chain,
|
|
39
42
|
walletParams,
|
|
40
43
|
publicClient,
|
|
41
|
-
user:
|
|
42
|
-
entryPoint:
|
|
43
|
-
version: entryPointVersion,
|
|
44
|
-
address: entryPointVersion === "v0.6" ? ENTRYPOINT_ADDRESS_V06 : ENTRYPOINT_ADDRESS_V07,
|
|
45
|
-
},
|
|
44
|
+
user: userWithId,
|
|
45
|
+
entryPoint: entryPointVersion === "v0.6" ? ENTRYPOINT_ADDRESS_V06 : ENTRYPOINT_ADDRESS_V07,
|
|
46
46
|
kernelVersion,
|
|
47
|
-
|
|
47
|
+
existing,
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
if (
|
|
51
|
-
throw new UserWalletAlreadyCreatedError(userId);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (existingSignerConfig == null) {
|
|
50
|
+
if (existing == null) {
|
|
55
51
|
await this.crossmintService.idempotentCreateSmartWallet(user, {
|
|
56
52
|
type: ZERO_DEV_TYPE,
|
|
57
53
|
smartContractWalletAddress: account.address,
|
|
@@ -64,6 +60,15 @@ export class SmartWalletService {
|
|
|
64
60
|
});
|
|
65
61
|
}
|
|
66
62
|
|
|
63
|
+
if (!cached) {
|
|
64
|
+
this.accountConfigService.cache({
|
|
65
|
+
entryPointVersion,
|
|
66
|
+
kernelVersion,
|
|
67
|
+
user: userWithId,
|
|
68
|
+
existing: { address: account.address, signerConfig },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
67
72
|
const kernelAccountClient: SmartWalletClient = createKernelAccountClient({
|
|
68
73
|
account,
|
|
69
74
|
chain: viemNetworks[chain],
|
package/src/error/processor.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { BaseError, stringify } from "viem";
|
|
2
2
|
|
|
3
|
+
import { SDKLogger } from "@crossmint/client-sdk-base";
|
|
4
|
+
|
|
3
5
|
import { SmartWalletError } from ".";
|
|
4
|
-
import { DatadogProvider } from "../services/logging/DatadogProvider";
|
|
5
6
|
import { SDK_VERSION } from "../utils/constants";
|
|
6
7
|
|
|
7
8
|
export class ErrorProcessor {
|
|
8
|
-
constructor(private readonly logger:
|
|
9
|
+
constructor(private readonly logger: SDKLogger) {}
|
|
9
10
|
|
|
10
11
|
public map(error: unknown, fallback: SmartWalletError): SmartWalletError | BaseError {
|
|
11
12
|
this.record(error);
|
|
@@ -24,7 +25,7 @@ export class ErrorProcessor {
|
|
|
24
25
|
|
|
25
26
|
private record(error: unknown) {
|
|
26
27
|
const message = error instanceof Error ? error.message : String(error);
|
|
27
|
-
this.logger.
|
|
28
|
+
this.logger.error(`Smart Wallet SDK Error: ${message}`, {
|
|
28
29
|
stack: error instanceof Error ? error.stack : undefined,
|
|
29
30
|
name: error instanceof Error ? error.name : "UnknownError",
|
|
30
31
|
details: stringify(error),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logger";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SDKLogger, getBrowserLogger } from "@crossmint/client-sdk-base";
|
|
2
|
+
|
|
3
|
+
import { SCW_SERVICE } from "../utils/constants";
|
|
4
|
+
|
|
5
|
+
export const scwLogger = new SDKLogger(SCW_SERVICE);
|
|
6
|
+
export const scwDatadogLogger = new SDKLogger(SCW_SERVICE, getBrowserLogger(SCW_SERVICE, { onlyDatadog: true }));
|
package/src/types/internal.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { KernelSmartAccount } from "@zerodev/sdk";
|
|
|
2
2
|
import type { SmartAccountClient } from "permissionless";
|
|
3
3
|
import type { SmartAccount } from "permissionless/accounts";
|
|
4
4
|
import type { EntryPoint } from "permissionless/types/entrypoint";
|
|
5
|
-
import type { Chain, HttpTransport, PublicClient } from "viem";
|
|
5
|
+
import type { Address, Chain, HttpTransport, PublicClient } from "viem";
|
|
6
6
|
|
|
7
7
|
import type { SmartWalletChain } from "../blockchain/chains";
|
|
8
8
|
import type { EOASignerConfig, PasskeySignerConfig, SignerConfig } from "../blockchain/wallets/account/signer";
|
|
@@ -19,47 +19,53 @@ export function isSupportedEntryPointVersion(version: string): version is Suppor
|
|
|
19
19
|
return SUPPORTED_ENTRYPOINT_VERSIONS.includes(version as any);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export interface
|
|
22
|
+
export interface PreExistingWalletProperties {
|
|
23
|
+
signerConfig: SignerConfig;
|
|
24
|
+
address: Address;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface WalletCreationContext {
|
|
23
28
|
user: UserParams & { id: string };
|
|
24
29
|
chain: SmartWalletChain;
|
|
25
30
|
publicClient: PublicClient<HttpTransport>;
|
|
26
31
|
walletParams: WalletParams;
|
|
27
|
-
entryPoint:
|
|
32
|
+
entryPoint: EntryPoint;
|
|
28
33
|
kernelVersion: SupportedKernelVersion;
|
|
29
|
-
|
|
34
|
+
existing?: PreExistingWalletProperties;
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
export interface
|
|
37
|
+
export interface PasskeyCreationContext extends WalletCreationContext {
|
|
33
38
|
walletParams: WalletParams & { signer: PasskeySigner };
|
|
34
|
-
|
|
39
|
+
existing?: { signerConfig: PasskeySignerConfig; address: Address };
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
export interface
|
|
42
|
+
export interface EOACreationContext extends WalletCreationContext {
|
|
38
43
|
walletParams: WalletParams & { signer: EOASigner };
|
|
39
|
-
|
|
44
|
+
existing?: { signerConfig: EOASignerConfig; address: Address };
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
export function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"type" in params.walletParams.signer &&
|
|
46
|
-
params.walletParams.signer.type === "PASSKEY";
|
|
47
|
+
export function isPasskeyWalletParams(params: WalletParams): params is WalletParams & { signer: PasskeySigner } {
|
|
48
|
+
return "signer" in params && "type" in params.signer && params.signer.type === "PASSKEY";
|
|
49
|
+
}
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
export function isPasskeyCreationContext(params: WalletCreationContext): params is PasskeyCreationContext {
|
|
52
|
+
const signerIsPasskeyOrUndefined = params.existing == null || params.existing.signerConfig.type === "passkeys";
|
|
50
53
|
|
|
51
|
-
return
|
|
54
|
+
return isPasskeyWalletParams(params.walletParams) && signerIsPasskeyOrUndefined;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
"signer" in params
|
|
57
|
-
(("type" in params.
|
|
58
|
-
("request" in params.
|
|
57
|
+
export function isEOAWalletParams(params: WalletParams): params is WalletParams & { signer: EOASigner } {
|
|
58
|
+
return (
|
|
59
|
+
"signer" in params &&
|
|
60
|
+
(("type" in params.signer && params.signer.type === "VIEM_ACCOUNT") ||
|
|
61
|
+
("request" in params.signer && typeof params.signer.request === "function"))
|
|
62
|
+
);
|
|
63
|
+
}
|
|
59
64
|
|
|
60
|
-
|
|
65
|
+
export function isEOACreationContext(params: WalletCreationContext): params is EOACreationContext {
|
|
66
|
+
const signerIsEOAOrUndefined = params.existing == null || params.existing.signerConfig.type === "eoa";
|
|
61
67
|
|
|
62
|
-
return
|
|
68
|
+
return isEOAWalletParams(params.walletParams) && signerIsEOAOrUndefined;
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
export interface AccountAndSigner {
|
package/src/utils/constants.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export const ZERO_DEV_TYPE = "ZeroDev";
|
|
2
2
|
export const CURRENT_VERSION = 0;
|
|
3
|
-
export const DATADOG_CLIENT_TOKEN = "pub035be8a594b35be1887b6ba76c4029ca";
|
|
4
|
-
export const CROSSMINT_DEV_URL = "http://localhost:3000/api";
|
|
5
|
-
export const CROSSMINT_STG_URL = "https://staging.crossmint.com/api";
|
|
6
|
-
export const CROSSMINT_PROD_URL = "https://www.crossmint.com/api";
|
|
7
3
|
export const SCW_SERVICE = "SCW_SDK";
|
|
8
4
|
export const SDK_VERSION = "0.1.0";
|
|
9
5
|
export const API_VERSION = "2024-06-09";
|
package/src/utils/helpers.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export function isLocalhost() {
|
|
2
|
-
if (process.env.NODE_ENV === "test") {
|
|
3
|
-
return false;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
return window.location.origin.includes("localhost");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
1
|
export function isEmpty(str: string | undefined | null): str is undefined | null {
|
|
10
2
|
return !str || str.length === 0 || str.trim().length === 0;
|
|
11
3
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SmartWalletConfig } from "../types/service";
|
|
2
|
+
|
|
3
|
+
export const mockConfig: SmartWalletConfig = {
|
|
4
|
+
kernelVersion: "0.3.1",
|
|
5
|
+
entryPointVersion: "v0.7",
|
|
6
|
+
userId: "devlyn@paella.dev",
|
|
7
|
+
signers: [
|
|
8
|
+
{
|
|
9
|
+
signerData: {
|
|
10
|
+
entryPoint: "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
|
|
11
|
+
validatorAddress: "0xbA45a2BFb8De3D24cA9D7F1B551E14dFF5d690Fd",
|
|
12
|
+
pubKeyX: "110311240024954100085667226472791468894960420468782293097673057837941382345525",
|
|
13
|
+
pubKeyY: "55639753423913323920634804373610812340711881298092778447611544058799129775494",
|
|
14
|
+
authenticatorIdHash: "0xb7f951026ad956257e41c16f5e6c1c8969968356c9a8a8df916fcceda53f5c6a",
|
|
15
|
+
authenticatorId: "u76dDdMEjTBgm68gbqfbaAlSoqE",
|
|
16
|
+
passkeyName: "devlyn@paella.dev",
|
|
17
|
+
validatorContractVersion: "0.0.2" as any,
|
|
18
|
+
domain: "localhost",
|
|
19
|
+
type: "passkeys",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
smartContractWalletAddress: "0x7EAf93269C06Af4236E08d16d5220Df5f964eD87",
|
|
24
|
+
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CrossmintServiceError,
|
|
3
|
-
JWTDecryptionError,
|
|
4
|
-
JWTExpiredError,
|
|
5
|
-
JWTIdentifierError,
|
|
6
|
-
JWTInvalidError,
|
|
7
|
-
OutOfCreditsError,
|
|
8
|
-
} from "@crossmint/client-sdk-base";
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
AdminAlreadyUsedError,
|
|
12
|
-
SmartWalletError,
|
|
13
|
-
SmartWalletsNotEnabledError,
|
|
14
|
-
UserWalletAlreadyCreatedError,
|
|
15
|
-
} from "../error";
|
|
16
|
-
|
|
17
|
-
export type CrossmintAPIErrorCodes =
|
|
18
|
-
| "ERROR_JWT_INVALID"
|
|
19
|
-
| "ERROR_JWT_DECRYPTION"
|
|
20
|
-
| "ERROR_JWT_IDENTIFIER"
|
|
21
|
-
| "ERROR_JWT_EXPIRED"
|
|
22
|
-
| "ERROR_USER_WALLET_ALREADY_CREATED"
|
|
23
|
-
| "ERROR_ADMIN_SIGNER_ALREADY_USED"
|
|
24
|
-
| "ERROR_PROJECT_NONCUSTODIAL_WALLETS_NOT_ENABLED";
|
|
25
|
-
|
|
26
|
-
export class APIErrorService {
|
|
27
|
-
constructor(
|
|
28
|
-
private errors: Record<CrossmintAPIErrorCodes, (apiResponse: any) => SmartWalletError> = {
|
|
29
|
-
ERROR_JWT_INVALID: () => new JWTInvalidError(),
|
|
30
|
-
ERROR_JWT_DECRYPTION: () => new JWTDecryptionError(),
|
|
31
|
-
ERROR_JWT_EXPIRED: ({ expiredAt }: { expiredAt: string }) => new JWTExpiredError(new Date(expiredAt)),
|
|
32
|
-
ERROR_JWT_IDENTIFIER: ({ identifierKey }: { identifierKey: string }) =>
|
|
33
|
-
new JWTIdentifierError(identifierKey),
|
|
34
|
-
ERROR_USER_WALLET_ALREADY_CREATED: ({ userId }: { userId: string }) =>
|
|
35
|
-
new UserWalletAlreadyCreatedError(userId),
|
|
36
|
-
ERROR_ADMIN_SIGNER_ALREADY_USED: () => new AdminAlreadyUsedError(),
|
|
37
|
-
ERROR_PROJECT_NONCUSTODIAL_WALLETS_NOT_ENABLED: () => new SmartWalletsNotEnabledError(),
|
|
38
|
-
}
|
|
39
|
-
) {}
|
|
40
|
-
|
|
41
|
-
async throwErrorFromResponse({
|
|
42
|
-
response,
|
|
43
|
-
onServerErrorMessage,
|
|
44
|
-
}: {
|
|
45
|
-
response: Response;
|
|
46
|
-
onServerErrorMessage: string;
|
|
47
|
-
}) {
|
|
48
|
-
if (response.ok) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (response.status >= 500) {
|
|
53
|
-
throw new CrossmintServiceError(onServerErrorMessage, response.status);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (response.status === 402) {
|
|
57
|
-
throw new OutOfCreditsError();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
const body = await response.json();
|
|
62
|
-
const code = body.code as CrossmintAPIErrorCodes | undefined;
|
|
63
|
-
if (code != null && this.errors[code] != null) {
|
|
64
|
-
throw this.errors[code](body);
|
|
65
|
-
}
|
|
66
|
-
if (body.message != null) {
|
|
67
|
-
throw new CrossmintServiceError(body.message, response.status);
|
|
68
|
-
}
|
|
69
|
-
} catch (e) {
|
|
70
|
-
if (e instanceof SmartWalletError) {
|
|
71
|
-
throw e;
|
|
72
|
-
}
|
|
73
|
-
console.error("Error parsing response", e);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
throw new CrossmintServiceError(await response.text(), response.status);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { CrossmintServiceError } from "@crossmint/client-sdk-base";
|
|
2
|
-
import { validateAPIKey } from "@crossmint/common-sdk-base";
|
|
3
|
-
|
|
4
|
-
import { CROSSMINT_DEV_URL, CROSSMINT_PROD_URL, CROSSMINT_STG_URL } from "../utils/constants";
|
|
5
|
-
import { logPerformance } from "../utils/log";
|
|
6
|
-
import { APIErrorService } from "./APIErrorService";
|
|
7
|
-
|
|
8
|
-
export abstract class BaseCrossmintService {
|
|
9
|
-
public crossmintAPIHeaders: Record<string, string>;
|
|
10
|
-
protected crossmintBaseUrl: string;
|
|
11
|
-
protected apiErrorService: APIErrorService;
|
|
12
|
-
private static urlMap: Record<string, string> = {
|
|
13
|
-
development: CROSSMINT_DEV_URL,
|
|
14
|
-
staging: CROSSMINT_STG_URL,
|
|
15
|
-
production: CROSSMINT_PROD_URL,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
constructor(apiKey: string) {
|
|
19
|
-
const result = validateAPIKey(apiKey);
|
|
20
|
-
if (!result.isValid) {
|
|
21
|
-
throw new Error("API key invalid");
|
|
22
|
-
}
|
|
23
|
-
this.crossmintAPIHeaders = {
|
|
24
|
-
accept: "application/json",
|
|
25
|
-
"content-type": "application/json",
|
|
26
|
-
"x-api-key": apiKey,
|
|
27
|
-
};
|
|
28
|
-
this.crossmintBaseUrl = this.getUrlFromEnv(result.environment);
|
|
29
|
-
this.apiErrorService = new APIErrorService();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
protected async fetchCrossmintAPI(
|
|
33
|
-
endpoint: string,
|
|
34
|
-
options: { body?: string; method: string } = { method: "GET" },
|
|
35
|
-
onServerErrorMessage: string,
|
|
36
|
-
authToken?: string
|
|
37
|
-
) {
|
|
38
|
-
return logPerformance(
|
|
39
|
-
"FETCH_CROSSMINT_API",
|
|
40
|
-
async () => {
|
|
41
|
-
const url = `${this.crossmintBaseUrl}/${endpoint}`;
|
|
42
|
-
const { body, method } = options;
|
|
43
|
-
|
|
44
|
-
let response: Response;
|
|
45
|
-
try {
|
|
46
|
-
response = await fetch(url, {
|
|
47
|
-
body,
|
|
48
|
-
method,
|
|
49
|
-
headers: {
|
|
50
|
-
...this.crossmintAPIHeaders,
|
|
51
|
-
...(authToken != null && {
|
|
52
|
-
Authorization: `Bearer ${authToken}`,
|
|
53
|
-
}),
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
} catch (error) {
|
|
57
|
-
throw new CrossmintServiceError(`Error fetching Crossmint API: ${error}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!response.ok) {
|
|
61
|
-
await this.apiErrorService.throwErrorFromResponse({
|
|
62
|
-
response,
|
|
63
|
-
onServerErrorMessage,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return await response.json();
|
|
68
|
-
},
|
|
69
|
-
{ endpoint }
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
protected getUrlFromEnv(environment: string) {
|
|
74
|
-
const url = BaseCrossmintService.urlMap[environment];
|
|
75
|
-
if (!url) {
|
|
76
|
-
console.log(" CrossmintService.urlMap: ", BaseCrossmintService.urlMap);
|
|
77
|
-
throw new Error(`URL not found for environment: ${environment}`);
|
|
78
|
-
}
|
|
79
|
-
return url;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { BrowserLoggerInterface } from "./BrowserLoggerInterface";
|
|
2
|
-
|
|
3
|
-
export class ConsoleProvider implements BrowserLoggerInterface {
|
|
4
|
-
logInfo(message: string, context?: object) {
|
|
5
|
-
console.log(message, context);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
logError(message: string, context?: object) {
|
|
9
|
-
console.error(message, context);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
logWarn(message: string, context?: object) {
|
|
13
|
-
console.warn(message, context);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { datadogLogs } from "@datadog/browser-logs";
|
|
2
|
-
|
|
3
|
-
import { DATADOG_CLIENT_TOKEN, SCW_SERVICE } from "../../utils/constants";
|
|
4
|
-
import { BrowserLoggerInterface } from "./BrowserLoggerInterface";
|
|
5
|
-
|
|
6
|
-
export class DatadogProvider implements BrowserLoggerInterface {
|
|
7
|
-
logInfo(message: string, context?: object) {
|
|
8
|
-
log(message, "info", context);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
logError(message: string, context?: object) {
|
|
12
|
-
log(message, "error", context);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
logWarn(message: string, context?: object) {
|
|
16
|
-
log(message, "warn", context);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function log(message: string, loggerType: "info" | "error" | "warn", contextParam?: object) {
|
|
21
|
-
const _context = contextParam ? { ...contextParam, service: SCW_SERVICE } : { service: SCW_SERVICE };
|
|
22
|
-
|
|
23
|
-
init();
|
|
24
|
-
datadogLogs.logger[loggerType](message, _context);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function init() {
|
|
28
|
-
const isDatadogInitialized = datadogLogs.getInternalContext() != null;
|
|
29
|
-
if (isDatadogInitialized) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
datadogLogs.init({
|
|
34
|
-
clientToken: DATADOG_CLIENT_TOKEN,
|
|
35
|
-
site: "datadoghq.com",
|
|
36
|
-
forwardErrorsToLogs: false,
|
|
37
|
-
sampleRate: 100,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { isClient } from "../../utils/environment";
|
|
2
|
-
import { isLocalhost } from "../../utils/helpers";
|
|
3
|
-
import { ConsoleProvider } from "./ConsoleProvider";
|
|
4
|
-
import { DatadogProvider } from "./DatadogProvider";
|
|
5
|
-
|
|
6
|
-
function getBrowserLogger() {
|
|
7
|
-
if (isClient() && isLocalhost()) {
|
|
8
|
-
return new ConsoleProvider();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return new DatadogProvider();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { logInfo, logWarn, logError } = getBrowserLogger();
|
|
15
|
-
|
|
16
|
-
export { logInfo, logWarn, logError };
|
package/src/utils/log.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { logError, logInfo } from "../services/logging";
|
|
2
|
-
import { SCW_SERVICE } from "./constants";
|
|
3
|
-
|
|
4
|
-
export async function logPerformance<T>(name: string, cb: () => Promise<T>, extraInfo?: object) {
|
|
5
|
-
const start = new Date().getTime();
|
|
6
|
-
const result = await cb();
|
|
7
|
-
const durationInMs = new Date().getTime() - start;
|
|
8
|
-
const args = { durationInMs, ...extraInfo };
|
|
9
|
-
logInfo(`[${SCW_SERVICE} - ${name} - TIME] - ${beautify(args)}`, { args });
|
|
10
|
-
return result;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function beautify(json: any) {
|
|
14
|
-
try {
|
|
15
|
-
return json != null ? JSON.stringify(json, null, 2) : json;
|
|
16
|
-
} catch (error) {
|
|
17
|
-
return stringifyAvoidingCircular(json);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function stringifyAvoidingCircular(json: any) {
|
|
22
|
-
// stringify an object, avoiding circular structures
|
|
23
|
-
// https://stackoverflow.com/a/31557814
|
|
24
|
-
const simpleObject: { [key: string]: any } = {};
|
|
25
|
-
for (const prop in json) {
|
|
26
|
-
if (!Object.prototype.hasOwnProperty.call(json, prop)) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (typeof json[prop] == "object") {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (typeof json[prop] == "function") {
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
simpleObject[prop] = json[prop];
|
|
36
|
-
}
|
|
37
|
-
return JSON.stringify(simpleObject, null, 2); // returns cleaned up JSON
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function errorToJSON(error: Error | unknown) {
|
|
41
|
-
const errorToLog = error instanceof Error ? error : { message: "Unknown error", name: "Unknown error" };
|
|
42
|
-
|
|
43
|
-
if (!(errorToLog instanceof Error) && (errorToLog as any).constructor?.name !== "SyntheticBaseEvent") {
|
|
44
|
-
logError("ERROR_TO_JSON_FAILED", { error: errorToLog });
|
|
45
|
-
throw new Error("[errorToJSON] err is not instanceof Error nor SyntheticBaseEvent");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return JSON.parse(JSON.stringify(errorToLog, Object.getOwnPropertyNames(errorToLog)));
|
|
49
|
-
}
|