Sign In

@expofp/config

Package Overview
Dependencies
Maintainers
6
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@expofp/config - npm Package Compare versions

Comparing version
3.19.0
to
3.20.0
+1
-1
dist/index.d.ts
export { applyIntents } from './lib/apply-intents.js';
export { getConfig, setConfig } from './lib/config-store.js';
export { type DebugSettingDescriptor, toDebugSettings } from './lib/debug-settings.js';
export { type LegacyOneShot, type LegacyPrimary, type LegacyUrlQuery, parseLegacyQuery, serializeSelection, type UrlSelection, } from './lib/legacy-url.js';
export { type LegacyOneShot, type LegacyPrimary, type LegacyUrlQuery, parseLegacyQuery, serializeSelection, splitPlatformParams, type UrlSelection, } from './lib/legacy-url.js';
export { loadConfig } from './lib/load-config.js';

@@ -6,0 +6,0 @@ export { type StorageLike } from './lib/local-storage-codec.js';

export { applyIntents } from './lib/apply-intents.js';
export { getConfig, setConfig } from './lib/config-store.js';
export { toDebugSettings } from './lib/debug-settings.js';
export { parseLegacyQuery, serializeSelection, } from './lib/legacy-url.js';
export { parseLegacyQuery, serializeSelection, splitPlatformParams, } from './lib/legacy-url.js';
export { loadConfig } from './lib/load-config.js';

@@ -6,0 +6,0 @@ export { serializeConfigResources, } from './lib/serialize-config-resources.js';

@@ -161,2 +161,17 @@ /**

/**
* Split a raw `location.search` into the floor plan's own query and the
* platform's routing params (`?expo=…` — {@link platformParamKeys}).
* Raw-segment level (split on `&`, no decoding): platform params travel
* outside the legacy grammar's single-`encodeURIComponent`-unit payload, and
* that payload must pass through untouched. The floor plan's single URL
* writer (`url-sync`) hides the platform half from what the app reads back
* and re-attaches it verbatim to every URL it writes — a preview URL
* `/s/<sha>/?expo=…` must survive reload and sharing after any rewrite.
* When no platform param is present, `search` is returned byte-identical.
*/
export declare function splitPlatformParams(search: string): {
search: string;
platform: string;
};
/**
* The selection's canonical query — `''` for none, else `?<payload>` with the

@@ -163,0 +178,0 @@ * whole payload as one `encodeURIComponent` unit (the legacy contract). This is

@@ -47,2 +47,19 @@ /**

const legacyCameraKeys = new Set(['centerxy', 'center', 'z', 'bearing', 'zoomtime', 'roll']);
/**
* Query keys owned by the DELIVERY PLATFORM, not the floor plan: `?expo=` is
* the routing param the sha-delivery platform materializes for expo-aware
* origins, and preview URLs (`/s/<sha>/?expo=…`) carry it literally in the
* page URL (design note 2026-08-05-sha-delivery-iac.md § 2). Not a grammar
* extension — a third partition of the query alongside config-owned and
* one-shot keys: the parser strips these from the residual slug (in their
* `key=value` form only — a bare slug that merely spells `expo` still
* resolves via the catalog), and the floor plan's URL writer carries them
* verbatim across query rewrites ({@link splitPlatformParams}).
*
* Unlike config-owned keys, platform params do NOT classify a query as
* `ownedByConfig`: `?expo=…` alone DESCRIBES the empty selection — browser
* back onto it must clear the selection like any genuinely empty query,
* whereas config keys are instructions riding alongside the selection state.
*/
const platformParamKeys = new Set(['expo']);
export function parseLegacyQuery(search) {

@@ -250,4 +267,5 @@ const rawQuery = search.startsWith('?') ? search.slice(1) : search;

* The slug is the decoded query minus every key another consumer owns: the
* config layer's keys and intent shortcuts (read by `loadConfig`), and the
* one-shot keys consumed above. `heatmap`/`type`/`subtype` stay in the slug —
* config layer's keys and intent shortcuts (read by `loadConfig`), the
* one-shot keys consumed above, and the platform's routing params.
* `heatmap`/`type`/`subtype` stay in the slug —
* heatmap mode historically froze the URL with them in place (its data loader

@@ -275,2 +293,4 @@ * re-reads them), and the select fallback knows not to treat a query carrying

return false;
if (platformParamKeys.has(key) && part.includes('='))
return false;
// Carve-out (retirement plan §4.8): `heatmap` is a UrlConfigSchema key

@@ -288,2 +308,29 @@ // now, so the canonical bracketed `heatmap[…]=` form is config-owned and

}
/* ── Platform routing params: the writer-side partition ────────────────────── */
/**
* Split a raw `location.search` into the floor plan's own query and the
* platform's routing params (`?expo=…` — {@link platformParamKeys}).
* Raw-segment level (split on `&`, no decoding): platform params travel
* outside the legacy grammar's single-`encodeURIComponent`-unit payload, and
* that payload must pass through untouched. The floor plan's single URL
* writer (`url-sync`) hides the platform half from what the app reads back
* and re-attaches it verbatim to every URL it writes — a preview URL
* `/s/<sha>/?expo=…` must survive reload and sharing after any rewrite.
* When no platform param is present, `search` is returned byte-identical.
*/
export function splitPlatformParams(search) {
const raw = search.startsWith('?') ? search.slice(1) : search;
if (!raw)
return { search, platform: '' };
const segments = raw.split('&');
const platform = segments.filter(isPlatformParam);
if (!platform.length)
return { search, platform: '' };
const app = segments.filter((segment) => !isPlatformParam(segment));
return { search: app.length ? '?' + app.join('&') : '', platform: platform.join('&') };
}
function isPlatformParam(segment) {
const eq = segment.indexOf('=');
return eq > 0 && platformParamKeys.has(segment.slice(0, eq));
}
/* ── Serialize: selection → location.search ────────────────────────────────── */

