@l.x/config 1.0.4 → 1.0.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/LICENSE ADDED
@@ -0,0 +1,122 @@
1
+ Lux Ecosystem License
2
+ Version 1.2, December 2025
3
+
4
+ Copyright (c) 2020-2025 Lux Industries Inc.
5
+ All rights reserved.
6
+
7
+ TECHNOLOGY PORTFOLIO - PATENT APPLICATIONS PLANNED
8
+ Contact: licensing@lux.network
9
+
10
+ ================================================================================
11
+ TERMS AND CONDITIONS
12
+ ================================================================================
13
+
14
+ 1. DEFINITIONS
15
+
16
+ "Lux Primary Network" means the official Lux blockchain with Network ID=1
17
+ and EVM Chain ID=96369.
18
+
19
+ "Authorized Network" means the Lux Primary Network, official testnets/devnets,
20
+ and any L1/L2/L3 chain descending from the Lux Primary Network.
21
+
22
+ "Descending Chain" means an L1/L2/L3 chain built on, anchored to, or deriving
23
+ security from the Lux Primary Network or its authorized testnets.
24
+
25
+ "Research Use" means non-commercial academic research, education, personal
26
+ study, or evaluation purposes.
27
+
28
+ "Commercial Use" means any use in connection with a product or service
29
+ offered for sale or fee, internal use by a for-profit entity, or any use
30
+ to generate revenue.
31
+
32
+ 2. GRANT OF LICENSE
33
+
34
+ Subject to these terms, Lux Industries Inc grants you a non-exclusive,
35
+ royalty-free license to:
36
+
37
+ (a) Use for Research Use without restriction;
38
+
39
+ (b) Operate on the Lux Primary Network (Network ID=1, EVM Chain ID=96369);
40
+
41
+ (c) Operate on official Lux testnets and devnets;
42
+
43
+ (d) Operate L1/L2/L3 chains descending from the Lux Primary Network;
44
+
45
+ (e) Build applications within the Lux ecosystem;
46
+
47
+ (f) Contribute improvements back to the original repositories.
48
+
49
+ 3. RESTRICTIONS
50
+
51
+ Without a commercial license from Lux Industries Inc, you may NOT:
52
+
53
+ (a) Fork the Lux Network or any Lux software;
54
+
55
+ (b) Create competing networks not descending from Lux Primary Network;
56
+
57
+ (c) Use for Commercial Use outside the Lux ecosystem;
58
+
59
+ (d) Sublicense or transfer rights outside the Lux ecosystem;
60
+
61
+ (e) Use to create competing blockchain networks, exchanges, custody
62
+ services, or cryptographic systems outside the Lux ecosystem.
63
+
64
+ 4. NO FORKS POLICY
65
+
66
+ Lux Industries Inc maintains ZERO TOLERANCE for unauthorized forks.
67
+ Any fork or deployment on an unauthorized network constitutes:
68
+
69
+ (a) Breach of this license;
70
+ (b) Grounds for immediate legal action.
71
+
72
+ 5. RIGHTS RESERVATION
73
+
74
+ All rights not explicitly granted are reserved by Lux Industries Inc.
75
+
76
+ We plan to apply for patent protection for the technology in this
77
+ repository. Any implementation outside the Lux ecosystem may require
78
+ a separate commercial license.
79
+
80
+ 6. DISCLAIMER OF WARRANTY
81
+
82
+ THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
83
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
84
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
85
+
86
+ 7. LIMITATION OF LIABILITY
87
+
88
+ IN NO EVENT SHALL LUX INDUSTRIES INC BE LIABLE FOR ANY CLAIM, DAMAGES
89
+ OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
90
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE.
91
+
92
+ 8. TERMINATION
93
+
94
+ This license terminates immediately upon any breach, including but not
95
+ limited to deployment on unauthorized networks or creation of forks.
96
+
97
+ 9. GOVERNING LAW
98
+
99
+ This License shall be governed by the laws of the State of Delaware.
100
+
101
+ 10. COMMERCIAL LICENSING
102
+
103
+ For commercial use outside the Lux ecosystem:
104
+
105
+ Lux Industries Inc.
106
+ Email: licensing@lux.network
107
+ Subject: Commercial License Request
108
+
109
+ ================================================================================
110
+ TL;DR
111
+ ================================================================================
112
+
113
+ - Research/academic use = OK
114
+ - Lux Primary Network (Network ID=1, Chain ID=96369) = OK
115
+ - L1/L2/L3 chains descending from Lux Primary Network = OK
116
+ - Commercial products outside Lux ecosystem = Contact licensing@lux.network
117
+ - Forks = Absolutely not
118
+
119
+ ================================================================================
120
+
121
+ See LP-0012 for full licensing documentation:
122
+ https://github.com/luxfi/lps/blob/main/LPs/lp-0012-ecosystem-licensing.md
@@ -20,6 +20,9 @@ describe('BrandConfig interface completeness', () => {
20
20
  'title',
21
21
  'description',
22
22
  'legalEntity',
23
+ 'walletName',
24
+ 'protocolName',
25
+ 'copyrightHolder',
23
26
  'appDomain',
24
27
  'docsDomain',
25
28
  'infoDomain',
@@ -318,4 +321,65 @@ describe('loadBrandConfig()', () => {
318
321
  expect(brand.faviconUrl).toBe('/favicon.ico')
319
322
  expect(brand.primaryColor).toBe('#FC72FF')
320
323
  })
324
+
325
+ it('derives walletName from name when not explicitly set', async () => {
326
+ vi.stubGlobal(
327
+ 'fetch',
328
+ vi.fn().mockResolvedValue({
329
+ ok: true,
330
+ json: async () => ({
331
+ brand: { name: 'Zoo Exchange' },
332
+ chains: { defaultChainId: 200200, supported: [200200] },
333
+ rpc: {},
334
+ api: { graphql: '', gateway: '', insights: '' },
335
+ walletConnect: { projectId: '' },
336
+ }),
337
+ }),
338
+ )
339
+
340
+ await loadBrandConfig()
341
+
342
+ expect(brand.walletName).toBe('Zoo Wallet')
343
+ expect(brand.protocolName).toBe('Zoo Protocol')
344
+ })
345
+
346
+ it('uses explicit walletName over derived value', async () => {
347
+ vi.stubGlobal(
348
+ 'fetch',
349
+ vi.fn().mockResolvedValue({
350
+ ok: true,
351
+ json: async () => ({
352
+ brand: { name: 'Zoo Exchange', walletName: 'Custom Wallet' },
353
+ chains: { defaultChainId: 200200, supported: [200200] },
354
+ rpc: {},
355
+ api: { graphql: '', gateway: '', insights: '' },
356
+ walletConnect: { projectId: '' },
357
+ }),
358
+ }),
359
+ )
360
+
361
+ await loadBrandConfig()
362
+
363
+ expect(brand.walletName).toBe('Custom Wallet')
364
+ })
365
+
366
+ it('derives copyrightHolder from legalEntity when not set', async () => {
367
+ vi.stubGlobal(
368
+ 'fetch',
369
+ vi.fn().mockResolvedValue({
370
+ ok: true,
371
+ json: async () => ({
372
+ brand: { name: 'Zoo Exchange', legalEntity: 'Zoo Labs Foundation' },
373
+ chains: { defaultChainId: 200200, supported: [200200] },
374
+ rpc: {},
375
+ api: { graphql: '', gateway: '', insights: '' },
376
+ walletConnect: { projectId: '' },
377
+ }),
378
+ }),
379
+ )
380
+
381
+ await loadBrandConfig()
382
+
383
+ expect(brand.copyrightHolder).toBe('Zoo Labs Foundation')
384
+ })
321
385
  })
