@salesforce/metadata-visualizer-web 1.0.1
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/LICENSE.txt +27 -0
- package/README.md +269 -0
- package/dist/WebVisualizationEngine.d.ts +165 -0
- package/dist/WebVisualizationEngine.d.ts.map +1 -0
- package/dist/WebVisualizationEngine.js +284 -0
- package/dist/WebVisualizationEngine.js.map +1 -0
- package/dist/createWebVisualizationEngine.d.ts +27 -0
- package/dist/createWebVisualizationEngine.d.ts.map +1 -0
- package/dist/createWebVisualizationEngine.js +91 -0
- package/dist/createWebVisualizationEngine.js.map +1 -0
- package/dist/design-system/platform.css +623 -0
- package/dist/errors/index.d.ts +25 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +31 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/CompositeFileSystem.d.ts +28 -0
- package/dist/internal/CompositeFileSystem.d.ts.map +1 -0
- package/dist/internal/CompositeFileSystem.js +82 -0
- package/dist/internal/CompositeFileSystem.js.map +1 -0
- package/dist/internal/assetInliner.d.ts +30 -0
- package/dist/internal/assetInliner.d.ts.map +1 -0
- package/dist/internal/assetInliner.js +126 -0
- package/dist/internal/assetInliner.js.map +1 -0
- package/dist/internal/constants.d.ts +20 -0
- package/dist/internal/constants.d.ts.map +1 -0
- package/dist/internal/constants.js +34 -0
- package/dist/internal/constants.js.map +1 -0
- package/dist/internal/htmlPipeline.d.ts +50 -0
- package/dist/internal/htmlPipeline.d.ts.map +1 -0
- package/dist/internal/htmlPipeline.js +86 -0
- package/dist/internal/htmlPipeline.js.map +1 -0
- package/dist/pluginAssets/BundledPluginAssetReader.d.ts +34 -0
- package/dist/pluginAssets/BundledPluginAssetReader.d.ts.map +1 -0
- package/dist/pluginAssets/BundledPluginAssetReader.js +77 -0
- package/dist/pluginAssets/BundledPluginAssetReader.js.map +1 -0
- package/dist/plugins/flexipage/ui/assets/index-BAFqMU7k.js +48 -0
- package/dist/plugins/flexipage/ui/assets/index-U3SB2gLS.css +1 -0
- package/dist/plugins/flexipage/ui/index.html +16 -0
- package/dist/plugins/schema/ui/assets/index-DCLgZby3.css +1 -0
- package/dist/plugins/schema/ui/assets/index-Ho7jg9o_.js +70 -0
- package/dist/plugins/schema/ui/index.html +14 -0
- package/dist/types/HttpAsset.d.ts +18 -0
- package/dist/types/HttpAsset.d.ts.map +1 -0
- package/dist/types/HttpAsset.js +8 -0
- package/dist/types/HttpAsset.js.map +1 -0
- package/dist/types/PluginDataUpdateMessage.d.ts +24 -0
- package/dist/types/PluginDataUpdateMessage.d.ts.map +1 -0
- package/dist/types/PluginDataUpdateMessage.js +8 -0
- package/dist/types/PluginDataUpdateMessage.js.map +1 -0
- package/dist/types/PluginInfo.d.ts +20 -0
- package/dist/types/PluginInfo.d.ts.map +1 -0
- package/dist/types/PluginInfo.js +8 -0
- package/dist/types/PluginInfo.js.map +1 -0
- package/dist/types/VisualizeOutcome.d.ts +19 -0
- package/dist/types/VisualizeOutcome.d.ts.map +1 -0
- package/dist/types/VisualizeOutcome.js +8 -0
- package/dist/types/VisualizeOutcome.js.map +1 -0
- package/dist/types/WebAdapterOptions.d.ts +22 -0
- package/dist/types/WebAdapterOptions.d.ts.map +1 -0
- package/dist/types/WebAdapterOptions.js +8 -0
- package/dist/types/WebAdapterOptions.js.map +1 -0
- package/package.json +77 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* @salesforce/metadata-visualizer-web — Public API.
|
|
9
|
+
*
|
|
10
|
+
* Web/HTTP SDK for the Salesforce Metadata Visualizer framework. Lets any
|
|
11
|
+
* HTTP-style host (custom web services, browser applications, demo pages)
|
|
12
|
+
* plug a host-supplied IFileSystem into the framework and serve plugin
|
|
13
|
+
* visualizations to a browser without seeing plugin internals.
|
|
14
|
+
*/
|
|
15
|
+
// Factory + engine.
|
|
16
|
+
export { createWebVisualizationEngine } from './createWebVisualizationEngine.js';
|
|
17
|
+
export { WebVisualizationEngine } from './WebVisualizationEngine.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ;;;;;;;GAOG;AAEH,oBAAoB;AACpB,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
import type { IFileSystem } from '@salesforce/metadata-core-sdk';
|
|
8
|
+
/**
|
|
9
|
+
* Wrap a host `IFileSystem` so reads under `bundledRoot` resolve through
|
|
10
|
+
* `node:fs` against the adapter's bundled plugin assets, while every other
|
|
11
|
+
* call passes through to the host unchanged.
|
|
12
|
+
*
|
|
13
|
+
* Why this exists: the framework's `visualize(filePath)` flow uses
|
|
14
|
+
* `IPlatformContext.fileSystem` to BOTH parse the user's metadata file AND
|
|
15
|
+
* read the plugin's `index.html` (via HtmlVizGenerator). The web adapter
|
|
16
|
+
* needs the parser-side reads to go through the host's filesystem (so
|
|
17
|
+
* the host's restricted-path rules apply), and the plugin-asset reads to
|
|
18
|
+
* come from the adapter's bundle (so the host's filesystem is never asked
|
|
19
|
+
* for paths it doesn't know about).
|
|
20
|
+
*
|
|
21
|
+
* Only `readFile` and `exists` actually need bundled-side handling — every
|
|
22
|
+
* other `IFileSystem` method (path helpers, workspace ops, writeFile, etc.)
|
|
23
|
+
* is forwarded verbatim. We use a `Proxy` rather than a class with delegating
|
|
24
|
+
* stubs so the wrapper stays in sync automatically when `IFileSystem` grows
|
|
25
|
+
* new members.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createCompositeFileSystem(host: IFileSystem, bundledRoot: string): IFileSystem;
|
|
28
|
+
//# sourceMappingURL=CompositeFileSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeFileSystem.d.ts","sourceRoot":"","sources":["../../src/internal/CompositeFileSystem.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAIJ,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,+BAA+B,CAAC;AAEzE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CAiD7F"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
/**
|
|
10
|
+
* Wrap a host `IFileSystem` so reads under `bundledRoot` resolve through
|
|
11
|
+
* `node:fs` against the adapter's bundled plugin assets, while every other
|
|
12
|
+
* call passes through to the host unchanged.
|
|
13
|
+
*
|
|
14
|
+
* Why this exists: the framework's `visualize(filePath)` flow uses
|
|
15
|
+
* `IPlatformContext.fileSystem` to BOTH parse the user's metadata file AND
|
|
16
|
+
* read the plugin's `index.html` (via HtmlVizGenerator). The web adapter
|
|
17
|
+
* needs the parser-side reads to go through the host's filesystem (so
|
|
18
|
+
* the host's restricted-path rules apply), and the plugin-asset reads to
|
|
19
|
+
* come from the adapter's bundle (so the host's filesystem is never asked
|
|
20
|
+
* for paths it doesn't know about).
|
|
21
|
+
*
|
|
22
|
+
* Only `readFile` and `exists` actually need bundled-side handling — every
|
|
23
|
+
* other `IFileSystem` method (path helpers, workspace ops, writeFile, etc.)
|
|
24
|
+
* is forwarded verbatim. We use a `Proxy` rather than a class with delegating
|
|
25
|
+
* stubs so the wrapper stays in sync automatically when `IFileSystem` grows
|
|
26
|
+
* new members.
|
|
27
|
+
*/
|
|
28
|
+
export function createCompositeFileSystem(host, bundledRoot) {
|
|
29
|
+
const bundledRootNormalized = path.resolve(bundledRoot);
|
|
30
|
+
const isBundled = (p) => {
|
|
31
|
+
if (!p) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const abs = path.isAbsolute(p) ? path.normalize(p) : path.resolve(p);
|
|
35
|
+
return abs === bundledRootNormalized || abs.startsWith(bundledRootNormalized + path.sep);
|
|
36
|
+
};
|
|
37
|
+
const readFile = async (filePath) => {
|
|
38
|
+
if (!isBundled(filePath)) {
|
|
39
|
+
return host.readFile(filePath);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return { success: true, data: await fs.readFile(filePath, 'utf-8') };
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
return { success: false, error: asError(err) };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const exists = async (filePath) => {
|
|
49
|
+
if (!isBundled(filePath)) {
|
|
50
|
+
return host.exists(filePath);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await fs.stat(filePath);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return new Proxy(host, {
|
|
61
|
+
get(target, prop) {
|
|
62
|
+
if (prop === 'readFile') {
|
|
63
|
+
return readFile;
|
|
64
|
+
}
|
|
65
|
+
if (prop === 'exists') {
|
|
66
|
+
return exists;
|
|
67
|
+
}
|
|
68
|
+
const value = target[prop];
|
|
69
|
+
// Bind methods to the host so `this` resolves correctly inside them.
|
|
70
|
+
return typeof value === 'function'
|
|
71
|
+
? value.bind(target)
|
|
72
|
+
: value;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function asError(value) {
|
|
77
|
+
if (value && typeof value === 'object' && 'message' in value) {
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
return new Error(String(value));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=CompositeFileSystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeFileSystem.js","sourceRoot":"","sources":["../../src/internal/CompositeFileSystem.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAiB,EAAE,WAAmB;IAC9E,MAAM,qBAAqB,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAExD,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE;QACvC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACrE,OAAO,GAAG,KAAK,qBAAqB,IAAI,GAAG,CAAC,UAAU,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3F,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,EAAE,QAAgB,EAA2B,EAAE;QACnE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;QACvE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,EAAE,QAAgB,EAAoB,EAAE;QAC1D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE;QACrB,GAAG,CAAC,MAAmB,EAAE,IAAqB;YAC5C,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;gBACxB,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,MAAM,KAAK,GAAI,MAAsD,CAAC,IAAI,CAAC,CAAC;YAC5E,qEAAqE;YACrE,OAAO,OAAO,KAAK,KAAK,UAAU;gBAChC,CAAC,CAAE,KAAyC,CAAC,IAAI,CAAC,MAAM,CAAC;gBACzD,CAAC,CAAC,KAAK,CAAC;QACZ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,KAAc;IAC7B,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;QAC7D,OAAO,KAAc,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
import type { BundledPluginAssetReader } from '../pluginAssets/BundledPluginAssetReader.js';
|
|
8
|
+
/**
|
|
9
|
+
* Asset reader interface - the minimal contract needed for asset inlining.
|
|
10
|
+
*/
|
|
11
|
+
type AssetReader = Pick<BundledPluginAssetReader, 'readPluginAsset' | 'readPluginIndexHtml' | 'readDesignSystemCss'>;
|
|
12
|
+
/**
|
|
13
|
+
* Inline all external assets (JS, CSS) referenced in a plugin's HTML into
|
|
14
|
+
* a single self-contained HTML document. This eliminates the waterfall of
|
|
15
|
+
* HTTP requests when loading a plugin in an iframe.
|
|
16
|
+
*
|
|
17
|
+
* Transformations:
|
|
18
|
+
* - <script src="./assets/index.js"> → <script>...inlined code...</script>
|
|
19
|
+
* - <link href="./assets/index.css"> → <style>...inlined css...</style>
|
|
20
|
+
* - Fonts/images in CSS remain as relative paths (or convert to data: URLs)
|
|
21
|
+
*
|
|
22
|
+
* @param html - Plugin's index.html content
|
|
23
|
+
* @param pluginId - Plugin identifier for asset resolution
|
|
24
|
+
* @param assetReader - Reader to fetch plugin assets
|
|
25
|
+
* @param platformCss - Optional platform CSS to inline (from @dist/ references)
|
|
26
|
+
* @returns HTML with all assets inlined
|
|
27
|
+
*/
|
|
28
|
+
export declare function inlineAssets(html: string, pluginId: string, assetReader: AssetReader, platformCss?: string): Promise<string>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=assetInliner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetInliner.d.ts","sourceRoot":"","sources":["../../src/internal/assetInliner.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAE5F;;GAEG;AACH,KAAK,WAAW,GAAG,IAAI,CACrB,wBAAwB,EACxB,iBAAiB,GAAG,qBAAqB,GAAG,qBAAqB,CAClE,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAajB"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* Inline all external assets (JS, CSS) referenced in a plugin's HTML into
|
|
9
|
+
* a single self-contained HTML document. This eliminates the waterfall of
|
|
10
|
+
* HTTP requests when loading a plugin in an iframe.
|
|
11
|
+
*
|
|
12
|
+
* Transformations:
|
|
13
|
+
* - <script src="./assets/index.js"> → <script>...inlined code...</script>
|
|
14
|
+
* - <link href="./assets/index.css"> → <style>...inlined css...</style>
|
|
15
|
+
* - Fonts/images in CSS remain as relative paths (or convert to data: URLs)
|
|
16
|
+
*
|
|
17
|
+
* @param html - Plugin's index.html content
|
|
18
|
+
* @param pluginId - Plugin identifier for asset resolution
|
|
19
|
+
* @param assetReader - Reader to fetch plugin assets
|
|
20
|
+
* @param platformCss - Optional platform CSS to inline (from @dist/ references)
|
|
21
|
+
* @returns HTML with all assets inlined
|
|
22
|
+
*/
|
|
23
|
+
export async function inlineAssets(html, pluginId, assetReader, platformCss) {
|
|
24
|
+
// First, inline platform CSS (@dist/ references)
|
|
25
|
+
if (platformCss) {
|
|
26
|
+
html = inlinePlatformCss(html, platformCss);
|
|
27
|
+
}
|
|
28
|
+
// Inline all <script src="..."> tags
|
|
29
|
+
html = await inlineScripts(html, pluginId, assetReader);
|
|
30
|
+
// Inline all <link rel="stylesheet" href="..."> tags
|
|
31
|
+
html = await inlineStylesheets(html, pluginId, assetReader);
|
|
32
|
+
return html;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Replace @dist/ link tags with inlined platform CSS.
|
|
36
|
+
*/
|
|
37
|
+
function inlinePlatformCss(html, platformCss) {
|
|
38
|
+
// Match: <link ... href="@dist/design-system/platform.css" ...>
|
|
39
|
+
const linkPattern = /<link\b[^>]*?\bhref=["']@dist\/[^"']*["'][^>]*?>/gi;
|
|
40
|
+
return html.replace(linkPattern, () => {
|
|
41
|
+
return `<style data-source="platform-css">\n${escapeForStyleTag(platformCss)}\n</style>`;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Escape a JS payload so it cannot prematurely close the surrounding <script> tag.
|
|
46
|
+
* Browsers terminate <script> on the literal substring `</script` (case-insensitive,
|
|
47
|
+
* regardless of whether a `>` follows), so any occurrence inside the payload — common
|
|
48
|
+
* in templated HTML strings, regex literals, or React server output — must be broken.
|
|
49
|
+
* `<\/script` is semantically identical in JS source but invisible to the HTML parser.
|
|
50
|
+
*/
|
|
51
|
+
function escapeForScriptTag(code) {
|
|
52
|
+
return code.replace(/<\/script/gi, '<\\/script');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Escape a CSS payload so it cannot prematurely close the surrounding <style> tag.
|
|
56
|
+
* Same hazard as escapeForScriptTag, but for `</style`. Replaced with `<\/style`,
|
|
57
|
+
* which CSS tokenizers ignore (the backslash is a valid CSS escape character).
|
|
58
|
+
*/
|
|
59
|
+
function escapeForStyleTag(css) {
|
|
60
|
+
return css.replace(/<\/style/gi, '<\\/style');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Inline all <script src="..."> tags that reference relative paths.
|
|
64
|
+
* Resolves each unique tag to its replacement asynchronously, then runs a single
|
|
65
|
+
* global regex pass so duplicate tags (e.g. shared vendor chunks) are all rewritten.
|
|
66
|
+
*/
|
|
67
|
+
async function inlineScripts(html, pluginId, assetReader) {
|
|
68
|
+
// Match: <script ... src="..." ...>
|
|
69
|
+
const scriptPattern = /<script\b([^>]*?\bsrc=["'])([^"']+)(["'][^>]*?)>/gi;
|
|
70
|
+
const replacements = new Map();
|
|
71
|
+
for (const tagMatch of html.matchAll(scriptPattern)) {
|
|
72
|
+
const fullTag = tagMatch[0];
|
|
73
|
+
const url = tagMatch[2];
|
|
74
|
+
if (replacements.has(fullTag) || isAbsoluteOrRooted(url)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const assetPath = url.startsWith('./') ? url.slice(2) : url;
|
|
78
|
+
try {
|
|
79
|
+
const bytes = await assetReader.readPluginAsset(pluginId, assetPath);
|
|
80
|
+
const code = escapeForScriptTag(new TextDecoder('utf-8').decode(bytes));
|
|
81
|
+
const inlineScript = fullTag.includes('type="module"')
|
|
82
|
+
? `<script type="module">\n${code}\n</script>`
|
|
83
|
+
: `<script>\n${code}\n</script>`;
|
|
84
|
+
replacements.set(fullTag, inlineScript);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.warn(`[assetInliner] Failed to inline script: ${assetPath}`, err);
|
|
89
|
+
// Leave fullTag absent from replacements so the original tag is preserved
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Single global pass: every occurrence of every resolved tag is rewritten.
|
|
93
|
+
return html.replace(scriptPattern, (fullTag) => replacements.get(fullTag) ?? fullTag);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Inline all <link rel="stylesheet" href="..."> tags that reference relative paths.
|
|
97
|
+
* Same single-pass strategy as inlineScripts to handle duplicate stylesheet refs.
|
|
98
|
+
*/
|
|
99
|
+
async function inlineStylesheets(html, pluginId, assetReader) {
|
|
100
|
+
// Match: <link ... rel="stylesheet" ... href="..." ...>
|
|
101
|
+
const linkPattern = /<link\b[^>]*?\brel=["']stylesheet["'][^>]*?\bhref=["']([^"']+)["'][^>]*?>/gi;
|
|
102
|
+
const replacements = new Map();
|
|
103
|
+
for (const tagMatch of html.matchAll(linkPattern)) {
|
|
104
|
+
const fullTag = tagMatch[0];
|
|
105
|
+
const url = tagMatch[1];
|
|
106
|
+
if (replacements.has(fullTag) || isAbsoluteOrRooted(url)) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const assetPath = url.startsWith('./') ? url.slice(2) : url;
|
|
110
|
+
try {
|
|
111
|
+
const bytes = await assetReader.readPluginAsset(pluginId, assetPath);
|
|
112
|
+
const css = escapeForStyleTag(new TextDecoder('utf-8').decode(bytes));
|
|
113
|
+
replacements.set(fullTag, `<style data-source="${assetPath}">\n${css}\n</style>`);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// eslint-disable-next-line no-console
|
|
117
|
+
console.warn(`[assetInliner] Failed to inline stylesheet: ${assetPath}`, err);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return html.replace(linkPattern, (fullTag) => replacements.get(fullTag) ?? fullTag);
|
|
121
|
+
}
|
|
122
|
+
function isAbsoluteOrRooted(url) {
|
|
123
|
+
// http(s)://, //cdn..., data:, blob:, /already-rooted
|
|
124
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//') || url.startsWith('/');
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=assetInliner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetInliner.js","sourceRoot":"","sources":["../../src/internal/assetInliner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* Bootstrap script for browser-iframe hosts.
|
|
9
|
+
*
|
|
10
|
+
* Defines `window.__ExtensionHostPostMessage` as a thin wrapper around
|
|
11
|
+
* `window.parent.postMessage(msg, '*')`. The embedding host's parent
|
|
12
|
+
* window is responsible for relaying the message to its server (e.g. via
|
|
13
|
+
* a `POST /visualize` REST call).
|
|
14
|
+
*
|
|
15
|
+
* Self-checks at runtime that the script is actually running inside a
|
|
16
|
+
* frame; logs an error if not, since `__ExtensionHostPostMessage` would
|
|
17
|
+
* otherwise post to the same window.
|
|
18
|
+
*/
|
|
19
|
+
export declare const BROWSER_IFRAME_BOOTSTRAP: string;
|
|
20
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/internal/constants.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,QAc7B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* Bootstrap script for browser-iframe hosts.
|
|
9
|
+
*
|
|
10
|
+
* Defines `window.__ExtensionHostPostMessage` as a thin wrapper around
|
|
11
|
+
* `window.parent.postMessage(msg, '*')`. The embedding host's parent
|
|
12
|
+
* window is responsible for relaying the message to its server (e.g. via
|
|
13
|
+
* a `POST /visualize` REST call).
|
|
14
|
+
*
|
|
15
|
+
* Self-checks at runtime that the script is actually running inside a
|
|
16
|
+
* frame; logs an error if not, since `__ExtensionHostPostMessage` would
|
|
17
|
+
* otherwise post to the same window.
|
|
18
|
+
*/
|
|
19
|
+
export const BROWSER_IFRAME_BOOTSTRAP = `
|
|
20
|
+
<script>
|
|
21
|
+
(function() {
|
|
22
|
+
if (window.parent === window) {
|
|
23
|
+
console.error('[browser-bootstrap] Not running inside a frame; __ExtensionHostPostMessage needs a parent window.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(window, '__ExtensionHostPostMessage', {
|
|
27
|
+
value: function(msg) { window.parent.postMessage(msg, '*'); },
|
|
28
|
+
writable: false,
|
|
29
|
+
configurable: false
|
|
30
|
+
});
|
|
31
|
+
})();
|
|
32
|
+
</script>
|
|
33
|
+
`.trim();
|
|
34
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/internal/constants.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;CAcvC,CAAC,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* Pure HTML transforms that prepare a plugin's `index.html` for delivery to
|
|
9
|
+
* an iframe under a host's URL prefixes. No I/O. No host imports.
|
|
10
|
+
*
|
|
11
|
+
* The three transforms are applied by `WebVisualizationEngine.getPluginIndexHtml`
|
|
12
|
+
* in this order:
|
|
13
|
+
* 1. rewriteDistPlaceholders — turn `@dist/...` into URLs under the
|
|
14
|
+
* consumer's `platformAssetBaseUrl` (the platform CSS specifically).
|
|
15
|
+
* 2. rewritePluginAssetUrls — turn the plugin's relative asset URLs
|
|
16
|
+
* (`./assets/index-abc.js`, `./fonts/x.woff2`, etc.) into absolute
|
|
17
|
+
* URLs under `pluginUiBaseUrl`.
|
|
18
|
+
* 3. injectBootstrap — splice the host bridge's bootstrap
|
|
19
|
+
* `<script>` into the document so plugins can postMessage to host.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Inject the host-bridge bootstrap `<script>` into the document. Tries
|
|
23
|
+
* `</head>` first, falls back to `</body>`, and prepends if neither exists.
|
|
24
|
+
*/
|
|
25
|
+
export declare function injectBootstrap(html: string, scriptTag: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Rewrite `@dist/` placeholders in the plugin's HTML to URLs under the
|
|
28
|
+
* consumer's platform-asset base URL. Plugins emit `<link href="@dist/design-system/platform.css">`
|
|
29
|
+
* as a host-portable indirection. The web adapter resolves it to
|
|
30
|
+
* `<base>/design-system/platform.css`, where `<base>` is the consumer-supplied
|
|
31
|
+
* `platformAssetBaseUrl`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function rewriteDistPlaceholders(html: string, platformAssetBaseUrl: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Rewrite the plugin's RELATIVE asset URLs to absolute URLs under
|
|
36
|
+
* `pluginUiBaseUrl`. Today, plugin builds emit:
|
|
37
|
+
*
|
|
38
|
+
* <script type="module" crossorigin src="./assets/index-abc.js"></script>
|
|
39
|
+
* <link rel="stylesheet" crossorigin href="./assets/index-abc.css">
|
|
40
|
+
*
|
|
41
|
+
* They may also emit `./fonts/...`, `./images/...`, or other relative
|
|
42
|
+
* paths in the future. We rewrite ANY relative path on `<script src>`
|
|
43
|
+
* and `<link href>` (i.e., starts with `./` or `assets/`-style without
|
|
44
|
+
* leading slash) to `<base>/<original>`.
|
|
45
|
+
*
|
|
46
|
+
* The "assets/" path segment lives only in this file. The consumer's
|
|
47
|
+
* route handlers never see it.
|
|
48
|
+
*/
|
|
49
|
+
export declare function rewritePluginAssetUrls(html: string, pluginUiBaseUrl: string): string;
|
|
50
|
+
//# sourceMappingURL=htmlPipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlPipeline.d.ts","sourceRoot":"","sources":["../../src/internal/htmlPipeline.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ;;;;;;;;;;;;;GAaG;AAEH;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQvE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAG1F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CA4BpF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* Pure HTML transforms that prepare a plugin's `index.html` for delivery to
|
|
9
|
+
* an iframe under a host's URL prefixes. No I/O. No host imports.
|
|
10
|
+
*
|
|
11
|
+
* The three transforms are applied by `WebVisualizationEngine.getPluginIndexHtml`
|
|
12
|
+
* in this order:
|
|
13
|
+
* 1. rewriteDistPlaceholders — turn `@dist/...` into URLs under the
|
|
14
|
+
* consumer's `platformAssetBaseUrl` (the platform CSS specifically).
|
|
15
|
+
* 2. rewritePluginAssetUrls — turn the plugin's relative asset URLs
|
|
16
|
+
* (`./assets/index-abc.js`, `./fonts/x.woff2`, etc.) into absolute
|
|
17
|
+
* URLs under `pluginUiBaseUrl`.
|
|
18
|
+
* 3. injectBootstrap — splice the host bridge's bootstrap
|
|
19
|
+
* `<script>` into the document so plugins can postMessage to host.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Inject the host-bridge bootstrap `<script>` into the document. Tries
|
|
23
|
+
* `</head>` first, falls back to `</body>`, and prepends if neither exists.
|
|
24
|
+
*/
|
|
25
|
+
export function injectBootstrap(html, scriptTag) {
|
|
26
|
+
if (html.includes('</head>')) {
|
|
27
|
+
return html.replace('</head>', `${scriptTag}\n</head>`);
|
|
28
|
+
}
|
|
29
|
+
if (html.includes('</body>')) {
|
|
30
|
+
return html.replace('</body>', `${scriptTag}\n</body>`);
|
|
31
|
+
}
|
|
32
|
+
return `${scriptTag}\n${html}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rewrite `@dist/` placeholders in the plugin's HTML to URLs under the
|
|
36
|
+
* consumer's platform-asset base URL. Plugins emit `<link href="@dist/design-system/platform.css">`
|
|
37
|
+
* as a host-portable indirection. The web adapter resolves it to
|
|
38
|
+
* `<base>/design-system/platform.css`, where `<base>` is the consumer-supplied
|
|
39
|
+
* `platformAssetBaseUrl`.
|
|
40
|
+
*/
|
|
41
|
+
export function rewriteDistPlaceholders(html, platformAssetBaseUrl) {
|
|
42
|
+
const base = stripTrailingSlash(platformAssetBaseUrl);
|
|
43
|
+
return html.replace(/@dist\//g, `${base}/`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Rewrite the plugin's RELATIVE asset URLs to absolute URLs under
|
|
47
|
+
* `pluginUiBaseUrl`. Today, plugin builds emit:
|
|
48
|
+
*
|
|
49
|
+
* <script type="module" crossorigin src="./assets/index-abc.js"></script>
|
|
50
|
+
* <link rel="stylesheet" crossorigin href="./assets/index-abc.css">
|
|
51
|
+
*
|
|
52
|
+
* They may also emit `./fonts/...`, `./images/...`, or other relative
|
|
53
|
+
* paths in the future. We rewrite ANY relative path on `<script src>`
|
|
54
|
+
* and `<link href>` (i.e., starts with `./` or `assets/`-style without
|
|
55
|
+
* leading slash) to `<base>/<original>`.
|
|
56
|
+
*
|
|
57
|
+
* The "assets/" path segment lives only in this file. The consumer's
|
|
58
|
+
* route handlers never see it.
|
|
59
|
+
*/
|
|
60
|
+
export function rewritePluginAssetUrls(html, pluginUiBaseUrl) {
|
|
61
|
+
const base = stripTrailingSlash(pluginUiBaseUrl);
|
|
62
|
+
// Match <script ... src="..."> and <link ... href="..."> attributes.
|
|
63
|
+
// We rewrite only paths that look relative; we leave absolute URLs and
|
|
64
|
+
// already-absolute paths alone. The trailing closing-quote is included
|
|
65
|
+
// in the replacement, so we don't need a separate capture for it.
|
|
66
|
+
const rewrite = (match, prefix, quote, url) => {
|
|
67
|
+
if (isAbsoluteOrRooted(url)) {
|
|
68
|
+
return match;
|
|
69
|
+
}
|
|
70
|
+
const cleaned = url.startsWith('./') ? url.slice(2) : url;
|
|
71
|
+
return `${prefix}${quote}${base}/${cleaned}${quote}`;
|
|
72
|
+
};
|
|
73
|
+
// Process <script src="..."> tags.
|
|
74
|
+
html = html.replace(/(<script\b[^>]*?\bsrc=)(["'])([^"']+)\2/gi, (m, p, q, u) => rewrite(m, p, q, u));
|
|
75
|
+
// Process <link href="..."> tags.
|
|
76
|
+
html = html.replace(/(<link\b[^>]*?\bhref=)(["'])([^"']+)\2/gi, (m, p, q, u) => rewrite(m, p, q, u));
|
|
77
|
+
return html;
|
|
78
|
+
}
|
|
79
|
+
function isAbsoluteOrRooted(url) {
|
|
80
|
+
// http(s)://, //cdn..., data:, blob:, /already-rooted
|
|
81
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//') || url.startsWith('/');
|
|
82
|
+
}
|
|
83
|
+
function stripTrailingSlash(s) {
|
|
84
|
+
return s.endsWith('/') ? s.slice(0, -1) : s;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=htmlPipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlPipeline.js","sourceRoot":"","sources":["../../src/internal/htmlPipeline.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ;;;;;;;;;;;;;GAaG;AAEH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAAiB;IAC7D,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,GAAG,SAAS,KAAK,IAAI,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,oBAA4B;IAChF,MAAM,IAAI,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,eAAuB;IAC1E,MAAM,IAAI,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAEjD,qEAAqE;IACrE,uEAAuE;IACvE,uEAAuE;IACvE,kEAAkE;IAClE,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,MAAc,EAAE,KAAa,EAAE,GAAW,EAAU,EAAE;QACpF,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1D,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI,IAAI,OAAO,GAAG,KAAK,EAAE,CAAC;IACvD,CAAC,CAAC;IAEF,mCAAmC;IACnC,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,2CAA2C,EAC3C,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CACpE,CAAC;IAEF,kCAAkC;IAClC,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,0CAA0C,EAC1C,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CACpE,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,sDAAsD;IACtD,OAAO,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACzF,CAAC;AAED,SAAS,kBAAkB,CAAC,CAAS;IACnC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
/**
|
|
8
|
+
* Plugin asset reader for the web adapter.
|
|
9
|
+
*
|
|
10
|
+
* Reads plugin React builds and the platform CSS from a bundled `dist/`
|
|
11
|
+
* directory, populated by `scripts/copy-plugin-assets.mjs` at build time.
|
|
12
|
+
* The adapter has zero runtime dependency on `@salesforce/metadata-plugins`
|
|
13
|
+
* — this reader only touches paths under its constructor-provided
|
|
14
|
+
* `bundledRoot`.
|
|
15
|
+
*
|
|
16
|
+
* Layout under `bundledRoot`:
|
|
17
|
+
* <root>/plugins/<pluginId>/ui/index.html
|
|
18
|
+
* <root>/plugins/<pluginId>/ui/assets/...
|
|
19
|
+
* <root>/design-system/platform.css
|
|
20
|
+
*/
|
|
21
|
+
export declare class BundledPluginAssetReader {
|
|
22
|
+
private readonly bundledRoot;
|
|
23
|
+
/**
|
|
24
|
+
* @param bundledRoot Absolute path to the directory containing the
|
|
25
|
+
* `plugins/` and `design-system/` subdirs. The factory in
|
|
26
|
+
* `createWebVisualizationEngine` resolves this to the package's own
|
|
27
|
+
* `dist/` at runtime; tests pass a tempdir.
|
|
28
|
+
*/
|
|
29
|
+
constructor(bundledRoot: string);
|
|
30
|
+
readPluginIndexHtml(pluginId: string): Promise<string>;
|
|
31
|
+
readPluginAsset(pluginId: string, relativePath: string): Promise<Uint8Array>;
|
|
32
|
+
readDesignSystemCss(): Promise<string>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=BundledPluginAssetReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BundledPluginAssetReader.d.ts","sourceRoot":"","sources":["../../src/pluginAssets/BundledPluginAssetReader.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAOJ;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC;;;;;OAKG;gBACS,WAAW,EAAE,MAAM;IAIzB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAetD,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAe5E,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAW7C"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
**/
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { REACT_UI_DIR_NAME } from '@salesforce/metadata-core-sdk';
|
|
10
|
+
import { AssetNotFoundError, PluginNotFoundError } from '../errors/index.js';
|
|
11
|
+
/**
|
|
12
|
+
* Plugin asset reader for the web adapter.
|
|
13
|
+
*
|
|
14
|
+
* Reads plugin React builds and the platform CSS from a bundled `dist/`
|
|
15
|
+
* directory, populated by `scripts/copy-plugin-assets.mjs` at build time.
|
|
16
|
+
* The adapter has zero runtime dependency on `@salesforce/metadata-plugins`
|
|
17
|
+
* — this reader only touches paths under its constructor-provided
|
|
18
|
+
* `bundledRoot`.
|
|
19
|
+
*
|
|
20
|
+
* Layout under `bundledRoot`:
|
|
21
|
+
* <root>/plugins/<pluginId>/ui/index.html
|
|
22
|
+
* <root>/plugins/<pluginId>/ui/assets/...
|
|
23
|
+
* <root>/design-system/platform.css
|
|
24
|
+
*/
|
|
25
|
+
export class BundledPluginAssetReader {
|
|
26
|
+
/**
|
|
27
|
+
* @param bundledRoot Absolute path to the directory containing the
|
|
28
|
+
* `plugins/` and `design-system/` subdirs. The factory in
|
|
29
|
+
* `createWebVisualizationEngine` resolves this to the package's own
|
|
30
|
+
* `dist/` at runtime; tests pass a tempdir.
|
|
31
|
+
*/
|
|
32
|
+
constructor(bundledRoot) {
|
|
33
|
+
this.bundledRoot = bundledRoot;
|
|
34
|
+
}
|
|
35
|
+
async readPluginIndexHtml(pluginId) {
|
|
36
|
+
const indexPath = path.join(this.bundledRoot, 'plugins', pluginId, REACT_UI_DIR_NAME, 'index.html');
|
|
37
|
+
try {
|
|
38
|
+
return await fs.readFile(indexPath, 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
throw mapEnoent(err, () => new PluginNotFoundError(pluginId));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async readPluginAsset(pluginId, relativePath) {
|
|
45
|
+
const assetPath = path.join(this.bundledRoot, 'plugins', pluginId, REACT_UI_DIR_NAME, relativePath);
|
|
46
|
+
try {
|
|
47
|
+
return await fs.readFile(assetPath);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
throw mapEnoent(err, () => new AssetNotFoundError(pluginId, relativePath));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async readDesignSystemCss() {
|
|
54
|
+
const cssPath = path.join(this.bundledRoot, 'design-system', 'platform.css');
|
|
55
|
+
try {
|
|
56
|
+
return await fs.readFile(cssPath, 'utf-8');
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
throw mapEnoent(err, () => new Error(`Platform CSS not found in bundled dist (looked at ${cssPath})`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function mapEnoent(err, build) {
|
|
64
|
+
// We avoid `instanceof Error` here because cross-realm errors (e.g. errors
|
|
65
|
+
// thrown by node:fs/promises and observed by a CommonJS-compiled test) can
|
|
66
|
+
// fail the prototype check even though they are functionally Error objects.
|
|
67
|
+
// Duck-type on `code` and gracefully wrap anything else.
|
|
68
|
+
const code = err?.code;
|
|
69
|
+
if (code === 'ENOENT') {
|
|
70
|
+
return build();
|
|
71
|
+
}
|
|
72
|
+
if (err && typeof err === 'object' && 'message' in err) {
|
|
73
|
+
return err;
|
|
74
|
+
}
|
|
75
|
+
return new Error(String(err));
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=BundledPluginAssetReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BundledPluginAssetReader.js","sourceRoot":"","sources":["../../src/pluginAssets/BundledPluginAssetReader.ts"],"names":[],"mappings":"AAAA;;;;;IAKI;AAEJ,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,wBAAwB;IAGnC;;;;;OAKG;IACH,YAAY,WAAmB;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,QAAgB;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,IAAI,CAAC,WAAW,EAChB,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,YAAY,CACb,CAAC;QACF,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,YAAoB;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,IAAI,CAAC,WAAW,EAChB,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,YAAY,CACb,CAAC;QACF,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;QAC7E,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,SAAS,CACb,GAAG,EACH,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,qDAAqD,OAAO,GAAG,CAAC,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AAED,SAAS,SAAS,CAAC,GAAY,EAAE,KAAkB;IACjD,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,yDAAyD;IACzD,MAAM,IAAI,GAAI,GAAoC,EAAE,IAAI,CAAC;IACzD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,KAAK,EAAE,CAAC;IACjB,CAAC;IACD,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;QACvD,OAAO,GAAY,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC"}
|