@dynamic-labs-sdk/client 1.16.1 → 1.17.1
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/core.cjs +53 -53
- package/dist/core.cjs.map +1 -1
- package/dist/core.esm.js +5 -5
- package/dist/core.native.esm.js +5 -5
- package/dist/exports/index.d.ts +2 -2
- package/dist/exports/index.d.ts.map +1 -1
- package/dist/exports/waas.d.ts +2 -1
- package/dist/exports/waas.d.ts.map +1 -1
- package/dist/exports/waasCore.d.ts +3 -2
- package/dist/exports/waasCore.d.ts.map +1 -1
- package/dist/{getNetworkProviderFromNetworkId-D79icjmX.native.esm.js → getNetworkProviderFromNetworkId-Bfg-NkNJ.native.esm.js} +12 -4
- package/dist/getNetworkProviderFromNetworkId-Bfg-NkNJ.native.esm.js.map +1 -0
- package/dist/{getNetworkProviderFromNetworkId-BHxkTbiJ.cjs → getNetworkProviderFromNetworkId-CS4r9hi7.cjs} +43 -44
- package/dist/{getNetworkProviderFromNetworkId-BHxkTbiJ.cjs.map → getNetworkProviderFromNetworkId-CS4r9hi7.cjs.map} +1 -1
- package/dist/{getNetworkProviderFromNetworkId-BPeOK1Xx.esm.js → getNetworkProviderFromNetworkId-pknqqhk1.esm.js} +2 -3
- package/dist/{getNetworkProviderFromNetworkId-BPeOK1Xx.esm.js.map → getNetworkProviderFromNetworkId-pknqqhk1.esm.js.map} +1 -1
- package/dist/{getSignedSessionId-DzjHW7Rw.esm.js → getSignedSessionId-CUw7LJ35.esm.js} +3 -3
- package/dist/{getSignedSessionId-DzjHW7Rw.esm.js.map → getSignedSessionId-CUw7LJ35.esm.js.map} +1 -1
- package/dist/{getSignedSessionId-Dh4Df1mY.native.esm.js → getSignedSessionId-Cl3PEqa8.native.esm.js} +3 -3
- package/dist/{getSignedSessionId-Dh4Df1mY.native.esm.js.map → getSignedSessionId-Cl3PEqa8.native.esm.js.map} +1 -1
- package/dist/{getSignedSessionId-BjSUL8Br.cjs → getSignedSessionId-cMGkmojJ.cjs} +11 -11
- package/dist/{getSignedSessionId-BjSUL8Br.cjs.map → getSignedSessionId-cMGkmojJ.cjs.map} +1 -1
- package/dist/getWalletProviderByKey-24co0tBE.native.esm.js +20 -0
- package/dist/getWalletProviderByKey-24co0tBE.native.esm.js.map +1 -0
- package/dist/getWalletProviderByKey-CP9Te5Sz.cjs +31 -0
- package/dist/getWalletProviderByKey-CP9Te5Sz.cjs.map +1 -0
- package/dist/getWalletProviderByKey-lQVfIGFi.esm.js +20 -0
- package/dist/getWalletProviderByKey-lQVfIGFi.esm.js.map +1 -0
- package/dist/index.cjs +560 -541
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +29 -28
- package/dist/index.esm.js.map +1 -1
- package/dist/index.native.esm.js +29 -28
- package/dist/index.native.esm.js.map +1 -1
- package/dist/isDynamicWaasEnabled-BXe0VyI4.native.esm.js +70 -0
- package/dist/isDynamicWaasEnabled-BXe0VyI4.native.esm.js.map +1 -0
- package/dist/isDynamicWaasEnabled-BYaqAOml.esm.js +70 -0
- package/dist/isDynamicWaasEnabled-BYaqAOml.esm.js.map +1 -0
- package/dist/isDynamicWaasEnabled-BwP1oowd.cjs +88 -0
- package/dist/isDynamicWaasEnabled-BwP1oowd.cjs.map +1 -0
- package/dist/{isMfaRequiredForAction-3fWX5MEF.cjs → isMfaRequiredForAction-Btejc5g3.cjs} +38 -29
- package/dist/isMfaRequiredForAction-Btejc5g3.cjs.map +1 -0
- package/dist/{isMfaRequiredForAction-CkX6CfJf.esm.js → isMfaRequiredForAction-CqEcCTIe.esm.js} +11 -2
- package/dist/isMfaRequiredForAction-CqEcCTIe.esm.js.map +1 -0
- package/dist/{isMfaRequiredForAction-CBW-d9C6.native.esm.js → isMfaRequiredForAction-Demz9zlH.native.esm.js} +2 -2
- package/dist/{isMfaRequiredForAction-CBW-d9C6.native.esm.js.map → isMfaRequiredForAction-Demz9zlH.native.esm.js.map} +1 -1
- package/dist/{isUserOnboardingComplete-D0JrQGvR.cjs → isUserOnboardingComplete-C86NDY7I.cjs} +13 -13
- package/dist/{isUserOnboardingComplete-D0JrQGvR.cjs.map → isUserOnboardingComplete-C86NDY7I.cjs.map} +1 -1
- package/dist/{isUserOnboardingComplete-C4_b3pDb.esm.js → isUserOnboardingComplete-CBrAH0ZF.esm.js} +3 -3
- package/dist/{isUserOnboardingComplete-C4_b3pDb.esm.js.map → isUserOnboardingComplete-CBrAH0ZF.esm.js.map} +1 -1
- package/dist/{isUserOnboardingComplete-m6E6GbB0.native.esm.js → isUserOnboardingComplete-Cr-YTpcU.native.esm.js} +3 -3
- package/dist/{isUserOnboardingComplete-m6E6GbB0.native.esm.js.map → isUserOnboardingComplete-Cr-YTpcU.native.esm.js.map} +1 -1
- package/dist/migrateFromFireblocks-B_q8Oawb.cjs +82 -0
- package/dist/migrateFromFireblocks-B_q8Oawb.cjs.map +1 -0
- package/dist/migrateFromFireblocks-Bbx2wHZD.esm.js +65 -0
- package/dist/migrateFromFireblocks-Bbx2wHZD.esm.js.map +1 -0
- package/dist/migrateFromFireblocks-D-J6-gRo.native.esm.js +65 -0
- package/dist/migrateFromFireblocks-D-J6-gRo.native.esm.js.map +1 -0
- package/dist/modules/flow/attachFlowSource/attachFlowSource.d.ts.map +1 -1
- package/dist/modules/sessionKeys/generateSessionKeys/generateSessionKeys.d.ts.map +1 -1
- package/dist/modules/waas/createWaasProvider/createWaasProvider.d.ts.map +1 -1
- package/dist/modules/waas/migrateFromFireblocks/index.d.ts +2 -0
- package/dist/modules/waas/migrateFromFireblocks/index.d.ts.map +1 -0
- package/dist/modules/waas/migrateFromFireblocks/migrateFromFireblocks.d.ts +52 -0
- package/dist/modules/waas/migrateFromFireblocks/migrateFromFireblocks.d.ts.map +1 -0
- package/dist/modules/waas/waas.types.d.ts +9 -1
- package/dist/modules/waas/waas.types.d.ts.map +1 -1
- package/dist/modules/wallets/networks/getTransactionHistory/getTransactionHistory.d.ts +1 -1
- package/dist/modules/wallets/networks/getTransactionHistory/getTransactionHistory.d.ts.map +1 -1
- package/dist/modules/wallets/walletProviderRegistry/events.d.ts +2 -1
- package/dist/modules/wallets/walletProviderRegistry/events.d.ts.map +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/{InvalidParamError-DCpeZMBr.cjs → updateAuthFromVerifyResponse-CElYpi97.cjs} +291 -9
- package/dist/updateAuthFromVerifyResponse-CElYpi97.cjs.map +1 -0
- package/dist/{InvalidParamError-5AXtm6Zp.native.esm.js → updateAuthFromVerifyResponse-D1w-Aw9P.native.esm.js} +457 -4
- package/dist/updateAuthFromVerifyResponse-D1w-Aw9P.native.esm.js.map +1 -0
- package/dist/{InvalidParamError-PQ2Xen_o.esm.js → updateAuthFromVerifyResponse-azIi_3FB.esm.js} +237 -3
- package/dist/updateAuthFromVerifyResponse-azIi_3FB.esm.js.map +1 -0
- package/dist/waas.cjs +53 -67
- package/dist/waas.cjs.map +1 -1
- package/dist/waas.esm.js +5 -20
- package/dist/waas.esm.js.map +1 -1
- package/dist/waas.native.esm.js +5 -20
- package/dist/waas.native.esm.js.map +1 -1
- package/dist/waasCore.cjs +40 -23
- package/dist/waasCore.cjs.map +1 -1
- package/dist/waasCore.esm.js +23 -7
- package/dist/waasCore.esm.js.map +1 -1
- package/dist/waasCore.native.esm.js +23 -7
- package/dist/waasCore.native.esm.js.map +1 -1
- package/package.json +3 -3
- package/dist/InvalidParamError-5AXtm6Zp.native.esm.js.map +0 -1
- package/dist/InvalidParamError-DCpeZMBr.cjs.map +0 -1
- package/dist/InvalidParamError-PQ2Xen_o.esm.js.map +0 -1
- package/dist/getNetworkProviderFromNetworkId-D79icjmX.native.esm.js.map +0 -1
- package/dist/getWaasWalletProviderFromWalletAccount-BxyUZBpT.cjs +0 -19
- package/dist/getWaasWalletProviderFromWalletAccount-BxyUZBpT.cjs.map +0 -1
- package/dist/getWaasWalletProviderFromWalletAccount-Ca0SiNEz.native.esm.js +0 -14
- package/dist/getWaasWalletProviderFromWalletAccount-Ca0SiNEz.native.esm.js.map +0 -1
- package/dist/getWaasWalletProviderFromWalletAccount-CupLo7EC.esm.js +0 -14
- package/dist/getWaasWalletProviderFromWalletAccount-CupLo7EC.esm.js.map +0 -1
- package/dist/getWalletProviderByKey-B6vtKHJy.esm.js +0 -255
- package/dist/getWalletProviderByKey-B6vtKHJy.esm.js.map +0 -1
- package/dist/getWalletProviderByKey-DIFBlGlR.cjs +0 -321
- package/dist/getWalletProviderByKey-DIFBlGlR.cjs.map +0 -1
- package/dist/getWalletProviderByKey-Dh2qnBmw.native.esm.js +0 -474
- package/dist/getWalletProviderByKey-Dh2qnBmw.native.esm.js.map +0 -1
- package/dist/isDynamicWaasEnabled-A8Humh0r.cjs +0 -49
- package/dist/isDynamicWaasEnabled-A8Humh0r.cjs.map +0 -1
- package/dist/isDynamicWaasEnabled-BmWqrgz1.esm.js +0 -37
- package/dist/isDynamicWaasEnabled-BmWqrgz1.esm.js.map +0 -1
- package/dist/isDynamicWaasEnabled-Djp4QuBw.native.esm.js +0 -37
- package/dist/isDynamicWaasEnabled-Djp4QuBw.native.esm.js.map +0 -1
- package/dist/isMfaRequiredForAction-3fWX5MEF.cjs.map +0 -1
- package/dist/isMfaRequiredForAction-CkX6CfJf.esm.js.map +0 -1
- package/dist/refreshAuth-BKeW1dSq.cjs +0 -43
- package/dist/refreshAuth-BKeW1dSq.cjs.map +0 -1
- package/dist/refreshAuth-Cykyxvpz.native.esm.js +0 -38
- package/dist/refreshAuth-Cykyxvpz.native.esm.js.map +0 -1
- package/dist/refreshAuth-LzA2xxNC.esm.js +0 -38
- package/dist/refreshAuth-LzA2xxNC.esm.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { AuthStorageEnum, Configuration, SDKApi, isDeviceNonceSignatureRequiredForUrl } from "@dynamic-labs/sdk-api-core";
|
|
1
|
+
import { AuthStorageEnum, Configuration, JwtVerifiedCredentialFormatEnum, SDKApi, WalletProviderEnum, isDeviceNonceSignatureRequiredForUrl } from "@dynamic-labs/sdk-api-core";
|
|
2
2
|
import { Platform } from "react-native";
|
|
3
3
|
|
|
4
4
|
//#region package.json
|
|
5
5
|
var name = "@dynamic-labs-sdk/client";
|
|
6
|
-
var version = "1.
|
|
6
|
+
var version = "1.17.1";
|
|
7
7
|
var dependencies = {
|
|
8
8
|
"@dynamic-labs-sdk/assert-package-version": "workspace:*",
|
|
9
9
|
"@dynamic-labs-wallet/browser-wallet-client": "1.0.46",
|
|
@@ -617,6 +617,16 @@ const fetchAndStoreNonces = async (client) => {
|
|
|
617
617
|
return fetchPromise;
|
|
618
618
|
};
|
|
619
619
|
|
|
620
|
+
//#endregion
|
|
621
|
+
//#region src/utils/setCookie/setCookie.ts
|
|
622
|
+
/**
|
|
623
|
+
* Sefelly sets the cookie in the browser.
|
|
624
|
+
* @notInstrumented
|
|
625
|
+
*/
|
|
626
|
+
const setCookie = (cookie) => {
|
|
627
|
+
document.cookie = cookie;
|
|
628
|
+
};
|
|
629
|
+
|
|
620
630
|
//#endregion
|
|
621
631
|
//#region src/modules/clientEvents/clientEvents.ts
|
|
622
632
|
/**
|
|
@@ -690,6 +700,71 @@ const emitEvent = ({ event, args }, client) => {
|
|
|
690
700
|
eventEmitter.emit(event, args);
|
|
691
701
|
};
|
|
692
702
|
|
|
703
|
+
//#endregion
|
|
704
|
+
//#region src/errors/InvalidWalletProviderKeyError.ts
|
|
705
|
+
var InvalidWalletProviderKeyError = class extends BaseError {
|
|
706
|
+
constructor(value) {
|
|
707
|
+
super({
|
|
708
|
+
cause: null,
|
|
709
|
+
code: "invalid_wallet_provider_key",
|
|
710
|
+
docsUrl: null,
|
|
711
|
+
name: "InvalidWalletProviderKeyError",
|
|
712
|
+
shortMessage: `Invalid wallet provider key: ${value}. Key must be in the format of <normalizedWalletNameWithChain>:<walletProviderType>[:<suffix>]`
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
//#endregion
|
|
718
|
+
//#region src/modules/wallets/walletProvider/splitWalletProviderKey/splitWalletProviderKey.ts
|
|
719
|
+
/** @notInstrumented */
|
|
720
|
+
const splitWalletProviderKey = (walletProviderKey) => {
|
|
721
|
+
const [normalizedWalletNameWithChain, walletProviderType, suffix, ...rest] = walletProviderKey.split(":");
|
|
722
|
+
if (!normalizedWalletNameWithChain || !Object.values(WalletProviderEnum).includes(walletProviderType) || rest.length > 0) throw new InvalidWalletProviderKeyError(walletProviderKey);
|
|
723
|
+
return {
|
|
724
|
+
normalizedWalletNameWithChain,
|
|
725
|
+
suffix,
|
|
726
|
+
walletProviderType
|
|
727
|
+
};
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
//#endregion
|
|
731
|
+
//#region src/modules/wallets/utils/normalizeAddress/normalizeAddress.ts
|
|
732
|
+
/** @notInstrumented */
|
|
733
|
+
const normalizeAddress = ({ address, chain }) => {
|
|
734
|
+
let normalizedAddress = address;
|
|
735
|
+
if (normalizedAddress?.startsWith("0x")) normalizedAddress = normalizedAddress.slice(2);
|
|
736
|
+
normalizedAddress = ["EVM", "FLOW"].includes(chain) ? normalizedAddress?.toLowerCase() : normalizedAddress;
|
|
737
|
+
return normalizedAddress;
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
//#endregion
|
|
741
|
+
//#region src/modules/wallets/utils/formatWalletAccountId/formatWalletAccountId.ts
|
|
742
|
+
/** @notInstrumented */
|
|
743
|
+
const formatWalletAccountId = ({ address, chain, walletProviderKey }) => {
|
|
744
|
+
const { normalizedWalletNameWithChain } = splitWalletProviderKey(walletProviderKey);
|
|
745
|
+
return `${normalizedWalletNameWithChain}:${normalizeAddress({
|
|
746
|
+
address,
|
|
747
|
+
chain
|
|
748
|
+
})}`;
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
//#endregion
|
|
752
|
+
//#region src/modules/wallets/utils/convertUnverifiedWalletAccountToWalletAccount/convertUnverifiedWalletAccountToWalletAccount.ts
|
|
753
|
+
/** @notInstrumented */
|
|
754
|
+
const convertUnverifiedWalletAccountToWalletAccount = ({ unverifiedWalletAccount }) => ({
|
|
755
|
+
address: unverifiedWalletAccount.address,
|
|
756
|
+
addressesWithTypes: unverifiedWalletAccount.addressesWithTypes,
|
|
757
|
+
chain: unverifiedWalletAccount.chain,
|
|
758
|
+
id: formatWalletAccountId({
|
|
759
|
+
address: unverifiedWalletAccount.address,
|
|
760
|
+
chain: unverifiedWalletAccount.chain,
|
|
761
|
+
walletProviderKey: unverifiedWalletAccount.walletProviderKey
|
|
762
|
+
}),
|
|
763
|
+
lastSelectedAt: unverifiedWalletAccount.lastSelectedAt,
|
|
764
|
+
verifiedCredentialId: null,
|
|
765
|
+
walletProviderKey: unverifiedWalletAccount.walletProviderKey
|
|
766
|
+
});
|
|
767
|
+
|
|
693
768
|
//#endregion
|
|
694
769
|
//#region src/modules/wallets/constants.ts
|
|
695
770
|
const CHAINS_INFO_MAP = {
|
|
@@ -793,6 +868,146 @@ const getChainFromVerifiedCredentialChain = (verifiedCredentialChain) => {
|
|
|
793
868
|
return chain;
|
|
794
869
|
};
|
|
795
870
|
|
|
871
|
+
//#endregion
|
|
872
|
+
//#region src/modules/wallets/utils/normalizeWalletNameWithChain/normalizeWalletNameWithChain.ts
|
|
873
|
+
/**
|
|
874
|
+
* Format the raw wallet name and chain to get the value we can use for
|
|
875
|
+
* verified credentials' `walletName` field.
|
|
876
|
+
* @notInstrumented
|
|
877
|
+
*/
|
|
878
|
+
const normalizeWalletNameWithChain = ({ displayName, chain }) => {
|
|
879
|
+
const sanitizedWalletName = displayName.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
880
|
+
const chainLowered = chain.toLocaleLowerCase();
|
|
881
|
+
if (sanitizedWalletName.endsWith(chainLowered)) return sanitizedWalletName;
|
|
882
|
+
return `${sanitizedWalletName}${chainLowered}`;
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
//#endregion
|
|
886
|
+
//#region src/modules/wallets/utils/formatWalletProviderKey/formatWalletProviderKey.ts
|
|
887
|
+
/**
|
|
888
|
+
* Assembles the wallet provider key from the wallet name, chain, and wallet provider type.
|
|
889
|
+
*
|
|
890
|
+
* The suffix is optional and can be used to add a uniquely identifying string to the key, which
|
|
891
|
+
* might be necessary for some wallet providers (like Wallet Connect).
|
|
892
|
+
*
|
|
893
|
+
* IMPORTANT: Do NOT add a suffix unless absolutely necessary, as it will cause the wallet account
|
|
894
|
+
* to not be able to find its wallet provider when connecting to a new device (it won't be possible
|
|
895
|
+
* to determine the full key just from the Verified Credential data).
|
|
896
|
+
* @notInstrumented
|
|
897
|
+
*/
|
|
898
|
+
const formatWalletProviderKey = ({ suffix, chain, displayName, walletProviderType }) => {
|
|
899
|
+
return `${normalizeWalletNameWithChain({
|
|
900
|
+
chain,
|
|
901
|
+
displayName
|
|
902
|
+
})}:${walletProviderType}${suffix ? `:${suffix}` : ""}`;
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
//#endregion
|
|
906
|
+
//#region src/modules/wallets/walletProvider/walletProviderKeyMap/getWalletProviderKeyFromVerifiedCredential/getWalletProviderKeyFromVerifiedCredential.ts
|
|
907
|
+
/** @notInstrumented */
|
|
908
|
+
const getWalletProviderKeyFromVerifiedCredential = ({ verifiedCredential }, client) => {
|
|
909
|
+
const { walletProviderKeyMap } = getCore(client).state.get();
|
|
910
|
+
const storedWalletProviderKey = walletProviderKeyMap[verifiedCredential.id];
|
|
911
|
+
if (storedWalletProviderKey) return { walletProviderKey: storedWalletProviderKey };
|
|
912
|
+
/**
|
|
913
|
+
* We fallback to comprising the wallet provider key from walletName and walletProvider.
|
|
914
|
+
*
|
|
915
|
+
* Some wallet provider types (like Wallet Connect) also use a special suffix for their wallet provider
|
|
916
|
+
* keys, so this won't be enough for them.
|
|
917
|
+
* Therefore, for those specific wallet providers, the wallet account will remain without a wallet provider
|
|
918
|
+
* and will require reconnection.
|
|
919
|
+
* Read walletProvider.types.ts for more info.
|
|
920
|
+
*/
|
|
921
|
+
assertDefined(verifiedCredential.walletName, `Failed to get wallet provider for verified credential with ID ${verifiedCredential.id}: missing walletName`);
|
|
922
|
+
assertDefined(verifiedCredential.walletProvider, `Failed to get wallet provider for verified credential with ID ${verifiedCredential.id}: missing walletProvider`);
|
|
923
|
+
assertDefined(verifiedCredential.chain, `Failed to get wallet provider for verified credential with ID ${verifiedCredential.id}: missing chain`);
|
|
924
|
+
return { walletProviderKey: formatWalletProviderKey({
|
|
925
|
+
chain: getChainFromVerifiedCredentialChain(verifiedCredential.chain),
|
|
926
|
+
displayName: verifiedCredential.walletName,
|
|
927
|
+
walletProviderType: verifiedCredential.walletProvider
|
|
928
|
+
}) };
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
//#endregion
|
|
932
|
+
//#region src/modules/wallets/utils/convertVerifiedCredentialToWalletAccount/convertVerifiedCredentialToWalletAccount.ts
|
|
933
|
+
/** @notInstrumented */
|
|
934
|
+
const convertVerifiedCredentialToWalletAccount = ({ verifiedCredential }, client) => {
|
|
935
|
+
assertDefined(verifiedCredential.address, "Missing address in verified credential");
|
|
936
|
+
assertDefined(verifiedCredential.chain, "Missing chain in verified credential");
|
|
937
|
+
const chain = getChainFromVerifiedCredentialChain(verifiedCredential.chain);
|
|
938
|
+
const { walletProviderKey } = getWalletProviderKeyFromVerifiedCredential({ verifiedCredential }, client);
|
|
939
|
+
const walletAccountId = formatWalletAccountId({
|
|
940
|
+
address: verifiedCredential.address,
|
|
941
|
+
chain,
|
|
942
|
+
walletProviderKey
|
|
943
|
+
});
|
|
944
|
+
return {
|
|
945
|
+
address: verifiedCredential.address,
|
|
946
|
+
addressesWithTypes: verifiedCredential.walletAdditionalAddresses,
|
|
947
|
+
chain,
|
|
948
|
+
hardwareWalletVendor: verifiedCredential.walletProperties?.hardwareWallet,
|
|
949
|
+
id: walletAccountId,
|
|
950
|
+
lastSelectedAt: verifiedCredential.lastSelectedAt ?? null,
|
|
951
|
+
verifiedCredentialId: verifiedCredential.id,
|
|
952
|
+
walletProviderKey
|
|
953
|
+
};
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
//#endregion
|
|
957
|
+
//#region src/modules/wallets/getWalletAccounts/getWalletAccountsFromState/getWalletAccountsFromState.ts
|
|
958
|
+
/** @notInstrumented */
|
|
959
|
+
const getWalletAccountsFromState = ({ unverifiedWalletAccounts, user }, client) => {
|
|
960
|
+
const walletAccountsMap = /* @__PURE__ */ new Map();
|
|
961
|
+
/**
|
|
962
|
+
* Handle the unverified wallet accounts before the user verified credentials
|
|
963
|
+
* so the later verified wallet accounts can override the unverified wallet accounts
|
|
964
|
+
*/
|
|
965
|
+
unverifiedWalletAccounts.forEach((unverifiedWalletAccount) => {
|
|
966
|
+
const walletAccount = convertUnverifiedWalletAccountToWalletAccount({ unverifiedWalletAccount });
|
|
967
|
+
walletAccountsMap.set(walletAccount.id, walletAccount);
|
|
968
|
+
});
|
|
969
|
+
(user?.verifiedCredentials ?? []).filter((verified) => verified.format === JwtVerifiedCredentialFormatEnum.Blockchain).forEach((verifiedWalletAccount) => {
|
|
970
|
+
try {
|
|
971
|
+
const walletAccount = convertVerifiedCredentialToWalletAccount({ verifiedCredential: verifiedWalletAccount }, client);
|
|
972
|
+
walletAccountsMap.set(walletAccount.id, walletAccount);
|
|
973
|
+
} catch (error) {
|
|
974
|
+
/**
|
|
975
|
+
* A verified credential can be missing the data required to resolve its
|
|
976
|
+
* wallet provider (e.g. a legacy credential without a walletName). Skip
|
|
977
|
+
* it instead of throwing so a single unconvertible credential does not
|
|
978
|
+
* abort the whole mapping — which, during client initialization, would
|
|
979
|
+
* otherwise fail init and leave the app stuck loading. The wallet stays
|
|
980
|
+
* absent until the user reconnects it.
|
|
981
|
+
*/
|
|
982
|
+
getCore(client).logger.debug(`Skipping verified credential ${verifiedWalletAccount.id}: unable to convert to wallet account`, error);
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
return Array.from(walletAccountsMap.values());
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/modules/wallets/getWalletAccounts/getWalletAccounts.ts
|
|
990
|
+
/**
|
|
991
|
+
* Retrieves all wallet accounts associated with the current session.
|
|
992
|
+
*
|
|
993
|
+
* This function returns both verified and unverified wallet accounts,
|
|
994
|
+
* combining data from user credentials and local unverified accounts.
|
|
995
|
+
* You can differentiate between verified and unverified wallet accounts by
|
|
996
|
+
* checking the `verifiedCredentialId` property.
|
|
997
|
+
*
|
|
998
|
+
* @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.
|
|
999
|
+
* @returns An array of wallet accounts associated with the session.
|
|
1000
|
+
* @notInstrumented
|
|
1001
|
+
* @hook Exposed as a hook so consumers get the reactive list of wallet accounts.
|
|
1002
|
+
*/
|
|
1003
|
+
const getWalletAccounts = (client = getDefaultClient()) => {
|
|
1004
|
+
const { unverifiedWalletAccounts, user } = getCore(client).state.get();
|
|
1005
|
+
return getWalletAccountsFromState({
|
|
1006
|
+
unverifiedWalletAccounts,
|
|
1007
|
+
user
|
|
1008
|
+
}, client);
|
|
1009
|
+
};
|
|
1010
|
+
|
|
796
1011
|
//#endregion
|
|
797
1012
|
//#region src/errors/NoWalletProviderFoundError.ts
|
|
798
1013
|
var NoWalletProviderFoundError = class extends BaseError {
|
|
@@ -948,6 +1163,10 @@ const getWalletProviderFromWalletAccount = ({ walletAccount }, client) => {
|
|
|
948
1163
|
return walletProvider;
|
|
949
1164
|
};
|
|
950
1165
|
|
|
1166
|
+
//#endregion
|
|
1167
|
+
//#region src/modules/auth/consts.ts
|
|
1168
|
+
const DYNAMIC_AUTH_COOKIE_NAME = "DYNAMIC_JWT_TOKEN";
|
|
1169
|
+
|
|
951
1170
|
//#endregion
|
|
952
1171
|
//#region src/modules/auth/extractSessionId/extractSessionId.ts
|
|
953
1172
|
/**
|
|
@@ -1390,6 +1609,28 @@ const instrumentFunction = ({ fn, functionName, getCore: getCore$1, redactAll })
|
|
|
1390
1609
|
const SDK_API_CORE_VERSION = dependencies["@dynamic-labs/sdk-api-core"];
|
|
1391
1610
|
const DYNAMIC_ICONIC_SPRITE_URL = "https://iconic.dynamic-static-assets.com/icons/sprite.svg";
|
|
1392
1611
|
|
|
1612
|
+
//#endregion
|
|
1613
|
+
//#region src/modules/wallets/emitWalletAccountsChangedEvent/emitWalletAccountsChangedEvent.ts
|
|
1614
|
+
/**
|
|
1615
|
+
* Emits the `walletAccountsChanged` event.
|
|
1616
|
+
* @notInstrumented
|
|
1617
|
+
*/
|
|
1618
|
+
const emitWalletAccountsChangedEvent = (client) => {
|
|
1619
|
+
emitEvent({
|
|
1620
|
+
args: { walletAccounts: getWalletAccounts(client) },
|
|
1621
|
+
event: "walletAccountsChanged"
|
|
1622
|
+
}, client);
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
//#endregion
|
|
1626
|
+
//#region src/modules/auth/updateAuthFromVerifyResponse/checkAndRaiseWalletAccountsChangedEvent/checkAndRaiseWalletAccountsChangedEvent.ts
|
|
1627
|
+
/** @notInstrumented */
|
|
1628
|
+
const checkAndRaiseWalletAccountsChangedEvent = ({ previousState }, client) => {
|
|
1629
|
+
const core = getCore(client);
|
|
1630
|
+
if (getWalletAccountsHash(previousState, client) !== getWalletAccountsHash(core.state.get(), client)) emitWalletAccountsChangedEvent(client);
|
|
1631
|
+
};
|
|
1632
|
+
const getWalletAccountsHash = (state, client) => getWalletAccountsFromState(state, client).map((walletAccount) => JSON.stringify(walletAccount)).sort().join("-");
|
|
1633
|
+
|
|
1393
1634
|
//#endregion
|
|
1394
1635
|
//#region src/modules/mfa/isUserMissingMfaAuth/isUserMissingMfaAuth.ts
|
|
1395
1636
|
/**
|
|
@@ -1408,6 +1649,16 @@ const isUserMissingMfaAuth = (client = getDefaultClient()) => {
|
|
|
1408
1649
|
return Boolean(user.scope?.includes("requiresAdditionalAuth"));
|
|
1409
1650
|
};
|
|
1410
1651
|
|
|
1652
|
+
//#endregion
|
|
1653
|
+
//#region src/modules/wallets/getWalletProviders/getWalletProviders.ts
|
|
1654
|
+
/**
|
|
1655
|
+
* Get all available wallet providers to interact with internally.
|
|
1656
|
+
* @notInstrumented
|
|
1657
|
+
*/
|
|
1658
|
+
const getWalletProviders = (client) => {
|
|
1659
|
+
return getWalletProviderRegistry(client).listProviders();
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1411
1662
|
//#endregion
|
|
1412
1663
|
//#region src/modules/waas/constants.ts
|
|
1413
1664
|
const DEFAULT_WAAS_BASE_API_URL = "https://app.dynamicauth.com";
|
|
@@ -1425,6 +1676,68 @@ const isWaasWalletProvider = (walletProvider) => {
|
|
|
1425
1676
|
return walletProvider.key.includes(DYNAMIC_WAAS_METADATA.normalizedWalletName);
|
|
1426
1677
|
};
|
|
1427
1678
|
|
|
1679
|
+
//#endregion
|
|
1680
|
+
//#region src/modules/waas/findWaasWalletProviderByChain/findWaasWalletProviderByChain.ts
|
|
1681
|
+
/** @notInstrumented */
|
|
1682
|
+
const findWaasWalletProviderByChain = ({ chain }, client) => {
|
|
1683
|
+
const providers = getWalletProviders(client);
|
|
1684
|
+
const waasProviderKey = formatWalletProviderKey({
|
|
1685
|
+
chain,
|
|
1686
|
+
displayName: DYNAMIC_WAAS_METADATA.displayName,
|
|
1687
|
+
walletProviderType: WalletProviderEnum.EmbeddedWallet
|
|
1688
|
+
});
|
|
1689
|
+
const waasProvider = providers.find((provider) => provider.key === waasProviderKey && provider.chain === chain);
|
|
1690
|
+
if (!waasProvider || !isWaasWalletProvider(waasProvider)) return null;
|
|
1691
|
+
return waasProvider;
|
|
1692
|
+
};
|
|
1693
|
+
|
|
1694
|
+
//#endregion
|
|
1695
|
+
//#region src/modules/waas/isWaasWalletAccount/isWaasWalletAccount.ts
|
|
1696
|
+
/**
|
|
1697
|
+
* This function determines whether the provided wallet account is a Dynamic
|
|
1698
|
+
* WaaS wallet account.
|
|
1699
|
+
*
|
|
1700
|
+
* @param params.walletAccount - The wallet account to check.
|
|
1701
|
+
* @returns True if the wallet account is a WaaS wallet account, false otherwise.
|
|
1702
|
+
* @notInstrumented
|
|
1703
|
+
*/
|
|
1704
|
+
const isWaasWalletAccount = ({ walletAccount }) => {
|
|
1705
|
+
return walletAccount.walletProviderKey.includes(DYNAMIC_WAAS_METADATA.normalizedWalletName);
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
//#endregion
|
|
1709
|
+
//#region src/modules/waas/initializeWaasClientsForEagerRecovery/initializeWaasClientsForEagerRecovery.ts
|
|
1710
|
+
/**
|
|
1711
|
+
* On login, boots the WaaS client once per chain so the SDK eagerly recovers
|
|
1712
|
+
* key shares itself (the `eagerlyRecoverKeyShares` capability) instead of the
|
|
1713
|
+
* host looping per wallet. Booting calls `initialize()`, which sends the auth
|
|
1714
|
+
* token the iframe needs to self-recover.
|
|
1715
|
+
*
|
|
1716
|
+
* @notInstrumented
|
|
1717
|
+
*/
|
|
1718
|
+
const initializeWaasClientsForEagerRecovery = async (client) => {
|
|
1719
|
+
/**
|
|
1720
|
+
* Booting triggers recovery, which fails if the user is missing the MFA auth.
|
|
1721
|
+
* This early return avoids attempting a call we know will fail and just adds
|
|
1722
|
+
* noise to the logs.
|
|
1723
|
+
*/
|
|
1724
|
+
if (isUserMissingMfaAuth(client)) return;
|
|
1725
|
+
const waasChains = new Set(getWalletAccounts(client).filter((walletAccount) => isWaasWalletAccount({ walletAccount })).map((walletAccount) => walletAccount.chain));
|
|
1726
|
+
await Promise.all([...waasChains].map(async (chain) => {
|
|
1727
|
+
const provider = findWaasWalletProviderByChain({ chain }, client);
|
|
1728
|
+
/**
|
|
1729
|
+
* The environment might not have the embedded wallet extensions installed.
|
|
1730
|
+
* In that case there is no provider for the chain and nothing to boot.
|
|
1731
|
+
*/
|
|
1732
|
+
if (!provider) return;
|
|
1733
|
+
try {
|
|
1734
|
+
await provider.getWaasClient();
|
|
1735
|
+
} catch (error) {
|
|
1736
|
+
getCore(client).logger.warn("[initializeWaasClientsForEagerRecovery] failed to boot waas client", error);
|
|
1737
|
+
}
|
|
1738
|
+
}));
|
|
1739
|
+
};
|
|
1740
|
+
|
|
1428
1741
|
//#endregion
|
|
1429
1742
|
//#region src/errors/InvalidParamError.ts
|
|
1430
1743
|
var InvalidParamError = class extends BaseError {
|
|
@@ -1440,5 +1753,145 @@ var InvalidParamError = class extends BaseError {
|
|
|
1440
1753
|
};
|
|
1441
1754
|
|
|
1442
1755
|
//#endregion
|
|
1443
|
-
|
|
1444
|
-
|
|
1756
|
+
//#region src/modules/auth/decodeJwt/decodeJwt.ts
|
|
1757
|
+
/**
|
|
1758
|
+
* Decodes a JWT token and returns the full payload.
|
|
1759
|
+
*
|
|
1760
|
+
* This function extracts and returns the complete JWT payload including scopes,
|
|
1761
|
+
* expiration time, and other claims.
|
|
1762
|
+
*
|
|
1763
|
+
* @param jwt - The JWT token string.
|
|
1764
|
+
* @returns The decoded JWT payload object.
|
|
1765
|
+
* @throws InvalidParamError if the token is invalid or cannot be decoded.
|
|
1766
|
+
*
|
|
1767
|
+
* @example
|
|
1768
|
+
* ```typescript
|
|
1769
|
+
* const payload = decodeJwt(jwt);
|
|
1770
|
+
* // Returns: { scopes: ['wallet:export'], exp: 1234567890, ... }
|
|
1771
|
+
* ```
|
|
1772
|
+
* @notInstrumented
|
|
1773
|
+
*/
|
|
1774
|
+
const decodeJwt = (jwt) => {
|
|
1775
|
+
try {
|
|
1776
|
+
const parts = jwt.split(".");
|
|
1777
|
+
if (parts.length !== 3) throw new InvalidParamError("Invalid JWT format");
|
|
1778
|
+
const base64Payload = parts[1].replaceAll("-", "+").replaceAll("_", "/");
|
|
1779
|
+
const paddedPayload = base64Payload + "=".repeat((4 - base64Payload.length % 4) % 4);
|
|
1780
|
+
const decodedPayload = atob(paddedPayload);
|
|
1781
|
+
return JSON.parse(decodedPayload);
|
|
1782
|
+
} catch (error) {
|
|
1783
|
+
if (error instanceof InvalidParamError) throw error;
|
|
1784
|
+
throw new InvalidParamError(`Failed to decode JWT: ${error instanceof Error ? error.message : String(error)}`);
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
//#endregion
|
|
1789
|
+
//#region src/modules/auth/updateAuthFromVerifyResponse/elevatedAccessTokens/normalizeScopes/normalizeScopes.ts
|
|
1790
|
+
/**
|
|
1791
|
+
* Normalizes scopes by deduplicating and sorting them.
|
|
1792
|
+
* This creates a canonical representation for comparison.
|
|
1793
|
+
*
|
|
1794
|
+
* @param scopes - Array of scope strings (may contain duplicates)
|
|
1795
|
+
* @returns Normalized, sorted array of unique scopes
|
|
1796
|
+
* @notInstrumented
|
|
1797
|
+
*/
|
|
1798
|
+
const normalizeScopes = (scopes) => {
|
|
1799
|
+
return [...new Set(scopes)].sort((a, b) => a.localeCompare(b));
|
|
1800
|
+
};
|
|
1801
|
+
|
|
1802
|
+
//#endregion
|
|
1803
|
+
//#region src/modules/auth/updateAuthFromVerifyResponse/elevatedAccessTokens/parseElevatedAccessToken/parseElevatedAccessToken.ts
|
|
1804
|
+
/**
|
|
1805
|
+
* Validates and parses an elevated access token from a JWT string.
|
|
1806
|
+
* Extracts scopes, expiration, and validates the token structure.
|
|
1807
|
+
*
|
|
1808
|
+
* Policy decisions:
|
|
1809
|
+
* - Tokens without scopes are rejected (returns null)
|
|
1810
|
+
* - Tokens with empty scopes array are rejected (returns null)
|
|
1811
|
+
* - Tokens without exp field are rejected (returns null)
|
|
1812
|
+
* - Expired tokens are rejected (returns null)
|
|
1813
|
+
*
|
|
1814
|
+
* @returns Parsed token data or null if token is invalid/expired
|
|
1815
|
+
* @notInstrumented
|
|
1816
|
+
*/
|
|
1817
|
+
const parseElevatedAccessToken = ({ token }) => {
|
|
1818
|
+
const payload = decodeJwt(token);
|
|
1819
|
+
const filteredScopes = ((payload?.scope)?.split(" ") ?? []).filter((s) => s.length > 0);
|
|
1820
|
+
const singleUse = payload.singleUse ?? false;
|
|
1821
|
+
if (!filteredScopes || filteredScopes.length === 0) return null;
|
|
1822
|
+
if (!payload.exp) return null;
|
|
1823
|
+
const expiresAt = /* @__PURE__ */ new Date(payload.exp * 1e3);
|
|
1824
|
+
if (expiresAt <= /* @__PURE__ */ new Date()) return null;
|
|
1825
|
+
return {
|
|
1826
|
+
expiresAt,
|
|
1827
|
+
normalizedScopes: normalizeScopes(filteredScopes),
|
|
1828
|
+
scopes: filteredScopes,
|
|
1829
|
+
singleUse,
|
|
1830
|
+
token
|
|
1831
|
+
};
|
|
1832
|
+
};
|
|
1833
|
+
|
|
1834
|
+
//#endregion
|
|
1835
|
+
//#region src/modules/auth/updateAuthFromVerifyResponse/elevatedAccessTokens/upsertElevatedAccessToken/upsertElevatedAccessToken.ts
|
|
1836
|
+
/**
|
|
1837
|
+
* Upserts an elevated access token into the current tokens array.
|
|
1838
|
+
*
|
|
1839
|
+
* Policy: Only one token per normalized scope-set is allowed.
|
|
1840
|
+
* If a token with the same normalized scopes exists, it is replaced.
|
|
1841
|
+
* This ensures we don't accumulate multiple tokens for the same scope combination.
|
|
1842
|
+
*
|
|
1843
|
+
* @param currentTokens - Current array of elevated access tokens
|
|
1844
|
+
* @param newToken - New token to upsert
|
|
1845
|
+
* @returns Updated array of tokens with the new token upserted
|
|
1846
|
+
* @notInstrumented
|
|
1847
|
+
*/
|
|
1848
|
+
const upsertElevatedAccessToken = ({ currentTokens, newToken }) => {
|
|
1849
|
+
const newScopeKey = normalizeScopes(newToken.scopes).join(" ");
|
|
1850
|
+
return [...currentTokens.filter((existingToken) => {
|
|
1851
|
+
return normalizeScopes(existingToken.scopes).join(" ") !== newScopeKey;
|
|
1852
|
+
}), {
|
|
1853
|
+
expiresAt: newToken.expiresAt,
|
|
1854
|
+
scopes: newToken.scopes,
|
|
1855
|
+
singleUse: newToken.singleUse,
|
|
1856
|
+
token: newToken.token
|
|
1857
|
+
}];
|
|
1858
|
+
};
|
|
1859
|
+
|
|
1860
|
+
//#endregion
|
|
1861
|
+
//#region src/modules/auth/updateAuthFromVerifyResponse/updateAuthFromVerifyResponse.ts
|
|
1862
|
+
/** @notInstrumented */
|
|
1863
|
+
const updateAuthFromVerifyResponse = ({ response }, client) => {
|
|
1864
|
+
const core = getCore(client);
|
|
1865
|
+
const previousState = { ...core.state.get() };
|
|
1866
|
+
const { user, minifiedJwt, jwt, expiresAt, mfaToken, elevatedAccessToken } = response;
|
|
1867
|
+
const sessionExpiresAt = /* @__PURE__ */ new Date(expiresAt * 1e3);
|
|
1868
|
+
const newState = {
|
|
1869
|
+
legacyToken: jwt ?? null,
|
|
1870
|
+
sessionExpiresAt,
|
|
1871
|
+
token: minifiedJwt ?? null,
|
|
1872
|
+
user
|
|
1873
|
+
};
|
|
1874
|
+
if (mfaToken) newState.mfaToken = mfaToken;
|
|
1875
|
+
const currentTokens = core.state.get().elevatedAccessTokens || [];
|
|
1876
|
+
newState.elevatedAccessTokens = currentTokens;
|
|
1877
|
+
if (elevatedAccessToken) {
|
|
1878
|
+
const parsedToken = parseElevatedAccessToken({ token: elevatedAccessToken });
|
|
1879
|
+
if (parsedToken) newState.elevatedAccessTokens = upsertElevatedAccessToken({
|
|
1880
|
+
currentTokens,
|
|
1881
|
+
newToken: parsedToken
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
core.state.set(newState);
|
|
1885
|
+
/**
|
|
1886
|
+
* For customers using a sandbox environment with cookies enabled, we need to set the cookie
|
|
1887
|
+
* programmatically because Redcoast won't set the cookie via headers. We set the cookie programmatically
|
|
1888
|
+
* so customers can access the cookie from document.cookie consistently between sandbox and live environments.
|
|
1889
|
+
*/
|
|
1890
|
+
if (minifiedJwt && isCookieEnabled(client)) setCookie(`${DYNAMIC_AUTH_COOKIE_NAME}=${minifiedJwt}; expires=${sessionExpiresAt.toUTCString()}; path=/; SameSite=Lax`);
|
|
1891
|
+
checkAndRaiseWalletAccountsChangedEvent({ previousState }, client);
|
|
1892
|
+
if (!previousState.user && Boolean(newState.user)) initializeWaasClientsForEagerRecovery(client);
|
|
1893
|
+
};
|
|
1894
|
+
|
|
1895
|
+
//#endregion
|
|
1896
|
+
export { MfaRateLimitedError as $, NoWalletProviderFoundError as A, emitEvent as B, getOperatingSystem as C, WalletProviderPriority as D, getWalletProviderFromWalletAccount as E, CHAINS_INFO_MAP as F, fetchAndStoreNonces as G, onEvent as H, formatWalletAccountId as I, createDeviceSignatureHeadersMiddleware as J, createApiClient as K, normalizeAddress as L, formatWalletProviderKey as M, normalizeWalletNameWithChain as N, getWalletProviderRegistry as O, getChainFromVerifiedCredentialChain as P, SandboxMaximumThresholdReachedError as Q, splitWalletProviderKey as R, getPlatform as S, DYNAMIC_AUTH_COOKIE_NAME as T, onceEvent as U, offEvent as V, setCookie as W, getDeviceSigner as X, getHeadersForNonceSignedByDeviceSigners as Y, getNonce as Z, SDK_API_CORE_VERSION as _, getCore as _t, initializeWaasClientsForEagerRecovery as a, isCookieEnabled as at, DEFAULT_PII_FIELDS as b, isWaasWalletProvider as c, getElevatedAccessToken as ct, DYNAMIC_WAAS_METADATA as d, DYNAMIC_SDK_API_VERSION as dt, MfaInvalidOtpError as et, getWalletProviders as f, NONCE_POOL_SIZE as ft, DYNAMIC_ICONIC_SPRITE_URL as g, BaseError as gt, emitWalletAccountsChangedEvent as h, ClientNotFoundError as ht, InvalidParamError as i, getSessionKeys as it, getWalletAccounts as j, createRuntimeServiceAccessKey as k, DEFAULT_WAAS_BASE_API_URL as l, randomString as lt, checkAndRaiseWalletAccountsChangedEvent as m, setDefaultClient as mt, upsertElevatedAccessToken as n, InvalidExternalAuthError as nt, isWaasWalletAccount as o, assertDefined as ot, isUserMissingMfaAuth as p, getDefaultClient as pt, UnauthorizedError as q, parseElevatedAccessToken as r, APIError as rt, findWaasWalletProviderByChain as s, ValueMustBeDefinedError as st, updateAuthFromVerifyResponse as t, LinkCredentialError as tt, DEFAULT_WAAS_BASE_MPC_RELAY_API_URL as u, CLIENT_SDK_NAME as ut, instrumentFunction as v, name as vt, extractSessionId as w, getUserAgent as x, scrubParameters as y, version as yt, InvalidWalletProviderKeyError as z };
|
|
1897
|
+
//# sourceMappingURL=updateAuthFromVerifyResponse-D1w-Aw9P.native.esm.js.map
|