@expofp/config 3.28.1 → 3.28.3

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.
@@ -8,7 +8,7 @@ import type { FpSvgLayerJs } from '@expofp/schema';
8
8
  * (`window['__fpBooth'] = …` — the chain had every layer script clobber the
9
9
  * shared `window.__fp`). The schemas and the floorplan know only the plain
10
10
  * `__fp`/`__fpPaths` keys, so the loader folds the alias onto them on the
11
- * payload's own copy, before the resource walk — the `svgAsset` href rewrite
11
+ * payload's own copy, before the resource walk — the `svgAsset` URL rewrite
12
12
  * then covers a folded drawing like a plain one. The folded values skip the
13
13
  * (opt-in) schema validation, which ran before the fold — the same trust the
14
14
  * untouched alias keys always had.
@@ -7,7 +7,7 @@
7
7
  * (`window['__fpBooth'] = …` — the chain had every layer script clobber the
8
8
  * shared `window.__fp`). The schemas and the floorplan know only the plain
9
9
  * `__fp`/`__fpPaths` keys, so the loader folds the alias onto them on the
10
- * payload's own copy, before the resource walk — the `svgAsset` href rewrite
10
+ * payload's own copy, before the resource walk — the `svgAsset` URL rewrite
11
11
  * then covers a folded drawing like a plain one. The folded values skip the
12
12
  * (opt-in) schema validation, which ran before the fold — the same trust the
13
13
  * untouched alias keys always had.
@@ -16,10 +16,10 @@ export declare function toAbsoluteUrl(path: string, baseUrl: string): string;
16
16
  export declare function isAbsoluteUrl(path: string): boolean;
17
17
  /** The ref's own directory — the base its document's relative paths resolve against. */
18
18
  export declare function refDirectory(ref: string): string;
19
- /** Every distinct `<image>` asset href in one SVG document string. */
20
- export declare function collectSvgImageHrefs(svg: string): string[];
21
- /** Rewrite every `<image>` asset href in one SVG document string. */
22
- export declare function rewriteSvgImageHrefs(svg: string, rewrite: (href: string) => string): string;
19
+ /** Every distinct `<image>` asset URL in one SVG document string. */
20
+ export declare function collectSvgImageAssets(svg: string): string[];
21
+ /** Rewrite every `<image>` asset URL in one SVG document string. */
22
+ export declare function rewriteSvgImageAssets(svg: string, rewrite: (url: string) => string): string;
23
23
  /** Every distinct non-`data:` `url(…)` in one CSS text. */
24
24
  export declare function collectCssUrls(css: string): string[];
25
25
  /** Rewrite every non-`data:` `url(…)` in one CSS text. */
@@ -42,37 +42,44 @@ function execAll(regex, text) {
42
42
  }
43
43
  return matches;
44
44
  }
45
- /* ── SVG documents (`svgAsset`) — `<image>` hrefs are asset paths ─────────── */
45
+ /* ── SVG documents (`svgAsset`) — an `<image>`'s URLs are asset paths ─────── */
46
46
  const IMAGE_TAG = /<image\b[^>]*>/g;
47
- const HREF_ATTR = /(\b(?:xlink:)?href\s*=\s*)(?:"([^"]*)"|'([^']*)')/g;
48
- /** In-document (`#id`) and empty hrefs are not asset URLs. */
49
- function isAssetHref(href) {
50
- return !!href && !href.startsWith('#');
47
+ /**
48
+ * The asset-bearing attributes of an `<image>`: the href it draws, and
49
+ * `data-model-3d` — the URL of the 3D model the floor plan renders *instead* of
50
+ * the image, whose href then never loads (floorplan's `layer-models.ts`). Both are
51
+ * authored relative to the drawing, so both need the same rebase; a model URL
52
+ * left behind resolves against the page and 404s.
53
+ */
54
+ const ASSET_ATTR = /(\b(?:(?:xlink:)?href|data-model-3d)\s*=\s*)(?:"([^"]*)"|'([^']*)')/g;
55
+ /** In-document (`#id`) and empty references are not asset URLs. */
56
+ function isAssetUrl(url) {
57
+ return !!url && !url.startsWith('#');
51
58
  }
