@expofp/schema 0.0.0-experimental.cf063fc

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.
Files changed (49) hide show
  1. package/dist/index.d.ts +24 -0
  2. package/dist/index.js +23 -0
  3. package/dist/lib/booth.d.ts +74 -0
  4. package/dist/lib/booth.js +35 -0
  5. package/dist/lib/branding.d.ts +21 -0
  6. package/dist/lib/branding.js +20 -0
  7. package/dist/lib/camera.d.ts +24 -0
  8. package/dist/lib/camera.js +36 -0
  9. package/dist/lib/categories.d.ts +9 -0
  10. package/dist/lib/categories.js +7 -0
  11. package/dist/lib/config-defaults.d.ts +147 -0
  12. package/dist/lib/config-defaults.js +164 -0
  13. package/dist/lib/config.d.ts +2146 -0
  14. package/dist/lib/config.js +438 -0
  15. package/dist/lib/exhibitor.d.ts +66 -0
  16. package/dist/lib/exhibitor.js +69 -0
  17. package/dist/lib/filters.d.ts +23 -0
  18. package/dist/lib/filters.js +24 -0
  19. package/dist/lib/flags.d.ts +17 -0
  20. package/dist/lib/flags.js +63 -0
  21. package/dist/lib/fp-geo.d.ts +105 -0
  22. package/dist/lib/fp-geo.js +55 -0
  23. package/dist/lib/fp-svg.d.ts +399 -0
  24. package/dist/lib/fp-svg.js +196 -0
  25. package/dist/lib/heatmap.d.ts +23 -0
  26. package/dist/lib/heatmap.js +24 -0
  27. package/dist/lib/intents.d.ts +173 -0
  28. package/dist/lib/intents.js +153 -0
  29. package/dist/lib/journey.d.ts +27 -0
  30. package/dist/lib/journey.js +26 -0
  31. package/dist/lib/kiosk.d.ts +39 -0
  32. package/dist/lib/kiosk.js +65 -0
  33. package/dist/lib/maplibre.d.ts +43 -0
  34. package/dist/lib/maplibre.js +51 -0
  35. package/dist/lib/maps.d.ts +22 -0
  36. package/dist/lib/maps.js +19 -0
  37. package/dist/lib/poi-types.d.ts +13 -0
  38. package/dist/lib/poi-types.js +17 -0
  39. package/dist/lib/schedule.d.ts +25 -0
  40. package/dist/lib/schedule.js +20 -0
  41. package/dist/lib/search.d.ts +51 -0
  42. package/dist/lib/search.js +36 -0
  43. package/dist/lib/venues.d.ts +222 -0
  44. package/dist/lib/venues.js +150 -0
  45. package/dist/lib/visibility.d.ts +17 -0
  46. package/dist/lib/visibility.js +23 -0
  47. package/dist/lib/wayfinding.d.ts +104 -0
  48. package/dist/lib/wayfinding.js +52 -0
  49. package/package.json +35 -0
