chore: sync working tree

Commits 4 outstanding change(s) that were sitting uncommitted.
No build artifacts and no secrets in the changeset (both checked).
This commit is contained in:
zeekay
2026-07-26 10:06:48 -07:00
parent 75c529deb8
commit b0e0d789f9
10 changed files with 265 additions and 6 deletions
+48
View File
@@ -0,0 +1,48 @@
# Default / shared build-time env for the Lux Wallet monorepo.
#
# Consumed by `react-native-dotenv` (metro/jest, `safe: true`) and by the web
# build. Real secrets are injected at deploy time (KMS) and via `.env*.local`;
# the values here are inert placeholders so the config schema resolves and the
# `safe` check passes. Keep every key that `@l.x/config` imports listed here.
# API keys (placeholders — real values come from KMS / .env.local)
ALCHEMY_API_KEY=stored-in-.env.local
APPSFLYER_API_KEY=stored-in-.env.local
APPSFLYER_APP_ID=stored-in-.env.local
DATADOG_CLIENT_TOKEN=stored-in-.env.local
DATADOG_PROJECT_ID=stored-in-.env.local
INFURA_KEY=stored-in-.env.local
ONESIGNAL_APP_ID=stored-in-.env.local
QUICKNODE_ENDPOINT_NAME=stored-in-.env.local
QUICKNODE_ENDPOINT_TOKEN=stored-in-.env.local
STATSIG_API_KEY=stored-in-.env.local
LX_API_KEY=stored-in-.env.local
TRADING_API_KEY=stored-in-.env.local
WALLETCONNECT_PROJECT_ID=stored-in-.env.local
WALLETCONNECT_PROJECT_ID_BETA=stored-in-.env.local
WALLETCONNECT_PROJECT_ID_DEV=stored-in-.env.local
# Feature flags
INCLUDE_PROTOTYPE_FEATURES=false
IS_E2E_TEST=false
ENABLE_SESSION_SERVICE=false
ENABLE_SESSION_UPGRADE_AUTO=false
ENABLE_ENTRY_GATEWAY_PROXY=false
# Proxy URLs
BLOCKAID_PROXY_URL=
JUPITER_PROXY_URL=
# URL overrides (keep empty in this shared file)
AMPLITUDE_PROXY_URL_OVERRIDE=
API_BASE_URL_OVERRIDE=
API_BASE_URL_V2_OVERRIDE=
ENTRY_GATEWAY_API_URL_OVERRIDE=
FOR_API_URL_OVERRIDE=
GRAPHQL_URL_OVERRIDE=
LIQUIDITY_SERVICE_URL_OVERRIDE=
LX_NOTIF_API_BASE_URL_OVERRIDE=
SCANTASTIC_API_URL_OVERRIDE=
STATSIG_PROXY_URL_OVERRIDE=
TRADING_API_URL_OVERRIDE=
UNITAGS_API_URL_OVERRIDE=
@@ -0,0 +1,2 @@
// Static-asset stub for jest: images/fonts/media resolve to a stable string.
module.exports = 'mock-asset'
+26
View File
@@ -0,0 +1,26 @@
// Deterministic timezone + APP_ID so config schema validation passes under jest.
process.env.TZ = process.env.TZ ?? 'America/New_York'
process.env.APP_ID = process.env.APP_ID ?? 'web'
module.exports = {
globals: {
ALCHEMY_API_KEY: 'key',
AMPLITUDE_PROXY_URL_OVERRIDE: '',
API_BASE_URL_OVERRIDE: '',
API_BASE_URL_V2_OVERRIDE: '',
APPSFLYER_API_KEY: 'key',
APPSFLYER_APP_ID: 123,
DATADOG_CLIENT_TOKEN: 'key',
DATADOG_PROJECT_ID: 123,
INFURA_KEY: 'key',
ONESIGNAL_APP_ID: 'key',
STATSIG_API_KEY: 'key',
STATSIG_PROXY_URL_OVERRIDE: '',
TRADING_API_KEY: 'key',
TRADING_API_URL_OVERRIDE: '',
WALLETCONNECT_PROJECT_ID: 'key',
QUICKNODE_ENDPOINT_NAME: '',
QUICKNODE_ENDPOINT_TOKEN: '',
UNITAGS_API_URL_OVERRIDE: '',
},
}
+51
View File
@@ -0,0 +1,51 @@
// Jest preset for the Lux Wallet monorepo.
//
// The source was migrated to the published `@l.x/*` + `@luxfi/*` package
// names, but the shared feature code (and the `@l.x/*` packages themselves)
// still import each other by the upstream short names (`lux/…`, `utilities/…`,
// `ui/…`, `wallet/…`, `config/…`). This preset restores those aliases for the
// jest resolver and stubs static assets. The RN transform layer comes from
// `jest-expo`, which each package sets as its `preset`.
const path = require('path')
const globals = require('./globals')
const assetFileMock = path.resolve(__dirname, 'assetFileMock.js')
module.exports = {
moduleNameMapper: {
// Static assets → stable stub string.
'\\.(png|jpg|jpeg|gif|webp|ttf|otf|woff|woff2|mp4|mp3|wav|m4a|lottie)$': assetFileMock,
// Upstream short-name → published package aliases. Longest / most
// specific first (jest uses first-match-wins).
// The published @l.x/utils omits its jest mocks; serve the shared copy.
'^utilities/jest-package-mocks$': path.resolve(__dirname, '../utilities-package-mocks.js'),
'^config/jest-presets/(.*)$': path.resolve(__dirname, '../$1'),
'^utilities/(.*)$': '@l.x/utils/$1',
'^uniswap/(.*)$': '@l.x/lx/$1',
'^lux/(.*)$': '@l.x/lx/$1',
'^lx/(.*)$': '@l.x/lx/$1',
'^ui/(.*)$': '@l.x/ui/$1',
// The wallet package is @luxfi/wallet == this rootDir (no self-symlink
// under pnpm), so route its own name and the short `wallet/` alias to src.
'^@luxfi/wallet/(.*)$': '<rootDir>/$1',
'^wallet/(.*)$': '<rootDir>/$1',
// `@luxexchange/*` is the internal scope name the `@l.x/*` packages use to
// reference each other; alias the whole scope to the published packages.
'^@luxexchange/(.*)$': '@l.x/$1',
},
setupFilesAfterEnv: [path.resolve(__dirname, 'setup.js')],
// The RN surface is the @hanzogui fork; jest-expo's default ignore list only
// whitelists upstream `react-native`. Let the Flow-typed fork packages + the
// ESM-only deps through babel so the expo preset can strip their types.
//
// pnpm flattens scoped packages to `.pnpm/@scope+name@ver/…`, so the classic
// `@scope/name/`-anchored whitelist never matches the virtual store. Match at
// scope level and allow the pnpm separators (`+`, `@`) as well as `/`.
transformIgnorePatterns: [
'node_modules/(?!(?:\\.pnpm/)?(?:@hanzogui|@react-native|@react-navigation|@shopify|@gorhom|@l\\.x|@luxfi|@noble|@scure|@walletconnect|@statsig|@solana|react-native[a-z-]*|expo[a-z-]*|moti|nanoid|uuid|viem|wagmi|redux-persist)[-+@/])',
],
clearMocks: true,
...globals,
}
+32
View File
@@ -0,0 +1,32 @@
// Shared jest environment setup for the Lux Wallet monorepo.
// Provides the browser/runtime globals the RN + web code assumes.
// rtk-query baseQueryFn and viem expect a global fetch.
if (typeof globalThis.fetch === 'undefined') {
try {
require('cross-fetch/polyfill')
} catch {
// Node 18+ ships a global fetch; nothing to polyfill.
}
}
// crypto.randomUUID for environments that lack it.
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = require('node:crypto')
} else if (typeof globalThis.crypto.randomUUID !== 'function') {
globalThis.crypto.randomUUID = require('node:crypto').randomUUID
}
// chrome.* extension APIs used by shared wallet code.
if (typeof global.chrome === 'undefined') {
global.chrome = {
storage: {
local: { set: jest.fn(), get: jest.fn(), remove: jest.fn() },
session: { set: jest.fn(), get: jest.fn(), remove: jest.fn() },
},
runtime: {
getURL: (path) => `chrome/path/to/${path}`,
onMessage: { addListener: jest.fn(), removeListener: jest.fn() },
},
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"name": "config",
"version": "1.0.0",
"private": true,
"description": "Jest presets + shared test mocks for the Lux Wallet monorepo (jest-expo base).",
"main": "jest/jest-preset.js"
}
@@ -0,0 +1,44 @@
// Shared UI-layer jest mocks. Imported by each package's jest-setup.
// Kept conservative: only the RN primitives that have no jsdom/native
// implementation under jest. Package-specific mocks live in each package's
// own jest-package-mocks.
jest.mock('react-native-safe-area-context', () => ({
useSafeAreaInsets: jest.fn().mockReturnValue({ top: 0, bottom: 0, left: 0, right: 0 }),
useSafeAreaFrame: jest.fn().mockReturnValue({ x: 0, y: 0, width: 0, height: 0 }),
SafeAreaProvider: jest.fn(({ children }) => children),
SafeAreaView: jest.fn(({ children }) => children),
}))
jest.mock('react-native-webview', () => {
const { View } = require('react-native')
return { WebView: View }
})
// Native modules with no jest-usable implementation. Imported at the top of
// each package's jest-setup (before the lux/wallet mocks that pull these in),
// so registering them here makes them active for the whole setup chain.
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter')
jest.mock('react-native-device-info', () =>
require('react-native-device-info/jest/react-native-device-info-mock'),
)
jest.mock('@react-native-async-storage/async-storage', () =>
require('@react-native-async-storage/async-storage/jest/async-storage-mock'),
)
jest.mock('@react-native-community/netinfo', () => ({
...require('@react-native-community/netinfo/jest/netinfo-mock.js'),
NetInfoStateType: {
unknown: 'unknown',
none: 'none',
cellular: 'cellular',
wifi: 'wifi',
bluetooth: 'bluetooth',
ethernet: 'ethernet',
wimax: 'wimax',
vpn: 'vpn',
other: 'other',
},
}))
@@ -0,0 +1,38 @@
/**
* Common mocks for the utilities layer. Imported by each package's jest-setup.
* The published `@l.x/utils` package does not ship its jest mocks, so the
* shared copy lives here (matches the upstream `utilities/jest-package-mocks`).
*
* Notes:
* * Try not to add test-specific mocks here.
* * Be wary of import order.
* * mocks can be overridden per-package.
*/
const util = require('util')
global.TextEncoder = global.TextEncoder ?? util.TextEncoder
global.TextDecoder = global.TextDecoder ?? util.TextDecoder
jest.mock('expo-localization', () => ({
getLocales: () => [
{
languageCode: 'en',
languageTag: 'en-US',
regionCode: null,
currencyCode: null,
currencySymbol: null,
decimalSeparator: null,
digitGroupingSeparator: null,
textDirection: null,
measurementSystem: null,
temperatureUnit: null,
},
],
}))
jest.mock('@datadog/browser-logs', () => ({
datadogLogs: {
// intentionally empty — datadog must be inert under test
logger: {},
},
}))
+4 -4
View File
@@ -77,10 +77,10 @@ jest.mock('@l.x/utils/src/device/locales', () => {
return jest.requireActual('@l.x/utils/src/device/locales.native.ts')
})
// Mock getConfig to use native implementation
// Force getConfig to the native implementation while preserving the rest of
// the config surface (brand, getGatewayUrl, getWsUrl, …) that @l.x/api needs.
jest.mock('@luxexchange/config', () => {
const actual = jest.requireActual('@luxexchange/config')
const { getConfig } = jest.requireActual('@luxexchange/config/src/getConfig.native')
return {
getConfig
}
return { ...actual, getConfig }
})
+13 -2
View File
@@ -25,11 +25,22 @@ module.exports = {
// avoid native because wallet tests assume no .native.ts
platforms: ['web', 'ios', 'android'],
},
// Override moduleFileExtensions to NOT prioritize .web.ts for native tests
// This ensures wallet tests use moti animations from index.ts, not CSS from index.web.ts
// Native-first resolution: `.ios`/`.native` platform splits win over the base
// file, but `.web` is never consulted (wallet tests run against the native
// bundle — e.g. moti animations, not the CSS web variants). This is required
// so platform-split stubs like `@l.x/utils/src/environment/env.ts` resolve to
// their real `env.native.ts` implementation instead of throwing.
moduleFileExtensions: [
'ios.ts',
'ios.tsx',
'native.ts',
'native.tsx',
'ts',
'tsx',
'ios.js',
'ios.jsx',
'native.js',
'native.jsx',
'js',
'jsx',
'json',