@treasuryspatial/surface-kit 0.1.0

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.
@@ -0,0 +1,55 @@
1
+ import type { DeepPartial, UiBrandProfile, UiManifest } from '@treasuryspatial/ui-manifest';
2
+ export type SurfaceKitId = 'composer' | 'transit' | 'courtyard';
3
+ export type SurfaceSkinId = 'transitguy';
4
+ export type SurfaceCompatibilityMode = 'direct-tenant' | 'tenant-subtenant-bridge';
5
+ export type SurfaceKitProfile = {
6
+ id: SurfaceKitId;
7
+ manifest: DeepPartial<UiManifest>;
8
+ };
9
+ export type SurfaceSkinProfile = {
10
+ id: SurfaceSkinId | string;
11
+ manifest: DeepPartial<UiManifest>;
12
+ };
13
+ export type SurfaceHostContext = {
14
+ publicHost: string;
15
+ hostSlug: string;
16
+ tenantSlug: string;
17
+ effectiveTenantSlug: string;
18
+ subtenantSlug: string | null;
19
+ surfaceId: string;
20
+ brandProfile: UiBrandProfile;
21
+ compatibilityMode: SurfaceCompatibilityMode;
22
+ isMarketingHost: boolean;
23
+ };
24
+ export type SurfaceHostPreset = Omit<SurfaceHostContext, 'publicHost' | 'hostSlug' | 'isMarketingHost'>;
25
+ export type SurfaceHostResolverOptions = {
26
+ defaultTenantSlug: string;
27
+ defaultSurfaceId: SurfaceKitId;
28
+ fallbackHostSlug?: string;
29
+ marketingSlugs?: string[];
30
+ hostPresets?: Record<string, SurfaceHostPreset>;
31
+ };
32
+ export declare const DEFAULT_MARKETING_SLUGS: string[];
33
+ export declare const TREASURY_LOGO: {
34
+ src: string;
35
+ alt: string;
36
+ };
37
+ export declare const TRANSITGUY_LOGO: {
38
+ src: string;
39
+ alt: string;
40
+ };
41
+ export declare const SURFACE_KITS: Record<SurfaceKitId, SurfaceKitProfile>;
42
+ export declare const SURFACE_SKINS: Record<string, SurfaceSkinProfile>;
43
+ export declare const SURFACE_HOST_PRESETS: Record<string, SurfaceHostPreset>;
44
+ export declare const resolveSurfaceKitProfile: (surfaceId: string) => SurfaceKitProfile | null;
45
+ export declare const resolveSurfaceSkinProfile: (skinId: string) => SurfaceSkinProfile | null;
46
+ export declare const buildMarketingSlugSet: (overrides?: string[]) => Set<string>;
47
+ export declare const isMarketingSlug: (slug?: string | null, marketingSlugs?: Set<string>) => boolean;
48
+ export declare const createSurfaceHostResolver: (options: SurfaceHostResolverOptions) => {
49
+ marketingSlugs: Set<string>;
50
+ isMarketingSlug: (slug?: string | null) => boolean;
51
+ resolveSurfaceHostContext: (host?: string | null) => SurfaceHostContext;
52
+ resolveTenantSlugFromHost: (host?: string | null) => string;
53
+ resolveCanonicalTenantSlugFromHost: (host?: string | null) => string;
54
+ };
55
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE5F,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAChE,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AACzC,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,yBAAyB,CAAC;AAEnF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,YAAY,CAAC;IACjB,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,aAAa,GAAG,MAAM,CAAC;IAC3B,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,cAAc,CAAC;IAC7B,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,EAAE,YAAY,GAAG,UAAU,GAAG,iBAAiB,CAAC,CAAC;AAExG,MAAM,MAAM,0BAA0B,GAAG;IACvC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,YAAY,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CACjD,CAAC;AAEF,eAAO,MAAM,uBAAuB,UAOnC,CAAC;AAEF,eAAO,MAAM,aAAa;;;CAGzB,CAAC;AAEF,eAAO,MAAM,eAAe;;;CAG3B,CAAC;AA6BF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,iBAAiB,CA2FhE,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAmD5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAiClE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,WAAW,MAAM,KAAG,iBAAiB,GAAG,IAGhF,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,QAAQ,MAAM,KAAG,kBAAkB,GAAG,IAG/E,CAAC;AAOF,eAAO,MAAM,qBAAqB,GAAI,YAAW,MAAM,EAAO,gBACmC,CAAC;AAElG,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,GAAG,IAAI,EAAE,4BAAwC,YAG7F,CAAC;AAcF,eAAO,MAAM,yBAAyB,GAAI,SAAS,0BAA0B;;6BA8ChD,MAAM,GAAG,IAAI;uCAtCE,MAAM,GAAG,IAAI,KAAG,kBAAkB;uCAwCvC,MAAM,GAAG,IAAI;gDAEJ,MAAM,GAAG,IAAI;CAG5D,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,290 @@
1
+ import { DEFAULT_COMPOSER_SURFACE_MODE_POLICY, mergeSurfaceModePolicy } from '@treasuryspatial/mode-policy';
2
+ export const DEFAULT_MARKETING_SLUGS = [
3
+ 'localhost',
4
+ 'treasury',
5
+ 'treasury-dev',
6
+ 'treasury-staging',
7
+ 'dev',
8
+ 'staging',
9
+ ];
10
+ export const TREASURY_LOGO = {
11
+ src: 'https://treasury.space/logo.svg',
12
+ alt: 'Treasury',
13
+ };
14
+ export const TRANSITGUY_LOGO = {
15
+ src: 'https://images.squarespace-cdn.com/content/v1/60074cff46d4c56a53f5b0f8/c9051ab0-28f7-4840-ae97-4d70737abffe/the%2Btransit%2Bgay%2Blogo%2B%281%29.png',
16
+ alt: 'The Transit Guy',
17
+ };
18
+ const TRANSIT_MODE_POLICY = mergeSurfaceModePolicy(DEFAULT_COMPOSER_SURFACE_MODE_POLICY, {
19
+ defaultMode: 'streetmix',
20
+ modes: {
21
+ design: {
22
+ launchState: 'hidden',
23
+ shell: { leftPanelOpen: false },
24
+ },
25
+ map: {
26
+ launchState: 'coming-soon',
27
+ panelTabs: ['render'],
28
+ defaultPanelTab: 'render',
29
+ kits: { upload: false, 'compute-target': false },
30
+ modules: { hud: false, inspector: false, viewControls: false },
31
+ actions: { 'generate-geometry': false, 'asset-download': false },
32
+ shell: { leftPanelOpen: false },
33
+ },
34
+ streetmix: {
35
+ enabled: true,
36
+ label: 'streetmix',
37
+ panelTabs: ['render'],
38
+ defaultPanelTab: 'render',
39
+ kits: { upload: false, 'compute-target': false },
40
+ actions: { 'generate-geometry': false, 'asset-download': false },
41
+ },
42
+ },
43
+ });
44
+ export const SURFACE_KITS = {
45
+ composer: {
46
+ id: 'composer',
47
+ manifest: {
48
+ surface: {
49
+ id: 'composer',
50
+ family: 'composer',
51
+ label: 'Composer',
52
+ promptFamily: 'composer',
53
+ brandProfile: 'treasury-native',
54
+ summary: 'Treasury design and render surface.',
55
+ standaloneCapable: true,
56
+ },
57
+ branding: {
58
+ profile: 'treasury-native',
59
+ poweredBy: { enabled: false },
60
+ },
61
+ },
62
+ },
63
+ transit: {
64
+ id: 'transit',
65
+ manifest: {
66
+ tenantId: 'transit',
67
+ surface: {
68
+ id: 'transit',
69
+ family: 'transit',
70
+ label: 'Transit',
71
+ promptFamily: 'transit',
72
+ brandProfile: 'treasury-native',
73
+ summary: 'Treasury-native transit surface built on the Composer runtime.',
74
+ description: 'Transit is the packaged Treasury surface for corridor visuals, stop environments, and street-section scaffold workflows.',
75
+ standaloneCapable: true,
76
+ scaffoldShell: {
77
+ badge: 'Streetmix',
78
+ footerText: 'Surface logos, copy, and support content live in the Treasury shell. Embedded Streetmix runtime customization remains a separate adapter concern.',
79
+ },
80
+ },
81
+ branding: {
82
+ profile: 'treasury-native',
83
+ poweredBy: {
84
+ enabled: false,
85
+ },
86
+ },
87
+ topbar: {
88
+ title: 'Treasury',
89
+ subtitle: 'Treasury-native transit surface',
90
+ productLabel: 'Transit Composer',
91
+ links: [
92
+ { label: 'Treasury', href: 'https://treasury.space/', target: '_blank' },
93
+ { label: 'Composer', href: 'https://composer.treasury.space/', target: '_blank' },
94
+ ],
95
+ },
96
+ modes: {
97
+ defaultMode: TRANSIT_MODE_POLICY.defaultMode,
98
+ modes: TRANSIT_MODE_POLICY.modes,
99
+ },
100
+ },
101
+ },
102
+ courtyard: {
103
+ id: 'courtyard',
104
+ manifest: {
105
+ tenantId: 'courtyard',
106
+ surface: {
107
+ id: 'courtyard',
108
+ family: 'courtyard',
109
+ label: 'Courtyard',
110
+ promptFamily: 'courtyard',
111
+ brandProfile: 'treasury-native',
112
+ summary: 'Treasury-native courtyard surface built on shared Composer kits.',
113
+ description: 'Courtyard is the packaged Treasury surface for design, geometry, and map-led place workflows.',
114
+ standaloneCapable: true,
115
+ },
116
+ branding: {
117
+ profile: 'treasury-native',
118
+ poweredBy: {
119
+ enabled: false,
120
+ },
121
+ },
122
+ topbar: {
123
+ title: 'Treasury',
124
+ subtitle: 'Treasury-native courtyard surface',
125
+ productLabel: 'Courtyard Composer',
126
+ links: [
127
+ { label: 'Treasury', href: 'https://treasury.space/', target: '_blank' },
128
+ { label: 'Composer', href: 'https://composer.treasury.space/', target: '_blank' },
129
+ ],
130
+ },
131
+ },
132
+ },
133
+ };
134
+ export const SURFACE_SKINS = {
135
+ transitguy: {
136
+ id: 'transitguy',
137
+ manifest: {
138
+ tenantId: 'transitguy',
139
+ surface: {
140
+ id: 'transitguy',
141
+ family: 'transit',
142
+ label: 'Transit',
143
+ promptFamily: 'transit',
144
+ brandProfile: 'client-skinned',
145
+ summary: 'Client-skinned transit surface built on the Treasury Transit runtime.',
146
+ description: 'Transitguy runs as a branded skin of the Treasury Transit surface, keeping scaffold-first transit modes and Treasury runtime behavior while swapping client identity and content.',
147
+ scaffoldShell: {
148
+ badge: 'Streetmix',
149
+ secondaryLogo: TRANSITGUY_LOGO,
150
+ footerText: 'Client branding and support content are shell-level overrides. Embedded Streetmix runtime customization remains a separate adapter concern.',
151
+ },
152
+ },
153
+ branding: {
154
+ profile: 'client-skinned',
155
+ poweredBy: {
156
+ enabled: true,
157
+ href: 'https://treasury.space',
158
+ logo: TREASURY_LOGO,
159
+ kicker: 'Powered by',
160
+ labelPrefix: 'Treasury',
161
+ labelAccent: 'Transit Runtime',
162
+ },
163
+ },
164
+ theme: {
165
+ typography: {
166
+ fontFamily: "'Epilogue', system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
167
+ weights: [400, 700],
168
+ },
169
+ },
170
+ topbar: {
171
+ logo: TRANSITGUY_LOGO,
172
+ secondaryLogo: TREASURY_LOGO,
173
+ title: 'TTG',
174
+ subtitle: 'Transit surface skin on Treasury Composer',
175
+ productLabel: 'Composer',
176
+ links: [
177
+ { label: 'Website', href: 'https://www.thetransitguy.com/', target: '_blank' },
178
+ { label: 'Substack', href: 'https://thetransitguy.substack.com/', target: '_blank' },
179
+ ],
180
+ },
181
+ },
182
+ },
183
+ };
184
+ export const SURFACE_HOST_PRESETS = {
185
+ composer: {
186
+ tenantSlug: 'treasury',
187
+ effectiveTenantSlug: 'treasury',
188
+ subtenantSlug: null,
189
+ surfaceId: 'composer',
190
+ brandProfile: 'treasury-native',
191
+ compatibilityMode: 'direct-tenant',
192
+ },
193
+ transit: {
194
+ tenantSlug: 'treasury',
195
+ effectiveTenantSlug: 'transit',
196
+ subtenantSlug: 'transit',
197
+ surfaceId: 'transit',
198
+ brandProfile: 'treasury-native',
199
+ compatibilityMode: 'tenant-subtenant-bridge',
200
+ },
201
+ transitguy: {
202
+ tenantSlug: 'transitguy',
203
+ effectiveTenantSlug: 'transitguy',
204
+ subtenantSlug: null,
205
+ surfaceId: 'transit',
206
+ brandProfile: 'client-skinned',
207
+ compatibilityMode: 'direct-tenant',
208
+ },
209
+ courtyard: {
210
+ tenantSlug: 'treasury',
211
+ effectiveTenantSlug: 'courtyard',
212
+ subtenantSlug: 'courtyard',
213
+ surfaceId: 'courtyard',
214
+ brandProfile: 'treasury-native',
215
+ compatibilityMode: 'tenant-subtenant-bridge',
216
+ },
217
+ };
218
+ export const resolveSurfaceKitProfile = (surfaceId) => {
219
+ const normalized = String(surfaceId || '').trim().toLowerCase();
220
+ return SURFACE_KITS[normalized] ?? null;
221
+ };
222
+ export const resolveSurfaceSkinProfile = (skinId) => {
223
+ const normalized = String(skinId || '').trim().toLowerCase();
224
+ return SURFACE_SKINS[normalized] ?? null;
225
+ };
226
+ const normalizeHost = (host) => {
227
+ if (!host)
228
+ return '';
229
+ return host.split(':')[0]?.toLowerCase() ?? '';
230
+ };
231
+ export const buildMarketingSlugSet = (overrides = []) => new Set([...DEFAULT_MARKETING_SLUGS, ...overrides.map((value) => value.toLowerCase())]);
232
+ export const isMarketingSlug = (slug, marketingSlugs = buildMarketingSlugSet()) => {
233
+ if (!slug)
234
+ return false;
235
+ return marketingSlugs.has(slug.toLowerCase());
236
+ };
237
+ const buildDirectTenantContext = (slug, options) => ({
238
+ tenantSlug: slug || options.defaultTenantSlug,
239
+ effectiveTenantSlug: slug || options.defaultTenantSlug,
240
+ subtenantSlug: null,
241
+ surfaceId: options.defaultSurfaceId,
242
+ brandProfile: slug && slug !== options.defaultTenantSlug ? 'client-skinned' : 'treasury-native',
243
+ compatibilityMode: 'direct-tenant',
244
+ });
245
+ export const createSurfaceHostResolver = (options) => {
246
+ const fallbackHostSlug = (options.fallbackHostSlug || options.defaultTenantSlug).trim().toLowerCase();
247
+ const marketingSlugs = buildMarketingSlugSet(options.marketingSlugs ?? []);
248
+ const hostPresets = {
249
+ ...SURFACE_HOST_PRESETS,
250
+ ...(options.hostPresets ?? {}),
251
+ };
252
+ const resolveSurfaceHostContext = (host) => {
253
+ const hostname = normalizeHost(host);
254
+ if (!hostname) {
255
+ const fallback = hostPresets[fallbackHostSlug] ??
256
+ buildDirectTenantContext(fallbackHostSlug, {
257
+ defaultTenantSlug: options.defaultTenantSlug,
258
+ defaultSurfaceId: options.defaultSurfaceId,
259
+ });
260
+ return {
261
+ publicHost: '',
262
+ hostSlug: fallbackHostSlug,
263
+ isMarketingHost: true,
264
+ ...fallback,
265
+ };
266
+ }
267
+ const candidate = hostname.split('.')[0] ?? '';
268
+ const normalizedCandidate = candidate.toLowerCase();
269
+ const marketingHost = !normalizedCandidate || marketingSlugs.has(normalizedCandidate);
270
+ const hostSlug = marketingHost ? fallbackHostSlug : normalizedCandidate;
271
+ const preset = hostPresets[hostSlug] ??
272
+ buildDirectTenantContext(hostSlug, {
273
+ defaultTenantSlug: options.defaultTenantSlug,
274
+ defaultSurfaceId: options.defaultSurfaceId,
275
+ });
276
+ return {
277
+ publicHost: hostname,
278
+ hostSlug,
279
+ isMarketingHost: marketingHost,
280
+ ...preset,
281
+ };
282
+ };
283
+ return {
284
+ marketingSlugs,
285
+ isMarketingSlug: (slug) => isMarketingSlug(slug, marketingSlugs),
286
+ resolveSurfaceHostContext,
287
+ resolveTenantSlugFromHost: (host) => resolveSurfaceHostContext(host).effectiveTenantSlug,
288
+ resolveCanonicalTenantSlugFromHost: (host) => resolveSurfaceHostContext(host).tenantSlug,
289
+ };
290
+ };
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@treasuryspatial/surface-kit",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "UNLICENSED",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "dependencies": {
21
+ "@treasuryspatial/mode-policy": "^0.1.5",
22
+ "@treasuryspatial/ui-manifest": "^0.1.6"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc -b",
26
+ "typecheck": "tsc -b --pretty false --noEmit"
27
+ }
28
+ }