@frontmcp/uipack 1.8.0 → 1.8.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/adapters/content-detector.d.ts.map +1 -1
- package/adapters/index.js +24 -17
- package/adapters/template-renderer.d.ts.map +1 -1
- package/component/index.js +13 -10
- package/esm/adapters/index.mjs +24 -17
- package/esm/component/index.mjs +13 -10
- package/esm/index.mjs +25 -15
- package/esm/package.json +2 -2
- package/esm/shell/index.mjs +14 -13
- package/esm/utils/index.mjs +5 -1
- package/index.js +25 -15
- package/package.json +2 -2
- package/shell/custom-shell-applier.d.ts +7 -6
- package/shell/custom-shell-applier.d.ts.map +1 -1
- package/shell/data-injector.d.ts.map +1 -1
- package/shell/index.js +14 -13
- package/utils/index.d.ts +7 -0
- package/utils/index.d.ts.map +1 -1
- package/utils/index.js +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-detector.d.ts","sourceRoot":"","sources":["../../src/adapters/content-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"content-detector.d.ts","sourceRoot":"","sources":["../../src/adapters/content-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AA2BzF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAsCrE"}
|
package/adapters/index.js
CHANGED
|
@@ -514,8 +514,9 @@ function escapeHtml(str) {
|
|
|
514
514
|
const s = String(str);
|
|
515
515
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
516
516
|
}
|
|
517
|
-
|
|
518
|
-
|
|
517
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
518
|
+
function toUnicodeEscape(character) {
|
|
519
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
519
520
|
}
|
|
520
521
|
function safeJsonForScript(value) {
|
|
521
522
|
if (value === void 0) {
|
|
@@ -531,7 +532,7 @@ function safeJsonForScript(value) {
|
|
|
531
532
|
if (jsonString === void 0) {
|
|
532
533
|
return "null";
|
|
533
534
|
}
|
|
534
|
-
return
|
|
535
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
535
536
|
} catch {
|
|
536
537
|
return '{"error":"Value could not be serialized"}';
|
|
537
538
|
}
|
|
@@ -1828,14 +1829,16 @@ var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
|
1828
1829
|
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
1829
1830
|
|
|
1830
1831
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
1832
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
1833
|
+
var VALUE_KEYS = {
|
|
1834
|
+
CSP: "csp",
|
|
1835
|
+
DATA: "data",
|
|
1836
|
+
BRIDGE: "bridge",
|
|
1837
|
+
CONTENT: "content",
|
|
1838
|
+
TITLE: "title"
|
|
1839
|
+
};
|
|
1831
1840
|
function applyShellTemplate(template, values) {
|
|
1832
|
-
|
|
1833
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
1834
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
1835
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
1836
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
1837
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
1838
|
-
return result;
|
|
1841
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
1839
1842
|
}
|
|
1840
1843
|
|
|
1841
1844
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
@@ -1907,9 +1910,7 @@ function createTemplateHelpers() {
|
|
|
1907
1910
|
uniqueId: (prefix = "mcp") => {
|
|
1908
1911
|
return `${prefix}-${++_uniqueIdCounter}`;
|
|
1909
1912
|
},
|
|
1910
|
-
jsonEmbed: (data) =>
|
|
1911
|
-
return escapeScriptClose(JSON.stringify(data));
|
|
1912
|
-
}
|
|
1913
|
+
jsonEmbed: (data) => safeJsonForScript(data)
|
|
1913
1914
|
};
|
|
1914
1915
|
}
|
|
1915
1916
|
|
|
@@ -2585,6 +2586,7 @@ var MERMAID_PREFIXES = [
|
|
|
2585
2586
|
"xychart"
|
|
2586
2587
|
];
|
|
2587
2588
|
var PDF_MAGIC = "JVBERi";
|
|
2589
|
+
var BASE64_PATTERN = /^[A-Za-z0-9+/=\r\n]+$/;
|
|
2588
2590
|
function detectContentType(value) {
|
|
2589
2591
|
if (value === null || value === void 0) {
|
|
2590
2592
|
return "text";
|
|
@@ -2599,7 +2601,7 @@ function detectContentType(value) {
|
|
|
2599
2601
|
if (typeof value === "string") {
|
|
2600
2602
|
const trimmed = value.trimStart();
|
|
2601
2603
|
if (trimmed.startsWith(PDF_MAGIC)) {
|
|
2602
|
-
return "pdf";
|
|
2604
|
+
return BASE64_PATTERN.test(trimmed.trimEnd()) ? "pdf" : "text";
|
|
2603
2605
|
}
|
|
2604
2606
|
for (const prefix of MERMAID_PREFIXES) {
|
|
2605
2607
|
if (trimmed.startsWith(prefix)) {
|
|
@@ -2661,7 +2663,7 @@ function buildPdfHtml(base64) {
|
|
|
2661
2663
|
import * as pdfjsLib from 'https://esm.sh/pdfjs-dist@4/build/pdf.min.mjs';
|
|
2662
2664
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://esm.sh/pdfjs-dist@4/build/pdf.worker.min.mjs';
|
|
2663
2665
|
|
|
2664
|
-
const base64 = ${
|
|
2666
|
+
const base64 = ${safeJsonForScript(base64)};
|
|
2665
2667
|
const binaryStr = atob(base64);
|
|
2666
2668
|
const bytes = new Uint8Array(binaryStr.length);
|
|
2667
2669
|
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
@@ -2756,6 +2758,12 @@ function buildCspConfig(resolver) {
|
|
|
2756
2758
|
}
|
|
2757
2759
|
return { resourceDomains: cspResourceDomains, connectDomains: cspConnectDomains };
|
|
2758
2760
|
}
|
|
2761
|
+
function renderUnwrappedResult(rawResult) {
|
|
2762
|
+
if (typeof rawResult !== "string") {
|
|
2763
|
+
return `<pre>${escapeHtml(JSON.stringify(rawResult, null, 2))}</pre>`;
|
|
2764
|
+
}
|
|
2765
|
+
return detectContentType(rawResult) === "html" ? rawResult : escapeHtml(rawResult);
|
|
2766
|
+
}
|
|
2759
2767
|
function renderToolTemplate(options) {
|
|
2760
2768
|
const { toolName, input, output, template, resolver, platformType, sizing } = options;
|
|
2761
2769
|
const uiType = detectUIType(template);
|
|
@@ -2794,8 +2802,7 @@ function renderToolTemplate(options) {
|
|
|
2794
2802
|
if (wrapped) {
|
|
2795
2803
|
html = wrapped;
|
|
2796
2804
|
} else {
|
|
2797
|
-
const
|
|
2798
|
-
const shellResult = buildShell(textContent, shellConfig);
|
|
2805
|
+
const shellResult = buildShell(renderUnwrappedResult(rawResult), shellConfig);
|
|
2799
2806
|
html = shellResult.html;
|
|
2800
2807
|
hash = shellResult.hash;
|
|
2801
2808
|
size = shellResult.size;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAOnD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAmCD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB,CAsG/F"}
|
package/component/index.js
CHANGED
|
@@ -450,8 +450,9 @@ function createEsmShResolver(options = {}) {
|
|
|
450
450
|
}
|
|
451
451
|
|
|
452
452
|
// libs/uipack/src/utils/index.ts
|
|
453
|
-
|
|
454
|
-
|
|
453
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
454
|
+
function toUnicodeEscape(character) {
|
|
455
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
455
456
|
}
|
|
456
457
|
function safeJsonForScript(value) {
|
|
457
458
|
if (value === void 0) {
|
|
@@ -467,7 +468,7 @@ function safeJsonForScript(value) {
|
|
|
467
468
|
if (jsonString === void 0) {
|
|
468
469
|
return "null";
|
|
469
470
|
}
|
|
470
|
-
return
|
|
471
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
471
472
|
} catch {
|
|
472
473
|
return '{"error":"Value could not be serialized"}';
|
|
473
474
|
}
|
|
@@ -2070,14 +2071,16 @@ var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
|
2070
2071
|
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
2071
2072
|
|
|
2072
2073
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
2074
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
2075
|
+
var VALUE_KEYS = {
|
|
2076
|
+
CSP: "csp",
|
|
2077
|
+
DATA: "data",
|
|
2078
|
+
BRIDGE: "bridge",
|
|
2079
|
+
CONTENT: "content",
|
|
2080
|
+
TITLE: "title"
|
|
2081
|
+
};
|
|
2073
2082
|
function applyShellTemplate(template, values) {
|
|
2074
|
-
|
|
2075
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
2076
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
2077
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
2078
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
2079
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
2080
|
-
return result;
|
|
2083
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
2081
2084
|
}
|
|
2082
2085
|
|
|
2083
2086
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
package/esm/adapters/index.mjs
CHANGED
|
@@ -482,8 +482,9 @@ function escapeHtml(str) {
|
|
|
482
482
|
const s = String(str);
|
|
483
483
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
484
484
|
}
|
|
485
|
-
|
|
486
|
-
|
|
485
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
486
|
+
function toUnicodeEscape(character) {
|
|
487
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
487
488
|
}
|
|
488
489
|
function safeJsonForScript(value) {
|
|
489
490
|
if (value === void 0) {
|
|
@@ -499,7 +500,7 @@ function safeJsonForScript(value) {
|
|
|
499
500
|
if (jsonString === void 0) {
|
|
500
501
|
return "null";
|
|
501
502
|
}
|
|
502
|
-
return
|
|
503
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
503
504
|
} catch {
|
|
504
505
|
return '{"error":"Value could not be serialized"}';
|
|
505
506
|
}
|
|
@@ -1796,14 +1797,16 @@ var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
|
1796
1797
|
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
1797
1798
|
|
|
1798
1799
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
1800
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
1801
|
+
var VALUE_KEYS = {
|
|
1802
|
+
CSP: "csp",
|
|
1803
|
+
DATA: "data",
|
|
1804
|
+
BRIDGE: "bridge",
|
|
1805
|
+
CONTENT: "content",
|
|
1806
|
+
TITLE: "title"
|
|
1807
|
+
};
|
|
1799
1808
|
function applyShellTemplate(template, values) {
|
|
1800
|
-
|
|
1801
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
1802
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
1803
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
1804
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
1805
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
1806
|
-
return result;
|
|
1809
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
1807
1810
|
}
|
|
1808
1811
|
|
|
1809
1812
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
@@ -1875,9 +1878,7 @@ function createTemplateHelpers() {
|
|
|
1875
1878
|
uniqueId: (prefix = "mcp") => {
|
|
1876
1879
|
return `${prefix}-${++_uniqueIdCounter}`;
|
|
1877
1880
|
},
|
|
1878
|
-
jsonEmbed: (data) =>
|
|
1879
|
-
return escapeScriptClose(JSON.stringify(data));
|
|
1880
|
-
}
|
|
1881
|
+
jsonEmbed: (data) => safeJsonForScript(data)
|
|
1881
1882
|
};
|
|
1882
1883
|
}
|
|
1883
1884
|
|
|
@@ -2553,6 +2554,7 @@ var MERMAID_PREFIXES = [
|
|
|
2553
2554
|
"xychart"
|
|
2554
2555
|
];
|
|
2555
2556
|
var PDF_MAGIC = "JVBERi";
|
|
2557
|
+
var BASE64_PATTERN = /^[A-Za-z0-9+/=\r\n]+$/;
|
|
2556
2558
|
function detectContentType(value) {
|
|
2557
2559
|
if (value === null || value === void 0) {
|
|
2558
2560
|
return "text";
|
|
@@ -2567,7 +2569,7 @@ function detectContentType(value) {
|
|
|
2567
2569
|
if (typeof value === "string") {
|
|
2568
2570
|
const trimmed = value.trimStart();
|
|
2569
2571
|
if (trimmed.startsWith(PDF_MAGIC)) {
|
|
2570
|
-
return "pdf";
|
|
2572
|
+
return BASE64_PATTERN.test(trimmed.trimEnd()) ? "pdf" : "text";
|
|
2571
2573
|
}
|
|
2572
2574
|
for (const prefix of MERMAID_PREFIXES) {
|
|
2573
2575
|
if (trimmed.startsWith(prefix)) {
|
|
@@ -2629,7 +2631,7 @@ function buildPdfHtml(base64) {
|
|
|
2629
2631
|
import * as pdfjsLib from 'https://esm.sh/pdfjs-dist@4/build/pdf.min.mjs';
|
|
2630
2632
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://esm.sh/pdfjs-dist@4/build/pdf.worker.min.mjs';
|
|
2631
2633
|
|
|
2632
|
-
const base64 = ${
|
|
2634
|
+
const base64 = ${safeJsonForScript(base64)};
|
|
2633
2635
|
const binaryStr = atob(base64);
|
|
2634
2636
|
const bytes = new Uint8Array(binaryStr.length);
|
|
2635
2637
|
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
@@ -2724,6 +2726,12 @@ function buildCspConfig(resolver) {
|
|
|
2724
2726
|
}
|
|
2725
2727
|
return { resourceDomains: cspResourceDomains, connectDomains: cspConnectDomains };
|
|
2726
2728
|
}
|
|
2729
|
+
function renderUnwrappedResult(rawResult) {
|
|
2730
|
+
if (typeof rawResult !== "string") {
|
|
2731
|
+
return `<pre>${escapeHtml(JSON.stringify(rawResult, null, 2))}</pre>`;
|
|
2732
|
+
}
|
|
2733
|
+
return detectContentType(rawResult) === "html" ? rawResult : escapeHtml(rawResult);
|
|
2734
|
+
}
|
|
2727
2735
|
function renderToolTemplate(options) {
|
|
2728
2736
|
const { toolName, input, output, template, resolver, platformType, sizing } = options;
|
|
2729
2737
|
const uiType = detectUIType(template);
|
|
@@ -2762,8 +2770,7 @@ function renderToolTemplate(options) {
|
|
|
2762
2770
|
if (wrapped) {
|
|
2763
2771
|
html = wrapped;
|
|
2764
2772
|
} else {
|
|
2765
|
-
const
|
|
2766
|
-
const shellResult = buildShell(textContent, shellConfig);
|
|
2773
|
+
const shellResult = buildShell(renderUnwrappedResult(rawResult), shellConfig);
|
|
2767
2774
|
html = shellResult.html;
|
|
2768
2775
|
hash = shellResult.hash;
|
|
2769
2776
|
size = shellResult.size;
|
package/esm/component/index.mjs
CHANGED
|
@@ -421,8 +421,9 @@ function createEsmShResolver(options = {}) {
|
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
// libs/uipack/src/utils/index.ts
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
425
|
+
function toUnicodeEscape(character) {
|
|
426
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
426
427
|
}
|
|
427
428
|
function safeJsonForScript(value) {
|
|
428
429
|
if (value === void 0) {
|
|
@@ -438,7 +439,7 @@ function safeJsonForScript(value) {
|
|
|
438
439
|
if (jsonString === void 0) {
|
|
439
440
|
return "null";
|
|
440
441
|
}
|
|
441
|
-
return
|
|
442
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
442
443
|
} catch {
|
|
443
444
|
return '{"error":"Value could not be serialized"}';
|
|
444
445
|
}
|
|
@@ -2041,14 +2042,16 @@ var REQUIRED_PLACEHOLDERS = ["CONTENT"];
|
|
|
2041
2042
|
var OPTIONAL_PLACEHOLDERS = ["CSP", "DATA", "BRIDGE", "TITLE"];
|
|
2042
2043
|
|
|
2043
2044
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
2045
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
2046
|
+
var VALUE_KEYS = {
|
|
2047
|
+
CSP: "csp",
|
|
2048
|
+
DATA: "data",
|
|
2049
|
+
BRIDGE: "bridge",
|
|
2050
|
+
CONTENT: "content",
|
|
2051
|
+
TITLE: "title"
|
|
2052
|
+
};
|
|
2044
2053
|
function applyShellTemplate(template, values) {
|
|
2045
|
-
|
|
2046
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
2047
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
2048
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
2049
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
2050
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
2051
|
-
return result;
|
|
2054
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
2052
2055
|
}
|
|
2053
2056
|
|
|
2054
2057
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
package/esm/index.mjs
CHANGED
|
@@ -107,6 +107,10 @@ function escapeJsString(str) {
|
|
|
107
107
|
function escapeScriptClose(jsonString) {
|
|
108
108
|
return jsonString.replace(/<\//g, "<\\/");
|
|
109
109
|
}
|
|
110
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
111
|
+
function toUnicodeEscape(character) {
|
|
112
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
113
|
+
}
|
|
110
114
|
function safeJsonForScript(value) {
|
|
111
115
|
if (value === void 0) {
|
|
112
116
|
return "null";
|
|
@@ -121,7 +125,7 @@ function safeJsonForScript(value) {
|
|
|
121
125
|
if (jsonString === void 0) {
|
|
122
126
|
return "null";
|
|
123
127
|
}
|
|
124
|
-
return
|
|
128
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
125
129
|
} catch {
|
|
126
130
|
return '{"error":"Value could not be serialized"}';
|
|
127
131
|
}
|
|
@@ -2885,14 +2889,16 @@ function isNpmShellSource(source) {
|
|
|
2885
2889
|
}
|
|
2886
2890
|
|
|
2887
2891
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
2892
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
2893
|
+
var VALUE_KEYS = {
|
|
2894
|
+
CSP: "csp",
|
|
2895
|
+
DATA: "data",
|
|
2896
|
+
BRIDGE: "bridge",
|
|
2897
|
+
CONTENT: "content",
|
|
2898
|
+
TITLE: "title"
|
|
2899
|
+
};
|
|
2888
2900
|
function applyShellTemplate(template, values) {
|
|
2889
|
-
|
|
2890
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
2891
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
2892
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
2893
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
2894
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
2895
|
-
return result;
|
|
2901
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
2896
2902
|
}
|
|
2897
2903
|
|
|
2898
2904
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
@@ -2964,9 +2970,7 @@ function createTemplateHelpers() {
|
|
|
2964
2970
|
uniqueId: (prefix = "mcp") => {
|
|
2965
2971
|
return `${prefix}-${++_uniqueIdCounter}`;
|
|
2966
2972
|
},
|
|
2967
|
-
jsonEmbed: (data) =>
|
|
2968
|
-
return escapeScriptClose(JSON.stringify(data));
|
|
2969
|
-
}
|
|
2973
|
+
jsonEmbed: (data) => safeJsonForScript(data)
|
|
2970
2974
|
};
|
|
2971
2975
|
}
|
|
2972
2976
|
|
|
@@ -3821,6 +3825,7 @@ var MERMAID_PREFIXES = [
|
|
|
3821
3825
|
"xychart"
|
|
3822
3826
|
];
|
|
3823
3827
|
var PDF_MAGIC = "JVBERi";
|
|
3828
|
+
var BASE64_PATTERN = /^[A-Za-z0-9+/=\r\n]+$/;
|
|
3824
3829
|
function detectContentType(value) {
|
|
3825
3830
|
if (value === null || value === void 0) {
|
|
3826
3831
|
return "text";
|
|
@@ -3835,7 +3840,7 @@ function detectContentType(value) {
|
|
|
3835
3840
|
if (typeof value === "string") {
|
|
3836
3841
|
const trimmed = value.trimStart();
|
|
3837
3842
|
if (trimmed.startsWith(PDF_MAGIC)) {
|
|
3838
|
-
return "pdf";
|
|
3843
|
+
return BASE64_PATTERN.test(trimmed.trimEnd()) ? "pdf" : "text";
|
|
3839
3844
|
}
|
|
3840
3845
|
for (const prefix of MERMAID_PREFIXES) {
|
|
3841
3846
|
if (trimmed.startsWith(prefix)) {
|
|
@@ -3897,7 +3902,7 @@ function buildPdfHtml(base64) {
|
|
|
3897
3902
|
import * as pdfjsLib from 'https://esm.sh/pdfjs-dist@4/build/pdf.min.mjs';
|
|
3898
3903
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://esm.sh/pdfjs-dist@4/build/pdf.worker.min.mjs';
|
|
3899
3904
|
|
|
3900
|
-
const base64 = ${
|
|
3905
|
+
const base64 = ${safeJsonForScript(base64)};
|
|
3901
3906
|
const binaryStr = atob(base64);
|
|
3902
3907
|
const bytes = new Uint8Array(binaryStr.length);
|
|
3903
3908
|
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
@@ -3992,6 +3997,12 @@ function buildCspConfig(resolver) {
|
|
|
3992
3997
|
}
|
|
3993
3998
|
return { resourceDomains: cspResourceDomains, connectDomains: cspConnectDomains };
|
|
3994
3999
|
}
|
|
4000
|
+
function renderUnwrappedResult(rawResult) {
|
|
4001
|
+
if (typeof rawResult !== "string") {
|
|
4002
|
+
return `<pre>${escapeHtml(JSON.stringify(rawResult, null, 2))}</pre>`;
|
|
4003
|
+
}
|
|
4004
|
+
return detectContentType(rawResult) === "html" ? rawResult : escapeHtml(rawResult);
|
|
4005
|
+
}
|
|
3995
4006
|
function renderToolTemplate(options) {
|
|
3996
4007
|
const { toolName, input, output, template, resolver, platformType, sizing } = options;
|
|
3997
4008
|
const uiType = detectUIType(template);
|
|
@@ -4030,8 +4041,7 @@ function renderToolTemplate(options) {
|
|
|
4030
4041
|
if (wrapped) {
|
|
4031
4042
|
html = wrapped;
|
|
4032
4043
|
} else {
|
|
4033
|
-
const
|
|
4034
|
-
const shellResult = buildShell(textContent, shellConfig);
|
|
4044
|
+
const shellResult = buildShell(renderUnwrappedResult(rawResult), shellConfig);
|
|
4035
4045
|
html = shellResult.html;
|
|
4036
4046
|
hash = shellResult.hash;
|
|
4037
4047
|
size = shellResult.size;
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/uipack",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "FrontMCP UIpack - HTML shell builder, pluggable import resolver, and NPM component loader for MCP UI (React-free core)",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -61,6 +61,6 @@
|
|
|
61
61
|
"typescript": "^5.9.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
64
|
+
"@frontmcp/lazy-zod": "1.8.1"
|
|
65
65
|
}
|
|
66
66
|
}
|
package/esm/shell/index.mjs
CHANGED
|
@@ -1283,14 +1283,16 @@ function isNpmShellSource(source) {
|
|
|
1283
1283
|
}
|
|
1284
1284
|
|
|
1285
1285
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
1286
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
1287
|
+
var VALUE_KEYS = {
|
|
1288
|
+
CSP: "csp",
|
|
1289
|
+
DATA: "data",
|
|
1290
|
+
BRIDGE: "bridge",
|
|
1291
|
+
CONTENT: "content",
|
|
1292
|
+
TITLE: "title"
|
|
1293
|
+
};
|
|
1286
1294
|
function applyShellTemplate(template, values) {
|
|
1287
|
-
|
|
1288
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
1289
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
1290
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
1291
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
1292
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
1293
|
-
return result;
|
|
1295
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
1294
1296
|
}
|
|
1295
1297
|
|
|
1296
1298
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
@@ -1317,8 +1319,9 @@ function escapeHtml(str) {
|
|
|
1317
1319
|
const s = String(str);
|
|
1318
1320
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1319
1321
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
1323
|
+
function toUnicodeEscape(character) {
|
|
1324
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
1322
1325
|
}
|
|
1323
1326
|
function safeJsonForScript(value) {
|
|
1324
1327
|
if (value === void 0) {
|
|
@@ -1334,7 +1337,7 @@ function safeJsonForScript(value) {
|
|
|
1334
1337
|
if (jsonString === void 0) {
|
|
1335
1338
|
return "null";
|
|
1336
1339
|
}
|
|
1337
|
-
return
|
|
1340
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
1338
1341
|
} catch {
|
|
1339
1342
|
return '{"error":"Value could not be serialized"}';
|
|
1340
1343
|
}
|
|
@@ -1393,9 +1396,7 @@ function createTemplateHelpers() {
|
|
|
1393
1396
|
uniqueId: (prefix = "mcp") => {
|
|
1394
1397
|
return `${prefix}-${++_uniqueIdCounter}`;
|
|
1395
1398
|
},
|
|
1396
|
-
jsonEmbed: (data) =>
|
|
1397
|
-
return escapeScriptClose(JSON.stringify(data));
|
|
1398
|
-
}
|
|
1399
|
+
jsonEmbed: (data) => safeJsonForScript(data)
|
|
1399
1400
|
};
|
|
1400
1401
|
}
|
|
1401
1402
|
|
package/esm/utils/index.mjs
CHANGED
|
@@ -33,6 +33,10 @@ function escapeJsString(str) {
|
|
|
33
33
|
function escapeScriptClose(jsonString) {
|
|
34
34
|
return jsonString.replace(/<\//g, "<\\/");
|
|
35
35
|
}
|
|
36
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
37
|
+
function toUnicodeEscape(character) {
|
|
38
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
39
|
+
}
|
|
36
40
|
function safeJsonForScript(value) {
|
|
37
41
|
if (value === void 0) {
|
|
38
42
|
return "null";
|
|
@@ -47,7 +51,7 @@ function safeJsonForScript(value) {
|
|
|
47
51
|
if (jsonString === void 0) {
|
|
48
52
|
return "null";
|
|
49
53
|
}
|
|
50
|
-
return
|
|
54
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
51
55
|
} catch {
|
|
52
56
|
return '{"error":"Value could not be serialized"}';
|
|
53
57
|
}
|
package/index.js
CHANGED
|
@@ -224,6 +224,10 @@ function escapeJsString(str) {
|
|
|
224
224
|
function escapeScriptClose(jsonString) {
|
|
225
225
|
return jsonString.replace(/<\//g, "<\\/");
|
|
226
226
|
}
|
|
227
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
228
|
+
function toUnicodeEscape(character) {
|
|
229
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
230
|
+
}
|
|
227
231
|
function safeJsonForScript(value) {
|
|
228
232
|
if (value === void 0) {
|
|
229
233
|
return "null";
|
|
@@ -238,7 +242,7 @@ function safeJsonForScript(value) {
|
|
|
238
242
|
if (jsonString === void 0) {
|
|
239
243
|
return "null";
|
|
240
244
|
}
|
|
241
|
-
return
|
|
245
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
242
246
|
} catch {
|
|
243
247
|
return '{"error":"Value could not be serialized"}';
|
|
244
248
|
}
|
|
@@ -3002,14 +3006,16 @@ function isNpmShellSource(source) {
|
|
|
3002
3006
|
}
|
|
3003
3007
|
|
|
3004
3008
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
3009
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
3010
|
+
var VALUE_KEYS = {
|
|
3011
|
+
CSP: "csp",
|
|
3012
|
+
DATA: "data",
|
|
3013
|
+
BRIDGE: "bridge",
|
|
3014
|
+
CONTENT: "content",
|
|
3015
|
+
TITLE: "title"
|
|
3016
|
+
};
|
|
3005
3017
|
function applyShellTemplate(template, values) {
|
|
3006
|
-
|
|
3007
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
3008
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
3009
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
3010
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
3011
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
3012
|
-
return result;
|
|
3018
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
3013
3019
|
}
|
|
3014
3020
|
|
|
3015
3021
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
@@ -3081,9 +3087,7 @@ function createTemplateHelpers() {
|
|
|
3081
3087
|
uniqueId: (prefix = "mcp") => {
|
|
3082
3088
|
return `${prefix}-${++_uniqueIdCounter}`;
|
|
3083
3089
|
},
|
|
3084
|
-
jsonEmbed: (data) =>
|
|
3085
|
-
return escapeScriptClose(JSON.stringify(data));
|
|
3086
|
-
}
|
|
3090
|
+
jsonEmbed: (data) => safeJsonForScript(data)
|
|
3087
3091
|
};
|
|
3088
3092
|
}
|
|
3089
3093
|
|
|
@@ -3938,6 +3942,7 @@ var MERMAID_PREFIXES = [
|
|
|
3938
3942
|
"xychart"
|
|
3939
3943
|
];
|
|
3940
3944
|
var PDF_MAGIC = "JVBERi";
|
|
3945
|
+
var BASE64_PATTERN = /^[A-Za-z0-9+/=\r\n]+$/;
|
|
3941
3946
|
function detectContentType(value) {
|
|
3942
3947
|
if (value === null || value === void 0) {
|
|
3943
3948
|
return "text";
|
|
@@ -3952,7 +3957,7 @@ function detectContentType(value) {
|
|
|
3952
3957
|
if (typeof value === "string") {
|
|
3953
3958
|
const trimmed = value.trimStart();
|
|
3954
3959
|
if (trimmed.startsWith(PDF_MAGIC)) {
|
|
3955
|
-
return "pdf";
|
|
3960
|
+
return BASE64_PATTERN.test(trimmed.trimEnd()) ? "pdf" : "text";
|
|
3956
3961
|
}
|
|
3957
3962
|
for (const prefix of MERMAID_PREFIXES) {
|
|
3958
3963
|
if (trimmed.startsWith(prefix)) {
|
|
@@ -4014,7 +4019,7 @@ function buildPdfHtml(base64) {
|
|
|
4014
4019
|
import * as pdfjsLib from 'https://esm.sh/pdfjs-dist@4/build/pdf.min.mjs';
|
|
4015
4020
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://esm.sh/pdfjs-dist@4/build/pdf.worker.min.mjs';
|
|
4016
4021
|
|
|
4017
|
-
const base64 = ${
|
|
4022
|
+
const base64 = ${safeJsonForScript(base64)};
|
|
4018
4023
|
const binaryStr = atob(base64);
|
|
4019
4024
|
const bytes = new Uint8Array(binaryStr.length);
|
|
4020
4025
|
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
|
|
@@ -4109,6 +4114,12 @@ function buildCspConfig(resolver) {
|
|
|
4109
4114
|
}
|
|
4110
4115
|
return { resourceDomains: cspResourceDomains, connectDomains: cspConnectDomains };
|
|
4111
4116
|
}
|
|
4117
|
+
function renderUnwrappedResult(rawResult) {
|
|
4118
|
+
if (typeof rawResult !== "string") {
|
|
4119
|
+
return `<pre>${escapeHtml(JSON.stringify(rawResult, null, 2))}</pre>`;
|
|
4120
|
+
}
|
|
4121
|
+
return detectContentType(rawResult) === "html" ? rawResult : escapeHtml(rawResult);
|
|
4122
|
+
}
|
|
4112
4123
|
function renderToolTemplate(options) {
|
|
4113
4124
|
const { toolName, input, output, template, resolver, platformType, sizing } = options;
|
|
4114
4125
|
const uiType = detectUIType(template);
|
|
@@ -4147,8 +4158,7 @@ function renderToolTemplate(options) {
|
|
|
4147
4158
|
if (wrapped) {
|
|
4148
4159
|
html = wrapped;
|
|
4149
4160
|
} else {
|
|
4150
|
-
const
|
|
4151
|
-
const shellResult = buildShell(textContent, shellConfig);
|
|
4161
|
+
const shellResult = buildShell(renderUnwrappedResult(rawResult), shellConfig);
|
|
4152
4162
|
html = shellResult.html;
|
|
4153
4163
|
hash = shellResult.hash;
|
|
4154
4164
|
size = shellResult.size;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/uipack",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "FrontMCP UIpack - HTML shell builder, pluggable import resolver, and NPM component loader for MCP UI (React-free core)",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -61,6 +61,6 @@
|
|
|
61
61
|
"typescript": "^5.9.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
64
|
+
"@frontmcp/lazy-zod": "1.8.1"
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
* Replaces placeholder tokens in a custom shell template with
|
|
5
5
|
* the generated fragment values (CSP, data script, bridge, content, title).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* All placeholders are replaced in a single pass over the template, so an
|
|
8
|
+
* inserted value is never re-scanned for placeholders.
|
|
9
9
|
*
|
|
10
10
|
* @packageDocumentation
|
|
11
11
|
*/
|
|
12
|
-
import type
|
|
12
|
+
import { type ShellPlaceholderValues } from './custom-shell-types';
|
|
13
13
|
/**
|
|
14
14
|
* Apply placeholder values to a custom shell template.
|
|
15
15
|
*
|
|
16
|
-
* Each `{{PLACEHOLDER}}` token is replaced with the corresponding value.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Each `{{PLACEHOLDER}}` token is replaced with the corresponding value, verbatim.
|
|
17
|
+
* Values carry tool input and output (GHSA-rhr9-vhpf-jqp7), so they are inserted by a
|
|
18
|
+
* function replacer: a value is never re-scanned for other placeholders, and `$&`, `$'`
|
|
19
|
+
* or `` $` `` inside it are not expanded.
|
|
19
20
|
*
|
|
20
21
|
* @param template - The shell template with `{{PLACEHOLDER}}` tokens
|
|
21
22
|
* @param values - The values to inject for each placeholder
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-shell-applier.d.ts","sourceRoot":"","sources":["../../src/shell/custom-shell-applier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"custom-shell-applier.d.ts","sourceRoot":"","sources":["../../src/shell/custom-shell-applier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAsD,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAYvH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAE3F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-injector.d.ts","sourceRoot":"","sources":["../../src/shell/data-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,IAAI,YAAY,CASvE;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,MAAM,CAgBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAeT;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IACrC,gCAAgC;IAChC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D,kCAAkC;IAClC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9D,4CAA4C;IAC5C,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,qCAAqC;IACrC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;CACtC;AAID;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"data-injector.d.ts","sourceRoot":"","sources":["../../src/shell/data-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,IAAI,YAAY,CASvE;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,MAAM,CAgBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAeT;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IACrC,gCAAgC;IAChC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D,kCAAkC;IAClC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9D,4CAA4C;IAC5C,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,qCAAqC;IACrC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;CACtC;AAID;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CA2BvD"}
|
package/shell/index.js
CHANGED
|
@@ -1332,14 +1332,16 @@ function isNpmShellSource(source) {
|
|
|
1332
1332
|
}
|
|
1333
1333
|
|
|
1334
1334
|
// libs/uipack/src/shell/custom-shell-applier.ts
|
|
1335
|
+
var PLACEHOLDER_PATTERN = new RegExp(`\\{\\{(${SHELL_PLACEHOLDER_NAMES.join("|")})\\}\\}`, "g");
|
|
1336
|
+
var VALUE_KEYS = {
|
|
1337
|
+
CSP: "csp",
|
|
1338
|
+
DATA: "data",
|
|
1339
|
+
BRIDGE: "bridge",
|
|
1340
|
+
CONTENT: "content",
|
|
1341
|
+
TITLE: "title"
|
|
1342
|
+
};
|
|
1335
1343
|
function applyShellTemplate(template, values) {
|
|
1336
|
-
|
|
1337
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CSP, values.csp);
|
|
1338
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.DATA, values.data);
|
|
1339
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.BRIDGE, values.bridge);
|
|
1340
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.CONTENT, values.content);
|
|
1341
|
-
result = result.replaceAll(SHELL_PLACEHOLDERS.TITLE, values.title);
|
|
1342
|
-
return result;
|
|
1344
|
+
return template.replace(PLACEHOLDER_PATTERN, (_token, name) => values[VALUE_KEYS[name]]);
|
|
1343
1345
|
}
|
|
1344
1346
|
|
|
1345
1347
|
// libs/uipack/src/shell/custom-shell-validator.ts
|
|
@@ -1366,8 +1368,9 @@ function escapeHtml(str) {
|
|
|
1366
1368
|
const s = String(str);
|
|
1367
1369
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1368
1370
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
1372
|
+
function toUnicodeEscape(character) {
|
|
1373
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
1371
1374
|
}
|
|
1372
1375
|
function safeJsonForScript(value) {
|
|
1373
1376
|
if (value === void 0) {
|
|
@@ -1383,7 +1386,7 @@ function safeJsonForScript(value) {
|
|
|
1383
1386
|
if (jsonString === void 0) {
|
|
1384
1387
|
return "null";
|
|
1385
1388
|
}
|
|
1386
|
-
return
|
|
1389
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
1387
1390
|
} catch {
|
|
1388
1391
|
return '{"error":"Value could not be serialized"}';
|
|
1389
1392
|
}
|
|
@@ -1442,9 +1445,7 @@ function createTemplateHelpers() {
|
|
|
1442
1445
|
uniqueId: (prefix = "mcp") => {
|
|
1443
1446
|
return `${prefix}-${++_uniqueIdCounter}`;
|
|
1444
1447
|
},
|
|
1445
|
-
jsonEmbed: (data) =>
|
|
1446
|
-
return escapeScriptClose(JSON.stringify(data));
|
|
1447
|
-
}
|
|
1448
|
+
jsonEmbed: (data) => safeJsonForScript(data)
|
|
1448
1449
|
};
|
|
1449
1450
|
}
|
|
1450
1451
|
|
package/utils/index.d.ts
CHANGED
|
@@ -11,5 +11,12 @@ export declare function escapeHtml(str: unknown): string;
|
|
|
11
11
|
export declare function escapeHtmlAttr(str: string): string;
|
|
12
12
|
export declare function escapeJsString(str: string): string;
|
|
13
13
|
export declare function escapeScriptClose(jsonString: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Serialize a value as JSON that can be embedded in an inline `<script>`.
|
|
16
|
+
*
|
|
17
|
+
* `<`, `>`, `&`, U+2028 and U+2029 are written as `\uXXXX`, so the output can neither close
|
|
18
|
+
* the element, open a comment or nested script, nor end a line; `JSON.parse` and the JS engine
|
|
19
|
+
* read the escapes back as the original characters.
|
|
20
|
+
*/
|
|
14
21
|
export declare function safeJsonForScript(value: unknown): string;
|
|
15
22
|
//# sourceMappingURL=index.d.ts.map
|
package/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBpE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAc/C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBpE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAc/C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;AAQD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAqBxD"}
|
package/utils/index.js
CHANGED
|
@@ -62,6 +62,10 @@ function escapeJsString(str) {
|
|
|
62
62
|
function escapeScriptClose(jsonString) {
|
|
63
63
|
return jsonString.replace(/<\//g, "<\\/");
|
|
64
64
|
}
|
|
65
|
+
var SCRIPT_UNSAFE_CHARACTERS = /[<>&\u2028\u2029]/g;
|
|
66
|
+
function toUnicodeEscape(character) {
|
|
67
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
68
|
+
}
|
|
65
69
|
function safeJsonForScript(value) {
|
|
66
70
|
if (value === void 0) {
|
|
67
71
|
return "null";
|
|
@@ -76,7 +80,7 @@ function safeJsonForScript(value) {
|
|
|
76
80
|
if (jsonString === void 0) {
|
|
77
81
|
return "null";
|
|
78
82
|
}
|
|
79
|
-
return
|
|
83
|
+
return jsonString.replace(SCRIPT_UNSAFE_CHARACTERS, toUnicodeEscape);
|
|
80
84
|
} catch {
|
|
81
85
|
return '{"error":"Value could not be serialized"}';
|
|
82
86
|
}
|