package/package.json CHANGED
@@ -1,20 +1,26 @@
1
1
  {
2
2
  "name": "@l.x/config",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "dependencies": {
5
5
  "react-native-dotenv": "3.2.0",
6
- "@luxfi/utilities": "workspace:^"
6
+ "@luxfi/utilities": "^1.0.6"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@types/node": "22.13.1",
10
10
  "@typescript/native-preview": "7.0.0-dev.20260311.1",
11
- "@luxfi/eslint-config": "workspace:^",
12
11
  "depcheck": "1.4.7",
13
12
  "eslint": "8.57.1",
14
13
  "jsdom": "^26.1.0",
15
14
  "typescript": "5.8.3",
16
- "vitest": "^4.0.16"
15
+ "vitest": "^4.0.16",
16
+ "@luxfi/eslint-config": "^1.0.6"
17
17
  },
18
+ "nx": {
19
+ "includedScripts": []
20
+ },
21
+ "main": "src/index.ts",
22
+ "private": false,
23
+ "sideEffects": false,
18
24
  "scripts": {
19
25
  "typecheck": "nx typecheck config",
20
26
  "typecheck:tsgo": "nx typecheck:tsgo config",
@@ -26,11 +32,5 @@
26
32
  "lint:eslint:fix": "nx lint:eslint:fix config",
27
33
  "test": "vitest run",
28
34
  "check:deps:usage": "nx check:deps:usage config"
29
- },
30
- "nx": {
31
- "includedScripts": []
32
- },
33
- "main": "src/index.ts",
34
- "private": false,
35
- "sideEffects": false
35
+ }
36
36
  }
package/src/brand.ts CHANGED
@@ -10,14 +10,45 @@
10
10
  *
11
11
  * For zoo.exchange: mount a ConfigMap with Zoo branding over /config.json
12
12
  * For any L2: same image, different ConfigMap
13
+ *
14
+ * KMS integration: set KMS_BRAND_SECRET env var to load brand config from
15
+ * KMS (Infisical) instead of a ConfigMap. The secret should contain the
16
+ * full RuntimeConfig JSON. The /config.json endpoint in the serving layer
17
+ * should proxy to KMS when this env var is set.
13
18
  */
14
19
 
