@luxfi/ui 7.4.0 → 7.4.2
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/dist/avatar.cjs +7 -6
- package/dist/avatar.js +7 -5
- package/dist/badge.cjs +30 -32
- package/dist/badge.js +30 -32
- package/dist/bank.d.cts +3 -3
- package/dist/bank.d.ts +3 -3
- package/dist/checkbox.cjs +4 -4
- package/dist/checkbox.d.cts +3 -2
- package/dist/checkbox.d.ts +3 -2
- package/dist/checkbox.js +5 -4
- package/dist/chrome.cjs +950 -0
- package/dist/chrome.d.cts +93 -0
- package/dist/chrome.d.ts +93 -0
- package/dist/chrome.js +921 -0
- package/dist/drawer.cjs +86 -20
- package/dist/drawer.js +85 -19
- package/dist/expiration-selector.cjs +3 -2
- package/dist/expiration-selector.js +3 -2
- package/dist/greeks-display.cjs +6 -6
- package/dist/greeks-display.js +6 -6
- package/dist/gui.cjs +13 -0
- package/dist/gui.d.cts +2 -0
- package/dist/gui.d.ts +2 -0
- package/dist/gui.js +2 -0
- package/dist/heading.cjs +4 -2
- package/dist/heading.js +4 -2
- package/dist/iam.cjs +206 -0
- package/dist/iam.d.cts +65 -0
- package/dist/iam.d.ts +65 -0
- package/dist/iam.js +201 -0
- package/dist/icons.cjs +13 -0
- package/dist/icons.d.cts +1 -0
- package/dist/icons.d.ts +1 -0
- package/dist/icons.js +2 -0
- package/dist/identity.cjs +420 -0
- package/dist/identity.d.cts +64 -0
- package/dist/identity.d.ts +64 -0
- package/dist/identity.js +398 -0
- package/dist/index.cjs +1597 -833
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +1574 -828
- package/dist/input.cjs +3 -1
- package/dist/input.d.cts +3 -5
- package/dist/input.d.ts +3 -5
- package/dist/input.js +3 -1
- package/dist/lux.config.cjs +23 -2
- package/dist/lux.config.d.cts +28 -10
- package/dist/lux.config.d.ts +28 -10
- package/dist/lux.config.js +23 -2
- package/dist/menu.cjs +4 -4
- package/dist/menu.js +4 -4
- package/dist/next.cjs +99 -0
- package/dist/next.d.cts +29 -0
- package/dist/next.d.ts +29 -0
- package/dist/next.js +96 -0
- package/dist/option-chain.cjs +1 -1
- package/dist/option-chain.js +1 -1
- package/dist/option-position.cjs +2 -1
- package/dist/option-position.js +2 -1
- package/dist/pnl-diagram.cjs +8 -6
- package/dist/pnl-diagram.js +8 -6
- package/dist/progress.cjs +7 -6
- package/dist/progress.js +7 -5
- package/dist/provider.cjs +136 -4
- package/dist/provider.d.cts +15 -3
- package/dist/provider.d.ts +15 -3
- package/dist/provider.js +136 -5
- package/dist/radio.cjs +9 -7
- package/dist/radio.js +10 -7
- package/dist/separator.cjs +3 -1
- package/dist/separator.js +3 -1
- package/dist/slider.cjs +28 -16
- package/dist/slider.js +28 -15
- package/dist/strategy-builder.cjs +2 -1
- package/dist/strategy-builder.js +2 -1
- package/dist/switch.cjs +11 -12
- package/dist/switch.js +12 -12
- package/dist/tag.cjs +31 -33
- package/dist/tag.js +30 -32
- package/dist/textarea.cjs +3 -1
- package/dist/textarea.js +3 -1
- package/dist/tooltip.cjs +25 -27
- package/dist/tooltip.js +24 -26
- package/dist/use-narrow.cjs +46 -0
- package/dist/use-narrow.d.cts +12 -0
- package/dist/use-narrow.d.ts +12 -0
- package/dist/use-narrow.js +20 -0
- package/dist/vite.cjs +40 -0
- package/dist/vite.d.cts +29 -0
- package/dist/vite.d.ts +29 -0
- package/dist/vite.js +38 -0
- package/dist/white-label.cjs +132 -0
- package/dist/white-label.d.cts +59 -0
- package/dist/white-label.d.ts +59 -0
- package/dist/white-label.js +124 -0
- package/package.json +85 -19
- package/src/avatar.tsx +22 -16
- package/src/checkbox.tsx +15 -10
- package/src/chrome.tsx +459 -0
- package/src/drawer.tsx +83 -10
- package/src/expiration-selector.tsx +3 -2
- package/src/greeks-display.tsx +9 -6
- package/src/gui.ts +17 -0
- package/src/heading.tsx +12 -8
- package/src/iam.ts +170 -0
- package/src/icons.ts +18 -0
- package/src/identity.tsx +318 -0
- package/src/index.ts +44 -1
- package/src/input.tsx +13 -9
- package/src/lux.config.ts +16 -15
- package/src/menu.tsx +4 -4
- package/src/next.ts +142 -0
- package/src/option-chain.tsx +1 -1
- package/src/option-position.tsx +2 -1
- package/src/pnl-diagram.tsx +11 -6
- package/src/progress.tsx +15 -8
- package/src/provider.tsx +48 -7
- package/src/radio.tsx +15 -11
- package/src/separator.tsx +8 -3
- package/src/slider.tsx +35 -19
- package/src/strategy-builder.tsx +3 -2
- package/src/switch.tsx +17 -16
- package/src/textarea.tsx +8 -4
- package/src/tooltip.tsx +2 -21
- package/src/use-narrow.ts +40 -0
- package/src/vite.ts +78 -0
- package/src/white-label.ts +240 -0
- package/tokens.css +544 -319
- package/src/tokens.css +0 -438
package/src/vite.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// The bundler wiring the gui engine needs on web, as ONE plugin.
|
|
2
|
+
//
|
|
3
|
+
// @hanzo/gui is authored against React Native primitives, so a web bundle has to
|
|
4
|
+
// alias `react-native` → `react-native-web`, pre-bundle the CJS-only pieces, keep
|
|
5
|
+
// exactly one physical copy of React and of the engine, and define the platform
|
|
6
|
+
// flags the engine reads at module scope. Every Lux surface needs the identical
|
|
7
|
+
// six-part incantation, and every surface that hand-rolled it got a different
|
|
8
|
+
// subset — which is how you end up debugging `createContext of undefined` in one
|
|
9
|
+
// app and a duplicate-React theme context in another.
|
|
10
|
+
//
|
|
11
|
+
// import { luxUi } from '@luxfi/ui/vite'
|
|
12
|
+
// export default defineConfig({ plugins: [react(), luxUi()] })
|
|
13
|
+
//
|
|
14
|
+
// Node-only (it is a build-time module) and dependency-free: it returns a plain
|
|
15
|
+
// Vite plugin object, so it does not force `vite` into anyone's runtime graph.
|
|
16
|
+
|
|
17
|
+
interface LuxUiViteOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Extra packages to keep to a single physical copy. React, the gui engine and
|
|
20
|
+
* TanStack Query are always deduped.
|
|
21
|
+
*/
|
|
22
|
+
readonly dedupe?: ReadonlyArray<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Extra packages to pre-bundle. The engine, react-native-web and the CJS-only
|
|
25
|
+
* colour helper are always included.
|
|
26
|
+
*/
|
|
27
|
+
readonly include?: ReadonlyArray<string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Minimal structural shape of a Vite plugin — avoids a hard `vite` type dep. */
|
|
31
|
+
interface LuxUiVitePlugin {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly config: () => {
|
|
34
|
+
define: Record<string, string>;
|
|
35
|
+
resolve: { alias: Record<string, string>; dedupe: Array<string> };
|
|
36
|
+
optimizeDeps: { include: Array<string> };
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DEDUPE = [
|
|
41
|
+
'react',
|
|
42
|
+
'react-dom',
|
|
43
|
+
'@tanstack/react-query',
|
|
44
|
+
'@hanzo/gui',
|
|
45
|
+
'@hanzogui/core',
|
|
46
|
+
'@hanzogui/web',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const INCLUDE = [
|
|
50
|
+
'react-native-web',
|
|
51
|
+
'@react-native/normalize-color',
|
|
52
|
+
'@hanzo/gui',
|
|
53
|
+
'@hanzogui/core',
|
|
54
|
+
'@luxfi/ui',
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
export function luxUi(options: LuxUiViteOptions = {}): LuxUiVitePlugin {
|
|
58
|
+
return {
|
|
59
|
+
name: '@luxfi/ui',
|
|
60
|
+
config: () => ({
|
|
61
|
+
// The engine branches on these at module scope; without them it takes the
|
|
62
|
+
// native path in a browser bundle.
|
|
63
|
+
define: {
|
|
64
|
+
'process.env.EXPO_OS': JSON.stringify('web'),
|
|
65
|
+
'process.env.IS_WEB': JSON.stringify('true'),
|
|
66
|
+
},
|
|
67
|
+
resolve: {
|
|
68
|
+
alias: { 'react-native': 'react-native-web' },
|
|
69
|
+
dedupe: [ ...new Set([ ...DEDUPE, ...(options.dedupe ?? []) ]) ],
|
|
70
|
+
},
|
|
71
|
+
optimizeDeps: {
|
|
72
|
+
include: [ ...new Set([ ...INCLUDE, ...(options.include ?? []) ]) ],
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type { LuxUiViteOptions };
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// White-label resolution — BY HOSTNAME, never per deployment.
|
|
2
|
+
//
|
|
3
|
+
// One image, many brands. Brand, gui theme row, IAM client id and OIDC issuer
|
|
4
|
+
// are all a pure function of the Host header, so the same container serves
|
|
5
|
+
// lux.cloud, zoo.network, hanzo.ai and pars.id without a rebuild, an env var or
|
|
6
|
+
// a per-deployment override. Nothing here reads process.env.
|
|
7
|
+
//
|
|
8
|
+
// This module is VALUES ONLY (no React, no DOM) so it resolves identically in
|
|
9
|
+
// three places that must agree:
|
|
10
|
+
// - the Next/SSR server, from `req.headers.host`
|
|
11
|
+
// - the browser, from `location.host`
|
|
12
|
+
// - an edge/middleware rewrite, from the incoming URL
|
|
13
|
+
//
|
|
14
|
+
// Logos, SEO copy and marketing palettes live in @luxfi/brand. This is the
|
|
15
|
+
// runtime identity the UI layer needs and nothing more.
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Branding = VALUE, not place.
|
|
19
|
+
// The ONE spot brand hex is allowed to live (project rule: never hardcode hex
|
|
20
|
+
// in components). It lives HERE, beside the identity table it colours, rather
|
|
21
|
+
// than in ./lux.config — that module builds the gui engine, and an identity
|
|
22
|
+
// value that drags a Tamagui config behind it cannot be read by a server
|
|
23
|
+
// component, a route handler or the `@luxfi/ui/iam` client. lux.config imports
|
|
24
|
+
// these; nothing imports lux.config to get them.
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
export const LUX_BRAND = {
|
|
27
|
+
lux: '#7000FF',
|
|
28
|
+
zoo: '#6C5EFB',
|
|
29
|
+
hanzo: '#EA580C',
|
|
30
|
+
pars: '#1C3879',
|
|
31
|
+
// bootno.de is its own white label with its own IdP (id.bootno.de) — accent
|
|
32
|
+
// taken from the bootnode console's own brand default, not invented here.
|
|
33
|
+
bootnode: '#3B82F6',
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
export const PARS_GOLD = '#C8A45C';
|
|
37
|
+
|
|
38
|
+
export type LuxBrand = keyof typeof LUX_BRAND;
|
|
39
|
+
|
|
40
|
+
export type Org = LuxBrand;
|
|
41
|
+
|
|
42
|
+
export interface OrgIdentity {
|
|
43
|
+
/** Org id — also the gui child-theme suffix (`dark_lux`, `dark_zoo`, …). */
|
|
44
|
+
readonly org: Org;
|
|
45
|
+
/** Display name for chrome (header, title, sign-in copy). */
|
|
46
|
+
readonly name: string;
|
|
47
|
+
/** Canonical apex domain. */
|
|
48
|
+
readonly domain: string;
|
|
49
|
+
/** IAM/OIDC host. The issuer is `https://` + this. */
|
|
50
|
+
readonly iamDomain: string;
|
|
51
|
+
/** Brand accent hex — the same value the gui child-theme row is built from. */
|
|
52
|
+
readonly accent: string;
|
|
53
|
+
/** Foreground used on top of the accent. */
|
|
54
|
+
readonly accentForeground: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// The ONE table. Every hostname in the fleet resolves into one of these rows.
|
|
58
|
+
const ORGS: Readonly<Record<Org, OrgIdentity>> = {
|
|
59
|
+
lux: {
|
|
60
|
+
org: 'lux',
|
|
61
|
+
name: 'Lux',
|
|
62
|
+
domain: 'lux.network',
|
|
63
|
+
iamDomain: 'lux.id',
|
|
64
|
+
accent: LUX_BRAND.lux,
|
|
65
|
+
accentForeground: '#FFFFFF',
|
|
66
|
+
},
|
|
67
|
+
zoo: {
|
|
68
|
+
org: 'zoo',
|
|
69
|
+
name: 'Zoo',
|
|
70
|
+
domain: 'zoo.ngo',
|
|
71
|
+
// Zoo's IdP is `id.zoo.network`, not a `zoo.id` apex — the one row in this
|
|
72
|
+
// table where the issuer is not `<org>.id`, and the one every hand-rolled
|
|
73
|
+
// per-app branding map got wrong.
|
|
74
|
+
iamDomain: 'id.zoo.network',
|
|
75
|
+
accent: LUX_BRAND.zoo,
|
|
76
|
+
accentForeground: '#FFFFFF',
|
|
77
|
+
},
|
|
78
|
+
bootnode: {
|
|
79
|
+
org: 'bootnode',
|
|
80
|
+
name: 'Bootnode',
|
|
81
|
+
domain: 'bootno.de',
|
|
82
|
+
iamDomain: 'id.bootno.de',
|
|
83
|
+
accent: LUX_BRAND.lux,
|
|
84
|
+
accentForeground: '#FFFFFF',
|
|
85
|
+
},
|
|
86
|
+
hanzo: {
|
|
87
|
+
org: 'hanzo',
|
|
88
|
+
name: 'Hanzo',
|
|
89
|
+
domain: 'hanzo.ai',
|
|
90
|
+
iamDomain: 'hanzo.id',
|
|
91
|
+
accent: LUX_BRAND.hanzo,
|
|
92
|
+
accentForeground: '#FFFFFF',
|
|
93
|
+
},
|
|
94
|
+
pars: {
|
|
95
|
+
org: 'pars',
|
|
96
|
+
name: 'Pars',
|
|
97
|
+
domain: 'pars.id',
|
|
98
|
+
iamDomain: 'pars.id',
|
|
99
|
+
accent: LUX_BRAND.pars,
|
|
100
|
+
accentForeground: PARS_GOLD,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Registrable domains that belong to each org. Matched against the hostname
|
|
105
|
+
// SUFFIX on a label boundary, so `mpc.lux.cloud` and `lux.cloud` both hit `lux`
|
|
106
|
+
// while `notlux.cloud` does not.
|
|
107
|
+
//
|
|
108
|
+
// The third slot names the app at the domain's APEX. It is usually derivable
|
|
109
|
+
// (`lux.cloud` → `cloud` → client `lux-cloud`), so it is only written where the
|
|
110
|
+
// registered client says otherwise — `bootno.de` is `bootnode-platform`, not
|
|
111
|
+
// `bootnode-de`. A client id is a registration, not a guess.
|
|
112
|
+
const DOMAIN_ORG: ReadonlyArray<readonly [string, Org, string?]> = [
|
|
113
|
+
[ 'lux.network', 'lux' ],
|
|
114
|
+
[ 'lux.cloud', 'lux' ],
|
|
115
|
+
[ 'lux.id', 'lux' ],
|
|
116
|
+
[ 'lux.finance', 'lux' ],
|
|
117
|
+
[ 'zoo.ngo', 'zoo' ],
|
|
118
|
+
[ 'zoo.network', 'zoo' ],
|
|
119
|
+
[ 'zoo.cloud', 'zoo' ],
|
|
120
|
+
[ 'zoo.id', 'zoo' ],
|
|
121
|
+
[ 'hanzo.ai', 'hanzo' ],
|
|
122
|
+
[ 'hanzo.cloud', 'hanzo' ],
|
|
123
|
+
[ 'hanzo.id', 'hanzo' ],
|
|
124
|
+
[ 'pars.id', 'pars' ],
|
|
125
|
+
[ 'parsdao.org', 'pars' ],
|
|
126
|
+
[ 'bootno.de', 'bootnode', 'platform' ],
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
export const DEFAULT_ORG: Org = 'lux';
|
|
130
|
+
|
|
131
|
+
export interface WhiteLabel extends OrgIdentity {
|
|
132
|
+
/** Hostname the identity was resolved from, port stripped, lowercased. */
|
|
133
|
+
readonly host: string;
|
|
134
|
+
/** App slug taken from the hostname — `mpc.lux.cloud` → `mpc`. */
|
|
135
|
+
readonly app: string;
|
|
136
|
+
/** gui child-theme row to hand GuiProvider — `dark_lux`, `dark_zoo`, … */
|
|
137
|
+
readonly theme: string;
|
|
138
|
+
/** OIDC issuer — `https://lux.id`. */
|
|
139
|
+
readonly issuer: string;
|
|
140
|
+
/** IAM client id, `<org>-<app>` per the fleet naming scheme — `lux-mpc`. */
|
|
141
|
+
readonly clientId: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Strip the port and any trailing dot, lowercase. `LUX.cloud:3000` → `lux.cloud`. */
|
|
145
|
+
function normalizeHost(host: string): string {
|
|
146
|
+
const noPort = host.trim().toLowerCase().split(':')[0] ?? '';
|
|
147
|
+
return noPort.replace(/\.$/, '');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** true when `host` is `domain` or a subdomain of it (label boundary respected). */
|
|
151
|
+
function isUnder(host: string, domain: string): boolean {
|
|
152
|
+
return host === domain || host.endsWith(`.${ domain }`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The registrable domain this host sits under, or undefined for unknown hosts. */
|
|
156
|
+
function matchDomain(host: string): readonly [string, Org, string?] | undefined {
|
|
157
|
+
// Longest domain first so `zoo.network` wins over a hypothetical `network`.
|
|
158
|
+
let best: readonly [string, Org, string?] | undefined;
|
|
159
|
+
for (const entry of DOMAIN_ORG) {
|
|
160
|
+
if (isUnder(host, entry[0]) && (!best || entry[0].length > best[0].length)) {
|
|
161
|
+
best = entry;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return best;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* App slug for the IAM client id.
|
|
169
|
+
*
|
|
170
|
+
* `mpc.lux.cloud` → `mpc` (leftmost label)
|
|
171
|
+
* `lux.cloud` → `cloud` (apex: the service name, not the org)
|
|
172
|
+
* `www.lux.network`→ `network` (www is chrome, not an app)
|
|
173
|
+
* `localhost` → `local`
|
|
174
|
+
*/
|
|
175
|
+
function appSlug(host: string, domain: string, apexApp?: string): string {
|
|
176
|
+
const sub = host === domain ? '' : host.slice(0, -(domain.length + 1));
|
|
177
|
+
const leftmost = sub.split('.')[0] ?? '';
|
|
178
|
+
if (leftmost && leftmost !== 'www') return leftmost;
|
|
179
|
+
// Apex (or www) — the registered name when the table gives one, else the
|
|
180
|
+
// domain's own service label.
|
|
181
|
+
if (apexApp) return apexApp;
|
|
182
|
+
const label = domain.split('.')[0] ?? '';
|
|
183
|
+
const tld = domain.split('.').slice(1).join('.');
|
|
184
|
+
// `lux.network` → `network`, `lux.cloud` → `cloud`, `pars.id` → `id`.
|
|
185
|
+
return tld.split('.')[0] || label;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Loopback / LAN / *.local hosts a developer actually types. */
|
|
189
|
+
function isLocal(host: string): boolean {
|
|
190
|
+
return (
|
|
191
|
+
host === 'localhost' ||
|
|
192
|
+
host.endsWith('.localhost') ||
|
|
193
|
+
host === '127.0.0.1' ||
|
|
194
|
+
host === '0.0.0.0' ||
|
|
195
|
+
host === '[::1]' ||
|
|
196
|
+
host.endsWith('.local')
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Resolve the full white-label identity from a Host header value.
|
|
202
|
+
*
|
|
203
|
+
* Pure and total: an unknown or missing host falls back to the Lux row rather
|
|
204
|
+
* than throwing, so a preview URL or a health probe never blanks the UI.
|
|
205
|
+
*
|
|
206
|
+
* resolveWhiteLabel('mpc.lux.cloud') // org lux, clientId lux-mpc, issuer https://lux.id
|
|
207
|
+
* resolveWhiteLabel('zoo.network') // org zoo, clientId zoo-network, issuer https://zoo.id
|
|
208
|
+
* resolveWhiteLabel('id.pars.id') // org pars, clientId pars-id, issuer https://pars.id
|
|
209
|
+
*/
|
|
210
|
+
export function resolveWhiteLabel(host?: string | null): WhiteLabel {
|
|
211
|
+
const h = normalizeHost(host ?? '');
|
|
212
|
+
const match = h ? matchDomain(h) : undefined;
|
|
213
|
+
const org = match ? match[1] : DEFAULT_ORG;
|
|
214
|
+
const identity = ORGS[org];
|
|
215
|
+
const app = match ? appSlug(h, match[0], match[2]) : (h && isLocal(h) ? 'local' : 'app');
|
|
216
|
+
return {
|
|
217
|
+
...identity,
|
|
218
|
+
host: h,
|
|
219
|
+
app,
|
|
220
|
+
theme: `dark_${ org }`,
|
|
221
|
+
issuer: `https://${ identity.iamDomain }`,
|
|
222
|
+
clientId: `${ org }-${ app }`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The current host in a browser, or '' during SSR / prerender.
|
|
228
|
+
* Server code must pass `req.headers.host` to resolveWhiteLabel explicitly —
|
|
229
|
+
* there is no ambient request here, and guessing would bake in a brand.
|
|
230
|
+
*/
|
|
231
|
+
export function currentHost(): string {
|
|
232
|
+
return typeof window === 'undefined' ? '' : window.location.host;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Identity for the org id itself, for the rare surface that is not host-routed. */
|
|
236
|
+
export function orgIdentity(org: Org): OrgIdentity {
|
|
237
|
+
return ORGS[org];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export { ORGS as orgs };
|