@ledgerhq/live-common 34.49.0-nightly.4 → 34.49.0-nightly.5
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/lib/bridge/react/BridgeSync.d.ts.map +1 -1
- package/lib/bridge/react/BridgeSync.js +17 -4
- package/lib/bridge/react/BridgeSync.js.map +1 -1
- package/lib/bridge/syncSessionManager/index.d.ts +18 -0
- package/lib/bridge/syncSessionManager/index.d.ts.map +1 -0
- package/lib/bridge/syncSessionManager/index.js +75 -0
- package/lib/bridge/syncSessionManager/index.js.map +1 -0
- package/lib/bridge/syncSessionManager/index.test.d.ts +2 -0
- package/lib/bridge/syncSessionManager/index.test.d.ts.map +1 -0
- package/lib/bridge/syncSessionManager/index.test.js +118 -0
- package/lib/bridge/syncSessionManager/index.test.js.map +1 -0
- package/lib/e2e/data/deviceLabelsData.js +2 -2
- package/lib/e2e/data/deviceLabelsData.js.map +1 -1
- package/lib/e2e/enum/DeviceLabels.d.ts +1 -9
- package/lib/e2e/enum/DeviceLabels.d.ts.map +1 -1
- package/lib/e2e/enum/DeviceLabels.js +0 -8
- package/lib/e2e/enum/DeviceLabels.js.map +1 -1
- package/lib/e2e/families/tezos.d.ts.map +1 -1
- package/lib/e2e/families/tezos.js +5 -3
- package/lib/e2e/families/tezos.js.map +1 -1
- package/lib/e2e/index.d.ts +2 -0
- package/lib/e2e/index.d.ts.map +1 -1
- package/lib/e2e/models/Swap.d.ts +2 -0
- package/lib/e2e/models/Swap.d.ts.map +1 -1
- package/lib/e2e/models/Swap.js +6 -0
- package/lib/e2e/models/Swap.js.map +1 -1
- package/lib/e2e/speculos.d.ts +8 -0
- package/lib/e2e/speculos.d.ts.map +1 -1
- package/lib/e2e/speculos.js +17 -31
- package/lib/e2e/speculos.js.map +1 -1
- package/lib/exchange/providers/swap.js +2 -2
- package/lib/exchange/providers/swap.js.map +1 -1
- package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
- package/lib/featureFlags/defaultFeatures.js +1 -0
- package/lib/featureFlags/defaultFeatures.js.map +1 -1
- package/lib/featureFlags/useFeature.d.ts +1 -1
- package/lib/featureFlags/useFeature.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/modules/useLeftApyModule.d.ts +1 -0
- package/lib/modularDrawer/hooks/modules/useLeftApyModule.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/modules/useLeftMarketTrendModule.d.ts +1 -0
- package/lib/modularDrawer/hooks/modules/useLeftMarketTrendModule.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/modules/useRightMarketTrendModule.d.ts +1 -0
- package/lib/modularDrawer/hooks/modules/useRightMarketTrendModule.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/useRightBalanceAsset.d.ts +1 -0
- package/lib/modularDrawer/hooks/useRightBalanceAsset.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/useRightBalanceNetwork.d.ts +1 -0
- package/lib/modularDrawer/hooks/useRightBalanceNetwork.d.ts.map +1 -1
- package/lib/notifications/ServiceStatusProvider/entry-points.d.ts +3 -0
- package/lib/notifications/ServiceStatusProvider/entry-points.d.ts.map +1 -0
- package/lib/notifications/ServiceStatusProvider/entry-points.js +3 -0
- package/lib/notifications/ServiceStatusProvider/entry-points.js.map +1 -0
- package/lib/notifications/ServiceStatusProvider/index.d.ts +18 -1
- package/lib/notifications/ServiceStatusProvider/index.d.ts.map +1 -1
- package/lib/notifications/ServiceStatusProvider/index.js +47 -9
- package/lib/notifications/ServiceStatusProvider/index.js.map +1 -1
- package/lib/notifications/ServiceStatusProvider/index.test.d.ts +2 -0
- package/lib/notifications/ServiceStatusProvider/index.test.d.ts.map +1 -0
- package/lib/notifications/ServiceStatusProvider/index.test.js +88 -0
- package/lib/notifications/ServiceStatusProvider/index.test.js.map +1 -0
- package/lib/notifications/ServiceStatusProvider/ledger-components.d.ts +2 -0
- package/lib/notifications/ServiceStatusProvider/ledger-components.d.ts.map +1 -0
- package/lib/notifications/ServiceStatusProvider/ledger-components.js +17 -0
- package/lib/notifications/ServiceStatusProvider/ledger-components.js.map +1 -0
- package/lib/notifications/ServiceStatusProvider/mocks/ledgerStatus.d.ts +154 -0
- package/lib/notifications/ServiceStatusProvider/mocks/ledgerStatus.d.ts.map +1 -0
- package/lib/notifications/ServiceStatusProvider/mocks/ledgerStatus.js +1192 -0
- package/lib/notifications/ServiceStatusProvider/mocks/ledgerStatus.js.map +1 -0
- package/lib/notifications/ServiceStatusProvider/types.d.ts +3 -1
- package/lib/notifications/ServiceStatusProvider/types.d.ts.map +1 -1
- package/lib-es/bridge/react/BridgeSync.d.ts.map +1 -1
- package/lib-es/bridge/react/BridgeSync.js +17 -4
- package/lib-es/bridge/react/BridgeSync.js.map +1 -1
- package/lib-es/bridge/syncSessionManager/index.d.ts +18 -0
- package/lib-es/bridge/syncSessionManager/index.d.ts.map +1 -0
- package/lib-es/bridge/syncSessionManager/index.js +68 -0
- package/lib-es/bridge/syncSessionManager/index.js.map +1 -0
- package/lib-es/bridge/syncSessionManager/index.test.d.ts +2 -0
- package/lib-es/bridge/syncSessionManager/index.test.d.ts.map +1 -0
- package/lib-es/bridge/syncSessionManager/index.test.js +116 -0
- package/lib-es/bridge/syncSessionManager/index.test.js.map +1 -0
- package/lib-es/e2e/data/deviceLabelsData.js +2 -2
- package/lib-es/e2e/data/deviceLabelsData.js.map +1 -1
- package/lib-es/e2e/enum/DeviceLabels.d.ts +1 -9
- package/lib-es/e2e/enum/DeviceLabels.d.ts.map +1 -1
- package/lib-es/e2e/enum/DeviceLabels.js +0 -8
- package/lib-es/e2e/enum/DeviceLabels.js.map +1 -1
- package/lib-es/e2e/families/tezos.d.ts.map +1 -1
- package/lib-es/e2e/families/tezos.js +6 -4
- package/lib-es/e2e/families/tezos.js.map +1 -1
- package/lib-es/e2e/index.d.ts +2 -0
- package/lib-es/e2e/index.d.ts.map +1 -1
- package/lib-es/e2e/models/Swap.d.ts +2 -0
- package/lib-es/e2e/models/Swap.d.ts.map +1 -1
- package/lib-es/e2e/models/Swap.js +6 -0
- package/lib-es/e2e/models/Swap.js.map +1 -1
- package/lib-es/e2e/speculos.d.ts +8 -0
- package/lib-es/e2e/speculos.d.ts.map +1 -1
- package/lib-es/e2e/speculos.js +16 -31
- package/lib-es/e2e/speculos.js.map +1 -1
- package/lib-es/exchange/providers/swap.js +2 -2
- package/lib-es/exchange/providers/swap.js.map +1 -1
- package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
- package/lib-es/featureFlags/defaultFeatures.js +1 -0
- package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
- package/lib-es/featureFlags/useFeature.d.ts +1 -1
- package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/modules/useLeftApyModule.d.ts +1 -0
- package/lib-es/modularDrawer/hooks/modules/useLeftApyModule.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/modules/useLeftMarketTrendModule.d.ts +1 -0
- package/lib-es/modularDrawer/hooks/modules/useLeftMarketTrendModule.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/modules/useRightMarketTrendModule.d.ts +1 -0
- package/lib-es/modularDrawer/hooks/modules/useRightMarketTrendModule.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/useRightBalanceAsset.d.ts +1 -0
- package/lib-es/modularDrawer/hooks/useRightBalanceAsset.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/useRightBalanceNetwork.d.ts +1 -0
- package/lib-es/modularDrawer/hooks/useRightBalanceNetwork.d.ts.map +1 -1
- package/lib-es/notifications/ServiceStatusProvider/entry-points.d.ts +3 -0
- package/lib-es/notifications/ServiceStatusProvider/entry-points.d.ts.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/entry-points.js +2 -0
- package/lib-es/notifications/ServiceStatusProvider/entry-points.js.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/index.d.ts +18 -1
- package/lib-es/notifications/ServiceStatusProvider/index.d.ts.map +1 -1
- package/lib-es/notifications/ServiceStatusProvider/index.js +47 -9
- package/lib-es/notifications/ServiceStatusProvider/index.js.map +1 -1
- package/lib-es/notifications/ServiceStatusProvider/index.test.d.ts +2 -0
- package/lib-es/notifications/ServiceStatusProvider/index.test.d.ts.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/index.test.js +86 -0
- package/lib-es/notifications/ServiceStatusProvider/index.test.js.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/ledger-components.d.ts +2 -0
- package/lib-es/notifications/ServiceStatusProvider/ledger-components.d.ts.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/ledger-components.js +14 -0
- package/lib-es/notifications/ServiceStatusProvider/ledger-components.js.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/mocks/ledgerStatus.d.ts +154 -0
- package/lib-es/notifications/ServiceStatusProvider/mocks/ledgerStatus.d.ts.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/mocks/ledgerStatus.js +1189 -0
- package/lib-es/notifications/ServiceStatusProvider/mocks/ledgerStatus.js.map +1 -0
- package/lib-es/notifications/ServiceStatusProvider/types.d.ts +3 -1
- package/lib-es/notifications/ServiceStatusProvider/types.d.ts.map +1 -1
- package/package.json +67 -67
- package/src/bridge/react/BridgeSync.tsx +17 -3
- package/src/bridge/syncSessionManager/index.test.ts +151 -0
- package/src/bridge/syncSessionManager/index.ts +93 -0
- package/src/e2e/data/deviceLabelsData.ts +2 -2
- package/src/e2e/enum/DeviceLabels.ts +0 -8
- package/src/e2e/families/tezos.ts +13 -4
- package/src/e2e/models/Swap.ts +8 -0
- package/src/e2e/speculos.ts +19 -34
- package/src/exchange/providers/swap.ts +2 -2
- package/src/featureFlags/defaultFeatures.ts +1 -0
- package/src/notifications/ServiceStatusProvider/entry-points.ts +3 -0
- package/src/notifications/ServiceStatusProvider/index.test.ts +102 -0
- package/src/notifications/ServiceStatusProvider/index.tsx +61 -13
- package/src/notifications/ServiceStatusProvider/ledger-components.ts +13 -0
- package/src/notifications/ServiceStatusProvider/mocks/ledgerStatus.ts +1188 -0
- package/src/notifications/ServiceStatusProvider/types.ts +4 -1
@@ -1,14 +1,23 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import {
|
2
|
+
getDelegateEvents,
|
3
|
+
getDeviceLabels,
|
4
|
+
getSpeculosModel,
|
5
|
+
pressBoth,
|
6
|
+
pressUntilTextFound,
|
7
|
+
} from "../speculos";
|
3
8
|
import { Delegate } from "../models/Delegate";
|
4
9
|
import { DeviceModelId } from "@ledgerhq/types-devices";
|
10
|
+
import { DeviceLabels } from "../enum/DeviceLabels";
|
5
11
|
|
6
12
|
export async function delegateTezos(delegatingAccount: Delegate) {
|
13
|
+
const { delegateConfirmLabel } = getDeviceLabels(delegatingAccount.account.currency.speculosApp);
|
14
|
+
|
7
15
|
await getDelegateEvents(delegatingAccount);
|
16
|
+
await pressUntilTextFound(delegateConfirmLabel);
|
8
17
|
await pressBoth();
|
9
18
|
|
10
|
-
if (getSpeculosModel()
|
11
|
-
await pressUntilTextFound(DeviceLabels.
|
19
|
+
if (getSpeculosModel() == DeviceModelId.nanoS) {
|
20
|
+
await pressUntilTextFound(DeviceLabels.ACCEPT_AND_SEND);
|
12
21
|
await pressBoth();
|
13
22
|
}
|
14
23
|
}
|
package/src/e2e/models/Swap.ts
CHANGED
@@ -27,4 +27,12 @@ export class Swap extends Transaction {
|
|
27
27
|
public get getAmount(): string {
|
28
28
|
return this.amount;
|
29
29
|
}
|
30
|
+
|
31
|
+
public get getAccountToDebit(): Account {
|
32
|
+
return this.accountToDebit;
|
33
|
+
}
|
34
|
+
|
35
|
+
public get getAccountToCredit(): Account {
|
36
|
+
return this.accountToCredit;
|
37
|
+
}
|
30
38
|
}
|
package/src/e2e/speculos.ts
CHANGED
@@ -630,7 +630,7 @@ type DeviceLabelsReturn = {
|
|
630
630
|
receiveVerifyLabel: string;
|
631
631
|
};
|
632
632
|
|
633
|
-
function getDeviceLabels(appInfo: AppInfos): DeviceLabelsReturn {
|
633
|
+
export function getDeviceLabels(appInfo: AppInfos): DeviceLabelsReturn {
|
634
634
|
const deviceModel = getSpeculosModel();
|
635
635
|
const deviceConfig = DEVICE_LABELS_CONFIG[deviceModel] ?? DEVICE_LABELS_CONFIG.default;
|
636
636
|
|
@@ -765,6 +765,7 @@ export async function getDelegateEvents(delegatingAccount: Delegate): Promise<st
|
|
765
765
|
);
|
766
766
|
|
767
767
|
await waitFor(delegateVerifyLabel);
|
768
|
+
|
768
769
|
return await pressUntilTextFound(delegateConfirmLabel);
|
769
770
|
}
|
770
771
|
|
@@ -774,54 +775,38 @@ export async function verifyAmountsAndAcceptSwap(swap: Swap, amount: string) {
|
|
774
775
|
getSpeculosModel() === DeviceModelId.nanoS
|
775
776
|
? await pressUntilTextFound(DeviceLabels.ACCEPT_AND_SEND)
|
776
777
|
: await pressUntilTextFound(DeviceLabels.SIGN_TRANSACTION);
|
777
|
-
|
778
|
+
verifySwapData(swap, events, amount);
|
778
779
|
await pressBoth();
|
779
780
|
}
|
780
781
|
|
781
782
|
export async function verifyAmountsAndAcceptSwapForDifferentSeed(swap: Swap, amount: string) {
|
782
|
-
await waitFor(DeviceLabels.
|
783
|
-
await pressUntilTextFound(DeviceLabels.I_UNDERSTAND);
|
784
|
-
await pressBoth();
|
783
|
+
await waitFor(DeviceLabels.REVIEW_TRANSACTION);
|
785
784
|
const events = await pressUntilTextFound(DeviceLabels.SIGN_TRANSACTION);
|
786
|
-
|
785
|
+
verifySwapData(swap, events, amount);
|
787
786
|
await pressBoth();
|
788
787
|
}
|
789
788
|
|
790
789
|
export async function verifyAmountsAndRejectSwap(swap: Swap, amount: string) {
|
791
790
|
await waitFor(DeviceLabels.REVIEW_TRANSACTION);
|
792
791
|
const events = await pressUntilTextFound(DeviceLabels.REJECT);
|
793
|
-
|
792
|
+
verifySwapData(swap, events, amount);
|
794
793
|
await pressBoth();
|
795
794
|
}
|
796
795
|
|
797
|
-
|
798
|
-
const
|
799
|
-
expect(sendAmountScreen).toBeTruthy();
|
800
|
-
verifySwapGetAmountScreen(swap, events);
|
801
|
-
verifySwapFeesAmountScreen(swap, events);
|
802
|
-
}
|
803
|
-
|
804
|
-
function verifySwapGetAmountScreen(swap: Swap, events: string[]) {
|
805
|
-
const parsedAmountToReceive = extractNumberFromString(swap.amountToReceive);
|
806
|
-
swap.amountToReceive =
|
807
|
-
parsedAmountToReceive.length < 19
|
808
|
-
? parsedAmountToReceive
|
809
|
-
: parsedAmountToReceive.substring(0, 18);
|
796
|
+
function verifySwapData(swap: Swap, events: string[], amount: string) {
|
797
|
+
const swapPair = `swap ${swap.getAccountToDebit.currency.ticker} to ${swap.getAccountToCredit.currency.ticker}`;
|
810
798
|
|
811
|
-
|
812
|
-
|
799
|
+
if (getSpeculosModel() !== DeviceModelId.nanoS) {
|
800
|
+
expectDeviceScreenContains(swapPair, events, "Swap pair not found on the device screen");
|
801
|
+
}
|
802
|
+
expectDeviceScreenContains(amount, events, `Amount ${amount} not found on the device screen`);
|
813
803
|
}
|
814
804
|
|
815
|
-
function
|
816
|
-
const
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
805
|
+
function expectDeviceScreenContains(substring: string, events: string[], message: string) {
|
806
|
+
const found = containsSubstringInEvent(substring, events);
|
807
|
+
if (!found) {
|
808
|
+
throw new Error(
|
809
|
+
`${message}. Expected events to contain "${substring}". Got: ${JSON.stringify(events)}`,
|
810
|
+
);
|
811
|
+
}
|
822
812
|
}
|
823
|
-
|
824
|
-
const extractNumberFromString = (input: string | undefined): string => {
|
825
|
-
const match = input?.match(/[\d.]+/);
|
826
|
-
return match ? match[0] : "";
|
827
|
-
};
|
@@ -177,9 +177,9 @@ const DEFAULT_SWAP_PROVIDERS: Record<string, ProviderConfig & Partial<Additional
|
|
177
177
|
type: "CEX",
|
178
178
|
name: "NEAR Intents",
|
179
179
|
needsBearerToken: false,
|
180
|
-
termsOfUseUrl: "https://
|
180
|
+
termsOfUseUrl: "https://swapkit.dev/terms-of-service/",
|
181
181
|
supportUrl: "https://ledgerhelp.swapkit.dev/",
|
182
|
-
mainUrl: "https://www.
|
182
|
+
mainUrl: "https://www.near.org/intents",
|
183
183
|
needsKYC: false,
|
184
184
|
version: 2,
|
185
185
|
publicKey: {
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { filterServiceStatusIncidents } from "./index";
|
2
|
+
import { LEDGER_COMPONENTS } from "./ledger-components";
|
3
|
+
import type { Incident } from "./types";
|
4
|
+
|
5
|
+
const makeIncident = (overrides: Partial<Incident> = {}): Incident => ({
|
6
|
+
created_at: "2025-01-01T00:00:00Z",
|
7
|
+
id: Math.random().toString(16).slice(2),
|
8
|
+
impact: "minor",
|
9
|
+
incident_updates: [],
|
10
|
+
monitoring_at: null,
|
11
|
+
name: "Test incident",
|
12
|
+
page_id: null,
|
13
|
+
resolved_at: null,
|
14
|
+
shortlink: null,
|
15
|
+
status: "investigating",
|
16
|
+
updated_at: null,
|
17
|
+
...overrides,
|
18
|
+
});
|
19
|
+
|
20
|
+
describe("filterServiceStatusIncidents", () => {
|
21
|
+
it("returns empty when no tickers or no incidents", () => {
|
22
|
+
expect(filterServiceStatusIncidents([], ["BTC"]).length).toBe(0);
|
23
|
+
expect(filterServiceStatusIncidents([makeIncident()], []).length).toBe(0);
|
24
|
+
});
|
25
|
+
|
26
|
+
it("matches incidents with known Ledger components (case-insensitive)", () => {
|
27
|
+
const incidents: Incident[] = [
|
28
|
+
makeIncident({ components: [{ id: "1", name: "Ledger Application Store" }] }),
|
29
|
+
makeIncident({ components: [{ id: "2", name: "ledger appliCAtion store" }] }),
|
30
|
+
makeIncident({ components: [{ id: "3", name: "Unknown Component" }] }),
|
31
|
+
];
|
32
|
+
|
33
|
+
const result = filterServiceStatusIncidents(incidents, ["BTC"], "notifications");
|
34
|
+
expect(result.map(i => i.components?.[0].id)).toEqual(["1", "2"]);
|
35
|
+
});
|
36
|
+
|
37
|
+
it("matches incidents if a component contains a tracked ticker as a whole word (case-insensitive)", () => {
|
38
|
+
const incidents: Incident[] = [
|
39
|
+
makeIncident({ components: [{ id: "1", name: "BTC Node" }] }),
|
40
|
+
makeIncident({ components: [{ id: "2", name: "eth Node" }] }),
|
41
|
+
makeIncident({ components: [{ id: "3", name: "TETHER Service" }] }),
|
42
|
+
makeIncident({ components: [{ id: "4", name: "NOTBTCService" }] }),
|
43
|
+
];
|
44
|
+
|
45
|
+
const result = filterServiceStatusIncidents(incidents, ["BTC", "ETH"]);
|
46
|
+
expect(result.map(i => i.components?.[0].id)).toEqual(["1", "2"]);
|
47
|
+
});
|
48
|
+
|
49
|
+
it("includes incidents with no components array or empty array", () => {
|
50
|
+
const incidents: Incident[] = [
|
51
|
+
makeIncident({ components: undefined }),
|
52
|
+
makeIncident({ components: [] }),
|
53
|
+
];
|
54
|
+
|
55
|
+
const result = filterServiceStatusIncidents(incidents, ["BTC"]);
|
56
|
+
expect(result.length).toBe(2);
|
57
|
+
});
|
58
|
+
|
59
|
+
it("escapes tickers so special regex characters do not break matching", () => {
|
60
|
+
const incidents: Incident[] = [
|
61
|
+
makeIncident({ components: [{ id: "1", name: "USDT Node" }] }),
|
62
|
+
makeIncident({ components: [{ id: "2", name: "US.DT Node" }] }),
|
63
|
+
makeIncident({ components: [{ id: "3", name: "(USDT) Node" }] }),
|
64
|
+
makeIncident({ components: [{ id: "4", name: "Ethereum Node" }] }),
|
65
|
+
makeIncident({ components: [{ id: "5", name: "Ethereum (ETH) swap issue" }] }),
|
66
|
+
];
|
67
|
+
|
68
|
+
const result = filterServiceStatusIncidents(incidents, ["USDT", "ETH"]);
|
69
|
+
expect(result.map(i => i.components?.[0].id)).toEqual(["1", "3", "5"]);
|
70
|
+
expect(result.length).toBe(3);
|
71
|
+
});
|
72
|
+
|
73
|
+
it("matches incidents for all known Ledger components", () => {
|
74
|
+
const incidents: Incident[] = LEDGER_COMPONENTS.map((name, index) =>
|
75
|
+
makeIncident({ components: [{ id: `${index + 1}`, name }] }),
|
76
|
+
);
|
77
|
+
|
78
|
+
const result = filterServiceStatusIncidents(incidents, ["BTC"], "notifications");
|
79
|
+
expect(result.length).toBe(LEDGER_COMPONENTS.length);
|
80
|
+
});
|
81
|
+
|
82
|
+
it("filters correctly with common tickers", () => {
|
83
|
+
const tickers = ["XRP", "SOL", "ETH", "BTC", "ADA", "USDC", "USDT"];
|
84
|
+
const incidents: Incident[] = [
|
85
|
+
makeIncident({ components: [{ id: "1", name: "BTC Node" }] }),
|
86
|
+
makeIncident({ components: [{ id: "2", name: "eth Node" }] }),
|
87
|
+
makeIncident({ components: [{ id: "3", name: "ADA-Service" }] }),
|
88
|
+
makeIncident({ components: [{ id: "4", name: "usdc gateway" }] }),
|
89
|
+
makeIncident({ components: [{ id: "5", name: "NOTUSDTService" }] }),
|
90
|
+
makeIncident({ components: [{ id: "6", name: "USDT" }] }),
|
91
|
+
makeIncident({ components: [{ id: "7", name: "xrp relayer" }] }),
|
92
|
+
makeIncident({ components: [{ id: "8", name: "SOL Node" }] }),
|
93
|
+
makeIncident({ components: [{ id: "9", name: "SOLANA Node" }] }),
|
94
|
+
makeIncident({ components: [{ id: "10", name: "Random Service" }] }),
|
95
|
+
makeIncident({ components: [] }),
|
96
|
+
];
|
97
|
+
|
98
|
+
const result = filterServiceStatusIncidents(incidents, tickers);
|
99
|
+
expect(result.map(i => i.components?.[0]?.id)).toEqual(["1", "2", "3", "4", "6", "7", "8"]);
|
100
|
+
expect(result.length).toBe(8);
|
101
|
+
});
|
102
|
+
});
|
@@ -4,6 +4,9 @@ import defaultNetworkApi from "./api";
|
|
4
4
|
import { fromPromise } from "xstate";
|
5
5
|
import { useMachine } from "@xstate/react";
|
6
6
|
import { serviceStatusMachine } from "./machine";
|
7
|
+
import { LEDGER_COMPONENTS } from "./ledger-components";
|
8
|
+
import { EntryPoint } from "./entry-points";
|
9
|
+
|
7
10
|
type Props = {
|
8
11
|
children: React.ReactNode;
|
9
12
|
autoUpdateDelay: number;
|
@@ -33,21 +36,61 @@ function escapeRegExp(string) {
|
|
33
36
|
return string.replace(/[.*+?^${}()[\]\\]/g, "\\$&"); // $& means the whole matched string
|
34
37
|
}
|
35
38
|
|
39
|
+
function sanitizeName(name: string): string {
|
40
|
+
return name.toLowerCase().trim().replace(/\s+/g, " "); // collapse multiple spaces
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Filters service status incidents based on related tickers or Ledger components.
|
45
|
+
*
|
46
|
+
* ## Behavior:
|
47
|
+
* - If there are no `tickers` or no `incidents`, returns an empty list.
|
48
|
+
* - For each incident:
|
49
|
+
* 1. ✅ If the incident has no components → keep it (always relevant).
|
50
|
+
* 2. ✅ If at least one component name matches a known **Ledger component** → keep it.
|
51
|
+
* 3. ✅ If at least one component name contains a **currency ticker** → keep it.
|
52
|
+
* 4. ❌ Otherwise, the incident is discarded.
|
53
|
+
*
|
54
|
+
* @param {Incident[]} [incidents=[]] - List of incidents to filter.
|
55
|
+
* @param {string[]} [tickers=[]] - List of currency tickers to match against incident components.
|
56
|
+
* @param {EntryPoint} [entryPoint] - Entry point where the incidents are displayed (specifically for Ledger components)
|
57
|
+
* @returns {Incident[]} The list of incidents relevant to the provided tickers or Ledger components.
|
58
|
+
*/
|
59
|
+
|
36
60
|
export function filterServiceStatusIncidents(
|
37
61
|
incidents: Incident[],
|
38
62
|
tickers: string[] = [],
|
63
|
+
entryPoint?: EntryPoint,
|
39
64
|
): Incident[] {
|
40
|
-
if (!
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
65
|
+
if (!incidents.length) return [];
|
66
|
+
if (!tickers.length) return [];
|
67
|
+
|
68
|
+
const tickerRegex = tickers.length
|
69
|
+
? new RegExp(`\\b(${tickers.map(escapeRegExp).join("|")})\\b`, "i")
|
70
|
+
: null;
|
71
|
+
|
72
|
+
const ledgerComponentsSet = new Set(LEDGER_COMPONENTS.map(component => sanitizeName(component)));
|
73
|
+
|
74
|
+
return incidents.filter(({ components }) => {
|
75
|
+
// Keep global incidents with no components
|
76
|
+
if (!components?.length) return true;
|
77
|
+
|
78
|
+
return components.some(({ name }) => {
|
79
|
+
const sanitizedName = sanitizeName(name);
|
80
|
+
|
81
|
+
// Show Ledger components only for Notification Center
|
82
|
+
if (entryPoint === "notifications" && ledgerComponentsSet.has(sanitizedName)) {
|
83
|
+
return true;
|
84
|
+
}
|
85
|
+
|
86
|
+
// Show coin/ticker-specific components for flows
|
87
|
+
if (tickerRegex && tickerRegex.test(sanitizedName)) {
|
88
|
+
return true;
|
89
|
+
}
|
90
|
+
|
91
|
+
return false;
|
92
|
+
});
|
93
|
+
});
|
51
94
|
}
|
52
95
|
|
53
96
|
// filter out service status incidents by given currencies or fallback on context currencies
|
@@ -55,8 +98,12 @@ export function useFilteredServiceStatus(filters?: ServiceStatusUserSettings): S
|
|
55
98
|
const stateData = useContext(ServiceStatusContext);
|
56
99
|
const { incidents, context } = stateData;
|
57
100
|
const filteredIncidents = useMemo(() => {
|
58
|
-
return filterServiceStatusIncidents(
|
59
|
-
|
101
|
+
return filterServiceStatusIncidents(
|
102
|
+
incidents,
|
103
|
+
filters?.tickers || context?.tickers,
|
104
|
+
filters?.entryPoint,
|
105
|
+
);
|
106
|
+
}, [incidents, filters?.tickers, context?.tickers, filters?.entryPoint]);
|
60
107
|
|
61
108
|
return { ...stateData, incidents: filteredIncidents };
|
62
109
|
}
|
@@ -69,6 +116,7 @@ export const ServiceStatusProvider = ({
|
|
69
116
|
}: Props): ReactElement => {
|
70
117
|
const fetchData = useCallback(async () => {
|
71
118
|
const serviceStatusSummary = await networkApi.fetchStatusSummary();
|
119
|
+
|
72
120
|
return {
|
73
121
|
incidents: serviceStatusSummary.incidents,
|
74
122
|
updateTime: Date.now(),
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export const LEDGER_COMPONENTS = [
|
2
|
+
"Ledger Application Store",
|
3
|
+
"Ledger Live Security Services",
|
4
|
+
"Swap API",
|
5
|
+
"Buy",
|
6
|
+
"Earn Dashboard",
|
7
|
+
"Crypto Assets Service",
|
8
|
+
"Cloud Sync",
|
9
|
+
"Trustchain",
|
10
|
+
"Loyalty Program",
|
11
|
+
"Card Program",
|
12
|
+
"Countervalue API",
|
13
|
+
] as const;
|