Skip to content

Commit 98dbced

Browse files
guanbinruihanszhoounuanyang233UncleBill
authored
[Release] Hotfix 2.18.2 => 2.18.3 (patch) (#9143)
* chore: bump version to 2.18.3 * chore: pick simple hash (#9147) * chore: pick simple hash * chore: sync simplehash (#9083) * refactor: gray simple hash (#9104) * refactor: add canvas fingerprinting (#9012) * refactor: opt fp * test: add createDeviceSeed * fix: lint errors * feat: add isDeviceOnWhitelist * test: isDeviceOnWhitelist * fix: ci errors * refactor: update comment * fix: type error * fix: type error * feat: A/B simplehash (#9019) * refactor: set tag * chore: add ab tags * feat: debug A/B * chore: type * fix: type --------- Co-authored-by: guanbinrui <[email protected]> * fix: bugfix for invalid gas (#9127) * fix: simple hash img fallback (#9155) * refactor: adjust sample rate (#9159) * refactor: events as transactions (#9160) * refactor: events as transactions * refactor: send events as transactions * refactor: update lock file * fix: mf-3718 NFTScan gnosis host is incorrect (#9118) * fix: mf-3719 image size in dashboard assets * fix: mf-3718 NFTScan gnosis host is incorrect * fix: several bugs (#9171) * fix: several bugs * fix: type * fix: mf-3717 pass plugin id to collectible card (#9168) * fix: mf-3717 pass plugin id to collectible card * fixup! fix: mf-3717 pass plugin id to collectible card * feat: remote flags (#9176) * refactor: add @masknet/flags (#9053) * chore: simplehash_ab_percentage * feat: remote flags * refactor: comment * refactor: error handling * fix: cspell * fix: logic errors * fix: simple hash rp history nft (#9177) --------- Co-authored-by: Hancheng Zhou <[email protected]> Co-authored-by: nuanyang233 <[email protected]> Co-authored-by: UncleBill <[email protected]>
1 parent d039d37 commit 98dbced

File tree

81 files changed

+1084
-298
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1084
-298
lines changed

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@
380380
"rehype",
381381
"renfil",
382382
"shapeclip",
383+
"simplehash",
383384
"ssrb",
384385
"steth",
385386
"swaptoken",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"yarn": ">=999.0.0",
88
"npm": ">=999.0.0"
99
},
10-
"version": "2.18.2",
10+
"version": "2.18.3",
1111
"private": true,
1212
"license": "AGPL-3.0-or-later",
1313
"scripts": {

packages/dashboard/src/pages/Wallets/components/CollectibleCard/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ const useStyles = makeStyles()((theme) => ({
3636
width: '100%',
3737
height: 186,
3838
backgroundColor: theme.palette.mode === 'dark' ? MaskColorVar.lineLight : '#f6f6f7',
39+
img: {
40+
objectFit: 'contain !important' as 'contain',
41+
},
3942
},
4043
description: {
4144
flex: 1,
@@ -102,14 +105,17 @@ export const CollectibleCard = memo<CollectibleCardProps>(({ asset, onSend }) =>
102105
return Others?.explorerResolver.nonFungibleTokenLink(asset.chainId, asset.address, asset.tokenId)
103106
}, [currentPluginId, asset.chainId, asset.address, asset.tokenId])
104107

108+
// NFTScan can't recognize address uppercase
109+
const link = (asset.link ?? nftLink)?.toLowerCase()
110+
105111
return (
106112
<Box className={`${classes.container} ${isHovering || isHoveringTooltip ? classes.hover : ''}`} ref={ref}>
107113
<div className={classes.card}>
108114
<Link
109115
target={asset.link ?? nftLink ? '_blank' : '_self'}
110116
rel="noopener noreferrer"
111117
className={classes.linkWrapper}
112-
href={asset.link ?? nftLink}>
118+
href={link}>
113119
<div className={classes.blocker} />
114120
<div className={classes.mediaContainer}>
115121
<AssetPreviewer
@@ -156,3 +162,5 @@ export const CollectibleCard = memo<CollectibleCardProps>(({ asset, onSend }) =>
156162
</Box>
157163
)
158164
})
165+
166+
CollectibleCard.displayName = 'CollectibleCard'

packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export const CollectibleList = memo<CollectibleListProps>(({ selectedChain }) =>
6161
[...trustedOwnNonFungibleTokens, ...value],
6262
(x) => x?.contract?.address.toLowerCase() + x?.tokenId,
6363
).filter((x) => (selectedChain ? x.chainId === selectedChain.chainId : true))
64-
}, [value.length, trustedNonFungibleTokens.length, selectedChain?.chainId])
64+
}, [value.length, trustedNonFungibleTokens, selectedChain?.chainId])
6565