@@ -290,0 +337,0 @@ /**

@@ -9,4 +9,5 @@ import { type Ref } from '@expofp/resolve';

*
* With a `legacyDataUrlBase` (live events), the version probe settles the
* `?v=` cache-buster, refs to the sibling drawing / wayfinding files are
* With a `legacyDataUrlBase` (live events), the manifest's `legacyDataVersion`
* pin — or, absent one, the version probe — settles the `?v=` cache-buster,
* refs to the sibling drawing / wayfinding files are
* derived from it (`data.js` never carries them), and all three legacy files —

@@ -13,0 +14,0 @@ * `data.js` evaluated to its `__data` document like every legacy `.js` file,

@@ -20,4 +20,5 @@ /// <reference lib="dom" />

*
* With a `legacyDataUrlBase` (live events), the version probe settles the
* `?v=` cache-buster, refs to the sibling drawing / wayfinding files are
* With a `legacyDataUrlBase` (live events), the manifest's `legacyDataVersion`
* pin — or, absent one, the version probe — settles the `?v=` cache-buster,
* refs to the sibling drawing / wayfinding files are
* derived from it (`data.js` never carries them), and all three legacy files —

@@ -49,7 +50,6 @@ * `data.js` evaluated to its `__data` document like every legacy `.js` file,

manifest = validateOrClone(ManifestSchema, await resolve(manifest));
// The legacy event-data directory (and the old manifests' version pointer,
// replaced by the version.json probe) are INPUTS, consumed right here — the
// effective config carries only the refs derived from them, so neither is
// merged.
const { legacyDataUrlBase, legacyDataVersion: _manifestVersion, ...manifestFields } = manifest;
// The legacy event-data directory and the data-revision pin are INPUTS,
// consumed right here — the effective config carries only the refs derived
// from them, so neither is merged.
const { legacyDataUrlBase, legacyDataVersion: manifestPin, ...manifestFields } = manifest;
applyConsentAlias(manifestFields);

@@ -60,14 +60,31 @@ assignDefined(config, manifestFields);

applyConsentAlias(options);
// every legacy file URL is ?v= cache-busted; a timestamp busts when no
// version.json exists (TODO: drop once the legacy data directory is gone)
// every legacy file URL is ?v= cache-busted; a timestamp busts when neither
// the manifest nor version.json pins a revision (TODO: drop once the legacy
// data directory is gone)
let legacyDataVersion = String(Date.now());
// live legacy directory: version probe, then the sibling file refs — data.js
// never carries the payload refs, so both are known before it lands
// live legacy directory: settle the version (manifest pin, else the
// version.json probe), then the sibling file refs — data.js never carries
// the payload refs, so both are known before it lands
if (legacyDataUrlBase) {
if (isFromDesignerReferrer()) {
// The designer previews in-progress edits — the directory's files change
// without a version bump, so the published version must not pin `?v=`;
// the unique timestamp stands and every load fetches fresh files.
// without a version bump, so a published version (the manifest pin and
// version.json alike) must not pin `?v=`; the unique timestamp stands
// and every load fetches fresh files.
log('loadConfig', 'designer referrer — cache-busting with a timestamp');
}
else if (typeof manifestPin === 'string' && manifestPin) {
// The manifest pins the data revision (get-manifest already probed
// version.json server-side) — honor it, no client probe: manifest and
// data stay consistent by construction.
legacyDataVersion = manifestPin;
}
else if (manifestPin === null) {
// The generator probed and there IS no version.json for this expo — the
// per-load timestamp stands, and the client must not re-probe (on the
// cross-origin contour that probe could only fail). Only an ABSENT pin
// (legacy manifests; the retired `$ref` pointer counts as absent) falls
// through to the probe below.
log('loadConfig', 'manifest pins "no version" — cache-busting with a timestamp');
}
else {

@@ -74,0 +91,0 @@ try {

{
"name": "@expofp/config",
"version": "3.19.0",
"version": "3.20.0",
"type": "module",

@@ -32,6 +32,6 @@ "description": "ExpoFP SDK internal: config layer and schemas",

"zod": "4.4.3",
"@expofp/schema": "3.19.0",
"@expofp/resolve": "3.19.0",
"@expofp/utils": "3.19.0"
"@expofp/schema": "3.20.0",
"@expofp/utils": "3.20.0",
"@expofp/resolve": "3.20.0"
}
}