@pie-players/pie-players-shared 0.3.29 → 0.3.30
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/{src → dist}/components/PieItemPlayer.svelte +156 -88
- package/dist/i18n/translations/en/tools.json +1 -1
- package/{src → dist}/i18n/use-i18n-standalone.svelte.ts +1 -0
- package/{src → dist}/i18n/use-i18n.svelte.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/loader-config.d.ts +25 -0
- package/dist/loader-config.d.ts.map +1 -1
- package/dist/loader-config.js +5 -0
- package/dist/loader-config.js.map +1 -1
- package/dist/pie/config.d.ts.map +1 -1
- package/dist/pie/config.js +12 -5
- package/dist/pie/config.js.map +1 -1
- package/dist/pie/iife-loader.d.ts +35 -0
- package/dist/pie/iife-loader.d.ts.map +1 -1
- package/dist/pie/iife-loader.js +138 -2
- package/dist/pie/iife-loader.js.map +1 -1
- package/dist/pie/index.d.ts +3 -1
- package/dist/pie/index.d.ts.map +1 -1
- package/dist/pie/index.js +1 -0
- package/dist/pie/index.js.map +1 -1
- package/dist/pie/overrides.d.ts +9 -0
- package/dist/pie/overrides.d.ts.map +1 -1
- package/dist/pie/overrides.js +36 -0
- package/dist/pie/overrides.js.map +1 -1
- package/dist/pie/resource-monitor.d.ts +17 -0
- package/dist/pie/resource-monitor.d.ts.map +1 -1
- package/dist/pie/resource-monitor.js +284 -81
- package/dist/pie/resource-monitor.js.map +1 -1
- package/dist/pie/updates.d.ts.map +1 -1
- package/dist/pie/updates.js +65 -2
- package/dist/pie/updates.js.map +1 -1
- package/dist/security/index.d.ts +5 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +5 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/sanitize-item-markup.d.ts +46 -0
- package/dist/security/sanitize-item-markup.d.ts.map +1 -0
- package/dist/security/sanitize-item-markup.js +174 -0
- package/dist/security/sanitize-item-markup.js.map +1 -0
- package/dist/security/sanitize-svg-icon.d.ts +15 -0
- package/dist/security/sanitize-svg-icon.d.ts.map +1 -0
- package/dist/security/sanitize-svg-icon.js +89 -0
- package/dist/security/sanitize-svg-icon.js.map +1 -0
- package/dist/security/validate-style-url.d.ts +28 -0
- package/dist/security/validate-style-url.d.ts.map +1 -0
- package/dist/security/validate-style-url.js +58 -0
- package/dist/security/validate-style-url.js.map +1 -0
- package/dist/security/wrap-overwide-images.d.ts +31 -0
- package/dist/security/wrap-overwide-images.d.ts.map +1 -0
- package/dist/security/wrap-overwide-images.js +92 -0
- package/dist/security/wrap-overwide-images.js.map +1 -0
- package/dist/server/npm-registry.d.ts +8 -0
- package/dist/server/npm-registry.d.ts.map +1 -0
- package/dist/server/npm-registry.js +60 -0
- package/dist/server/npm-registry.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/ui/first-focusable.d.ts +21 -0
- package/dist/ui/first-focusable.d.ts.map +1 -0
- package/dist/ui/first-focusable.js +73 -0
- package/dist/ui/first-focusable.js.map +1 -0
- package/dist/ui/focus-trap.d.ts.map +1 -1
- package/dist/ui/focus-trap.js +2 -13
- package/dist/ui/focus-trap.js.map +1 -1
- package/package.json +44 -34
- package/dist/i18n/scripts/check-coverage.d.ts +0 -16
- package/dist/i18n/scripts/check-coverage.d.ts.map +0 -1
- package/dist/i18n/scripts/check-coverage.js +0 -262
- package/dist/i18n/scripts/check-coverage.js.map +0 -1
- package/dist/i18n/scripts/scan-hardcoded.d.ts +0 -16
- package/dist/i18n/scripts/scan-hardcoded.d.ts.map +0 -1
- package/dist/i18n/scripts/scan-hardcoded.js +0 -266
- package/dist/i18n/scripts/scan-hardcoded.js.map +0 -1
- package/dist/i18n/use-i18n-standalone.svelte.d.ts +0 -87
- package/dist/i18n/use-i18n-standalone.svelte.d.ts.map +0 -1
- package/dist/i18n/use-i18n-standalone.svelte.js +0 -151
- package/dist/i18n/use-i18n-standalone.svelte.js.map +0 -1
- package/dist/i18n/use-i18n.svelte.d.ts +0 -67
- package/dist/i18n/use-i18n.svelte.d.ts.map +0 -1
- package/dist/i18n/use-i18n.svelte.js +0 -144
- package/dist/i18n/use-i18n.svelte.js.map +0 -1
- package/dist/instrumentation/providers/DataDogInstrumentationProvider.d.ts +0 -170
- package/dist/instrumentation/providers/DataDogInstrumentationProvider.d.ts.map +0 -1
- package/dist/instrumentation/providers/DataDogInstrumentationProvider.js +0 -183
- package/dist/instrumentation/providers/DataDogInstrumentationProvider.js.map +0 -1
- package/dist/theming/css-variables.d.ts +0 -7
- package/dist/theming/css-variables.d.ts.map +0 -1
- package/dist/theming/css-variables.js +0 -43
- package/dist/theming/css-variables.js.map +0 -1
- package/dist/theming/index.d.ts +0 -4
- package/dist/theming/index.d.ts.map +0 -1
- package/dist/theming/index.js +0 -3
- package/dist/theming/index.js.map +0 -1
- package/dist/theming/presets.d.ts +0 -7
- package/dist/theming/presets.d.ts.map +0 -1
- package/dist/theming/presets.js +0 -146
- package/dist/theming/presets.js.map +0 -1
- package/dist/theming/types.d.ts +0 -5
- package/dist/theming/types.d.ts.map +0 -1
- package/dist/theming/types.js +0 -2
- package/dist/theming/types.js.map +0 -1
- package/dist/types/custom-elements.d.ts +0 -158
- package/dist/types/custom-elements.d.ts.map +0 -1
- package/dist/types/custom-elements.js +0 -8
- package/dist/types/custom-elements.js.map +0 -1
- package/dist/types/search.d.ts +0 -105
- package/dist/types/search.d.ts.map +0 -1
- package/dist/types/search.js +0 -12
- package/dist/types/search.js.map +0 -1
- package/dist/types/transform.d.ts +0 -48
- package/dist/types/transform.d.ts.map +0 -1
- package/dist/types/transform.js +0 -21
- package/dist/types/transform.js.map +0 -1
- package/src/i18n/README.md +0 -223
- package/src/i18n/index.ts +0 -26
- package/src/i18n/loader.ts +0 -156
- package/src/i18n/scripts/check-coverage.ts +0 -345
- package/src/i18n/scripts/scan-hardcoded.ts +0 -342
- package/src/i18n/simple-i18n.ts +0 -236
- package/src/i18n/translations/ar/common.json +0 -36
- package/src/i18n/translations/ar/toolkit.json +0 -48
- package/src/i18n/translations/ar/tools.json +0 -103
- package/src/i18n/translations/en/common.json +0 -36
- package/src/i18n/translations/en/toolkit.json +0 -48
- package/src/i18n/translations/en/tools.json +0 -103
- package/src/i18n/translations/es/common.json +0 -36
- package/src/i18n/translations/es/toolkit.json +0 -48
- package/src/i18n/translations/es/tools.json +0 -103
- package/src/i18n/translations/zh/common.json +0 -36
- package/src/i18n/translations/zh/toolkit.json +0 -48
- package/src/i18n/translations/zh/tools.json +0 -103
- package/src/i18n/types.ts +0 -66
- /package/{src → dist}/components/PiePreviewLayout.svelte +0 -0
- /package/{src → dist}/components/PiePreviewToggle.svelte +0 -0
- /package/{src → dist}/components/PieSpinner.svelte +0 -0
- /package/{src → dist}/components/ToolSettingsButton.svelte +0 -0
- /package/{src → dist}/components/ToolSettingsPanel.svelte +0 -0
- /package/{src → dist}/components/index.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../src/pie/updates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../src/pie/updates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAY,MAAM,mBAAmB,CAAC;AAGrE,OAAO,KAAK,EAAc,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAiPtE;;GAEG;AACH,eAAO,MAAM,uBAAuB,GACnC,IAAI,OAAO,EACX,MAAM,uBAAuB,KAC3B,IAUF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC5B,QAAQ,MAAM,EACd,MAAM,uBAAuB,KAC3B,IAiBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC7B,QAAQ,YAAY,EACpB,SAAS,GAAG,EAAE,EACd,KAAK,GAAG,EACR,YAAY,OAAO,GAAG,QAAQ,KAC5B,IAKF,CAAC"}
|
package/dist/pie/updates.js
CHANGED
|
@@ -10,6 +10,50 @@ import { defaultPieElementOptions } from "./types.js";
|
|
|
10
10
|
import { findOrAddSession } from "./utils.js";
|
|
11
11
|
// Create module-level logger (respects global debug flag - pass function for dynamic checking)
|
|
12
12
|
const logger = createPieLogger("pie-updates", () => isGlobalDebugEnabled());
|
|
13
|
+
const describeControllerShape = (controller) => {
|
|
14
|
+
if (!controller)
|
|
15
|
+
return "missing";
|
|
16
|
+
if (typeof controller === "function")
|
|
17
|
+
return "function";
|
|
18
|
+
if (typeof controller !== "object")
|
|
19
|
+
return typeof controller;
|
|
20
|
+
const keys = Object.keys(controller);
|
|
21
|
+
const defaultValue = controller.default;
|
|
22
|
+
const defaultKeys = defaultValue && typeof defaultValue === "object"
|
|
23
|
+
? Object.keys(defaultValue)
|
|
24
|
+
: [];
|
|
25
|
+
return defaultKeys.length > 0
|
|
26
|
+
? `object(keys=[${keys.join(",")}],defaultKeys=[${defaultKeys.join(",")}])`
|
|
27
|
+
: `object(keys=[${keys.join(",")}])`;
|
|
28
|
+
};
|
|
29
|
+
const resolveControllerModelFunction = (controller) => {
|
|
30
|
+
if (!controller)
|
|
31
|
+
return null;
|
|
32
|
+
if (typeof controller === "function") {
|
|
33
|
+
return controller;
|
|
34
|
+
}
|
|
35
|
+
if (typeof controller !== "object")
|
|
36
|
+
return null;
|
|
37
|
+
const direct = controller.model;
|
|
38
|
+
if (typeof direct === "function") {
|
|
39
|
+
return (model, sessionData, env, updateSession) => direct.call(controller, model, sessionData, env, updateSession);
|
|
40
|
+
}
|
|
41
|
+
const fromDefault = controller.default;
|
|
42
|
+
if (fromDefault && typeof fromDefault === "object") {
|
|
43
|
+
const nested = fromDefault.model;
|
|
44
|
+
if (typeof nested === "function") {
|
|
45
|
+
return (model, sessionData, env, updateSession) => nested.call(fromDefault, model, sessionData, env, updateSession);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
};
|
|
50
|
+
const emitControllerError = (pieElement, detail) => {
|
|
51
|
+
pieElement.dispatchEvent(new CustomEvent("pie-controller-error", {
|
|
52
|
+
detail,
|
|
53
|
+
bubbles: true,
|
|
54
|
+
composed: true,
|
|
55
|
+
}));
|
|
56
|
+
};
|
|
13
57
|
/**
|
|
14
58
|
* Helper function to apply controller to element
|
|
15
59
|
* Extracted to eliminate duplication and ensure consistent controller invocation
|
|
@@ -28,12 +72,19 @@ const applyControllerToElement = async (element, model, elementSession, controll
|
|
|
28
72
|
return Promise.resolve();
|
|
29
73
|
};
|
|
30
74
|
try {
|
|
31
|
-
const
|
|
75
|
+
const modelFunction = resolveControllerModelFunction(controller);
|
|
76
|
+
if (!modelFunction) {
|
|
77
|
+
throw new Error(`Controller contract mismatch: expected a model() function but received ${describeControllerShape(controller)}`);
|
|
78
|
+
}
|
|
79
|
+
const controllerResult = await modelFunction(model, elementSession, env, updateSession);
|
|
32
80
|
// Merge controller result with id and element (like server-side PieControllerExecutor does)
|
|
81
|
+
const controllerResultObject = controllerResult && typeof controllerResult === "object"
|
|
82
|
+
? controllerResult
|
|
83
|
+
: {};
|
|
33
84
|
const filteredModel = {
|
|
34
85
|
id: model.id,
|
|
35
86
|
element: model.element,
|
|
36
|
-
...
|
|
87
|
+
...controllerResultObject,
|
|
37
88
|
};
|
|
38
89
|
logger.debug(`${logPrefix} ✅ Controller filtered model:`, {
|
|
39
90
|
id: filteredModel.id,
|
|
@@ -91,7 +142,19 @@ const updateSinglePieElement = (pieElement, controllerLookupTag, options, logCon
|
|
|
91
142
|
hasCorrectResponse: "correctResponse" in model,
|
|
92
143
|
});
|
|
93
144
|
applyControllerToElement(pieElement, model, elementSession, controller, env, `${logContext}(${controllerLookupTag}#${pieElement.id})`).catch((err) => {
|
|
145
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
146
|
+
const isContractError = errorMessage.includes("Controller contract mismatch");
|
|
94
147
|
logger.error(`${logContext} Controller failed for ${controllerLookupTag}#${pieElement.id}:`, err);
|
|
148
|
+
emitControllerError(pieElement, {
|
|
149
|
+
code: isContractError
|
|
150
|
+
? "PIE_CONTROLLER_CONTRACT_ERROR"
|
|
151
|
+
: "PIE_CONTROLLER_RUNTIME_ERROR",
|
|
152
|
+
message: `${controllerLookupTag} controller failed while applying model for ${pieElement.id}. ${errorMessage}`,
|
|
153
|
+
elementName: controllerLookupTag,
|
|
154
|
+
elementId: pieElement.id,
|
|
155
|
+
controllerShape: describeControllerShape(controller),
|
|
156
|
+
cause: errorMessage,
|
|
157
|
+
});
|
|
95
158
|
// Fall back to raw model on controller error
|
|
96
159
|
pieElement.model = model;
|
|
97
160
|
pieElement.session = elementSession;
|
package/dist/pie/updates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../../src/pie/updates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,+FAA+F;AAC/F,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../../src/pie/updates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,+FAA+F;AAC/F,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC;AAW5E,MAAM,uBAAuB,GAAG,CAAC,UAAmB,EAAU,EAAE;IAC/D,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,IAAI,OAAO,UAAU,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IACxD,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,OAAO,UAAU,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,UAAqC,CAAC,CAAC;IAChE,MAAM,YAAY,GAAI,UAAsC,CAAC,OAAO,CAAC;IACrE,MAAM,WAAW,GAChB,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ;QAC/C,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAuC,CAAC;QACtD,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC;QAC5B,CAAC,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;QAC3E,CAAC,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,8BAA8B,GAAG,CACtC,UAAmB,EACiE,EAAE;IACtF,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,UAAsF,CAAC;IAC/F,CAAC;IACD,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,MAAM,GAAI,UAAsC,CAAC,KAAK,CAAC;IAC7D,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,CAChD,MAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,WAAW,GAAI,UAAsC,CAAC,OAAO,CAAC;IACpE,IAAI,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;QACpD,MAAM,MAAM,GAAI,WAAuC,CAAC,KAAK,CAAC;QAC9D,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,CAChD,MAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;QACjF,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAC3B,UAAsB,EACtB,MAA6B,EACtB,EAAE;IACT,UAAU,CAAC,aAAa,CACvB,IAAI,WAAW,CAAC,sBAAsB,EAAE;QACvC,MAAM;QACN,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACd,CAAC,CACF,CAAC;AACH,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,wBAAwB,GAAG,KAAK,EACrC,OAAmB,EACnB,KAAe,EACf,cAAmB,EACnB,UAAmB,EACnB,GAAQ,EACR,SAAiB,EACD,EAAE;IAClB,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,yBAAyB,EAAE,GAAG,CAAC,CAAC;IACzD,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,uBAAuB,EAAE;QACjD,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,kBAAkB,EAAE,iBAAiB,IAAI,KAAK;KAC9C,CAAC,CAAC;IAEH,qEAAqE;IACrE,MAAM,aAAa,GAAG,CAAC,EAAU,EAAE,YAAoB,EAAE,UAAe,EAAE,EAAE;QAC3E,MAAM,CAAC,KAAK,CACX,GAAG,SAAS,6BAA6B,EAAE,QAAQ,EACnD,UAAU,CACV,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QAC1C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC,CAAC;IAEF,IAAI,CAAC;QACJ,MAAM,aAAa,GAAG,8BAA8B,CAAC,UAAU,CAAC,CAAC;QACjE,IAAI,CAAC,aAAa,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACd,0EAA0E,uBAAuB,CAChG,UAAU,CACV,EAAE,CACH,CAAC;QACH,CAAC;QACD,MAAM,gBAAgB,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;QAExF,4FAA4F;QAC5F,MAAM,sBAAsB,GAC3B,gBAAgB,IAAI,OAAO,gBAAgB,KAAK,QAAQ;YACvD,CAAC,CAAE,gBAA4C;YAC/C,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,aAAa,GAAG;YACrB,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,sBAAsB;SACzB,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,+BAA+B,EAAE;YACzD,EAAE,EAAE,aAAa,CAAC,EAAE;YACpB,OAAO,EAAE,aAAa,CAAC,OAAO;YAC9B,kBAAkB,EAAE,iBAAiB,IAAI,aAAa;YACtD,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;SACd,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC;QAC9B,OAAO,CAAC,OAAO,GAAG,cAAc,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,sBAAsB,EAAE,GAAG,CAAC,CAAC;QACtD,MAAM,GAAG,CAAC,CAAC,yCAAyC;IACrD,CAAC;AACF,CAAC,CAAC;AAOF,MAAM,+BAA+B,GAAG,CACvC,IAA6B,EACL,EAAE;IAC1B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,wBAAwB,EAAE,GACvE,iCAAiC,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC;IACnE,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,wBAAwB,EAAE,CAAC;AAC3E,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAC9B,UAAsB,EACtB,mBAA2B,EAC3B,OAA8B,EAC9B,UAAkB,EACX,EAAE;IACT,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,wBAAwB,EAAE,GACvE,OAAO,CAAC;IACT,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,EAAE,CAEnD,CAAC;IACb,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,uBAAuB,mBAAmB,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAE1E,yEAAyE;IACzE,IAAI,cAAc,EAAE,CAAC;QACpB,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;YACpD,UAAU,CAAC,gBAAgB,CAAC,GAAU,EAAE,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,IAAI,wBAAwB,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,CACX,GAAG,UAAU,yBAAyB,mBAAmB,gCAAgC,CACzF,CAAC;YACF,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;YACzB,UAAU,CAAC,OAAO,GAAG,cAAc,CAAC;YACpC,OAAO;QACR,CAAC;QAED,MAAM,CAAC,KAAK,CACX,GAAG,UAAU,4BAA4B,mBAAmB,IAAI,UAAU,CAAC,EAAE,EAAE,EAC/E;YACC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,kBAAkB,EAAE,iBAAiB,IAAI,KAAK;SAC9C,CACD,CAAC;QAEF,wBAAwB,CACvB,UAAU,EACV,KAAK,EACL,cAAc,EACd,UAAU,EACV,GAAG,EACH,GAAG,UAAU,IAAI,mBAAmB,IAAI,UAAU,CAAC,EAAE,GAAG,CACxD,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACf,MAAM,YAAY,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACtE,MAAM,eAAe,GAAG,YAAY,CAAC,QAAQ,CAC5C,8BAA8B,CAC9B,CAAC;YACF,MAAM,CAAC,KAAK,CACX,GAAG,UAAU,0BAA0B,mBAAmB,IAAI,UAAU,CAAC,EAAE,GAAG,EAC9E,GAAG,CACH,CAAC;YACF,mBAAmB,CAAC,UAAU,EAAE;gBAC/B,IAAI,EAAE,eAAe;oBACpB,CAAC,CAAC,+BAA+B;oBACjC,CAAC,CAAC,8BAA8B;gBACjC,OAAO,EAAE,GAAG,mBAAmB,+CAA+C,UAAU,CAAC,EAAE,KAAK,YAAY,EAAE;gBAC9G,WAAW,EAAE,mBAAmB;gBAChC,SAAS,EAAE,UAAU,CAAC,EAAE;gBACxB,eAAe,EAAE,uBAAuB,CAAC,UAAU,CAAC;gBACpD,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;YACH,6CAA6C;YAC7C,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;YACzB,UAAU,CAAC,OAAO,GAAG,cAAc,CAAC;QACrC,CAAC,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,KAAK,CACX,GAAG,UAAU,gCAAgC,mBAAmB,IAAI,UAAU,CAAC,EAAE,uCAAuC,CACxH,CAAC;QACF,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;QACzB,UAAU,CAAC,OAAO,GAAG,cAAc,CAAC;IACrC,CAAC;AACF,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACtC,EAAW,EACX,IAA6B,EACtB,EAAE;IACT,MAAM,OAAO,GAAG,+BAA+B,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,EAAgB,CAAC;IACpC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAChD,sBAAsB,CACrB,UAAU,EACV,MAAM,EACN,OAAO,EACP,2BAA2B,CAC3B,CAAC;AACH,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC/B,MAAc,EACd,IAA6B,EACtB,EAAE;IACT,MAAM,OAAO,GAAG,+BAA+B,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,EAAE,SAAS,EAAE,GAAG,iCAAiC,CACtD,wBAAwB,EACxB,IAAI,CACJ,CAAC;IACF,0EAA0E;IAC1E,MAAM,UAAU,GAAG,SAAS,IAAI,QAAQ,CAAC;IACzC,MAAM,WAAW,GAAG,UAAU,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,yBAAyB,MAAM,EAAE,CAAC,CAAC;QAChD,OAAO;IACR,CAAC;IACD,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;QAC1B,MAAM,UAAU,GAAG,EAAgB,CAAC;QACpC,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,MAAoB,EACpB,OAAc,EACd,GAAQ,EACR,SAA8B,EACvB,EAAE;IACT,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;IACzE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1D,gBAAgB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { buildAuthoringAllowList, createDefaultItemMarkupSanitizer, resetPurifierForTesting, sanitizeItemMarkup, type ItemMarkupSanitizer, type SanitizeItemMarkupOptions, } from "./sanitize-item-markup.js";
|
|
2
|
+
export { parseAllowedStyleOrigins, validateExternalStyleUrl, type StyleUrlValidationError, type StyleUrlValidationOk, type StyleUrlValidationOptions, type StyleUrlValidationResult, } from "./validate-style-url.js";
|
|
3
|
+
export { resetSvgSanitizerForTesting, sanitizeSvgIcon, } from "./sanitize-svg-icon.js";
|
|
4
|
+
export { wrapOverwideImages } from "./wrap-overwide-images.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,uBAAuB,EACvB,gCAAgC,EAChC,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,GAC9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,wBAAwB,EACxB,wBAAwB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACN,2BAA2B,EAC3B,eAAe,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { buildAuthoringAllowList, createDefaultItemMarkupSanitizer, resetPurifierForTesting, sanitizeItemMarkup, } from "./sanitize-item-markup.js";
|
|
2
|
+
export { parseAllowedStyleOrigins, validateExternalStyleUrl, } from "./validate-style-url.js";
|
|
3
|
+
export { resetSvgSanitizerForTesting, sanitizeSvgIcon, } from "./sanitize-svg-icon.js";
|
|
4
|
+
export { wrapOverwideImages } from "./wrap-overwide-images.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,uBAAuB,EACvB,gCAAgC,EAChC,uBAAuB,EACvB,kBAAkB,GAGlB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,wBAAwB,EACxB,wBAAwB,GAKxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACN,2BAA2B,EAC3B,eAAe,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sanitizer for PIE item / passage markup.
|
|
3
|
+
*
|
|
4
|
+
* Used by `PieItemPlayer.svelte` to strip scripts, event-handler attributes,
|
|
5
|
+
* and unknown tags before injecting authored markup via `{@html}`. Hosts can
|
|
6
|
+
* opt out with the `trust-markup` attribute on the `<pie-*-player>` element,
|
|
7
|
+
* or supply their own sanitizer function if they need a stricter / looser
|
|
8
|
+
* allow-list.
|
|
9
|
+
*/
|
|
10
|
+
export type ItemMarkupSanitizer = (markup: string) => string;
|
|
11
|
+
export interface SanitizeItemMarkupOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Extra custom-element tag names that should survive sanitization in
|
|
14
|
+
* addition to the default `pie-*` allow-list. Useful for authoring-mode
|
|
15
|
+
* tags that rewrite to `pie-*-config` or host-registered extensions.
|
|
16
|
+
*/
|
|
17
|
+
allowedCustomElements?: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sanitize raw item/passage markup before it is injected into the DOM.
|
|
21
|
+
*
|
|
22
|
+
* - Strips `<script>`, event-handler attributes, unknown protocols and
|
|
23
|
+
* a standard set of dangerous tags (`iframe`, `object`, `embed`, `base`,
|
|
24
|
+
* `form`, `meta`, `link`).
|
|
25
|
+
* - Preserves PIE custom elements (`pie-*`) and any extra tags listed in
|
|
26
|
+
* `allowedCustomElements`.
|
|
27
|
+
* - During SSR (no `window`) returns an empty string so untrusted markup
|
|
28
|
+
* never reaches the prerender output; the live renderer will re-run the
|
|
29
|
+
* sanitizer on hydrate.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sanitizeItemMarkup(markup: string, options?: SanitizeItemMarkupOptions): string;
|
|
32
|
+
/**
|
|
33
|
+
* Build the default `ItemMarkupSanitizer` used by the players. The returned
|
|
34
|
+
* function is stable for a given set of allowed custom elements so callers
|
|
35
|
+
* can safely use reference equality when deciding whether to re-sanitize.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createDefaultItemMarkupSanitizer(options?: SanitizeItemMarkupOptions): ItemMarkupSanitizer;
|
|
38
|
+
/**
|
|
39
|
+
* Derive the authoring-mode allow-list (`pie-*-config`) from a set of PIE
|
|
40
|
+
* element tag names. Used by `transformMarkupForAuthoring` so the sanitizer
|
|
41
|
+
* keeps the rewritten `-config` tags instead of stripping them.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildAuthoringAllowList(elementTagNames: Iterable<string>): string[];
|
|
44
|
+
/** Reset the memoised DOMPurify instance. Only intended for tests. */
|
|
45
|
+
export declare function resetPurifierForTesting(): void;
|
|
46
|
+
//# sourceMappingURL=sanitize-item-markup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-item-markup.d.ts","sourceRoot":"","sources":["../../src/security/sanitize-item-markup.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAE7D,MAAM,WAAW,yBAAyB;IACzC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAgGD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,yBAA8B,GACrC,MAAM,CAiDR;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC/C,OAAO,GAAE,yBAA8B,GACrC,mBAAmB,CAIrB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACtC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC/B,MAAM,EAAE,CASV;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,SAEtC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sanitizer for PIE item / passage markup.
|
|
3
|
+
*
|
|
4
|
+
* Used by `PieItemPlayer.svelte` to strip scripts, event-handler attributes,
|
|
5
|
+
* and unknown tags before injecting authored markup via `{@html}`. Hosts can
|
|
6
|
+
* opt out with the `trust-markup` attribute on the `<pie-*-player>` element,
|
|
7
|
+
* or supply their own sanitizer function if they need a stricter / looser
|
|
8
|
+
* allow-list.
|
|
9
|
+
*/
|
|
10
|
+
import DOMPurify from "dompurify";
|
|
11
|
+
import { wrapOverwideImages } from "./wrap-overwide-images.js";
|
|
12
|
+
// Attributes every PIE element / wrapper is allowed to carry.
|
|
13
|
+
const BASE_ALLOWED_ATTRS = [
|
|
14
|
+
"slot",
|
|
15
|
+
"role",
|
|
16
|
+
"tabindex",
|
|
17
|
+
"id",
|
|
18
|
+
"class",
|
|
19
|
+
"style",
|
|
20
|
+
"href",
|
|
21
|
+
"src",
|
|
22
|
+
"alt",
|
|
23
|
+
"title",
|
|
24
|
+
"hidden",
|
|
25
|
+
"disabled",
|
|
26
|
+
"lang",
|
|
27
|
+
"dir",
|
|
28
|
+
];
|
|
29
|
+
const BASE_URI_SAFE_ATTRS = ["pie-id"];
|
|
30
|
+
const FORBIDDEN_TAGS = [
|
|
31
|
+
"script",
|
|
32
|
+
"iframe",
|
|
33
|
+
"object",
|
|
34
|
+
"embed",
|
|
35
|
+
"base",
|
|
36
|
+
"form",
|
|
37
|
+
"meta",
|
|
38
|
+
"link",
|
|
39
|
+
// <foreignObject> inside an <svg> is a well-known escape hatch back
|
|
40
|
+
// into HTML context; match the SVG-icon sanitizer and forbid it here
|
|
41
|
+
// so both sanitizers agree on the surface.
|
|
42
|
+
"foreignobject",
|
|
43
|
+
];
|
|
44
|
+
// DOMPurify already strips `on*` handlers via its default block-list;
|
|
45
|
+
// these entries guarantee they stay stripped even if a consumer tweaks
|
|
46
|
+
// defaults, and they cover the common SVG / math sinks.
|
|
47
|
+
const FORBIDDEN_ATTRS = [
|
|
48
|
+
"onerror",
|
|
49
|
+
"onload",
|
|
50
|
+
"onclick",
|
|
51
|
+
"onmouseover",
|
|
52
|
+
"onmouseout",
|
|
53
|
+
"onmouseenter",
|
|
54
|
+
"onmouseleave",
|
|
55
|
+
"onfocus",
|
|
56
|
+
"onblur",
|
|
57
|
+
"onkeydown",
|
|
58
|
+
"onkeyup",
|
|
59
|
+
"onkeypress",
|
|
60
|
+
"onsubmit",
|
|
61
|
+
"onchange",
|
|
62
|
+
"onbeforeunload",
|
|
63
|
+
"formaction",
|
|
64
|
+
"xlink:href",
|
|
65
|
+
];
|
|
66
|
+
// Any tag that looks like a custom element (contains a hyphen) is permitted
|
|
67
|
+
// provided it starts with `pie-` or is explicitly named in
|
|
68
|
+
// `allowedCustomElements`. This intentionally keeps third-party unknown
|
|
69
|
+
// custom elements out unless the host opts in.
|
|
70
|
+
const PIE_CUSTOM_ELEMENT_REGEX = /^pie-[a-z0-9-]+$/i;
|
|
71
|
+
// Attribute names that custom elements are allowed to declare. We stay
|
|
72
|
+
// permissive for the PIE element contract (`model-*`, `session-*`, ...) and
|
|
73
|
+
// the standard `data-*` / `aria-*` families.
|
|
74
|
+
const CUSTOM_ELEMENT_ATTR_REGEX = /^(id|class|style|slot|role|tabindex|hidden|disabled|lang|dir|data-[\w-]+|aria-[\w-]+|pie-[\w-]+|model-[\w-]+|session-[\w-]+|config-[\w-]+|context-[\w-]+)$/i;
|
|
75
|
+
let purifierInstance = null;
|
|
76
|
+
function resolvePurifier() {
|
|
77
|
+
if (purifierInstance)
|
|
78
|
+
return purifierInstance;
|
|
79
|
+
if (typeof window === "undefined" || !window.document)
|
|
80
|
+
return null;
|
|
81
|
+
// DOMPurify's default export is both the instance and the factory.
|
|
82
|
+
// Calling it with a window binds the instance to that document.
|
|
83
|
+
const factory = DOMPurify;
|
|
84
|
+
purifierInstance =
|
|
85
|
+
typeof factory === "function"
|
|
86
|
+
? factory(window)
|
|
87
|
+
: DOMPurify;
|
|
88
|
+
return purifierInstance;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Sanitize raw item/passage markup before it is injected into the DOM.
|
|
92
|
+
*
|
|
93
|
+
* - Strips `<script>`, event-handler attributes, unknown protocols and
|
|
94
|
+
* a standard set of dangerous tags (`iframe`, `object`, `embed`, `base`,
|
|
95
|
+
* `form`, `meta`, `link`).
|
|
96
|
+
* - Preserves PIE custom elements (`pie-*`) and any extra tags listed in
|
|
97
|
+
* `allowedCustomElements`.
|
|
98
|
+
* - During SSR (no `window`) returns an empty string so untrusted markup
|
|
99
|
+
* never reaches the prerender output; the live renderer will re-run the
|
|
100
|
+
* sanitizer on hydrate.
|
|
101
|
+
*/
|
|
102
|
+
export function sanitizeItemMarkup(markup, options = {}) {
|
|
103
|
+
if (!markup)
|
|
104
|
+
return "";
|
|
105
|
+
const purifier = resolvePurifier();
|
|
106
|
+
if (!purifier)
|
|
107
|
+
return "";
|
|
108
|
+
const allowedCustomElements = (options.allowedCustomElements ?? []).map((name) => name.toLowerCase());
|
|
109
|
+
const explicitCustomElementSet = new Set(allowedCustomElements);
|
|
110
|
+
const result = purifier.sanitize(markup, {
|
|
111
|
+
ADD_TAGS: allowedCustomElements,
|
|
112
|
+
ADD_ATTR: BASE_ALLOWED_ATTRS,
|
|
113
|
+
ADD_URI_SAFE_ATTR: BASE_URI_SAFE_ATTRS,
|
|
114
|
+
FORBID_TAGS: FORBIDDEN_TAGS,
|
|
115
|
+
FORBID_ATTR: FORBIDDEN_ATTRS,
|
|
116
|
+
ALLOW_UNKNOWN_PROTOCOLS: false,
|
|
117
|
+
SANITIZE_DOM: true,
|
|
118
|
+
// pie-item contract compatibility: PIE models are matched to DOM
|
|
119
|
+
// elements via strict `id` equality (see `updateSinglePieElement`
|
|
120
|
+
// in players-shared/src/pie/updates.ts). `SANITIZE_NAMED_PROPS`
|
|
121
|
+
// would prefix every `id`/`name` with `user-content-`, which silently
|
|
122
|
+
// breaks model lookup for every item. `SANITIZE_DOM: true` above
|
|
123
|
+
// still provides the core DOM-clobbering defenses we rely on.
|
|
124
|
+
SANITIZE_NAMED_PROPS: false,
|
|
125
|
+
WHOLE_DOCUMENT: false,
|
|
126
|
+
ALLOW_DATA_ATTR: true,
|
|
127
|
+
ALLOW_ARIA_ATTR: true,
|
|
128
|
+
CUSTOM_ELEMENT_HANDLING: {
|
|
129
|
+
tagNameCheck: (tagName) => {
|
|
130
|
+
const lower = tagName.toLowerCase();
|
|
131
|
+
return (PIE_CUSTOM_ELEMENT_REGEX.test(lower) ||
|
|
132
|
+
explicitCustomElementSet.has(lower));
|
|
133
|
+
},
|
|
134
|
+
attributeNameCheck: (attrName) => CUSTOM_ELEMENT_ATTR_REGEX.test(attrName),
|
|
135
|
+
allowCustomizedBuiltInElements: false,
|
|
136
|
+
},
|
|
137
|
+
RETURN_TRUSTED_TYPE: false,
|
|
138
|
+
});
|
|
139
|
+
const sanitized = typeof result === "string" ? result : String(result ?? "");
|
|
140
|
+
// PIE-94: wrap overwide authored images in a horizontal-scroll container
|
|
141
|
+
// so they don't get clipped by ancestor `overflow-x: hidden` regions in
|
|
142
|
+
// the section player (and match WCAG 1.4.10 Reflow at 400% zoom).
|
|
143
|
+
return wrapOverwideImages(sanitized);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Build the default `ItemMarkupSanitizer` used by the players. The returned
|
|
147
|
+
* function is stable for a given set of allowed custom elements so callers
|
|
148
|
+
* can safely use reference equality when deciding whether to re-sanitize.
|
|
149
|
+
*/
|
|
150
|
+
export function createDefaultItemMarkupSanitizer(options = {}) {
|
|
151
|
+
const { allowedCustomElements } = options;
|
|
152
|
+
return (markup) => sanitizeItemMarkup(markup, { allowedCustomElements });
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Derive the authoring-mode allow-list (`pie-*-config`) from a set of PIE
|
|
156
|
+
* element tag names. Used by `transformMarkupForAuthoring` so the sanitizer
|
|
157
|
+
* keeps the rewritten `-config` tags instead of stripping them.
|
|
158
|
+
*/
|
|
159
|
+
export function buildAuthoringAllowList(elementTagNames) {
|
|
160
|
+
const out = new Set();
|
|
161
|
+
for (const tag of elementTagNames) {
|
|
162
|
+
if (!tag)
|
|
163
|
+
continue;
|
|
164
|
+
const lower = tag.toLowerCase();
|
|
165
|
+
out.add(lower);
|
|
166
|
+
out.add(`${lower}-config`);
|
|
167
|
+
}
|
|
168
|
+
return [...out];
|
|
169
|
+
}
|
|
170
|
+
/** Reset the memoised DOMPurify instance. Only intended for tests. */
|
|
171
|
+
export function resetPurifierForTesting() {
|
|
172
|
+
purifierInstance = null;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=sanitize-item-markup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-item-markup.js","sourceRoot":"","sources":["../../src/security/sanitize-item-markup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize an SVG string intended to be rendered as an icon.
|
|
3
|
+
*
|
|
4
|
+
* Used by toolbars and tool-button components when their icon prop is an
|
|
5
|
+
* inline SVG supplied by a tool configuration. Runs DOMPurify with the
|
|
6
|
+
* SVG profile, forbids `<script>` / `<foreignObject>` and strips
|
|
7
|
+
* event-handler attributes.
|
|
8
|
+
*
|
|
9
|
+
* Returns an empty string when `window` / `document` are unavailable (SSR)
|
|
10
|
+
* or the input is not a string.
|
|
11
|
+
*/
|
|
12
|
+
export declare function sanitizeSvgIcon(icon: unknown): string;
|
|
13
|
+
/** Reset sanitizer state. Intended for tests. */
|
|
14
|
+
export declare function resetSvgSanitizerForTesting(): void;
|
|
15
|
+
//# sourceMappingURL=sanitize-svg-icon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-svg-icon.d.ts","sourceRoot":"","sources":["../../src/security/sanitize-svg-icon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAwDH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CA2BrD;AAED,iDAAiD;AACjD,wBAAgB,2BAA2B,SAG1C"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize an SVG string intended to be rendered as an icon.
|
|
3
|
+
*
|
|
4
|
+
* Used by toolbars and tool-button components when their icon prop is an
|
|
5
|
+
* inline SVG supplied by a tool configuration. Runs DOMPurify with the
|
|
6
|
+
* SVG profile, forbids `<script>` / `<foreignObject>` and strips
|
|
7
|
+
* event-handler attributes.
|
|
8
|
+
*
|
|
9
|
+
* Returns an empty string when `window` / `document` are unavailable (SSR)
|
|
10
|
+
* or the input is not a string.
|
|
11
|
+
*/
|
|
12
|
+
import DOMPurify from "dompurify";
|
|
13
|
+
let svgPurifierInstance = null;
|
|
14
|
+
function resolveSvgPurifier() {
|
|
15
|
+
if (svgPurifierInstance)
|
|
16
|
+
return svgPurifierInstance;
|
|
17
|
+
if (typeof window === "undefined" || !window.document)
|
|
18
|
+
return null;
|
|
19
|
+
const factory = DOMPurify;
|
|
20
|
+
svgPurifierInstance =
|
|
21
|
+
typeof factory === "function"
|
|
22
|
+
? factory(window)
|
|
23
|
+
: DOMPurify;
|
|
24
|
+
return svgPurifierInstance;
|
|
25
|
+
}
|
|
26
|
+
const FORBIDDEN_TAGS = [
|
|
27
|
+
"script",
|
|
28
|
+
"foreignobject",
|
|
29
|
+
"iframe",
|
|
30
|
+
"object",
|
|
31
|
+
"embed",
|
|
32
|
+
"base",
|
|
33
|
+
"form",
|
|
34
|
+
];
|
|
35
|
+
const FORBIDDEN_ATTRS = [
|
|
36
|
+
"onerror",
|
|
37
|
+
"onload",
|
|
38
|
+
"onclick",
|
|
39
|
+
"onmouseover",
|
|
40
|
+
"onmouseout",
|
|
41
|
+
"onmouseenter",
|
|
42
|
+
"onmouseleave",
|
|
43
|
+
"onfocus",
|
|
44
|
+
"onblur",
|
|
45
|
+
"onkeydown",
|
|
46
|
+
"onkeyup",
|
|
47
|
+
"onkeypress",
|
|
48
|
+
"formaction",
|
|
49
|
+
"xlink:href",
|
|
50
|
+
];
|
|
51
|
+
const stringCache = new Map();
|
|
52
|
+
const STRING_CACHE_MAX = 64;
|
|
53
|
+
export function sanitizeSvgIcon(icon) {
|
|
54
|
+
if (typeof icon !== "string" || icon.length === 0)
|
|
55
|
+
return "";
|
|
56
|
+
const trimmed = icon.trimStart();
|
|
57
|
+
if (!trimmed.toLowerCase().startsWith("<svg"))
|
|
58
|
+
return "";
|
|
59
|
+
const cached = stringCache.get(icon);
|
|
60
|
+
if (cached !== undefined)
|
|
61
|
+
return cached;
|
|
62
|
+
const purifier = resolveSvgPurifier();
|
|
63
|
+
if (!purifier)
|
|
64
|
+
return "";
|
|
65
|
+
const result = purifier.sanitize(icon, {
|
|
66
|
+
USE_PROFILES: { svg: true, svgFilters: true },
|
|
67
|
+
FORBID_TAGS: FORBIDDEN_TAGS,
|
|
68
|
+
FORBID_ATTR: FORBIDDEN_ATTRS,
|
|
69
|
+
ALLOW_UNKNOWN_PROTOCOLS: false,
|
|
70
|
+
RETURN_TRUSTED_TYPE: false,
|
|
71
|
+
});
|
|
72
|
+
const str = typeof result === "string" ? result : String(result ?? "");
|
|
73
|
+
if (stringCache.size >= STRING_CACHE_MAX) {
|
|
74
|
+
// Naive LRU: clear oldest half when the cache fills up. Tool icons are
|
|
75
|
+
// a small fixed set per assessment so this is rarely hit.
|
|
76
|
+
const keys = [...stringCache.keys()];
|
|
77
|
+
for (let i = 0; i < keys.length / 2; i += 1) {
|
|
78
|
+
stringCache.delete(keys[i]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
stringCache.set(icon, str);
|
|
82
|
+
return str;
|
|
83
|
+
}
|
|
84
|
+
/** Reset sanitizer state. Intended for tests. */
|
|
85
|
+
export function resetSvgSanitizerForTesting() {
|
|
86
|
+
svgPurifierInstance = null;
|
|
87
|
+
stringCache.clear();
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=sanitize-svg-icon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-svg-icon.js","sourceRoot":"","sources":["../../src/security/sanitize-svg-icon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,SAAS,MAAM,WAAW,CAAC;AASlC,IAAI,mBAAmB,GAA6B,IAAI,CAAC;AAEzD,SAAS,kBAAkB;IAC1B,IAAI,mBAAmB;QAAE,OAAO,mBAAmB,CAAC;IACpD,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,OAAO,GAAG,SAEM,CAAC;IACvB,mBAAmB;QAClB,OAAO,OAAO,KAAK,UAAU;YAC5B,CAAC,CAAC,OAAO,CAAC,MAAoC,CAAC;YAC/C,CAAC,CAAE,SAA0C,CAAC;IAChD,OAAO,mBAAmB,CAAC;AAC5B,CAAC;AAED,MAAM,cAAc,GAAG;IACtB,QAAQ;IACR,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;CACN,CAAC;AAEF,MAAM,eAAe,GAAG;IACvB,SAAS;IACT,QAAQ;IACR,SAAS;IACT,aAAa;IACb,YAAY;IACZ,cAAc;IACd,cAAc;IACd,SAAS;IACT,QAAQ;IACR,WAAW;IACX,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,YAAY;CACZ,CAAC;AAEF,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;AAC9C,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,MAAM,UAAU,eAAe,CAAC,IAAa;IAC5C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IACjC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExC,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IACtC,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QACtC,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC7C,WAAW,EAAE,cAAc;QAC3B,WAAW,EAAE,eAAe;QAC5B,uBAAuB,EAAE,KAAK;QAC9B,mBAAmB,EAAE,KAAK;KAC1B,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACvE,IAAI,WAAW,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC;QAC1C,uEAAuE;QACvE,0DAA0D;QAC1D,MAAM,IAAI,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC;IACD,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,2BAA2B;IAC1C,mBAAmB,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,KAAK,EAAE,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate that an external stylesheet URL supplied via
|
|
3
|
+
* `<pie-item-player external-style-urls="...">` (or the
|
|
4
|
+
* `itemConfig.resources.stylesheets[*].url` path) is safe to load.
|
|
5
|
+
*
|
|
6
|
+
* - Only `http:` / `https:` are allowed; `javascript:`, `data:`, `file:`
|
|
7
|
+
* and custom schemes are rejected.
|
|
8
|
+
* - When `allowedOrigins` is non-empty, the URL's origin must match one
|
|
9
|
+
* of the listed origins. This lets hosts restrict style loading to a
|
|
10
|
+
* known CDN allow-list.
|
|
11
|
+
*/
|
|
12
|
+
export type StyleUrlValidationOk = {
|
|
13
|
+
ok: true;
|
|
14
|
+
resolvedUrl: URL;
|
|
15
|
+
};
|
|
16
|
+
export type StyleUrlValidationError = {
|
|
17
|
+
ok: false;
|
|
18
|
+
reason: "invalid-url" | "disallowed-protocol" | "disallowed-origin";
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
export type StyleUrlValidationResult = StyleUrlValidationOk | StyleUrlValidationError;
|
|
22
|
+
export interface StyleUrlValidationOptions {
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
allowedOrigins?: string[];
|
|
25
|
+
}
|
|
26
|
+
export declare function validateExternalStyleUrl(url: unknown, options?: StyleUrlValidationOptions): StyleUrlValidationResult;
|
|
27
|
+
export declare function parseAllowedStyleOrigins(raw: unknown): string[];
|
|
28
|
+
//# sourceMappingURL=validate-style-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-style-url.d.ts","sourceRoot":"","sources":["../../src/security/validate-style-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,oBAAoB,GAAG;IAClC,EAAE,EAAE,IAAI,CAAC;IACT,WAAW,EAAE,GAAG,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACrC,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,aAAa,GAAG,qBAAqB,GAAG,mBAAmB,CAAC;IACpE,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GACjC,oBAAoB,GACpB,uBAAuB,CAAC;AAE3B,MAAM,WAAW,yBAAyB;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,OAAO,EACZ,OAAO,GAAE,yBAA8B,GACrC,wBAAwB,CAoC1B;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAM/D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate that an external stylesheet URL supplied via
|
|
3
|
+
* `<pie-item-player external-style-urls="...">` (or the
|
|
4
|
+
* `itemConfig.resources.stylesheets[*].url` path) is safe to load.
|
|
5
|
+
*
|
|
6
|
+
* - Only `http:` / `https:` are allowed; `javascript:`, `data:`, `file:`
|
|
7
|
+
* and custom schemes are rejected.
|
|
8
|
+
* - When `allowedOrigins` is non-empty, the URL's origin must match one
|
|
9
|
+
* of the listed origins. This lets hosts restrict style loading to a
|
|
10
|
+
* known CDN allow-list.
|
|
11
|
+
*/
|
|
12
|
+
export function validateExternalStyleUrl(url, options = {}) {
|
|
13
|
+
if (typeof url !== "string" || url.length === 0) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
reason: "invalid-url",
|
|
17
|
+
message: "External stylesheet URL must be a non-empty string.",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
let resolvedUrl;
|
|
21
|
+
try {
|
|
22
|
+
resolvedUrl = options.baseUrl
|
|
23
|
+
? new URL(url, options.baseUrl)
|
|
24
|
+
: new URL(url);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
reason: "invalid-url",
|
|
30
|
+
message: `External stylesheet URL could not be parsed: ${String(err)}`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (resolvedUrl.protocol !== "http:" && resolvedUrl.protocol !== "https:") {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
reason: "disallowed-protocol",
|
|
37
|
+
message: `External stylesheet protocol ${resolvedUrl.protocol} is not allowed (only http/https).`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const allowed = options.allowedOrigins ?? [];
|
|
41
|
+
if (allowed.length > 0 && !allowed.includes(resolvedUrl.origin)) {
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
reason: "disallowed-origin",
|
|
45
|
+
message: `External stylesheet origin ${resolvedUrl.origin} is not in the configured allow-list.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { ok: true, resolvedUrl };
|
|
49
|
+
}
|
|
50
|
+
export function parseAllowedStyleOrigins(raw) {
|
|
51
|
+
if (typeof raw !== "string" || raw.length === 0)
|
|
52
|
+
return [];
|
|
53
|
+
return raw
|
|
54
|
+
.split(",")
|
|
55
|
+
.map((entry) => entry.trim())
|
|
56
|
+
.filter((entry) => entry.length > 0);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=validate-style-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-style-url.js","sourceRoot":"","sources":["../../src/security/validate-style-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAsBH,MAAM,UAAU,wBAAwB,CACvC,GAAY,EACZ,UAAqC,EAAE;IAEvC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO;YACN,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE,qDAAqD;SAC9D,CAAC;IACH,CAAC;IACD,IAAI,WAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,WAAW,GAAG,OAAO,CAAC,OAAO;YAC5B,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC;YAC/B,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,OAAO;YACN,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE,gDAAgD,MAAM,CAAC,GAAG,CAAC,EAAE;SACtE,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,QAAQ,KAAK,OAAO,IAAI,WAAW,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3E,OAAO;YACN,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,qBAAqB;YAC7B,OAAO,EAAE,gCAAgC,WAAW,CAAC,QAAQ,oCAAoC;SACjG,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;IAC7C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACjE,OAAO;YACN,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,mBAAmB;YAC3B,OAAO,EAAE,8BAA8B,WAAW,CAAC,MAAM,uCAAuC;SAChG,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,GAAY;IACpD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3D,OAAO,GAAG;SACR,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps authored `<img>` elements with a horizontally scrollable container so
|
|
3
|
+
* images that are wider than their column surface a scrollbar instead of being
|
|
4
|
+
* clipped by ancestor `overflow-x: hidden` regions (PIE-94).
|
|
5
|
+
*
|
|
6
|
+
* The wrapper is rendered as
|
|
7
|
+
* `<span class="pie-image-scroll" tabindex="0" role="region" aria-label="...">`
|
|
8
|
+
* and receives the accompanying CSS from `@pie-players/pie-theme`. The CSS uses
|
|
9
|
+
* `overflow-x: auto` so small images stay visually unchanged: a scrollbar only
|
|
10
|
+
* appears when the image's intrinsic width exceeds the wrapper's available
|
|
11
|
+
* space (including at higher browser-zoom levels, which is the original driver
|
|
12
|
+
* for this change — WCAG 1.4.10 Reflow at 400% zoom).
|
|
13
|
+
*
|
|
14
|
+
* This helper runs as a post-sanitization step inside `sanitizeItemMarkup`, so
|
|
15
|
+
* every host that renders authored markup through the shared
|
|
16
|
+
* `pie-item-player` (including the section player) benefits uniformly.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Wrap `<img>` elements in `markup` with a horizontal-scroll container.
|
|
20
|
+
*
|
|
21
|
+
* - No-ops on empty input.
|
|
22
|
+
* - No-ops during SSR (no `window` / `DOMParser`) — the markup is returned
|
|
23
|
+
* unchanged; the browser re-run on hydrate will perform the wrap.
|
|
24
|
+
* - Idempotent: images whose direct parent already carries the
|
|
25
|
+
* `pie-image-scroll` class are left alone.
|
|
26
|
+
* - Leaves images inside PIE custom elements (`<pie-*>`) alone. Those are
|
|
27
|
+
* rendered by the element's own template / shadow DOM and should not be
|
|
28
|
+
* restructured by the authored-markup pipeline.
|
|
29
|
+
*/
|
|
30
|
+
export declare function wrapOverwideImages(markup: string): string;
|
|
31
|
+
//# sourceMappingURL=wrap-overwide-images.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap-overwide-images.d.ts","sourceRoot":"","sources":["../../src/security/wrap-overwide-images.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAyBH;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAqDzD"}
|