6666
useEffect(() => {
6767
if (next) next()

packages/flags/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "@masknet/flags",
3+
"private": true,
4+
"type": "module",
5+
"exports": {
6+
".": {
7+
"types": "./dist/index.d.ts",
8+
"mask-src": "./src/index.ts",
9+
"default": "./dist/index.js"
10+
}
11+
},
12+
"types": "./dist/index.d.ts",
13+
"devDependencies": {
14+
"urlcat": "^2.0.4"
15+
}
16+
}
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export const is_iOSApp = process.env.engine === 'safari' && process.env.architecture === 'app'
2-
export const isAndroidApp = process.env.architecture === 'app' && process.env.engine === 'firefox'
1+
const is_iOSApp = process.env.engine === 'safari' && process.env.architecture === 'app'
2+
const isAndroidApp = process.env.architecture === 'app' && process.env.engine === 'firefox'
33

44
const appOnly = process.env.architecture === 'app'
55
const devOnly = process.env.NODE_ENV === 'development'
@@ -8,7 +8,7 @@ const insiderOnly = process.env.channel === 'insider' || devOnly
88
const betaOrInsiderOnly = insiderOnly || process.env.channel === 'beta'
99

1010
// TODO: In future, we can turn this object into a Proxy to receive flags from remote
11-
export const Flags = {
11+
export const flags = {
1212
/** @deprecated */
1313
userGuideLevel: 'v2',
1414
isolated_dashboard_bridge_enabled: false,
@@ -57,8 +57,10 @@ export const Flags = {
5757
v37PayloadDefaultEnabled: false, // new Date() > new Date('2022-07-01'),
5858
i18nTranslationHotUpdate: true,
5959
sandboxedPluginRuntime: insiderOnly,
60+
61+
simplehash_ab_percentage: 50,
6062
} as const
6163

6264
if (process.env.NODE_ENV === 'development') {
63-
console.log('Mask Network starts with flags:', Flags)
65+
console.log('Mask Network starts with flags:', flags)
6466
}

packages/flags/src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { flags as defaultFlags } from './flags/index.js'
2+
import { RemoteFlags } from './libs/RemoteFlags.js'
3+
4+
const flags = new RemoteFlags('https://mask-flags.r2d2.to/', defaultFlags)
5+
6+
// fetch each time starts the app, updates will be enabled
7+
flags.fetchAndActive()
8+
9+
export const Flags = flags.accessor

packages/flags/src/libs/Flags.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export class Flags<T extends object> {
2+
constructor(protected defaults: T) {}
3+
4+
get accessor(): Readonly<T> {
5+
return new Proxy(this.defaults, {
6+
get(target, key, receiver) {
7+
return Reflect.get(target, key, receiver)
8+
},
9+
set(target, key, value, receiver) {
10+
throw new Error('Not allowed')
11+
},
12+
})
13+
}
14+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import urlcat from 'urlcat'
2+
import { has } from 'lodash-es'
3+
import { Flags } from './Flags.js'
4+
5+
interface FetchResult<T extends Record<string, unknown>> {
6+
flags?: T
7+
timestamp: number
8+
}
9+
10+
export class RemoteFlags<T extends Record<string, unknown>> extends Flags<T> {
11+
private readonly KEY = 'mask-last-fetch-result'
12+
13+
private lastFetchResult: FetchResult<T> | null = null
14+
15+
private get lastStorageResult() {
16+
try {
17+
const json = localStorage.getItem(this.KEY)
18+
const result: FetchResult<T> | null = json ? JSON.parse(json) : null
19+
return result
20+
} catch (error) {
21+
return null
22+
}
23+
}
24+
25+
constructor(
26+
private remoteFlagsURL: string,
27+
defaults: T,
28+
private initials?: {
29+
// the valid duration for remote fetched flags
30+
fetchTTL?: number
31+
// the valid duration for local storage flags
32+
storageTTL?: number
33+
},
34+
) {
35+
super(defaults)
36+
37+
this.sync()
38+
}
39+
40+
get options() {
41+
return {
42+
fetchTTL: 60 * 60 * 1000, // 1hr
43+
storageTTL: 2 * 60 * 60 * 1000, // 2hr
44+
...this.initials,
45+
}
46+
}
47+
48+
get isLastFetchResultFresh() {
49+
return Date.now() - this.lastFetchTimestamp < this.options.fetchTTL
50+
}
51+
52+
get isLastStorageResultFresh() {
53+
return Date.now() - this.lastStorageTimestamp < this.options.storageTTL
54+
}
55+
56+
get lastFetchTimestamp() {
57+
return this.lastFetchResult?.timestamp ?? 0
58+
}
59+
60+
get lastStorageTimestamp() {
61+
return this.lastStorageResult?.timestamp ?? 0
62+
}
63+
64+
override get accessor(): Readonly<T> {
65+
return new Proxy(this.defaults, {
66+
get: (target, key, receiver) => {
67+
if (has(this.lastFetchResult?.flags, key)) return this.lastFetchResult?.flags?.[key as string]
68+
return Reflect.get(target, key, receiver)
69+
},
70+
set: (target, key, value, receiver) => {
71+
throw new Error('Not allowed')
72+
},
73+
})
74+
}
75+
76+
/**
77+
* Sync with the local storage.
78+
*/
79+
sync() {
80+
if (!this.isLastStorageResultFresh) {
81+
localStorage.removeItem(this.KEY)
82+
}
83+
84+
const lastFetchResult = this.lastFetchResult
85+
const lastStorageResult = this.lastStorageResult
86+
87+
if (
88+
(lastFetchResult?.timestamp && !lastStorageResult?.timestamp) ||
89+
(lastFetchResult?.timestamp &&
90+
lastStorageResult?.timestamp &&
91+
lastStorageResult.timestamp < lastFetchResult.timestamp)
92+
) {
93+
console.log('[RemoteFlags] sync from remote')
94+
localStorage.setItem(this.KEY, JSON.stringify(lastFetchResult))
95+
} else if (lastStorageResult?.timestamp) {
96+
console.log('[RemoteFlags] sync from storage')
97+
this.lastFetchResult = lastStorageResult
98+
}
99+
}
100+
101+
/**
102+
* Fetch flags from the remote server.
103+
*/
104+
async fetch() {
105+
const response = await fetch(
106+
urlcat(this.remoteFlagsURL, {
107+
architecture: process.env.architecture,
108+
channel: process.env.channel,
109+
engine: process.env.engine,
110+
NODE_ENV: process.env.NODE_ENV,
111+
}),
112+
)
113+
const flags: T = await response.json()
114+
return flags
115+
}
116+
117+
/**
118+
* Fetch flags from the remote server and patch updates right after fetched.
119+
*/
120+
async fetchAndActive() {
121+
// Prevent fetching too frequently
122+
if (this.isLastFetchResultFresh) return
123+
124+
this.lastFetchResult = {
125+
flags: await this.fetch(),
126+
timestamp: Date.now(),
127+
}
128+
this.sync()
129+
}
130+
}

packages/flags/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"rootDir": "./src/",
5+
"outDir": "./dist/",
6+
"tsBuildInfoFile": "./dist/.tsbuildinfo"
7+
},
8+
"include": ["./src"],
9+
"references": []
10+
}

0 commit comments

Comments
 (0)