@treasuryspatial/surface-kit 0.1.9 → 0.1.16
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/index.d.ts +162 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +552 -48
- package/dist/server.d.ts +24 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +487 -131
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,300 @@
|
|
|
1
|
-
import { DEFAULT_COMPOSER_SURFACE_MODE_POLICY, mergeSurfaceModePolicy } from '@treasuryspatial/mode-policy';
|
|
1
|
+
import { DEFAULT_COMPOSER_SURFACE_MODE_POLICY, mergeSurfaceModePolicy, resolveModeLaunchState, } from '@treasuryspatial/mode-policy';
|
|
2
|
+
export const orderSurfaceModeTabs = (tabs) => {
|
|
3
|
+
const seen = new Set();
|
|
4
|
+
return tabs.filter((tab) => {
|
|
5
|
+
const key = `${tab.id}:${tabs.indexOf(tab)}`;
|
|
6
|
+
if (seen.has(key))
|
|
7
|
+
return false;
|
|
8
|
+
seen.add(key);
|
|
9
|
+
return true;
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
const hasDefinedKeys = (value) => Boolean(value && Object.values(value).some((entry) => entry !== undefined));
|
|
13
|
+
const compactRecord = (value) => Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
14
|
+
const mergeSurfaceComposerTopbar = (base, override) => {
|
|
15
|
+
const contexts = base?.contexts || override?.contexts
|
|
16
|
+
? ['landing', 'login', 'composer', 'admin'].reduce((acc, context) => {
|
|
17
|
+
const mergedContext = {
|
|
18
|
+
...(base?.contexts?.[context] ?? {}),
|
|
19
|
+
...(override?.contexts?.[context] ?? {}),
|
|
20
|
+
};
|
|
21
|
+
if (hasDefinedKeys(mergedContext)) {
|
|
22
|
+
acc[context] = mergedContext;
|
|
23
|
+
}
|
|
24
|
+
return acc;
|
|
25
|
+
}, {})
|
|
26
|
+
: undefined;
|
|
27
|
+
const merged = {
|
|
28
|
+
...(base ?? {}),
|
|
29
|
+
...(override ?? {}),
|
|
30
|
+
...(contexts && hasDefinedKeys(contexts) ? { contexts } : {}),
|
|
31
|
+
};
|
|
32
|
+
return hasDefinedKeys(merged) ? merged : undefined;
|
|
33
|
+
};
|
|
34
|
+
const hasEntries = (value) => Boolean(value && Object.keys(value).length > 0);
|
|
35
|
+
export const buildClientSkinControlPlaneWarnings = (surfaceLabel, runtimeSource, isClientSkinnedSurface) => {
|
|
36
|
+
if (!isClientSkinnedSurface)
|
|
37
|
+
return [];
|
|
38
|
+
const warnings = [];
|
|
39
|
+
if (runtimeSource?.modeTabs?.length) {
|
|
40
|
+
warnings.push(`${surfaceLabel}: modeTabs are control-plane policy and must live in composer_data.`);
|
|
41
|
+
}
|
|
42
|
+
if (runtimeSource?.routePolicy) {
|
|
43
|
+
warnings.push(`${surfaceLabel}: routePolicy is control-plane policy and must live in composer_data.`);
|
|
44
|
+
}
|
|
45
|
+
if (runtimeSource?.runtime) {
|
|
46
|
+
warnings.push(`${surfaceLabel}: runtime/toolset/prompt-pack policy is control-plane data and must live in composer_data.`);
|
|
47
|
+
}
|
|
48
|
+
if (runtimeSource?.featureFlags) {
|
|
49
|
+
warnings.push(`${surfaceLabel}: featureFlags are control-plane policy and must live in composer_data.`);
|
|
50
|
+
}
|
|
51
|
+
return warnings;
|
|
52
|
+
};
|
|
53
|
+
export const buildSurfaceTenantUiComposerSeed = (manifest) => {
|
|
54
|
+
if (!manifest)
|
|
55
|
+
return null;
|
|
56
|
+
const typographyCandidate = manifest.theme?.typography
|
|
57
|
+
? {
|
|
58
|
+
fontFamily: manifest.theme.typography.fontFamily,
|
|
59
|
+
weights: manifest.theme.typography.weights,
|
|
60
|
+
}
|
|
61
|
+
: undefined;
|
|
62
|
+
const typography = typographyCandidate && hasDefinedKeys(typographyCandidate)
|
|
63
|
+
? compactRecord(typographyCandidate)
|
|
64
|
+
: undefined;
|
|
65
|
+
const topbarCandidate = manifest.topbar
|
|
66
|
+
? {
|
|
67
|
+
title: manifest.topbar.title,
|
|
68
|
+
subtitle: manifest.topbar.subtitle,
|
|
69
|
+
productLabel: manifest.topbar.productLabel,
|
|
70
|
+
productSuffixLabel: manifest.topbar.productSuffixLabel,
|
|
71
|
+
links: manifest.topbar.links,
|
|
72
|
+
contexts: manifest.topbar.contexts,
|
|
73
|
+
}
|
|
74
|
+
: undefined;
|
|
75
|
+
const topbar = topbarCandidate && hasDefinedKeys(topbarCandidate)
|
|
76
|
+
? compactRecord(topbarCandidate)
|
|
77
|
+
: undefined;
|
|
78
|
+
const seed = {
|
|
79
|
+
...(typography ? { theme: { typography } } : {}),
|
|
80
|
+
...(topbar ? { topbar } : {}),
|
|
81
|
+
};
|
|
82
|
+
return hasDefinedKeys(seed) ? seed : null;
|
|
83
|
+
};
|
|
84
|
+
export const buildSurfaceShellNarrative = (spec, overrides = {}) => {
|
|
85
|
+
const surface = (spec.manifest.surface ?? {});
|
|
86
|
+
const topbar = (spec.manifest.topbar ?? {});
|
|
87
|
+
const productLabel = overrides.surfaceTitle ?? spec.navigation?.surfaceTitle ?? topbar.productLabel ?? surface.label ?? spec.id;
|
|
88
|
+
const summary = typeof surface.summary === 'string' ? surface.summary.trim() : '';
|
|
89
|
+
const description = typeof surface.description === 'string' ? surface.description.trim() : '';
|
|
90
|
+
const promptFamily = typeof surface.promptFamily === 'string' ? surface.promptFamily.trim() : '';
|
|
91
|
+
const scaffoldBadge = typeof surface.scaffoldShell?.badge === 'string' ? surface.scaffoldShell.badge.trim() : '';
|
|
92
|
+
const sharedSubtitle = overrides.subtitle ?? (summary || description || `Treasury ${productLabel}.`);
|
|
93
|
+
const loginHeading = overrides.loginHeading ?? topbar.productLabel ?? surface.label ?? productLabel;
|
|
94
|
+
const loginStrap = overrides.loginStrap ?? sharedSubtitle;
|
|
95
|
+
const loginBody = overrides.loginBody === null ? undefined : (overrides.loginBody ?? (description || undefined));
|
|
96
|
+
const loginDisclaimer = overrides.loginDisclaimer === null ? undefined : (overrides.loginDisclaimer ?? spec.content?.login?.disclaimer);
|
|
97
|
+
const landingHeader = overrides.landingHeader ?? topbar.productLabel ?? surface.label ?? productLabel;
|
|
98
|
+
const landingStrap = overrides.landingStrap ?? sharedSubtitle;
|
|
99
|
+
const landingBodyParagraphs = (overrides.landingBodyParagraphs ?? [
|
|
100
|
+
description || summary || `${productLabel} runs on the shared Treasury runtime.`,
|
|
101
|
+
promptFamily
|
|
102
|
+
? `Prompt family: ${promptFamily}.`
|
|
103
|
+
: 'Modes, tools, and prompt packs are governed by shared surface policy.',
|
|
104
|
+
scaffoldBadge
|
|
105
|
+
? `${scaffoldBadge} remains shell-level copy while the runtime stays shared.`
|
|
106
|
+
: 'Branding stays in the skin layer while the runtime remains shared.',
|
|
107
|
+
]).filter((entry) => typeof entry === 'string' && entry.trim().length > 0);
|
|
108
|
+
return {
|
|
109
|
+
navigation: {
|
|
110
|
+
surfaceTitle: productLabel,
|
|
111
|
+
introHref: overrides.introHref ?? spec.navigation?.introHref ?? '/',
|
|
112
|
+
composeHref: overrides.composeHref ?? spec.navigation?.composeHref ?? '/composer/compose',
|
|
113
|
+
introTitle: overrides.introTitle ?? spec.navigation?.introTitle,
|
|
114
|
+
composeTitle: overrides.composeTitle ?? spec.navigation?.composeTitle,
|
|
115
|
+
searchEnabled: overrides.searchEnabled ?? spec.navigation?.searchEnabled ?? true,
|
|
116
|
+
},
|
|
117
|
+
content: {
|
|
118
|
+
subtitle: sharedSubtitle,
|
|
119
|
+
login: {
|
|
120
|
+
heading: loginHeading,
|
|
121
|
+
strap: loginStrap,
|
|
122
|
+
body: loginBody,
|
|
123
|
+
disclaimer: loginDisclaimer,
|
|
124
|
+
},
|
|
125
|
+
landing: {
|
|
126
|
+
header: landingHeader,
|
|
127
|
+
strap: landingStrap,
|
|
128
|
+
bodyParagraphs: landingBodyParagraphs,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
const resolveSurfaceModePolicy = (spec) => mergeSurfaceModePolicy(DEFAULT_COMPOSER_SURFACE_MODE_POLICY, (spec.manifest.modes ?? {}));
|
|
134
|
+
const resolveModeHref = (composeHref, modeId, defaultModeId) => {
|
|
135
|
+
if (modeId === 'images') {
|
|
136
|
+
if (composeHref.endsWith('/compose')) {
|
|
137
|
+
return `${composeHref.slice(0, -'/compose'.length)}/images`;
|
|
138
|
+
}
|
|
139
|
+
return '/composer/images';
|
|
140
|
+
}
|
|
141
|
+
if (!modeId || modeId === defaultModeId)
|
|
142
|
+
return composeHref;
|
|
143
|
+
const separator = composeHref.includes('?') ? '&' : '?';
|
|
144
|
+
return `${composeHref}${separator}mode=${encodeURIComponent(modeId)}`;
|
|
145
|
+
};
|
|
146
|
+
export const buildSurfaceModeTabs = (spec, options = {}) => {
|
|
147
|
+
const policy = resolveSurfaceModePolicy(spec);
|
|
148
|
+
if (Object.prototype.hasOwnProperty.call(policy.modes ?? {}, 'gallery')) {
|
|
149
|
+
throw new Error(`${spec.id}: gallery is a first-class route and must not be authored as a composer mode.`);
|
|
150
|
+
}
|
|
151
|
+
const composeHref = options.composeHref ?? spec.navigation?.composeHref ?? '/composer/compose';
|
|
152
|
+
const gatedModeIds = new Set([...(spec.routePolicy?.gatedModeIds ?? []), ...(options.gatedModeIds ?? [])]);
|
|
153
|
+
const visibleModeIds = Object.keys(policy.modes ?? {}).filter((modeId) => resolveModeLaunchState(modeId, policy) === 'live');
|
|
154
|
+
const defaultModeId = policy.defaultMode && visibleModeIds.includes(policy.defaultMode) ? policy.defaultMode : undefined;
|
|
155
|
+
const orderedModeIds = defaultModeId
|
|
156
|
+
? [defaultModeId, ...visibleModeIds.filter((modeId) => modeId !== defaultModeId)]
|
|
157
|
+
: visibleModeIds;
|
|
158
|
+
const canonicalModeIds = (() => {
|
|
159
|
+
if (orderedModeIds.includes('images'))
|
|
160
|
+
return orderedModeIds;
|
|
161
|
+
const coreModeIds = new Set(['imagine', 'design', 'map']);
|
|
162
|
+
const lastCoreIndex = orderedModeIds.reduce((latestIndex, modeId, index) => (coreModeIds.has(modeId) ? index : latestIndex), -1);
|
|
163
|
+
if (lastCoreIndex === -1)
|
|
164
|
+
return [...orderedModeIds, 'images'];
|
|
165
|
+
return [
|
|
166
|
+
...orderedModeIds.slice(0, lastCoreIndex + 1),
|
|
167
|
+
'images',
|
|
168
|
+
...orderedModeIds.slice(lastCoreIndex + 1),
|
|
169
|
+
];
|
|
170
|
+
})();
|
|
171
|
+
return orderSurfaceModeTabs(canonicalModeIds.map((modeId) => ({
|
|
172
|
+
id: modeId,
|
|
173
|
+
label: modeId === 'images' ? 'image stream' : policy.modes?.[modeId]?.label ?? modeId,
|
|
174
|
+
href: resolveModeHref(composeHref, modeId, defaultModeId),
|
|
175
|
+
requiresAdmin: gatedModeIds.has(modeId) || undefined,
|
|
176
|
+
})));
|
|
177
|
+
};
|
|
178
|
+
export const buildSurfaceRuntimeAvailability = (spec) => {
|
|
179
|
+
if (!spec.runtime) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
const surfaceId = spec.id.trim();
|
|
183
|
+
const promptFamily = spec.manifest.surface?.promptFamily?.trim() || surfaceId;
|
|
184
|
+
const toolCatalogSource = spec.runtime.toolCatalogSource;
|
|
185
|
+
if (toolCatalogSource !== 'registry-live' && toolCatalogSource !== 'toolset') {
|
|
186
|
+
throw new Error(`${surfaceId}: runtime.toolCatalogSource must be explicitly set to "registry-live" or "toolset". Legacy shell defaults are removed.`);
|
|
187
|
+
}
|
|
188
|
+
const toolsetId = toolCatalogSource === 'toolset'
|
|
189
|
+
? spec.runtime.toolsetId?.trim() || spec.runtime.toolset?.id?.trim()
|
|
190
|
+
: undefined;
|
|
191
|
+
if (toolCatalogSource === 'toolset' && !toolsetId) {
|
|
192
|
+
throw new Error(`${surfaceId}: runtime.toolsetId or runtime.toolset.id is required when runtime.toolCatalogSource is "toolset".`);
|
|
193
|
+
}
|
|
194
|
+
const promptPolicyId = spec.runtime.promptPolicyId?.trim() || spec.runtime.promptPolicy?.id?.trim() || promptFamily;
|
|
195
|
+
const visibleToolIds = spec.runtime.visibleToolIds?.map((toolId) => toolId.trim()).filter(Boolean);
|
|
196
|
+
const hiddenToolIds = spec.runtime.hiddenToolIds?.map((toolId) => toolId.trim()).filter(Boolean);
|
|
197
|
+
const promptPackCatalogMode = spec.runtime.promptPackCatalogMode ?? (surfaceId === 'composer' ? 'all' : 'surface');
|
|
198
|
+
const moduleCatalogMode = spec.runtime.moduleCatalogMode ?? (surfaceId === 'composer' ? 'all' : 'surface');
|
|
199
|
+
return {
|
|
200
|
+
toolCatalogSource,
|
|
201
|
+
toolset: toolsetId ? { id: toolsetId } : undefined,
|
|
202
|
+
toolsetId: toolsetId || undefined,
|
|
203
|
+
promptPolicy: { id: promptPolicyId },
|
|
204
|
+
promptPolicyId,
|
|
205
|
+
visibleToolIds: visibleToolIds && visibleToolIds.length > 0 ? visibleToolIds : undefined,
|
|
206
|
+
hiddenToolIds: hiddenToolIds && hiddenToolIds.length > 0 ? hiddenToolIds : undefined,
|
|
207
|
+
promptPackCatalogMode,
|
|
208
|
+
moduleCatalogMode,
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
export const buildSurfaceComposerDataDocument = (target, spec, overrides = {}) => {
|
|
212
|
+
const isClientSkinnedSurface = spec.manifest.surface?.brandProfile === 'client-skinned';
|
|
213
|
+
const controlPlaneWarnings = buildClientSkinControlPlaneWarnings(spec.id, spec, isClientSkinnedSurface).concat(buildClientSkinControlPlaneWarnings(spec.id, overrides, isClientSkinnedSurface));
|
|
214
|
+
const mergedContent = spec.content || overrides.content
|
|
215
|
+
? {
|
|
216
|
+
subtitle: overrides.content?.subtitle ?? spec.content?.subtitle,
|
|
217
|
+
login: overrides.content?.login ?? spec.content?.login,
|
|
218
|
+
landing: overrides.content?.landing ?? spec.content?.landing,
|
|
219
|
+
}
|
|
220
|
+
: undefined;
|
|
221
|
+
const mergedTopbar = mergeSurfaceComposerTopbar(spec.manifest.topbar
|
|
222
|
+
? {
|
|
223
|
+
secondaryLogo: spec.manifest.topbar.secondaryLogo,
|
|
224
|
+
title: spec.manifest.topbar.title,
|
|
225
|
+
subtitle: spec.manifest.topbar.subtitle,
|
|
226
|
+
productLabel: spec.manifest.topbar.productLabel,
|
|
227
|
+
productSuffixLabel: spec.manifest.topbar.productSuffixLabel,
|
|
228
|
+
links: spec.manifest.topbar.links,
|
|
229
|
+
contexts: spec.manifest.topbar.contexts,
|
|
230
|
+
}
|
|
231
|
+
: undefined, overrides.topbar);
|
|
232
|
+
const mergedRuntime = overrides.runtime || (!isClientSkinnedSurface && spec.runtime)
|
|
233
|
+
? {
|
|
234
|
+
...(!isClientSkinnedSurface ? (spec.runtime ?? {}) : {}),
|
|
235
|
+
...(overrides.runtime ?? {}),
|
|
236
|
+
}
|
|
237
|
+
: undefined;
|
|
238
|
+
const runtimeAvailability = !isClientSkinnedSurface && spec.runtime ? buildSurfaceRuntimeAvailability(spec) : undefined;
|
|
239
|
+
const runtimeToolCatalogSource = mergedRuntime?.toolCatalogSource ?? runtimeAvailability?.toolCatalogSource;
|
|
240
|
+
const runtimeToolset = mergedRuntime?.toolset ?? runtimeAvailability?.toolset;
|
|
241
|
+
const runtimeToolsetId = mergedRuntime?.toolsetId ?? runtimeAvailability?.toolsetId;
|
|
242
|
+
const runtimePromptPolicy = mergedRuntime?.promptPolicy ?? runtimeAvailability?.promptPolicy;
|
|
243
|
+
const runtimePromptPolicyId = mergedRuntime?.promptPolicyId ?? runtimeAvailability?.promptPolicyId;
|
|
244
|
+
const runtimePromptPackCatalogMode = mergedRuntime?.promptPackCatalogMode ?? runtimeAvailability?.promptPackCatalogMode;
|
|
245
|
+
const runtimeModuleCatalogMode = mergedRuntime?.moduleCatalogMode ?? runtimeAvailability?.moduleCatalogMode;
|
|
246
|
+
const mergedFeatureFlags = overrides.featureFlags || (!isClientSkinnedSurface && spec.featureFlags)
|
|
247
|
+
? {
|
|
248
|
+
...(!isClientSkinnedSurface ? (spec.featureFlags ?? {}) : {}),
|
|
249
|
+
...(overrides.featureFlags ?? {}),
|
|
250
|
+
}
|
|
251
|
+
: undefined;
|
|
252
|
+
return {
|
|
253
|
+
tenantSlug: target.tenantSlug,
|
|
254
|
+
subtenantSlug: target.subtenantSlug ?? null,
|
|
255
|
+
surfaceId: target.surfaceId,
|
|
256
|
+
title: overrides.title ??
|
|
257
|
+
spec.navigation?.surfaceTitle ??
|
|
258
|
+
spec.manifest.surface?.label ??
|
|
259
|
+
spec.manifest.topbar?.productLabel ??
|
|
260
|
+
spec.id,
|
|
261
|
+
lockedLabel: overrides.lockedLabel,
|
|
262
|
+
topbar: mergedTopbar ? compactRecord(mergedTopbar) : undefined,
|
|
263
|
+
navigation: overrides.navigation ?? spec.navigation,
|
|
264
|
+
content: mergedContent,
|
|
265
|
+
modeTabs: overrides.modeTabs ||
|
|
266
|
+
(!isClientSkinnedSurface && (spec.modeTabs || buildSurfaceModeTabs(spec)))
|
|
267
|
+
? orderSurfaceModeTabs((overrides.modeTabs ??
|
|
268
|
+
(!isClientSkinnedSurface ? spec.modeTabs ?? buildSurfaceModeTabs(spec) : undefined)))
|
|
269
|
+
: undefined,
|
|
270
|
+
routePolicy: overrides.routePolicy || (!isClientSkinnedSurface && spec.routePolicy)
|
|
271
|
+
? {
|
|
272
|
+
...(!isClientSkinnedSurface ? (spec.routePolicy ?? {}) : {}),
|
|
273
|
+
...(overrides.routePolicy ?? {}),
|
|
274
|
+
}
|
|
275
|
+
: undefined,
|
|
276
|
+
runtime: mergedRuntime || runtimeAvailability
|
|
277
|
+
? {
|
|
278
|
+
...(mergedRuntime ?? {}),
|
|
279
|
+
...(runtimeToolCatalogSource ? { toolCatalogSource: runtimeToolCatalogSource } : {}),
|
|
280
|
+
...(runtimeToolset ? { toolset: runtimeToolset } : {}),
|
|
281
|
+
...(runtimeToolsetId ? { toolsetId: runtimeToolsetId } : {}),
|
|
282
|
+
...(runtimePromptPolicy ? { promptPolicy: runtimePromptPolicy } : {}),
|
|
283
|
+
...(runtimePromptPolicyId ? { promptPolicyId: runtimePromptPolicyId } : {}),
|
|
284
|
+
...(runtimePromptPackCatalogMode ? { promptPackCatalogMode: runtimePromptPackCatalogMode } : {}),
|
|
285
|
+
...(runtimeModuleCatalogMode ? { moduleCatalogMode: runtimeModuleCatalogMode } : {}),
|
|
286
|
+
}
|
|
287
|
+
: undefined,
|
|
288
|
+
featureFlags: mergedFeatureFlags,
|
|
289
|
+
controlPlaneWarnings: controlPlaneWarnings.length > 0 ? controlPlaneWarnings : undefined,
|
|
290
|
+
assetAccess: overrides.assetAccess,
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
export const buildSurfaceCanonicalProvisioning = (target, spec, options = {}) => ({
|
|
294
|
+
tenantBranding: options.tenantBranding,
|
|
295
|
+
tenantUiComposer: buildSurfaceTenantUiComposerSeed(spec.manifest),
|
|
296
|
+
composerData: buildSurfaceComposerDataDocument(target, spec, options.composerData),
|
|
297
|
+
});
|
|
2
298
|
export const DEFAULT_MARKETING_SLUGS = [
|
|
3
299
|
'localhost',
|
|
4
300
|
'treasury',
|
|
@@ -19,7 +315,7 @@ export const TREASURY_BASE_UI_MANIFEST = {
|
|
|
19
315
|
id: 'composer',
|
|
20
316
|
family: 'composer',
|
|
21
317
|
label: 'Composer',
|
|
22
|
-
promptFamily: '
|
|
318
|
+
promptFamily: 'spatial',
|
|
23
319
|
brandProfile: 'treasury-native',
|
|
24
320
|
summary: 'Treasury design and render surface.',
|
|
25
321
|
standaloneCapable: true,
|
|
@@ -32,8 +328,8 @@ export const TREASURY_BASE_UI_MANIFEST = {
|
|
|
32
328
|
},
|
|
33
329
|
theme: {
|
|
34
330
|
typography: {
|
|
35
|
-
fontFamily: "'Aeonik',
|
|
36
|
-
weights: [300,
|
|
331
|
+
fontFamily: "'Aeonik', -apple-system, BlinkMacSystemFont, system-ui, sans-serif",
|
|
332
|
+
weights: [300, 500, 700],
|
|
37
333
|
},
|
|
38
334
|
},
|
|
39
335
|
layout: {
|
|
@@ -47,7 +343,6 @@ export const TREASURY_BASE_UI_MANIFEST = {
|
|
|
47
343
|
productLabel: 'Composer',
|
|
48
344
|
links: [
|
|
49
345
|
{ label: 'Treasury', href: 'https://treasury.space', target: '_blank' },
|
|
50
|
-
{ label: 'Science', href: 'https://science.treasury.space', target: '_blank' },
|
|
51
346
|
],
|
|
52
347
|
},
|
|
53
348
|
modules: {
|
|
@@ -55,24 +350,25 @@ export const TREASURY_BASE_UI_MANIFEST = {
|
|
|
55
350
|
panelTabs: [
|
|
56
351
|
{ id: 'scene', label: 'scene' },
|
|
57
352
|
{ id: 'controls', label: 'controls' },
|
|
353
|
+
{ id: 'map-controls', label: 'map controls' },
|
|
58
354
|
{ id: 'lighting', label: 'lighting' },
|
|
59
355
|
{ id: 'materials', label: 'materials' },
|
|
60
356
|
{ id: 'render', label: 'render' },
|
|
61
|
-
{ id: '
|
|
357
|
+
{ id: 'compositions', label: 'compositions' },
|
|
62
358
|
{ id: 'upload', label: 'upload' },
|
|
63
359
|
],
|
|
64
360
|
rightRail: {
|
|
65
361
|
enabled: true,
|
|
66
|
-
defaultOpen:
|
|
67
|
-
defaultTab: '
|
|
362
|
+
defaultOpen: true,
|
|
363
|
+
defaultTab: 'feed',
|
|
68
364
|
tabs: [
|
|
69
|
-
{ id: '
|
|
365
|
+
{ id: 'feed', label: 'feed' },
|
|
70
366
|
{ id: 'metrics', label: 'metrics' },
|
|
71
367
|
{ id: 'feedback', label: 'feedback' },
|
|
72
368
|
],
|
|
73
369
|
},
|
|
74
|
-
metricsPanel: { enabled: true, defaultOpen:
|
|
75
|
-
inspector: { enabled: true, defaultOpen:
|
|
370
|
+
metricsPanel: { enabled: true, defaultOpen: true },
|
|
371
|
+
inspector: { enabled: true, defaultOpen: false },
|
|
76
372
|
hud: { enabled: true },
|
|
77
373
|
viewControls: { enabled: true },
|
|
78
374
|
veils: { enabled: true, defaultOn: false },
|
|
@@ -86,6 +382,10 @@ export const TRANSITGUY_LOGO = {
|
|
|
86
382
|
src: 'https://images.squarespace-cdn.com/content/v1/60074cff46d4c56a53f5b0f8/c9051ab0-28f7-4840-ae97-4d70737abffe/the%2Btransit%2Bgay%2Blogo%2B%281%29.png',
|
|
87
383
|
alt: 'The Transit Guy',
|
|
88
384
|
};
|
|
385
|
+
export const COURTYARD_URBANIST_LOGO = {
|
|
386
|
+
src: '/postcard/courtyard-urbanist.png',
|
|
387
|
+
alt: 'Courtyard Urbanist',
|
|
388
|
+
};
|
|
89
389
|
const buildManifestImage = (src, alt) => {
|
|
90
390
|
if (!src)
|
|
91
391
|
return null;
|
|
@@ -188,9 +488,7 @@ export const resolveSurfaceBrandingImages = (target, payload) => {
|
|
|
188
488
|
target.surfaceLabel ||
|
|
189
489
|
'Subtenant';
|
|
190
490
|
const topbarLogo = buildManifestImage(primaryLogoSrc, resolvedPrimaryAlt);
|
|
191
|
-
const subtenantLogo = subtenantLogoSrc
|
|
192
|
-
? buildManifestImage(subtenantLogoSrc, resolvedSubtenantAlt)
|
|
193
|
-
: null;
|
|
491
|
+
const subtenantLogo = subtenantLogoSrc ? buildManifestImage(subtenantLogoSrc, resolvedSubtenantAlt) : null;
|
|
194
492
|
return {
|
|
195
493
|
topbarLogo,
|
|
196
494
|
subtenantLogo,
|
|
@@ -275,32 +573,55 @@ export const mapSurfaceBrandingManifestImages = (manifest, mapSrc) => {
|
|
|
275
573
|
: manifest.surface,
|
|
276
574
|
};
|
|
277
575
|
};
|
|
278
|
-
const
|
|
279
|
-
defaultMode: 'streetmix',
|
|
576
|
+
const COMPOSER_MODE_POLICY = mergeSurfaceModePolicy(DEFAULT_COMPOSER_SURFACE_MODE_POLICY, {
|
|
280
577
|
modes: {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
578
|
+
streetmix: {
|
|
579
|
+
enabled: true,
|
|
580
|
+
label: 'streetmix',
|
|
284
581
|
},
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
defaultPanelTab: 'render',
|
|
289
|
-
kits: { upload: false, 'compute-target': false },
|
|
290
|
-
modules: { hud: false, inspector: false, viewControls: false },
|
|
291
|
-
actions: { 'generate-geometry': false, 'asset-download': false },
|
|
292
|
-
shell: { leftPanelOpen: false },
|
|
582
|
+
streetview: {
|
|
583
|
+
enabled: true,
|
|
584
|
+
label: 'streetview',
|
|
293
585
|
},
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
const TRANSIT_MODE_POLICY = mergeSurfaceModePolicy(DEFAULT_COMPOSER_SURFACE_MODE_POLICY, {
|
|
589
|
+
defaultMode: 'imagine',
|
|
590
|
+
modes: {
|
|
294
591
|
streetmix: {
|
|
295
592
|
enabled: true,
|
|
296
593
|
label: 'streetmix',
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
594
|
+
},
|
|
595
|
+
streetview: {
|
|
596
|
+
enabled: true,
|
|
597
|
+
label: 'streetview',
|
|
301
598
|
},
|
|
302
599
|
},
|
|
303
600
|
});
|
|
601
|
+
const SCIENCE_MODE_POLICY = {
|
|
602
|
+
defaultMode: 'design',
|
|
603
|
+
modes: {
|
|
604
|
+
imagine: DEFAULT_COMPOSER_SURFACE_MODE_POLICY.modes?.imagine ?? { label: 'imagine' },
|
|
605
|
+
design: {
|
|
606
|
+
...(DEFAULT_COMPOSER_SURFACE_MODE_POLICY.modes?.design ?? { label: 'design' }),
|
|
607
|
+
shell: { leftPanelOpen: true, rightPanelOpen: true, metricsOpen: true, inspectorOpen: false },
|
|
608
|
+
},
|
|
609
|
+
map: {
|
|
610
|
+
...(DEFAULT_COMPOSER_SURFACE_MODE_POLICY.modes?.map ?? { label: 'map' }),
|
|
611
|
+
shell: { leftPanelOpen: true, rightPanelOpen: true, metricsOpen: true, inspectorOpen: false },
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
const SCIENCE_BRAND_COLORS = {
|
|
616
|
+
primary: '#314390',
|
|
617
|
+
secondary: '#0b1320',
|
|
618
|
+
background: '#f9f9f9',
|
|
619
|
+
panel: '#ffffff',
|
|
620
|
+
panelBorder: '#e5e7eb',
|
|
621
|
+
textPrimary: '#0f172a',
|
|
622
|
+
textSecondary: '#64748b',
|
|
623
|
+
accent: '#263773',
|
|
624
|
+
};
|
|
304
625
|
export const SURFACE_KITS = {
|
|
305
626
|
composer: {
|
|
306
627
|
id: 'composer',
|
|
@@ -308,8 +629,8 @@ export const SURFACE_KITS = {
|
|
|
308
629
|
surface: {
|
|
309
630
|
id: 'composer',
|
|
310
631
|
family: 'composer',
|
|
311
|
-
label: 'Composer',
|
|
312
|
-
promptFamily: '
|
|
632
|
+
label: 'Spatial Composer',
|
|
633
|
+
promptFamily: 'spatial',
|
|
313
634
|
brandProfile: 'treasury-native',
|
|
314
635
|
summary: 'Treasury design and render surface.',
|
|
315
636
|
standaloneCapable: true,
|
|
@@ -318,6 +639,10 @@ export const SURFACE_KITS = {
|
|
|
318
639
|
profile: 'treasury-native',
|
|
319
640
|
poweredBy: { enabled: false },
|
|
320
641
|
},
|
|
642
|
+
modes: {
|
|
643
|
+
defaultMode: COMPOSER_MODE_POLICY.defaultMode,
|
|
644
|
+
modes: COMPOSER_MODE_POLICY.modes,
|
|
645
|
+
},
|
|
321
646
|
},
|
|
322
647
|
},
|
|
323
648
|
transit: {
|
|
@@ -327,16 +652,12 @@ export const SURFACE_KITS = {
|
|
|
327
652
|
surface: {
|
|
328
653
|
id: 'transit',
|
|
329
654
|
family: 'transit',
|
|
330
|
-
label: 'Transit',
|
|
655
|
+
label: 'Transit Composer',
|
|
331
656
|
promptFamily: 'transit',
|
|
332
657
|
brandProfile: 'treasury-native',
|
|
333
|
-
summary: '
|
|
334
|
-
description: 'Transit is
|
|
658
|
+
summary: 'Spatial Assets for Transit System Visualization and Development',
|
|
659
|
+
description: 'Treasury Transit Composer is an asset development system for public transit design, communication, and development. It enables calibrated, replicable visual renders at any location, using Streetmix, Google Street View, and custom 3D modelling tools.',
|
|
335
660
|
standaloneCapable: true,
|
|
336
|
-
scaffoldShell: {
|
|
337
|
-
badge: 'Streetmix',
|
|
338
|
-
footerText: 'Surface logos, copy, and support content live in the Treasury shell. Embedded Streetmix runtime customization remains a separate adapter concern.',
|
|
339
|
-
},
|
|
340
661
|
},
|
|
341
662
|
branding: {
|
|
342
663
|
profile: 'treasury-native',
|
|
@@ -346,7 +667,7 @@ export const SURFACE_KITS = {
|
|
|
346
667
|
},
|
|
347
668
|
topbar: {
|
|
348
669
|
title: 'Treasury',
|
|
349
|
-
productLabel: 'Composer',
|
|
670
|
+
productLabel: 'Transit Composer',
|
|
350
671
|
links: [
|
|
351
672
|
{ label: 'Treasury', href: 'https://treasury.space/', target: '_blank' },
|
|
352
673
|
{ label: 'Composer', href: 'https://composer.treasury.space/', target: '_blank' },
|
|
@@ -365,7 +686,7 @@ export const SURFACE_KITS = {
|
|
|
365
686
|
surface: {
|
|
366
687
|
id: 'courtyard',
|
|
367
688
|
family: 'courtyard',
|
|
368
|
-
label: 'Courtyard',
|
|
689
|
+
label: 'Courtyard Composer',
|
|
369
690
|
promptFamily: 'courtyard',
|
|
370
691
|
brandProfile: 'treasury-native',
|
|
371
692
|
summary: 'Treasury-native courtyard surface built on shared Composer kits.',
|
|
@@ -380,12 +701,83 @@ export const SURFACE_KITS = {
|
|
|
380
701
|
},
|
|
381
702
|
topbar: {
|
|
382
703
|
title: 'Treasury',
|
|
383
|
-
productLabel: 'Composer',
|
|
704
|
+
productLabel: 'Courtyard Composer',
|
|
384
705
|
links: [
|
|
385
706
|
{ label: 'Treasury', href: 'https://treasury.space/', target: '_blank' },
|
|
386
707
|
{ label: 'Composer', href: 'https://composer.treasury.space/', target: '_blank' },
|
|
387
708
|
],
|
|
388
709
|
},
|
|
710
|
+
modes: {
|
|
711
|
+
defaultMode: DEFAULT_COMPOSER_SURFACE_MODE_POLICY.defaultMode,
|
|
712
|
+
modes: DEFAULT_COMPOSER_SURFACE_MODE_POLICY.modes,
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
},
|
|
716
|
+
science: {
|
|
717
|
+
id: 'science',
|
|
718
|
+
manifest: {
|
|
719
|
+
tenantId: 'science',
|
|
720
|
+
surface: {
|
|
721
|
+
id: 'science',
|
|
722
|
+
family: 'science',
|
|
723
|
+
label: 'Science Composer',
|
|
724
|
+
promptFamily: 'spatial',
|
|
725
|
+
brandProfile: 'treasury-native',
|
|
726
|
+
summary: 'Calibrated Spatial Environments for Human Science',
|
|
727
|
+
description: 'Treasury Science Composer is a calibrated environment design and rendering surface for spatial cognition, perception, and research-facing scene development.',
|
|
728
|
+
standaloneCapable: true,
|
|
729
|
+
},
|
|
730
|
+
branding: {
|
|
731
|
+
profile: 'treasury-native',
|
|
732
|
+
poweredBy: {
|
|
733
|
+
enabled: false,
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
topbar: {
|
|
737
|
+
title: 'Treasury',
|
|
738
|
+
productLabel: 'Science',
|
|
739
|
+
contexts: {
|
|
740
|
+
composer: {
|
|
741
|
+
productSuffixLabel: 'Spatial Composer',
|
|
742
|
+
},
|
|
743
|
+
admin: {
|
|
744
|
+
productSuffixLabel: 'Spatial Composer',
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
links: [
|
|
748
|
+
{ label: 'Treasury', href: 'https://treasury.space/', target: '_blank' },
|
|
749
|
+
{ label: 'Spatial Composer', href: 'https://composer.treasury.space/', target: '_blank' },
|
|
750
|
+
],
|
|
751
|
+
},
|
|
752
|
+
modules: {
|
|
753
|
+
rightRail: {
|
|
754
|
+
enabled: true,
|
|
755
|
+
defaultOpen: true,
|
|
756
|
+
defaultTab: 'data',
|
|
757
|
+
tabs: [
|
|
758
|
+
{ id: 'metrics', label: 'metrics' },
|
|
759
|
+
{ id: 'data', label: 'data' },
|
|
760
|
+
{ id: 'feed', label: 'feed' },
|
|
761
|
+
{ id: 'feedback', label: 'feedback' },
|
|
762
|
+
],
|
|
763
|
+
},
|
|
764
|
+
metricsPanel: { enabled: true, defaultOpen: true },
|
|
765
|
+
inspector: { enabled: true, defaultOpen: false },
|
|
766
|
+
hud: { enabled: true },
|
|
767
|
+
viewControls: { enabled: true },
|
|
768
|
+
veils: { enabled: true, defaultOn: false },
|
|
769
|
+
},
|
|
770
|
+
modes: {
|
|
771
|
+
defaultMode: SCIENCE_MODE_POLICY.defaultMode,
|
|
772
|
+
modes: SCIENCE_MODE_POLICY.modes,
|
|
773
|
+
},
|
|
774
|
+
theme: {
|
|
775
|
+
typography: {
|
|
776
|
+
fontFamily: "'Aeonik', -apple-system, BlinkMacSystemFont, system-ui, sans-serif",
|
|
777
|
+
weights: [300, 500, 700],
|
|
778
|
+
},
|
|
779
|
+
colors: SCIENCE_BRAND_COLORS,
|
|
780
|
+
},
|
|
389
781
|
},
|
|
390
782
|
},
|
|
391
783
|
};
|
|
@@ -397,11 +789,11 @@ export const SURFACE_SKINS = {
|
|
|
397
789
|
surface: {
|
|
398
790
|
id: 'transitguy',
|
|
399
791
|
family: 'transit',
|
|
400
|
-
label: '
|
|
792
|
+
label: 'Composer',
|
|
401
793
|
promptFamily: 'transit',
|
|
402
794
|
brandProfile: 'client-skinned',
|
|
403
795
|
summary: 'Client-skinned transit surface built on the Treasury Transit runtime.',
|
|
404
|
-
description: 'Transitguy runs as a branded skin of the Treasury Transit surface, keeping
|
|
796
|
+
description: 'Transitguy runs as a branded skin of the Treasury Transit surface, keeping street-structure transit modes and Treasury runtime behavior while swapping client identity and content.',
|
|
405
797
|
scaffoldShell: {
|
|
406
798
|
badge: 'Streetmix',
|
|
407
799
|
secondaryLogo: TRANSITGUY_LOGO,
|
|
@@ -438,6 +830,49 @@ export const SURFACE_SKINS = {
|
|
|
438
830
|
},
|
|
439
831
|
},
|
|
440
832
|
},
|
|
833
|
+
courtyardurbanist: {
|
|
834
|
+
id: 'courtyardurbanist',
|
|
835
|
+
manifest: {
|
|
836
|
+
tenantId: 'courtyardurbanist',
|
|
837
|
+
surface: {
|
|
838
|
+
id: 'courtyardurbanist',
|
|
839
|
+
family: 'courtyard',
|
|
840
|
+
label: 'Composer',
|
|
841
|
+
promptFamily: 'courtyard',
|
|
842
|
+
brandProfile: 'client-skinned',
|
|
843
|
+
summary: 'Client-skinned courtyard surface built on the Treasury Courtyard runtime.',
|
|
844
|
+
description: 'Courtyard Urbanist runs as a branded skin of the Treasury Courtyard surface, keeping the courtyard prompt packs, gallery flows, and shared runtime behavior while swapping client identity and shell voice.',
|
|
845
|
+
},
|
|
846
|
+
branding: {
|
|
847
|
+
profile: 'client-skinned',
|
|
848
|
+
poweredBy: {
|
|
849
|
+
enabled: true,
|
|
850
|
+
href: 'https://treasury.space',
|
|
851
|
+
logo: TREASURY_LOGO,
|
|
852
|
+
kicker: 'Powered by',
|
|
853
|
+
labelPrefix: 'Treasury',
|
|
854
|
+
labelAccent: 'Courtyard Runtime',
|
|
855
|
+
},
|
|
856
|
+
},
|
|
857
|
+
theme: {
|
|
858
|
+
typography: {
|
|
859
|
+
fontFamily: "'Epilogue', system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
|
|
860
|
+
weights: [400, 700],
|
|
861
|
+
},
|
|
862
|
+
},
|
|
863
|
+
topbar: {
|
|
864
|
+
logo: COURTYARD_URBANIST_LOGO,
|
|
865
|
+
secondaryLogo: TREASURY_LOGO,
|
|
866
|
+
title: 'Urbanist',
|
|
867
|
+
subtitle: 'Courtyard skin on Treasury Composer',
|
|
868
|
+
productLabel: 'Composer',
|
|
869
|
+
links: [
|
|
870
|
+
{ label: 'Treasury', href: 'https://treasury.space/', target: '_blank' },
|
|
871
|
+
{ label: 'Composer', href: 'https://composer.treasury.space/', target: '_blank' },
|
|
872
|
+
],
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
},
|
|
441
876
|
};
|
|
442
877
|
export const SURFACE_HOST_PRESETS = {
|
|
443
878
|
composer: {
|
|
@@ -454,7 +889,7 @@ export const SURFACE_HOST_PRESETS = {
|
|
|
454
889
|
subtenantSlug: 'transit',
|
|
455
890
|
surfaceId: 'transit',
|
|
456
891
|
brandProfile: 'treasury-native',
|
|
457
|
-
compatibilityMode: 'tenant
|
|
892
|
+
compatibilityMode: 'direct-tenant',
|
|
458
893
|
},
|
|
459
894
|
transitguy: {
|
|
460
895
|
tenantSlug: 'transitguy',
|
|
@@ -464,15 +899,80 @@ export const SURFACE_HOST_PRESETS = {
|
|
|
464
899
|
brandProfile: 'client-skinned',
|
|
465
900
|
compatibilityMode: 'direct-tenant',
|
|
466
901
|
},
|
|
902
|
+
'transit-test': {
|
|
903
|
+
tenantSlug: 'treasury',
|
|
904
|
+
effectiveTenantSlug: 'transit',
|
|
905
|
+
subtenantSlug: 'transit',
|
|
906
|
+
surfaceId: 'transit',
|
|
907
|
+
brandProfile: 'treasury-native',
|
|
908
|
+
compatibilityMode: 'direct-tenant',
|
|
909
|
+
},
|
|
910
|
+
'neu-new': {
|
|
911
|
+
tenantSlug: 'neu',
|
|
912
|
+
effectiveTenantSlug: 'neu',
|
|
913
|
+
subtenantSlug: null,
|
|
914
|
+
surfaceId: 'composer',
|
|
915
|
+
brandProfile: 'client-skinned',
|
|
916
|
+
compatibilityMode: 'direct-tenant',
|
|
917
|
+
},
|
|
918
|
+
neu: {
|
|
919
|
+
tenantSlug: 'neu',
|
|
920
|
+
effectiveTenantSlug: 'neu',
|
|
921
|
+
subtenantSlug: null,
|
|
922
|
+
surfaceId: 'composer',
|
|
923
|
+
brandProfile: 'client-skinned',
|
|
924
|
+
compatibilityMode: 'direct-tenant',
|
|
925
|
+
},
|
|
926
|
+
'neu-test': {
|
|
927
|
+
tenantSlug: 'neu',
|
|
928
|
+
effectiveTenantSlug: 'neu',
|
|
929
|
+
subtenantSlug: null,
|
|
930
|
+
surfaceId: 'composer',
|
|
931
|
+
brandProfile: 'client-skinned',
|
|
932
|
+
compatibilityMode: 'direct-tenant',
|
|
933
|
+
},
|
|
934
|
+
courtyardurbanist: {
|
|
935
|
+
tenantSlug: 'courtyardurbanist',
|
|
936
|
+
effectiveTenantSlug: 'courtyardurbanist',
|
|
937
|
+
subtenantSlug: null,
|
|
938
|
+
surfaceId: 'courtyard',
|
|
939
|
+
brandProfile: 'client-skinned',
|
|
940
|
+
compatibilityMode: 'direct-tenant',
|
|
941
|
+
},
|
|
942
|
+
'courtyard-test': {
|
|
943
|
+
tenantSlug: 'treasury',
|
|
944
|
+
effectiveTenantSlug: 'courtyard',
|
|
945
|
+
subtenantSlug: 'courtyard',
|
|
946
|
+
surfaceId: 'courtyard',
|
|
947
|
+
brandProfile: 'treasury-native',
|
|
948
|
+
compatibilityMode: 'direct-tenant',
|
|
949
|
+
},
|
|
467
950
|
courtyard: {
|
|
468
951
|
tenantSlug: 'treasury',
|
|
469
952
|
effectiveTenantSlug: 'courtyard',
|
|
470
953
|
subtenantSlug: 'courtyard',
|
|
471
954
|
surfaceId: 'courtyard',
|
|
472
955
|
brandProfile: 'treasury-native',
|
|
473
|
-
compatibilityMode: 'tenant
|
|
956
|
+
compatibilityMode: 'direct-tenant',
|
|
957
|
+
},
|
|
958
|
+
science: {
|
|
959
|
+
tenantSlug: 'treasury',
|
|
960
|
+
effectiveTenantSlug: 'science',
|
|
961
|
+
subtenantSlug: 'science',
|
|
962
|
+
surfaceId: 'science',
|
|
963
|
+
brandProfile: 'treasury-native',
|
|
964
|
+
compatibilityMode: 'direct-tenant',
|
|
965
|
+
},
|
|
966
|
+
scienv: {
|
|
967
|
+
tenantSlug: 'treasury',
|
|
968
|
+
effectiveTenantSlug: 'science',
|
|
969
|
+
subtenantSlug: 'science',
|
|
970
|
+
surfaceId: 'science',
|
|
971
|
+
brandProfile: 'treasury-native',
|
|
972
|
+
compatibilityMode: 'direct-tenant',
|
|
474
973
|
},
|
|
475
974
|
};
|
|
975
|
+
const EXPLICIT_HOST_PRESETS = new Set(Object.keys(SURFACE_HOST_PRESETS).filter((key) => key !== 'composer' && key !== 'transit'));
|
|
476
976
|
export const resolveSurfaceKitProfile = (surfaceId) => {
|
|
477
977
|
const normalized = String(surfaceId || '').trim().toLowerCase();
|
|
478
978
|
return SURFACE_KITS[normalized] ?? null;
|
|
@@ -525,7 +1025,11 @@ export const createSurfaceHostResolver = (options) => {
|
|
|
525
1025
|
const candidate = hostname.split('.')[0] ?? '';
|
|
526
1026
|
const normalizedCandidate = candidate.toLowerCase();
|
|
527
1027
|
const marketingHost = !normalizedCandidate || marketingSlugs.has(normalizedCandidate);
|
|
528
|
-
const hostSlug =
|
|
1028
|
+
const hostSlug = (normalizedCandidate && EXPLICIT_HOST_PRESETS.has(normalizedCandidate)
|
|
1029
|
+
? normalizedCandidate
|
|
1030
|
+
: marketingHost
|
|
1031
|
+
? fallbackHostSlug
|
|
1032
|
+
: normalizedCandidate) || fallbackHostSlug;
|
|
529
1033
|
const preset = hostPresets[hostSlug] ??
|
|
530
1034
|
buildDirectTenantContext(hostSlug, {
|
|
531
1035
|
defaultTenantSlug: options.defaultTenantSlug,
|