52
- /** Every distinct `<image>` asset href in one SVG document string. */
53
- export function collectSvgImageHrefs(svg) {
54
- const hrefs = new Set();
59
+ /** Every distinct `<image>` asset URL in one SVG document string. */
60
+ export function collectSvgImageAssets(svg) {
61
+ const urls = new Set();
55
62
  if (!svg.includes('<image'))
56
63
  return [];
57
64
  for (const tag of svg.match(IMAGE_TAG) ?? []) {
58
- for (const match of execAll(HREF_ATTR, tag)) {
59
- const href = match[2] ?? match[3];
60
- if (isAssetHref(href))
61
- hrefs.add(href);
65
+ for (const match of execAll(ASSET_ATTR, tag)) {
66
+ const url = match[2] ?? match[3];
67
+ if (isAssetUrl(url))
68
+ urls.add(url);
62
69
  }
63
70
  }
64
- return [...hrefs];
71
+ return [...urls];
65
72
  }
66
- /** Rewrite every `<image>` asset href in one SVG document string. */
67
- export function rewriteSvgImageHrefs(svg, rewrite) {
73
+ /** Rewrite every `<image>` asset URL in one SVG document string. */
74
+ export function rewriteSvgImageAssets(svg, rewrite) {
68
75
  if (!svg.includes('<image'))
69
76
  return svg;
70
- return svg.replace(IMAGE_TAG, (tag) => tag.replace(HREF_ATTR, (match, attr, doubleQuoted, singleQuoted) => {
71
- const href = doubleQuoted ?? singleQuoted ?? '';
72
- if (!isAssetHref(href))
77
+ return svg.replace(IMAGE_TAG, (tag) => tag.replace(ASSET_ATTR, (match, attr, doubleQuoted, singleQuoted) => {
78
+ const url = doubleQuoted ?? singleQuoted ?? '';
79
+ if (!isAssetUrl(url))
73
80
  return match;
74
81
  const quote = doubleQuoted !== undefined ? '"' : "'";
75
- return `${attr}${quote}${rewrite(href)}${quote}`;
82
+ return `${attr}${quote}${rewrite(url)}${quote}`;
76
83
  }));
77
84
  }
78
85
  /* ── CSS text (`cssAsset`) — `url(…)`s are asset paths ────────────────────── */
@@ -20,7 +20,7 @@
20
20
  import { getResolved, isResolved, resolve } from '@expofp/resolve';
21
21
  import { deepClone } from '@expofp/utils';
22
22
  import { refSchemaOf, toJsonSchema, typeMatches } from './json-schema.js';
23
- import { collectCssUrls, collectSvgImageHrefs, inlineCssImports, isAbsoluteUrl, refDirectory, rewriteCssUrls, rewriteSvgImageHrefs, toAbsoluteUrl, } from './resource-urls.js';
23
+ import { collectCssUrls, collectSvgImageAssets, inlineCssImports, isAbsoluteUrl, refDirectory, rewriteCssUrls, rewriteSvgImageAssets, toAbsoluteUrl, } from './resource-urls.js';
24
24
  import { timeValidation } from './validate-timing.js';
25
25
  /**
26
26
  * Gates every schema validation (`parse`) of the large expo documents —
@@ -138,10 +138,10 @@ async function walk(node, value, assign, handler, options) {
138
138
  }
139
139
  else if (node?.svgAsset) {
140
140
  const rewrites = new Map();
141
- for (const href of collectSvgImageHrefs(value)) {
142
- rewrites.set(href, await handler.asset(href));
141
+ for (const url of collectSvgImageAssets(value)) {
142
+ rewrites.set(url, await handler.asset(url));
143
143
  }
144
- assign(rewriteSvgImageHrefs(value, (href) => rewrites.get(href) ?? href));
144
+ assign(rewriteSvgImageAssets(value, (url) => rewrites.get(url) ?? url));
145
145
  }
146
146
  else if (node?.cssAsset) {
147
147
  // a handler that can fetch stylesheets gets @imports spliced in first,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expofp/config",
3
- "version": "3.28.1",
3
+ "version": "3.28.3",
4
4
  "type": "module",
5
5
  "description": "ExpoFP SDK internal: config layer and schemas",
6
6
  "homepage": "https://developer.expofp.com/",
@@ -29,8 +29,8 @@
29
29
  "debug": "^4.4.3",
30
30
  "tslib": "^2.3.0",
31
31
  "zod": "4.4.3",
32
- "@expofp/resolve": "3.28.1",
33
- "@expofp/schema": "3.28.1",
34
- "@expofp/utils": "3.28.1"
32
+ "@expofp/resolve": "3.28.3",
33
+ "@expofp/schema": "3.28.3",
34
+ "@expofp/utils": "3.28.3"
35
35
  }
36
36
  }