@@ -0,0 +1,438 @@
1
+ import * as z from 'zod';
2
+ import { RawBoothSchema } from './booth.js';
3
+ import { SelectionStyleSchema, WayfindingColorsSchema } from './branding.js';
4
+ import { CameraSchema } from './camera.js';
5
+ import { RawCategorySchema } from './categories.js';
6
+ import { LegacyLogoSchema, RawExhibitorSchema } from './exhibitor.js';
7
+ import { FiltersSchema } from './filters.js';
8
+ import { FlagsSchema } from './flags.js';
9
+ import { FpSvgJsRefSchema, FpSvgLayerJsRefSchema } from './fp-svg.js';
10
+ import { HeatmapSchema } from './heatmap.js';
11
+ import { IntentsSchema } from './intents.js';
12
+ import { JourneyLinkSchema } from './journey.js';
13
+ import { KioskSchema } from './kiosk.js';
14
+ import { MapLibreConfigSchema } from './maplibre.js';
15
+ import { MapsProviderSchema } from './maps.js';
16
+ import { RawPoiTypeSchema } from './poi-types.js';
17
+ import { ScheduleItemSchema } from './schedule.js';
18
+ import { FilterButtonsConfigSchema } from './search.js';
19
+ import { VenueSchema, VenuesVersionSchema } from './venues.js';
20
+ import { VisibilitySchema } from './visibility.js';
21
+ import { WfDataJsRefSchema } from './wayfinding.js';
22
+ // The document schemas below are LOOSE objects (`z.looseObject`): the platform
23
+ // emits fields faster than this file learns them, and the effective config is
24
+ // the runtime's ONLY copy of the expo data — a stripping parse would silently
25
+ // lose anything unmodeled. Fields are declared for typing, docs and `asset`
26
+ // tagging (`resolveAssetUrlsInPlace`); everything else passes through.
27
+ /**
28
+ * One `customCssFonts` entry — a web font to load alongside custom CSS.
29
+ *
30
+ * Deliberately tolerant: `customCssFonts` is rare, author-authored platform
31
+ * data, and this schema now *validates* `data.js` (a shape slip used to be
32
+ * harmless on the untyped `window.__data`). Requiring the fields would let a
33
+ * numeric `weight` or a missing `style`/`url` throw and abort the whole config
34
+ * load — the label renderer already coerces `weight` with `+` and falls back to
35
+ * the default font when a field is absent, so a bad entry should degrade, not
36
+ * fail boot.
37
+ */
38
+ const FontUrlSchema = z.looseObject({
39
+ weight: z.union([z.string(), z.number()]).optional(),
40
+ style: z.string().optional(),
41
+ url: z.string().meta({ asset: true }).optional(),
42
+ });
43
+ /**
44
+ * The cookie-consent decision for analytics. `'granted'` / `'denied'` apply a
45
+ * pre-made decision — no consent prompt, analytics on/off accordingly. `'ask'`
46
+ * (the default) leaves the decision to the visitor: GDPR visitors get the
47
+ * consent prompt, everyone else falls back to the regional gtag defaults.
48
+ */
49
+ export const ConsentSchema = z.enum(['ask', 'granted', 'denied']);
50
+ // this one presented to the world
51
+ export const ConfigSchema = z.object({
52
+ expo: z.string(),
53
+ intents: z.array(IntentsSchema),
54
+ // The config carries only REFS to the legacy payload documents — the
55
+ // resolved payloads live in @expofp/resolve's memo (`getResolved`).
56
+ // `loadConfig` resolves fpSvgJsRef and wfDataJsRef eagerly before it
57
+ // returns, so they are always warm; layer refs resolve on demand.
58
+ /** `fp.svg.js` ref (the drawing); null derives `<legacyDataUrlBase>fp.svg.js`. */
59
+ fpSvgJsRef: FpSvgJsRefSchema.nullable(),
60
+ /** Per-layer `fp.svg.<layerName>.js` refs (by layer name), resolved on demand. */
61
+ fpSvgLayerJsRefs: z.record(z.string(), FpSvgLayerJsRefSchema),
62
+ /** `wf.data.js` (wayfinding graph) ref; null without legacy data. */
63
+ wfDataJsRef: WfDataJsRefSchema.nullable(),
64
+ // data.js (__data)
65
+ noFeatured: z.boolean(),
66
+ isTrial: z.boolean(),
67
+ expoFpAd: z.boolean(),
68
+ free: z.boolean(),
69
+ trialExpiresAt: z.string(),
70
+ title: z.string(),
71
+ subtitle: z.string(),
72
+ homeUrl: z.string(),
73
+ registerUrl: z.string(),
74
+ startDate: z.string(),
75
+ endDate: z.string(),
76
+ // `optionalAsset`: the effective logo can be a data-dir-relative *guess* —
77
+ // `normalizeLegacyData` fabricates `<expo>-logo.png` when data.js carries no
78
+ // logo — so a 404 must warn-and-skip during offline generation, not abort the
79
+ // whole archive (an event logo is non-critical branding).
80
+ logo: z.string().meta({ asset: true, optionalAsset: true }),
81
+ gallery: z.array(LegacyLogoSchema),
82
+ gtag: z.string(),
83
+ boothTerm: z.string(),
84
+ levelTerm: z.string(),
85
+ reserveButtonTerm: z.string(),
86
+ exhibitorTerm: z.string(),
87
+ exhibitorTermPlural: z.string(),
88
+ locale: z.string(),
89
+ booths: z.array(RawBoothSchema),
90
+ exhibitors: z.array(RawExhibitorSchema),
91
+ categories: z.array(RawCategorySchema),
92
+ poiTypes: z.array(RawPoiTypeSchema),
93
+ reserveInstructions: z.string(),
94
+ sendLoginLinkUrl: z.string(),
95
+ trackerUrl: z.string(),
96
+ hideWayInformation: z.boolean(),
97
+ hideDirections: z.boolean(),
98
+ hideExhibitors: z.boolean(),
99
+ onlyFeaturedExhibitors: z.boolean(),
100
+ hideExhibitorBoothNumber: z.boolean(),
101
+ dimensionless: z.boolean(),
102
+ hideCategoriesLink: z.boolean(),
103
+ hideEventHomeLink: z.boolean(),
104
+ hideRegisterToAttendLink: z.boolean(),
105
+ hideDownloadPdfLink: z.boolean(),
106
+ hideBookmarksLink: z.boolean(),
107
+ hideBookmarks: z.boolean(),
108
+ hideLanguage: z.boolean(),
109
+ hideLanguageLink: z.boolean(),
110
+ /** Only these locale ids are offered in the language menu; empty = all bundled locales. */
111
+ uiLanguages: z.array(z.string()),
112
+ /** Hide the level name on the booth badges inside the exhibitor card. */
113
+ hideBoothLevel: z.boolean(),
114
+ /** Selected booth highlight: blinking interpolation (default) or a solid fill without outline. */
115
+ selectionStyle: SelectionStyleSchema,
116
+ /** Selected booth / POI color; empty keeps the plan's `__fpSettings` value. */
117
+ selectionColor: z.string(),
118
+ wayfindingColors: WayfindingColorsSchema,
119
+ autoTrackingGps: z.boolean(),
120
+ enableIPS: z.boolean(),
121
+ allow3dView: z.boolean(),
122
+ hide3dMapDefault: z.boolean(),
123
+ hideModeSwitchButton: z.boolean(),
124
+ isRebooking: z.boolean(),
125
+ events: z.array(ScheduleItemSchema),
126
+ customCss: z.string().meta({ cssAsset: true }),
127
+ customCssFonts: z.array(FontUrlSchema),
128
+ showLevelLabel: z.boolean(),
129
+ showCategories: z.boolean(),
130
+ showCompaniesAndBooths: z.boolean(),
131
+ showOtherSpaces: z.boolean(),
132
+ hideShareButton: z.boolean(),
133
+ /**
134
+ * Fold long exhibitor and session descriptions under a fade that expands
135
+ * on tap (in kiosk mode, the whole details block behind "Show more").
136
+ * `false` always shows the full text.
137
+ */
138
+ collapseDescriptions: z.boolean(),
139
+ /**
140
+ * While the visitor types in search, frame the matching booths and points once typing pauses:
141
+ * the matches in the venue on screen, or the venue all matches share. `false` keeps the camera
142
+ * where it is until a result is picked.
143
+ */
144
+ searchCameraFollow: z.boolean(),
145
+ viewOptimizationLevel: z.number(),
146
+ shortLevelName: z.boolean(),
147
+ searchText: z.string(),
148
+ filterButtonsConfig: FilterButtonsConfigSchema,
149
+ enableRotation: z.boolean(),
150
+ alwaysShowSidebar: z.boolean(),
151
+ customKioskQrCodeUrl: z.string(),
152
+ /**
153
+ * Address every QR code the plan prints is built on — the route code and the
154
+ * cross-venue journey deep link alike. Empty, the default, means the plan's
155
+ * own canonical `https://<expo>.expofp.com`, which is right whenever the plan
156
+ * is served from there; a copy served from somewhere else — a branch runtime,
157
+ * an offline build, a page embedding the plan under its own address — sets
158
+ * this so a scanned code lands on a page that exists.
159
+ *
160
+ * Only the part before the query is honored: each code writes its own query
161
+ * over whatever this carries. Everything after it rides along untouched, so a
162
+ * host that selects the plan with a fragment keeps it.
163
+ */
164
+ qrCodeBaseUrl: z.string(),
165
+ /** Wire version of the multi-venue payload. Revision 2 defines version 1. */
166
+ venuesVersion: VenuesVersionSchema,
167
+ /**
168
+ * Multi-venue definitions. A plan has a venue model when this array is
169
+ * present, non-empty, and valid — the loose shape here lets a malformed
170
+ * venue through so it can be quarantined with a diagnostic rather than
171
+ * failing the whole plan (contract enforcement lives in
172
+ * `packages/floorplan/src/data/venues.ts`).
173
+ */
174
+ venues: z.array(VenueSchema),
175
+ /**
176
+ * Producer override for the external maps provider a cross-venue journey
177
+ * hands off to. Unset — the default — leaves the choice to the platform
178
+ * (Apple Maps on iOS/iPadOS, Google Maps elsewhere); setting it forces that
179
+ * provider everywhere, so a partnership or regional preference is honored on
180
+ * every device. Inert unless `crossVenueJourneys` is on.
181
+ */
182
+ mapsProvider: MapsProviderSchema.optional(),
183
+ /**
184
+ * The journey a deep link asks for — the query a scanned kiosk QR or a
185
+ * desktop "continue on your phone" link arrives as. Absent on an ordinary
186
+ * load. Identifiers only: opening the link recomputes the journey from the
187
+ * plan the device has now (`?journey[to]=A-12&journey[from]=B-30`).
188
+ */
189
+ journey: JourneyLinkSchema.optional(),
190
+ /**
191
+ * Indoor-positioning provider for the native SDKs, opaque web-side:
192
+ * `<provider>.<version>.<base64url credentials>`, e.g.
193
+ * `indooratlas.1.SGVsbG8gV29ybGQh`. `null` (the default) means none — not
194
+ * `''`, so the native bridge sees Kotlin `null` / Swift `nil`.
195
+ */
196
+ mobileLocationProvider: z.string().nullable(),
197
+ ...FlagsSchema.shape,
198
+ // user preferences
199
+ /** Debug mode: verbose logs, the in-map debug overlay, dev-leniency in error paths. */
200
+ debugMode: z.boolean(),
201
+ debugPattern: z.string(),
202
+ showDebugButton: z.boolean(),
203
+ // options
204
+ previewMode: z.boolean(),
205
+ noOverlay: z.boolean(),
206
+ offHistory: z.boolean(),
207
+ ignoreQuery: z.boolean(),
208
+ consent: ConsentSchema,
209
+ viewerMode: z.boolean(),
210
+ disableRuntimeAlerts: z.boolean(),
211
+ maplibre: MapLibreConfigSchema,
212
+ // presentation toggles, historically one-shot URL params scrubbed by the
213
+ // legacy router; now ordinary config fields every layer (manifest, options,
214
+ // localStorage, URL) can set
215
+ /** Render the plan in grayscale. */
216
+ monochrome: z.boolean(),
217
+ /** Hide the header logo (and the ExpoFP logo). */
218
+ hideHeaderLogo: z.boolean(),
219
+ /** Hide exhibitor logos inside booths. */
220
+ hideLogoInBooth: z.boolean(),
221
+ /** Drop the `featured` flag from every exhibitor (no featured view). */
222
+ disableFeatured: z.boolean(),
223
+ /** Disable adding entities to bookmarks. */
224
+ disableBookmarked: z.boolean(),
225
+ /** Start with GPS tracking off. */
226
+ disableGps: z.boolean(),
227
+ /**
228
+ * The initial camera, applied once at boot (an empty object means "don't
229
+ * move"). The URL form is `?camera[x]=…`; the runtime counterpart is
230
+ * `FloorPlan.setCamera` / the `setCamera` intent.
231
+ */
232
+ camera: CameraSchema,
233
+ /**
234
+ * Visibility of the map chrome, applied once at boot. An empty object leaves
235
+ * the chrome untouched; a non-empty one REBUILDS the set — every element it
236
+ * omits resets to visible — so a URL that hides one element must list every
237
+ * other element it also wants hidden. The URL form is
238
+ * `?visibility[header]=false`; the runtime counterpart is
239
+ * `FloorPlan.setVisibility` / the `setVisibility` intent.
240
+ */
241
+ visibility: VisibilitySchema,
242
+ /**
243
+ * Search filters applied once at boot by the URL filter manager (an empty
244
+ * object applies nothing). Canonical URL form `?filters[categories][0]=food`;
245
+ * the legacy `?categories=`/`?poiType=`/`?poiTypes=`/`?exhibitors=true` keys
246
+ * keep working — and remain the form the floor plan writes back to the URL
247
+ * as the visitor changes filters.
248
+ */
249
+ filters: FiltersSchema,
250
+ /**
251
+ * Heatmap mode, engaged once at boot (an empty object — the default — means
252
+ * no heatmap). A non-empty node engages the mode unless `enabled` is
253
+ * explicitly `false`, so `heatmap: { variant: 'yah' }` implies enabled;
254
+ * `variant` picks the dataset (`booths` view stats by default, `yah` for
255
+ * "You are here" QR scans; `kiosk: true` narrows `yah` to kiosk positions).
256
+ * Heatmap mode freezes the page URL for the whole session (the legacy
257
+ * contract). The legacy `?heatmap=true&type=yah&subtype=kiosk` links keep
258
+ * working as a translation; the access token `?t=` stays a separate raw
259
+ * query param, not config.
260
+ */
261
+ heatmap: HeatmapSchema,
262
+ /**
263
+ * The kiosk anchor — where a kiosk device stands and how its camera is
264
+ * framed, applied at boot when the device has no locally-saved kiosk (the
265
+ * on-device SetKiosk flow wins; `localStorage['kiosk']='0'` disables both).
266
+ * Canonical URL form `?kiosk[x]=…`, and `?kiosk=1/0` keeps toggling kiosk
267
+ * mode. The legacy `kiosk_x/y/z` params are a separate, narrower channel:
268
+ * they carry the anchor POSITION to a phone scanning a kiosk's route QR
269
+ * code, and put that phone in no kiosk mode of its own.
270
+ */
271
+ kiosk: KioskSchema,
272
+ });
273
+ /**
274
+ * Deprecated `allowConsent` input alias, accepted by the data and options input
275
+ * schemas and folded into `consent` by `loadConfig` (`true` → `'granted'`,
276
+ * `false` → `'denied'`; a layer's own `consent` wins). The effective config
277
+ * never carries it. RETIRED from the URL query — `?consent=` is the only query
278
+ * form (see `retiredKeys` in `@expofp/config`'s legacy-url codec).
279
+ */
280
+ const DeprecatedConsentAlias = {
281
+ allowConsent: z.boolean().optional(),
282
+ };
283
+ /**
284
+ * Load-time diagnostic inputs — accepted from the URL query and localStorage but
285
+ * NEVER carried on the effective config (`loadConfig` reads them up front, then
286
+ * strips them before the config is frozen). So far only `validateSchema`: it
287
+ * gates schema validation during the load itself (consumed by `@expofp/config`'s
288
+ * `readValidateFlag`) and is meaningless once the config exists — hence kept off
289
+ * `ConfigSchema`, like the deprecated `allowConsent` alias above.
290
+ */
291
+ const LoadDiagnostics = {
292
+ validateSchema: z.boolean().optional(),
293
+ };
294
+ /**
295
+ * The expo data document — the `__data` global of the legacy `data.js`: every
296
+ * config field optional, plus the deprecated nested `flags`.
297
+ */
298
+ export const DataSchema = z.looseObject({
299
+ ...ConfigSchema.partial().shape,
300
+ ...DeprecatedConsentAlias,
301
+ flags: FlagsSchema.optional().meta({ description: 'deprecated, use root-level fields' }),
302
+ });
303
+ /**
304
+ * The evaluated `data.js` payload. Like `fp.svg.js`, the file is a classic
305
+ * window-assigning browser script (`window.__data = …`) that `resolve`
306
+ * (`@expofp/resolve`) evaluates to its globals; the expo data document rides
307
+ * on `__data`.
308
+ */
309
+ export const DataJsSchema = z.looseObject({
310
+ __data: DataSchema.optional(),
311
+ });
312
+ // manifest, options, localStorage, URL -> all fields optional
313
+ // result config - all fields are set, except raw (bool/string that are empty)
314
+ // Loose for the same reason as DataSchema: an offline copy's manifest IS
315
+ // the merged expo data, so unmodeled fields must survive the parse.
316
+ export const ManifestSchema = z.looseObject({
317
+ ...ConfigSchema.partial().required({ expo: true }).shape,
318
+ ...DeprecatedConsentAlias,
319
+ /**
320
+ * The legacy expo-data directory (`data.js`, `fp.svg.js`, …). Consumed by
321
+ * `loadConfig` to fetch the document and derive the payload refs — it is NOT
322
+ * carried on the effective config; nothing outside the config package ever
323
+ * sees it.
324
+ */
325
+ legacyDataUrlBase: z.string().optional(),
326
+ /**
327
+ * Pin of the legacy data revision — the `version.json` value at manifest
328
+ * generation time. `loadConfig` cache-busts the legacy file refs with it
329
+ * (`?v=<pin>`) and skips its own `version.json` probe, so the manifest and
330
+ * the data it points at stay consistent by construction. `null` states
331
+ * "probed: no version.json exists" — the runtime cache-busts per load with
332
+ * a timestamp, still without probing. Only an ABSENT field (legacy
333
+ * manifests, which predate the pin) leaves the runtime to probe; the
334
+ * retired `$ref`-pointer shape still parses but is treated as absent. An
335
+ * input consumed by `loadConfig` like `legacyDataUrlBase`, never carried on
336
+ * the effective config.
337
+ */
338
+ legacyDataVersion: z.union([z.string(), z.null(), z.object({ $ref: z.string() })]).optional(),
339
+ });
340
+ /**
341
+ * Caller-supplied overrides — the config fields a host may set when embedding
342
+ * the floor plan (`load(manifest, options)`). Deliberately EXPLICIT (a `pick`,
343
+ * not `ConfigSchema.partial()`): the expo data proper — booths, exhibitors,
344
+ * branding, feature flags — comes from the manifest / `data.js`, so `loadConfig`
345
+ * parses the options layer and strips anything outside this set. `allowConsent`
346
+ * is the deprecated alias for `consent`.
347
+ */
348
+ export const OptionsSchema = ConfigSchema.partial()
349
+ .pick({
350
+ previewMode: true,
351
+ noOverlay: true,
352
+ offHistory: true,
353
+ ignoreQuery: true,
354
+ consent: true,
355
+ viewerMode: true,
356
+ disableRuntimeAlerts: true,
357
+ maplibre: true,
358
+ })
359
+ .extend(DeprecatedConsentAlias);
360
+ /** The subset tunable from the page URL query. */
361
+ export const UrlConfigSchema = ConfigSchema.partial()
362
+ .pick({
363
+ enableExperimentalMaplibre: true,
364
+ enableExperimentalOutdoorMarkers: true,
365
+ enableExperimentalVenueFraming: true,
366
+ enableExperimentalNorthUp: true,
367
+ crossVenueJourneys: true,
368
+ // the journey provider override — tunable here so a plan can be checked on
369
+ // either provider from any device, not only the one it defaults to
370
+ mapsProvider: true,
371
+ // the journey deep link: ?journey[to]=A-12&journey[from]=B-30 — a scanned
372
+ // kiosk QR or a desktop hand-off arrives as exactly this
373
+ journey: true,
374
+ intents: true,
375
+ consent: true,
376
+ // the former one-shot presentation params — the query keys keep their
377
+ // historical names, which match these field names exactly. `noOverlay` is
378
+ // NOT among them: the overlay is addressed by `?visibility[overlay]=false`
379
+ // from the URL, the field stays a manifest/options setting
380
+ monochrome: true,
381
+ hideHeaderLogo: true,
382
+ hideLogoInBooth: true,
383
+ disableFeatured: true,
384
+ disableBookmarked: true,
385
+ disableGps: true,
386
+ // the canonical camera form: ?camera[x]=6517&camera[y]=3826&camera[bearing]=180
387
+ camera: true,
388
+ // the canonical visibility form: ?visibility[header]=false
389
+ visibility: true,
390
+ // the canonical filters form: ?filters[categories][0]=food — the legacy
391
+ // `categories`/`poiType(s)`/`exhibitors` keys stay OUT of this pick: they
392
+ // live in the URL as the filter manager's property and are never scrubbed
393
+ filters: true,
394
+ // the canonical heatmap form: ?heatmap[variant]=yah&heatmap[enabled]=true
395
+ // (the legacy scalar ?heatmap=true is not this node's shape — it stays a
396
+ // legacy-URL one-shot and drops out of the tolerant config parse)
397
+ heatmap: true,
398
+ // the canonical kiosk-anchor form: ?kiosk[x]=6517&kiosk[y]=3826 — the
399
+ // legacy scalar ?kiosk=1/0 (the mode toggle) is not this node's shape: it
400
+ // drops out of the tolerant parse and keeps its params-based primary
401
+ kiosk: true,
402
+ })
403
+ .extend(LoadDiagnostics);
404
+ /**
405
+ * The subset persisted per-user in localStorage.
406
+ *
407
+ * `viewerMode` / `previewMode` / `uiScale` are schema-typed here (their keys
408
+ * are `efp-viewerMode` / `efp-previewMode` / `efp-uiScale`) but deliberately
409
+ * NOT merged into the effective config by `loadConfig`: the floor plan reads
410
+ * them from storage lazily, which is what keeps the legacy one-shot URL seeds
411
+ * (`?viewermode=` / `?previewMode=` / `?uiscale=`, which write these keys)
412
+ * effective within the same load — a frozen config value could not be
413
+ * revoked by a same-load disable seed.
414
+ */
415
+ export const LocalStorageConfigSchema = ConfigSchema.partial()
416
+ .pick({
417
+ enableExperimentalMaplibre: true,
418
+ enableExperimentalOutdoorMarkers: true,
419
+ enableExperimentalVenueFraming: true,
420
+ enableExperimentalNorthUp: true,
421
+ debugMode: true,
422
+ debugPattern: true,
423
+ showDebugButton: true,
424
+ viewerMode: true,
425
+ previewMode: true,
426
+ })
427
+ .extend({
428
+ /**
429
+ * Per-browser UI-scale preference (0.8–1.4), seeded by the legacy
430
+ * `?uiscale=` param. Not a `ConfigSchema` field: nothing consumes a
431
+ * config-level uiScale — the floor plan UI reads the storage key
432
+ * directly. Tolerant (`catch`): a hand-edited or out-of-range stored
433
+ * value reads as absent instead of failing the whole storage layer at
434
+ * boot.
435
+ */
436
+ uiScale: z.number().min(0.8).max(1.4).optional().catch(undefined),
437
+ })
438
+ .extend(LoadDiagnostics);
@@ -0,0 +1,66 @@
1
+ import * as z from 'zod';
2
+ /** A marketing asset an exhibitor uploads — an entry in `marketMaterials`. */
3
+ export declare const MarketMaterialSchema: z.ZodObject<{
4
+ fileName: z.ZodString;
5
+ path: z.ZodString;
6
+ }, z.core.$loose>;
7
+ /** The legacy string logo form — a bare asset URL. */
8
+ export declare const LegacyLogoSchema: z.ZodString;
9
+ /**
10
+ * The object logo form, carrying pre-scaled variant URLs. The variants are
11
+ * minted from the full URL without an existence check (`optionalAsset`), so
12
+ * the platform may never have produced the files — consumers fall back to
13
+ * `url`, and the offline generator skips a missing variant instead of failing.
14
+ */
15
+ export declare const LogoSchema: z.ZodObject<{
16
+ url: z.ZodString;
17
+ smallUrl: z.ZodOptional<z.ZodString>;
18
+ tinyUrl: z.ZodOptional<z.ZodString>;
19
+ }, z.core.$strip>;
20
+ export declare const RawExhibitorSchema: z.ZodObject<{
21
+ id: z.ZodNonOptional<z.ZodOptional<z.ZodNumber>>;
22
+ name: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
23
+ externalId: z.ZodOptional<z.ZodString>;
24
+ featured: z.ZodOptional<z.ZodBoolean>;
25
+ advertise: z.ZodOptional<z.ZodBoolean>;
26
+ description: z.ZodOptional<z.ZodString>;
27
+ address: z.ZodOptional<z.ZodString>;
28
+ address2: z.ZodOptional<z.ZodString>;
29
+ city: z.ZodOptional<z.ZodString>;
30
+ state: z.ZodOptional<z.ZodString>;
31
+ zip: z.ZodOptional<z.ZodString>;
32
+ country: z.ZodOptional<z.ZodString>;
33
+ phone1: z.ZodOptional<z.ZodString>;
34
+ website: z.ZodOptional<z.ZodString>;
35
+ facebook: z.ZodOptional<z.ZodString>;
36
+ instagram: z.ZodOptional<z.ZodString>;
37
+ linkedin: z.ZodOptional<z.ZodString>;
38
+ twitter: z.ZodOptional<z.ZodString>;
39
+ googlePlus: z.ZodOptional<z.ZodString>;
40
+ xing: z.ZodOptional<z.ZodString>;
41
+ youtube: z.ZodOptional<z.ZodString>;
42
+ email: z.ZodOptional<z.ZodString>;
43
+ privateEmail: z.ZodOptional<z.ZodString>;
44
+ order: z.ZodOptional<z.ZodNumber>;
45
+ logo: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
46
+ url: z.ZodString;
47
+ smallUrl: z.ZodOptional<z.ZodString>;
48
+ tinyUrl: z.ZodOptional<z.ZodString>;
49
+ }, z.core.$strip>]>>;
50
+ logoInBooth: z.ZodOptional<z.ZodBoolean>;
51
+ logoAspectRatio: z.ZodOptional<z.ZodNumber>;
52
+ gallery: z.ZodOptional<z.ZodArray<z.ZodString>>;
53
+ marketMaterials: z.ZodOptional<z.ZodArray<z.ZodObject<{
54
+ fileName: z.ZodString;
55
+ path: z.ZodString;
56
+ }, z.core.$loose>>>;
57
+ categories: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
58
+ leadingImageUrl: z.ZodOptional<z.ZodString>;
59
+ videoUrl: z.ZodOptional<z.ZodString>;
60
+ rebookingState: z.ZodOptional<z.ZodNumber>;
61
+ rebookingNote: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$loose>;
63
+ export type RawExhibitor = z.infer<typeof RawExhibitorSchema>;
64
+ export type MarketMaterial = z.infer<typeof MarketMaterialSchema>;
65
+ export type Logo = z.infer<typeof LogoSchema>;
66
+ //# sourceMappingURL=exhibitor.d.ts.map
@@ -0,0 +1,69 @@
1
+ import * as z from 'zod';
2
+ /** A marketing asset an exhibitor uploads — an entry in `marketMaterials`. */
3
+ export const MarketMaterialSchema = z.looseObject({
4
+ fileName: z.string(),
5
+ path: z.string().meta({ asset: true }),
6
+ });
7
+ /** The legacy string logo form — a bare asset URL. */
8
+ export const LegacyLogoSchema = z.string().meta({ asset: true });
9
+ /**
10
+ * The object logo form, carrying pre-scaled variant URLs. The variants are
11
+ * minted from the full URL without an existence check (`optionalAsset`), so
12
+ * the platform may never have produced the files — consumers fall back to
13
+ * `url`, and the offline generator skips a missing variant instead of failing.
14
+ */
15
+ export const LogoSchema = z.object({
16
+ url: z.string().meta({ asset: true }),
17
+ smallUrl: z.string().optional().meta({ asset: true, optionalAsset: true }),
18
+ tinyUrl: z.string().optional().meta({ asset: true, optionalAsset: true }),
19
+ });
20
+ /**
21
+ * An exhibitor logo. The platform still emits the legacy string form on input;
22
+ * `normalizeLegacyData` (`@expofp/config`) converts it to {@link LogoSchema} —
23
+ * the pre-scaled `__small`/`__tiny` siblings become explicit variant URLs — so
24
+ * the EFFECTIVE config only ever carries the object form. Plain code, not a zod
25
+ * transform: parse is validation only (gated by the opt-in `validateSchema` flag) and the
26
+ * pipeline must work without it.
27
+ */
28
+ const ExhibitorLogoSchema = LegacyLogoSchema.or(LogoSchema);
29
+ export const RawExhibitorSchema = z
30
+ .looseObject({
31
+ id: z.number(),
32
+ name: z.string(),
33
+ externalId: z.string(),
34
+ featured: z.boolean(),
35
+ advertise: z.boolean(),
36
+ description: z.string(),
37
+ address: z.string(),
38
+ address2: z.string(),
39
+ city: z.string(),
40
+ state: z.string(),
41
+ zip: z.string(),
42
+ country: z.string(),
43
+ phone1: z.string(),
44
+ website: z.string(),
45
+ facebook: z.string(),
46
+ instagram: z.string(),
47
+ linkedin: z.string(),
48
+ twitter: z.string(),
49
+ googlePlus: z.string(),
50
+ xing: z.string(),
51
+ youtube: z.string(),
52
+ email: z.string(),
53
+ privateEmail: z.string(),
54
+ order: z.number(),
55
+ logo: ExhibitorLogoSchema,
56
+ /** Paint the logo inside the exhibitor's booth shape on the drawing. */
57
+ logoInBooth: z.boolean(),
58
+ /** The logo's width divided by its height. */
59
+ logoAspectRatio: z.number(),
60
+ gallery: z.array(LegacyLogoSchema),
61
+ marketMaterials: z.array(MarketMaterialSchema),
62
+ categories: z.array(z.number()),
63
+ leadingImageUrl: z.string().meta({ asset: true }),
64
+ videoUrl: z.string(),
65
+ rebookingState: z.number(),
66
+ rebookingNote: z.string(),
67
+ })
68
+ .partial()
69
+ .required({ id: true, name: true });
@@ -0,0 +1,23 @@
1
+ import * as z from 'zod';
2
+ /**
3
+ * Boot-time search filters — the `config.filters` node, applied once by the
4
+ * floor plan's URL filter manager when the stores are ready. Values are plain
5
+ * catalog names (no URL encoding), matched case-insensitively; unknown names
6
+ * warn and drop, and `categories` win over POI types when both are given.
7
+ *
8
+ * `poiType` (single) and `poiTypes` (multi) are deliberately distinct fields —
9
+ * not one array as the retirement-plan sketch had it — because their apply
10
+ * paths differ: the single form also activates the matching search filter
11
+ * button (`setPoiFilterId`), while the multi form only pre-selects the
12
+ * filters. Folding them into one array would silently change what a
13
+ * one-element list does.
14
+ */
15
+ export declare const FiltersSchema: z.ZodObject<{
16
+ categories: z.ZodOptional<z.ZodArray<z.ZodString>>;
17
+ poiType: z.ZodOptional<z.ZodString>;
18
+ poiTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
19
+ exhibitors: z.ZodOptional<z.ZodBoolean>;
20
+ }, z.core.$strip>;
21
+ export interface Filters extends z.infer<typeof FiltersSchema> {
22
+ }
23
+ //# sourceMappingURL=filters.d.ts.map
@@ -0,0 +1,24 @@
1
+ import * as z from 'zod';
2
+ /**
3
+ * Boot-time search filters — the `config.filters` node, applied once by the
4
+ * floor plan's URL filter manager when the stores are ready. Values are plain
5
+ * catalog names (no URL encoding), matched case-insensitively; unknown names
6
+ * warn and drop, and `categories` win over POI types when both are given.
7
+ *
8
+ * `poiType` (single) and `poiTypes` (multi) are deliberately distinct fields —
9
+ * not one array as the retirement-plan sketch had it — because their apply
10
+ * paths differ: the single form also activates the matching search filter
11
+ * button (`setPoiFilterId`), while the multi form only pre-selects the
12
+ * filters. Folding them into one array would silently change what a
13
+ * one-element list does.
14
+ */
15
+ export const FiltersSchema = z.object({
16
+ /** Category names to pre-select; opens the category filter panel. */
17
+ categories: z.array(z.string()).optional(),
18
+ /** A single POI type to pre-select; also activates its search filter button. */
19
+ poiType: z.string().optional(),
20
+ /** POI type names to pre-select (no filter-button activation). */
21
+ poiTypes: z.array(z.string()).optional(),
22
+ /** `true` opens the exhibitors list at boot. */
23
+ exhibitors: z.boolean().optional(),
24
+ });
@@ -0,0 +1,17 @@
1
+ import * as z from 'zod';
2
+ /**
3
+ * Feature flags. Historically a nested `flags` object; now flattened onto the
4
+ * config root (`...FlagsSchema.shape` in `ConfigSchema`). The deprecated nested
5
+ * form still parses through `DataJsonSchema`.
6
+ */
7
+ export declare const FlagsSchema: z.ZodObject<{
8
+ enableExperimentalMaplibre: z.ZodOptional<z.ZodBoolean>;
9
+ enableExperimentalOutdoorMarkers: z.ZodOptional<z.ZodBoolean>;
10
+ enableExperimentalVenueFraming: z.ZodOptional<z.ZodBoolean>;
11
+ enableExperimentalNorthUp: z.ZodOptional<z.ZodBoolean>;
12
+ customSetKiosk: z.ZodOptional<z.ZodString>;
13
+ hideBoothBadges: z.ZodOptional<z.ZodBoolean>;
14
+ crossVenueJourneys: z.ZodOptional<z.ZodBoolean>;
15
+ busRoutes: z.ZodOptional<z.ZodBoolean>;
16
+ }, z.core.$loose>;
17
+ //# sourceMappingURL=flags.d.ts.map