20
+ /** Theme color overrides applied on top of the default dark/light themes */
21
+ export interface BrandTheme {
22
+ /** Primary accent color (buttons, links) */
23
+ accent1?: string
24
+ /** Background color */
25
+ surface1?: string
26
+ /** Secondary surface */
27
+ surface2?: string
28
+ /** Tertiary surface */
29
+ surface3?: string
30
+ /** Primary text color */
31
+ neutral1?: string
32
+ /** Secondary text color */
33
+ neutral2?: string
34
+ /** Success status color */
35
+ statusSuccess?: string
36
+ /** Critical/error status color */
37
+ statusCritical?: string
38
+ }
39
+
15
40
  export interface BrandConfig {
16
41
  name: string
17
42
  title: string
18
43
  description: string
19
44
  /** Legal entity name for Terms/Privacy, e.g. "Lux Industries Inc." */
20
45
  legalEntity: string
46
+ /** Wallet product name, e.g. "Zoo Wallet" or "Lux Wallet" */
47
+ walletName: string
48
+ /** Protocol product name, e.g. "Zoo Protocol" or "Lux Protocol" */
49
+ protocolName: string
50
+ /** Copyright holder name, e.g. "Zoo Labs Foundation" */
51
+ copyrightHolder: string
21
52
  appDomain: string
22
53
  docsDomain: string
23
54
  infoDomain: string
@@ -40,6 +71,11 @@ export interface BrandConfig {
40
71
  walletConnectProjectId: string
41
72
  insightsHost: string
42
73
  insightsApiKey: string
74
+ /** Theme color overrides for dark and light modes */
75
+ theme?: {
76
+ light?: BrandTheme
77
+ dark?: BrandTheme
78
+ }
43
79
  }
44
80
 
45
81
  export interface RuntimeConfig {
@@ -66,6 +102,9 @@ export const brand: BrandConfig = {
66
102
  title: '',
67
103
  description: '',
68
104
  legalEntity: '',
105
+ walletName: '',
106
+ protocolName: '',
107
+ copyrightHolder: '',
69
108
  appDomain: '',
70
109
  docsDomain: '',
71
110
  infoDomain: '',
@@ -97,6 +136,10 @@ export let runtimeConfig: RuntimeConfig | null = null
97
136
  * Load brand config from /config.json. Call once before React renders.
98
137
  * The config.json is either the default shipped in the image, or a
99
138
  * ConfigMap mounted by K8s for white-label deployments.
139
+ *
140
+ * KMS integration: when the serving layer sets KMS_BRAND_SECRET, it should
141
+ * proxy /config.json to fetch the secret value from KMS (Infisical). The
142
+ * SPA itself always fetches /config.json — KMS resolution is server-side.
100
143
  */
101
144
  export async function loadBrandConfig(): Promise<RuntimeConfig> {
102
145
  try {
@@ -109,6 +152,17 @@ export async function loadBrandConfig(): Promise<RuntimeConfig> {
109
152
  Object.assign(brand, config.brand)
110
153
  }
111
154
 
155
+ // Derive convenience fields from name if not explicitly set
156
+ if (!brand.walletName && brand.name) {
157
+ brand.walletName = brand.name.replace(/\s*exchange\s*/i, '') + ' Wallet'
158
+ }
159
+ if (!brand.protocolName && brand.name) {
160
+ brand.protocolName = brand.name.replace(/\s*exchange\s*/i, '') + ' Protocol'
161
+ }
162
+ if (!brand.copyrightHolder) {
163
+ brand.copyrightHolder = brand.legalEntity
164
+ }
165
+
112
166
  // Apply chain config
113
167
  if (config.chains) {
114
168
  brand.defaultChainId = config.chains.defaultChainId ?? brand.defaultChainId
@@ -125,9 +179,17 @@ export async function loadBrandConfig(): Promise<RuntimeConfig> {
125
179
  brand.insightsHost = config.api.insights
126
180
  }
127
181
 
128
- // Update document title
129
- if (typeof document !== 'undefined' && config.brand?.title) {
130
- document.title = config.brand.title
182
+ // Update document title and favicon
183
+ if (typeof document !== 'undefined') {
184
+ if (config.brand?.title) {
185
+ document.title = config.brand.title
186
+ }
187
+ if (config.brand?.faviconUrl) {
188
+ const link = document.querySelector("link[rel*='icon']") as HTMLLinkElement | null
189
+ if (link) {
190
+ link.href = config.brand.faviconUrl
191
+ }
192
+ }
131
193
  }
132
194
 
133
195
  runtimeConfig = config
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export type { Config } from './config-types'
2
2
  export { getConfig } from './getConfig'
3
- export { brand, getBrandUrl, getDocsUrl, getGatewayUrl, getWsUrl } from './brand'
4
- export type { BrandConfig } from './brand'
3
+ export { brand, loadBrandConfig, getBrandUrl, getDocsUrl, getGatewayUrl, getWsUrl } from './brand'
4
+ export type { BrandConfig, BrandTheme } from './brand'