Skip to content

Commit 98dbced

Browse files
guanbinruizhouhansengnuanyang233UncleBill
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

+1
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

+1-1
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

+9-1
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

+1-1
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

+16
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+
}

packages/mask/shared/flags.ts renamed to packages/flags/src/flags/index.ts

+6-4
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

+9
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

+14
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+
}
+130
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

+10
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+
}

packages/icons/brands/SimpleHash.png

3.95 KB
Loading

packages/mask/background/services/helper/i18n-cache-query.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Flags } from '../../../shared/flags.js'
1+
import { Flags } from '@masknet/flags'
22
import list from './i18n-cache-query-list.js'
33

44
export type Bundle = [namespace: string, lang: string, json: object]

packages/mask/background/services/helper/request-permission.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import type { Permissions } from 'webextension-polyfill'
2+
import { Flags } from '@masknet/flags'
13
import { getPermissionRequestURL } from '../../../shared/definitions/routes.js'
2-
import { Flags } from '../../../shared/flags.js'
34
import { MaskMessages } from '../../../shared/messages.js'
45
import type { SiteAdaptor } from '../../../shared/site-adaptors/types.js'
5-
import type { Permissions } from 'webextension-polyfill'
66

77
export async function requestExtensionPermission(permission: Permissions.Permissions): Promise<boolean> {
88
if (Flags.no_web_extension_dynamic_permission_request) return true

packages/mask/background/tasks/Cancellable/InjectContentScripts-mv3.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { noop } from 'lodash-es'
2-
import { Flags } from '../../../shared/flags.js'
2+
import { Flags } from '@masknet/flags'
33
import { hmr } from '../../../utils-pure/index.js'
44
import {
55
fetchInjectContentScriptList,

packages/mask/background/tasks/Cancellable/InjectContentScripts.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { noop } from 'lodash-es'
22
import { MaskMessages } from '../../../shared/messages.js'
3-
import { Flags } from '../../../shared/flags.js'
3+
import { Flags } from '@masknet/flags'
44
import { hmr } from '../../../utils-pure/index.js'
55
import type { ExtensionTypes, WebNavigation } from 'webextension-polyfill'
66

packages/mask/background/tasks/Cancellable/IsolatedDashboardBridge.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Environment, WebExtensionMessage } from '@dimensiondev/holoflows-kit'
2-
import { Flags } from '../../../shared/flags.js'
2+
import { Flags } from '@masknet/flags'
33
import { hmr } from '../../../utils-pure/index.js'
44

55
let disconnected = false

packages/mask/background/tasks/Cancellable/NewInstalled.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { DashboardRoutes } from '@masknet/shared-base'
21
import type { Runtime } from 'webextension-polyfill'
3-
import { Flags } from '../../../shared/flags.js'
2+
import { Flags } from '@masknet/flags'
3+
import { DashboardRoutes } from '@masknet/shared-base'
44
import { hmr } from '../../../utils-pure/index.js'
55
import { getOriginsWithoutPermission } from '../../services/site-adaptors/connect.js'
66

packages/mask/background/tasks/Cancellable/StartSandboxedPluginHost.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { PluginID } from '@masknet/shared-base'
33
import { Plugin, registerPlugin } from '@masknet/plugin-infra'
44
import { BackgroundInstance, BackgroundPluginHost } from '@masknet/sandboxed-plugin-runtime/background'
55
import { hmr } from '../../../utils-pure/index.js'
6-
import { Flags } from '../../../shared/flags.js'
6+
import { Flags } from '@masknet/flags'
77
import { createPluginDatabase } from '../../database/plugin-db/index.js'
88
import { createHostAPIs } from '../../../shared/sandboxed-plugin/host-api.js'
99

packages/mask/background/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
{ "path": "../../encryption" },
1717
{ "path": "../../backup-format" },
1818
{ "path": "../../gun-utils" },
19+
{ "path": "../../flags" },
1920
{ "path": "../../web3-providers" },
2021
{ "path": "../../sandboxed-plugin-runtime/src/background" }
2122
]

packages/mask/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@masknet/dashboard": "workspace:^",
2121
"@masknet/encryption": "workspace:^",
2222
"@masknet/external-plugin-previewer": "workspace:^",
23+
"@masknet/flags": "workspace:^",
2324
"@masknet/gun-utils": "workspace:^",
2425
"@masknet/icons": "workspace:^",
2526
"@masknet/injected-script": "workspace:^",

packages/mask/shared/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export * from './messages.js'
2-
export * from './flags.js'
32
export { InMemoryStorages, PersistentStorages } from './kv-storage.js'
43
export * from './helpers/index.js'

packages/mask/src/components/CompositionDialog/Composition.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import { useCallback, useEffect, useRef, useState } from 'react'
2+
import { useAsync } from 'react-use'
13
import type { CompositionType } from '@masknet/plugin-infra/content-script'
24
import { InjectedDialog, useCurrentPersonaConnectStatus } from '@masknet/shared'
35
import { CrossIsolationMessages, EMPTY_OBJECT } from '@masknet/shared-base'
46
import { makeStyles } from '@masknet/theme'
57
import { DialogActions, DialogContent } from '@mui/material'
6-
import { useCallback, useEffect, useRef, useState } from 'react'
7-
import { useAsync } from 'react-use'
8-
import { Flags } from '../../../shared/index.js'
8+
import { Flags } from '@masknet/flags'
99
import Services from '../../extension/service.js'
1010
import { activatedSocialNetworkUI } from '../../social-network/index.js'
1111
import { MaskMessages, useI18N } from '../../utils/index.js'

packages/mask/src/content-script.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { Flags } from '@masknet/flags'
12
import './setup.ui.js'
2-
import { Flags } from '../shared/index.js'
33

44
if (Flags.mask_SDK_ready) {
55
import('./extension/mask-sdk/index.js')

packages/mask/src/extension/options-page/DashboardComponents/CollectibleList/CollectibleCard.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ export const CollectibleCard = memo(function CollectibleCard({
7979
const networkDescriptor = useNetworkDescriptor(pluginID)
8080

8181
const networkIcon = useMemo(() => {
82+
// None is better than incorrect.
83+
if (!pluginID) return
8284
if (pluginID === NetworkPluginID.PLUGIN_EVM) {
8385
return NETWORK_DESCRIPTORS.find((network) => network?.chainId === asset.chainId)?.icon
8486
}
8587
return networkDescriptor?.icon
86-
}, [asset.chainId, pluginID])
88+
}, [asset.chainId, pluginID, networkDescriptor?.icon])
8789

8890
const content = (
8991
<>
@@ -123,3 +125,5 @@ export const CollectibleCard = memo(function CollectibleCard({
123125
</Link>
124126
)
125127
})
128+
129+
CollectibleCard.displayName = 'CollectibleCard'

0 commit comments

Comments
 (0)