tungsten 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-complete +1 -0
- package/dist/Components.d.ts +2 -1
- package/dist/Components.d.ts.map +1 -1
- package/dist/Components.js +10 -1
- package/dist/DomRegion.js +1 -1
- package/dist/Framework.d.ts +2 -0
- package/dist/Framework.d.ts.map +1 -1
- package/dist/Framework.js +68 -57
- package/dist/FrameworkConfig.d.ts +6 -0
- package/dist/FrameworkConfig.d.ts.map +1 -1
- package/dist/FunctionComponentStandIn.d.ts +2 -0
- package/dist/FunctionComponentStandIn.d.ts.map +1 -1
- package/dist/FunctionComponentStandIn.js +10 -1
- package/dist/Instance/Instance.d.ts.map +1 -1
- package/dist/Instance/Instance.js +18 -1
- package/dist/Instance/InstanceConfig.d.ts +1 -0
- package/dist/Instance/InstanceConfig.d.ts.map +1 -1
- package/dist/PopMessage.type.d.ts +6 -0
- package/dist/PopMessage.type.d.ts.map +1 -0
- package/dist/PopMessage.type.js +1 -0
- package/dist/Servers/DevServer.d.ts +4 -0
- package/dist/Servers/DevServer.d.ts.map +1 -1
- package/dist/Servers/DevServer.js +116 -13
- package/dist/Servers/MatchedRouteInfo.d.ts +1 -1
- package/dist/Servers/MatchedRouteInfo.d.ts.map +1 -1
- package/dist/Servers/ProdServer.d.ts +1 -0
- package/dist/Servers/ProdServer.d.ts.map +1 -1
- package/dist/Servers/ProdServer.js +79 -5
- package/dist/Servers/devErrorPageAutoRetry.d.ts +4 -0
- package/dist/Servers/devErrorPageAutoRetry.d.ts.map +1 -0
- package/dist/Servers/devErrorPageAutoRetry.js +26 -0
- package/dist/Servers/hono/DevServerHono.js +25 -29
- package/dist/Servers/hono/ProdServerHono.js +49 -142
- package/dist/Servers/hono/TungstenServerHono.d.ts +1 -1
- package/dist/Servers/hono/TungstenServerHono.d.ts.map +1 -1
- package/dist/Servers/hono/TungstenServerHono.js +12 -29
- package/dist/Servers/routing.d.ts.map +1 -1
- package/dist/Servers/routing.js +10 -6
- package/dist/Servers/tungstenCorePrivateEnvSchema.d.ts +0 -3
- package/dist/Servers/tungstenCorePrivateEnvSchema.d.ts.map +1 -1
- package/dist/Servers/tungstenCorePrivateEnvSchema.js +3 -3
- package/dist/Servers/tungstenCorePublicEnvSchema.d.ts +8 -0
- package/dist/Servers/tungstenCorePublicEnvSchema.d.ts.map +1 -0
- package/dist/Servers/tungstenCorePublicEnvSchema.js +14 -0
- package/dist/Store/InternalStoreSchema.d.ts +2 -0
- package/dist/Store/InternalStoreSchema.d.ts.map +1 -1
- package/dist/Store/InternalStoreSchema.js +1 -0
- package/dist/api/Request.d.ts +1 -1
- package/dist/api/Request.d.ts.map +1 -1
- package/dist/api/Response.d.ts +1 -1
- package/dist/api/Response.d.ts.map +1 -1
- package/dist/api/getExport.d.ts.map +1 -1
- package/dist/api/getExport.js +2 -1
- package/dist/babelPlugins/BabelAddDevCacheBust.d.ts +11 -0
- package/dist/babelPlugins/BabelAddDevCacheBust.d.ts.map +1 -0
- package/dist/babelPlugins/BabelAddDevCacheBust.js +68 -0
- package/dist/babelPlugins/BabelTypes.d.ts +2 -2
- package/dist/babelPlugins/BabelTypes.d.ts.map +1 -1
- package/dist/babelPlugins/BabelTypes.js +0 -1
- package/dist/bin/commands/build.d.ts.map +1 -1
- package/dist/bin/commands/build.js +3 -0
- package/dist/bin/commands/dev.d.ts.map +1 -1
- package/dist/bin/commands/dev.js +16 -3
- package/dist/bin/commands/devmon.d.ts +2 -0
- package/dist/bin/commands/devmon.d.ts.map +1 -0
- package/dist/bin/commands/devmon.js +66 -0
- package/dist/bin/index.d.ts.map +1 -1
- package/dist/bin/index.js +6 -0
- package/dist/booleanAttributeValue.d.ts +21 -0
- package/dist/booleanAttributeValue.d.ts.map +1 -0
- package/dist/booleanAttributeValue.js +23 -0
- package/dist/build/compileJavascript.js +1 -1
- package/dist/build/compileUserApp.d.ts +2 -1
- package/dist/build/compileUserApp.d.ts.map +1 -1
- package/dist/build/compileUserApp.js +10 -9
- package/dist/build/createInstanceConfigFile.js +1 -1
- package/dist/build/makeBabelUserDevConfig.d.ts.map +1 -1
- package/dist/build/makeBabelUserDevConfig.js +6 -1
- package/dist/compat/types.d.ts +1 -1
- package/dist/compat/types.d.ts.map +1 -1
- package/dist/components/PopMessages.d.ts +12 -0
- package/dist/components/PopMessages.d.ts.map +1 -0
- package/dist/components/PopMessages.js +45 -0
- package/dist/defaultConfig.d.ts +3 -0
- package/dist/defaultConfig.d.ts.map +1 -1
- package/dist/defaultConfig.js +4 -1
- package/dist/env/Interfaces.d.ts +2 -1
- package/dist/env/Interfaces.d.ts.map +1 -1
- package/dist/env/getEnvSchemas.d.ts +1 -1
- package/dist/env/getEnvSchemas.d.ts.map +1 -1
- package/dist/env/getEnvSchemas.js +2 -1
- package/dist/env/publicEnv.d.ts.map +1 -1
- package/dist/env/publicEnv.js +4 -1
- package/dist/frameworkConfigSchema.d.ts +4 -0
- package/dist/frameworkConfigSchema.d.ts.map +1 -1
- package/dist/frameworkConfigSchema.js +2 -1
- package/dist/getComponent.d.ts.map +1 -1
- package/dist/getComponent.js +2 -1
- package/dist/getRoutes.d.ts.map +1 -1
- package/dist/getRoutes.js +2 -1
- package/dist/hmr/applyHmrModule.d.ts +11 -0
- package/dist/hmr/applyHmrModule.d.ts.map +1 -0
- package/dist/hmr/applyHmrModule.js +78 -0
- package/dist/hmr/componentIdentity.d.ts +9 -0
- package/dist/hmr/componentIdentity.d.ts.map +1 -0
- package/dist/hmr/componentIdentity.js +17 -0
- package/dist/hmr/instanceRegistry.d.ts +4 -0
- package/dist/hmr/instanceRegistry.d.ts.map +1 -0
- package/dist/hmr/instanceRegistry.js +6 -0
- package/dist/hmr/liveReloadHub.d.ts +10 -0
- package/dist/hmr/liveReloadHub.d.ts.map +1 -0
- package/dist/{dev → hmr}/liveReloadHub.js +8 -2
- package/dist/hmr/refreshStylesheets.d.ts +2 -0
- package/dist/hmr/refreshStylesheets.d.ts.map +1 -0
- package/dist/hmr/refreshStylesheets.js +26 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useInstance.d.ts +3 -0
- package/dist/hooks/useInstance.d.ts.map +1 -0
- package/dist/hooks/useInstance.js +4 -0
- package/dist/hydrate/hydrate.d.ts +10 -0
- package/dist/hydrate/hydrate.d.ts.map +1 -1
- package/dist/hydrate/hydrate.js +81 -19
- package/dist/hydrate/reconcileHydratedAttributes.d.ts.map +1 -1
- package/dist/hydrate/reconcileHydratedAttributes.js +14 -5
- package/dist/hydrate/renderHydrationMismatchBanner.d.ts +7 -0
- package/dist/hydrate/renderHydrationMismatchBanner.d.ts.map +1 -0
- package/dist/hydrate/renderHydrationMismatchBanner.js +69 -0
- package/dist/importDevModuleWithRetry.d.ts +3 -0
- package/dist/importDevModuleWithRetry.d.ts.map +1 -0
- package/dist/importDevModuleWithRetry.js +46 -0
- package/dist/indexInner.d.ts +8 -0
- package/dist/indexInner.d.ts.map +1 -1
- package/dist/indexInner.js +7 -1
- package/dist/makeInstanceConfigFromFrameworkConfig.d.ts.map +1 -1
- package/dist/makeInstanceConfigFromFrameworkConfig.js +2 -1
- package/dist/pop.d.ts +10 -0
- package/dist/pop.d.ts.map +1 -0
- package/dist/pop.js +49 -0
- package/dist/rawHtml/filterContentNode.d.ts +20 -0
- package/dist/rawHtml/filterContentNode.d.ts.map +1 -0
- package/dist/rawHtml/filterContentNode.js +96 -0
- package/dist/rawHtml/parseHtml.d.ts +14 -0
- package/dist/rawHtml/parseHtml.d.ts.map +1 -1
- package/dist/rawHtml/parseHtml.js +4 -4
- package/dist/rawHtml/sanitizeHtml.d.ts +17 -0
- package/dist/rawHtml/sanitizeHtml.d.ts.map +1 -0
- package/dist/rawHtml/sanitizeHtml.js +19 -0
- package/dist/render/HeadData.d.ts +2 -0
- package/dist/render/HeadData.d.ts.map +1 -1
- package/dist/render/contentNodeToHtml.d.ts +18 -0
- package/dist/render/contentNodeToHtml.d.ts.map +1 -0
- package/dist/render/contentNodeToHtml.js +66 -0
- package/dist/render/contentToHtml.d.ts.map +1 -1
- package/dist/render/contentToHtml.js +3 -1
- package/dist/render/processHead.d.ts.map +1 -1
- package/dist/render/processHead.js +53 -6
- package/dist/render/renderingTreeToHtml.d.ts.map +1 -1
- package/dist/render/renderingTreeToHtml.js +8 -1
- package/dist/routing/ErrorRouteType.d.ts +6 -0
- package/dist/routing/ErrorRouteType.d.ts.map +1 -0
- package/dist/routing/ErrorRouteType.js +1 -0
- package/dist/routing/RouteTypes.d.ts +2 -1
- package/dist/routing/RouteTypes.d.ts.map +1 -1
- package/dist/routing/Routes.d.ts +5 -0
- package/dist/routing/Routes.d.ts.map +1 -1
- package/dist/routing/TungstenErrorInfo.d.ts +6 -0
- package/dist/routing/TungstenErrorInfo.d.ts.map +1 -0
- package/dist/routing/TungstenErrorInfo.js +6 -0
- package/dist/style/styleContentSxy.js +21 -0
- package/dist/testing/hydrateTestApp.d.ts +38 -0
- package/dist/testing/hydrateTestApp.d.ts.map +1 -0
- package/dist/testing/hydrateTestApp.js +242 -0
- package/dist/testing/index.d.ts +4 -3
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +16 -2
- package/dist/timeProfiler.d.ts +6 -0
- package/dist/timeProfiler.d.ts.map +1 -0
- package/dist/timeProfiler.js +31 -0
- package/dist/update/integrateUpdateVdom.d.ts +16 -1
- package/dist/update/integrateUpdateVdom.d.ts.map +1 -1
- package/dist/update/integrateUpdateVdom.js +116 -7
- package/dist/warnOnFrameworkChange.d.ts +2 -0
- package/dist/warnOnFrameworkChange.d.ts.map +1 -0
- package/dist/warnOnFrameworkChange.js +27 -0
- package/package.json +18 -16
- package/dist/Instance/gotoRedirect.sxyt.d.ts +0 -2
- package/dist/Instance/gotoRedirect.sxyt.d.ts.map +0 -1
- package/dist/Instance/gotoRedirect.sxyt.js +0 -148
- package/dist/Instance/runTrackedWork.sxyt.d.ts +0 -2
- package/dist/Instance/runTrackedWork.sxyt.d.ts.map +0 -1
- package/dist/Instance/runTrackedWork.sxyt.js +0 -35
- package/dist/_client/cjsHelpers.sxyt.d.ts +0 -2
- package/dist/_client/cjsHelpers.sxyt.d.ts.map +0 -1
- package/dist/_client/cjsHelpers.sxyt.js +0 -45
- package/dist/auth/passwordHashing.sxyt.d.ts +0 -2
- package/dist/auth/passwordHashing.sxyt.d.ts.map +0 -1
- package/dist/auth/passwordHashing.sxyt.js +0 -46
- package/dist/auth/ref/checkPasswordResetToken.sxyt.d.ts +0 -2
- package/dist/auth/ref/checkPasswordResetToken.sxyt.d.ts.map +0 -1
- package/dist/auth/ref/checkPasswordResetToken.sxyt.js +0 -40
- package/dist/auth/ref/createPasswordResetToken.sxyt.d.ts +0 -2
- package/dist/auth/ref/createPasswordResetToken.sxyt.d.ts.map +0 -1
- package/dist/auth/ref/createPasswordResetToken.sxyt.js +0 -10
- package/dist/babelPlugins/fixImportsInSassErrorMessage.sxyt.d.ts +0 -2
- package/dist/babelPlugins/fixImportsInSassErrorMessage.sxyt.d.ts.map +0 -1
- package/dist/babelPlugins/fixImportsInSassErrorMessage.sxyt.js +0 -108
- package/dist/babelPlugins/transformPackageImports/resolveBareImport.sxyt.d.ts +0 -2
- package/dist/babelPlugins/transformPackageImports/resolveBareImport.sxyt.d.ts.map +0 -1
- package/dist/babelPlugins/transformPackageImports/resolveBareImport.sxyt.js +0 -104
- package/dist/bin/commands/compile.sxyt.d.ts +0 -2
- package/dist/bin/commands/compile.sxyt.d.ts.map +0 -1
- package/dist/bin/commands/compile.sxyt.js +0 -255
- package/dist/build/modifySassImports.sxyt.d.ts +0 -2
- package/dist/build/modifySassImports.sxyt.d.ts.map +0 -1
- package/dist/build/modifySassImports.sxyt.js +0 -55
- package/dist/build/sassImportParser.sxyt.d.ts +0 -2
- package/dist/build/sassImportParser.sxyt.d.ts.map +0 -1
- package/dist/build/sassImportParser.sxyt.js +0 -110
- package/dist/build/scssImportParserChatgpt.sxyt.d.ts +0 -2
- package/dist/build/scssImportParserChatgpt.sxyt.d.ts.map +0 -1
- package/dist/build/scssImportParserChatgpt.sxyt.js +0 -120
- package/dist/clone.sxyt.d.ts +0 -2
- package/dist/clone.sxyt.d.ts.map +0 -1
- package/dist/clone.sxyt.js +0 -24
- package/dist/componentProxyHandlers.sxyt.d.ts +0 -2
- package/dist/componentProxyHandlers.sxyt.d.ts.map +0 -1
- package/dist/componentProxyHandlers.sxyt.js +0 -130
- package/dist/components/RawHtml.sxyt.d.ts +0 -2
- package/dist/components/RawHtml.sxyt.d.ts.map +0 -1
- package/dist/components/RawHtml.sxyt.js +0 -104
- package/dist/components/bindable/BindableSelect.sxyt.d.ts +0 -2
- package/dist/components/bindable/BindableSelect.sxyt.d.ts.map +0 -1
- package/dist/components/bindable/BindableSelect.sxyt.js +0 -186
- package/dist/dev/liveReloadHub.d.ts +0 -6
- package/dist/dev/liveReloadHub.d.ts.map +0 -1
- package/dist/env/injectEnv.sxyt.d.ts +0 -2
- package/dist/env/injectEnv.sxyt.d.ts.map +0 -1
- package/dist/env/injectEnv.sxyt.js +0 -20
- package/dist/env/parseEnv.sxyt.d.ts +0 -2
- package/dist/env/parseEnv.sxyt.d.ts.map +0 -1
- package/dist/env/parseEnv.sxyt.js +0 -11
- package/dist/findProjectDir.sxyt.d.ts +0 -2
- package/dist/findProjectDir.sxyt.d.ts.map +0 -1
- package/dist/findProjectDir.sxyt.js +0 -82
- package/dist/hydrate/reconcileHydratedAttributes.sxyt.d.ts +0 -2
- package/dist/hydrate/reconcileHydratedAttributes.sxyt.d.ts.map +0 -1
- package/dist/hydrate/reconcileHydratedAttributes.sxyt.js +0 -173
- package/dist/innerHtmlFromProps.sxyt.d.ts +0 -2
- package/dist/innerHtmlFromProps.sxyt.d.ts.map +0 -1
- package/dist/innerHtmlFromProps.sxyt.js +0 -99
- package/dist/postcssPlugins/parseSelectors.sxyt.d.ts +0 -2
- package/dist/postcssPlugins/parseSelectors.sxyt.d.ts.map +0 -1
- package/dist/postcssPlugins/parseSelectors.sxyt.js +0 -62
- package/dist/postcssPlugins/parseSelectorsRich.sxyt.d.ts +0 -2
- package/dist/postcssPlugins/parseSelectorsRich.sxyt.d.ts.map +0 -1
- package/dist/postcssPlugins/parseSelectorsRich.sxyt.js +0 -155
- package/dist/rawHtml/parseHtml.sxyt.d.ts +0 -2
- package/dist/rawHtml/parseHtml.sxyt.d.ts.map +0 -1
- package/dist/rawHtml/parseHtml.sxyt.js +0 -239
- package/dist/render/getFunctionBodyAsString.sxyt.d.ts +0 -2
- package/dist/render/getFunctionBodyAsString.sxyt.d.ts.map +0 -1
- package/dist/render/getFunctionBodyAsString.sxyt.js +0 -37
- package/dist/render/processProps.sxyt.d.ts +0 -2
- package/dist/render/processProps.sxyt.d.ts.map +0 -1
- package/dist/render/processProps.sxyt.js +0 -90
- package/dist/routing/compareRequestToRegex.sxyt.d.ts +0 -2
- package/dist/routing/compareRequestToRegex.sxyt.d.ts.map +0 -1
- package/dist/routing/compareRequestToRegex.sxyt.js +0 -65
- package/dist/routing/getPathPriority.sxyt.d.ts +0 -2
- package/dist/routing/getPathPriority.sxyt.d.ts.map +0 -1
- package/dist/routing/getPathPriority.sxyt.js +0 -24
- package/dist/routing/matchPath.sxyt.d.ts +0 -2
- package/dist/routing/matchPath.sxyt.d.ts.map +0 -1
- package/dist/routing/matchPath.sxyt.js +0 -41
- package/dist/routing/patternToRegex.sxyt.d.ts +0 -2
- package/dist/routing/patternToRegex.sxyt.d.ts.map +0 -1
- package/dist/routing/patternToRegex.sxyt.js +0 -69
- package/dist/routing/splitRequest.sxyt.d.ts +0 -2
- package/dist/routing/splitRequest.sxyt.d.ts.map +0 -1
- package/dist/routing/splitRequest.sxyt.js +0 -47
- package/dist/style/jssToCss.sxyt.d.ts +0 -2
- package/dist/style/jssToCss.sxyt.d.ts.map +0 -1
- package/dist/style/jssToCss.sxyt.js +0 -17
- package/dist/testing/createTestApp.sxyt.d.ts +0 -2
- package/dist/testing/createTestApp.sxyt.d.ts.map +0 -1
- package/dist/testing/createTestApp.sxyt.js +0 -470
- package/dist/testing/ensureTestEnvLoaded.sxyt.d.ts +0 -2
- package/dist/testing/ensureTestEnvLoaded.sxyt.d.ts.map +0 -1
- package/dist/testing/ensureTestEnvLoaded.sxyt.js +0 -20
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Read by the CSS rule below via attr() - not by Tungsten. Exported so an
|
|
2
|
+
// application that wants different styling can target the same selector.
|
|
3
|
+
export const hydrationMismatchAttribute = 'data-tungsten-hydration-mismatches';
|
|
4
|
+
const styleId = 'tungsten-hydration-mismatches-style';
|
|
5
|
+
// Reports hydration mismatches in the page, not only the console, without
|
|
6
|
+
// adding a real DOM node to the hydrated tree.
|
|
7
|
+
//
|
|
8
|
+
// A real element - even one appended after hydration finishes and never
|
|
9
|
+
// touched again by this code - is not actually safe here. Every container
|
|
10
|
+
// Tungsten re-renders gets a fresh `new DomRegion(containerDomNode)` built
|
|
11
|
+
// from whatever is *actually* in its childNodes at that moment, and every
|
|
12
|
+
// position Tungsten writes to next is a raw index into that same list
|
|
13
|
+
// (DomPointer.get/next/prev, and several inline `childNodes[domPointer.index]`
|
|
14
|
+
// reads in integrateUpdateVdom.ts/hydrate.tsx). An extra, untracked child
|
|
15
|
+
// shifts every index after it, so the next update touching that container
|
|
16
|
+
// - body, in a typical app - would compare and write to the wrong nodes.
|
|
17
|
+
// There is no flag on an element that makes the walker skip it; it would
|
|
18
|
+
// have to be built into DomPointer/DomRegion and every direct childNodes
|
|
19
|
+
// access alongside them, which is a core-framework change, not a banner.
|
|
20
|
+
//
|
|
21
|
+
// Attributes are a different story: reconcileHydratedAttributes only runs
|
|
22
|
+
// once, during hydration, before this ever runs, and every later update
|
|
23
|
+
// (updateAttributes) diffs against domNode.__tungsten_oldAttributes - its
|
|
24
|
+
// own private record of what it last set - never the DOM's live attribute
|
|
25
|
+
// list. A plain setAttribute() here is in neither its old props nor its new
|
|
26
|
+
// props, so it is never visited, and never removed.
|
|
27
|
+
//
|
|
28
|
+
// So: set an attribute on <html> (outside Tungsten's own bookkeeping, so
|
|
29
|
+
// permanently untouched by it) and let a `content: attr(...)` pseudo-element
|
|
30
|
+
// display it. A pseudo-element is not a real node - never in .childNodes,
|
|
31
|
+
// never visited by DomPointer or DomRegion - so this carries zero index risk
|
|
32
|
+
// for the app's own reconciliation, at the cost of one small, deliberately
|
|
33
|
+
// hacky wrinkle: a single <style> tag inserted into <head> once.
|
|
34
|
+
//
|
|
35
|
+
// head is not structurally exempt from diffing in general - it currently
|
|
36
|
+
// just never gets diffed node-by-node during hydration (hydrateNodeSingle's
|
|
37
|
+
// 'head' case skips it outright, a known hack, not a guarantee), and nothing
|
|
38
|
+
// in a typical app changes head's vdom children after mount, so the general
|
|
39
|
+
// update path never exercises it either. That could change. What head does
|
|
40
|
+
// already have is a marker for exactly this situation - data--t-persist,
|
|
41
|
+
// used by processHead.ts for framework-injected head content (the entry
|
|
42
|
+
// script, the component CSS link) that isn't part of the app's own vdom and
|
|
43
|
+
// must survive hydration - so this style tag carries it too, rather than
|
|
44
|
+
// riding on the blanket skip alone.
|
|
45
|
+
export function renderHydrationMismatchBanner(mismatches, doc = document) {
|
|
46
|
+
if (mismatches.length === 0) return;
|
|
47
|
+
if (doc.getElementById(styleId) === null) {
|
|
48
|
+
const style = doc.createElement('style');
|
|
49
|
+
style.id = styleId;
|
|
50
|
+
style.setAttribute('data--t-persist', 'true');
|
|
51
|
+
style.textContent = `
|
|
52
|
+
html[${hydrationMismatchAttribute}]::before {
|
|
53
|
+
content: attr(${hydrationMismatchAttribute});
|
|
54
|
+
display: block;
|
|
55
|
+
background: #7a1f1f;
|
|
56
|
+
color: #fff;
|
|
57
|
+
font: 13px/1.5 monospace;
|
|
58
|
+
padding: 8px 12px;
|
|
59
|
+
max-height: 33vh;
|
|
60
|
+
overflow: auto;
|
|
61
|
+
white-space: pre-wrap;
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
doc.head.appendChild(style);
|
|
65
|
+
}
|
|
66
|
+
const heading = `Tungsten: ${mismatches.length} hydration mismatch${mismatches.length === 1 ? '' : 'es'} (dev only)`;
|
|
67
|
+
const lines = mismatches.map(mismatch => `<${mismatch.tagName}> ${mismatch.name}: ` + `rendered ${JSON.stringify(mismatch.expected)}, server sent ${JSON.stringify(mismatch.actual)}`);
|
|
68
|
+
doc.documentElement.setAttribute(hydrationMismatchAttribute, [heading, ...lines].join('\n'));
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"importDevModuleWithRetry.d.ts","sourceRoot":"","sources":["../src/importDevModuleWithRetry.ts"],"names":[],"mappings":"AAuBA,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAU7D;AAMD,wBAAsB,wBAAwB,CAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,SAAK,EACb,OAAO,SAAM,GACd,OAAO,CAAC,GAAG,CAAC,CAUd"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// importDevModuleWithRetry
|
|
2
|
+
// exports importDevModuleWithRetry (function)
|
|
3
|
+
//
|
|
4
|
+
// Dev-mode dynamic import wrapper. tsc's own --watch mode emits a multi-file
|
|
5
|
+
// edit (e.g. a rename spanning two files) one recompiled file at a time, so
|
|
6
|
+
// there's a real window where one file has landed and the other hasn't yet.
|
|
7
|
+
// A dev-server request for a component in that window hits a genuine (but
|
|
8
|
+
// self-resolving within a few hundred ms) module-shape error - without this,
|
|
9
|
+
// that's a scary SSR error page for what is, from the developer's
|
|
10
|
+
// perspective, a completely normal edit. Retrying a few times with a fresh
|
|
11
|
+
// cache-busting query per attempt rides out the window; a real, permanent
|
|
12
|
+
// error still surfaces (just slightly slower) once attempts are exhausted.
|
|
13
|
+
// A two-file edit's compile cycle runs tsc's incremental emit followed by a
|
|
14
|
+
// separate downstream babel recompile, sequentially - observed live to take
|
|
15
|
+
// several seconds under load, so the default budget below is generous rather
|
|
16
|
+
// than tuned to a happy-path guess. There's no precise "compile cycle
|
|
17
|
+
// finished" signal plumbed through to here to await instead; this is a
|
|
18
|
+
// bounded heuristic, not a proper synchronization fix.
|
|
19
|
+
// Exported so other dev-only tools (the error page's auto-retry script - see
|
|
20
|
+
// devErrorPageAutoRetry.ts) can recognize the same transient shape without
|
|
21
|
+
// duplicating the heuristic.
|
|
22
|
+
export function isTransientDevModuleError(e) {
|
|
23
|
+
if (!(e instanceof Error)) return false;
|
|
24
|
+
if (e.code === 'ERR_MODULE_NOT_FOUND') return true;
|
|
25
|
+
if (/does not provide an export named/.test(e.message)) return true;
|
|
26
|
+
// A within-file version of the same race: a multi-step edit can transiently save a file
|
|
27
|
+
// whose import line was updated but whose JSX/body still references the old local name -
|
|
28
|
+
// that's a plain runtime ReferenceError, not an ESM linking error, but self-resolves the same
|
|
29
|
+
// way once the file's own recompile catches up. Kept narrow (a bare identifier only) so it
|
|
30
|
+
// doesn't swallow other ReferenceError shapes that are more likely to be genuine bugs.
|
|
31
|
+
return e instanceof ReferenceError && /^\w+ is not defined$/.test(e.message);
|
|
32
|
+
}
|
|
33
|
+
function delay(ms) {
|
|
34
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
35
|
+
}
|
|
36
|
+
export async function importDevModuleWithRetry(url, attempts = 30, delayMs = 250) {
|
|
37
|
+
for (let attempt = 0;; attempt++) {
|
|
38
|
+
try {
|
|
39
|
+
const attemptUrl = attempt === 0 ? url : `${url}${url.includes('?') ? '&' : '?'}retryAttempt=${attempt}`;
|
|
40
|
+
return await import(attemptUrl); // eslint-disable-line @typescript-eslint/no-unsafe-return
|
|
41
|
+
} catch (e) {
|
|
42
|
+
if (attempt >= attempts - 1 || !isTransientDevModuleError(e)) throw e;
|
|
43
|
+
await delay(delayMs);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
package/dist/indexInner.d.ts
CHANGED
|
@@ -16,13 +16,18 @@ export * from './components/bindable/BindableTextarea.jsx';
|
|
|
16
16
|
export * from './components/GoToComponent.jsx';
|
|
17
17
|
export * from './components/Lazy.js';
|
|
18
18
|
export * from './components/Link.jsx';
|
|
19
|
+
export * from './components/PopMessages.jsx';
|
|
19
20
|
export * from './components/RawHtml.jsx';
|
|
20
21
|
export * from './components/RouteRedirectComponent.jsx';
|
|
21
22
|
export { parseHtml, type ParseHtmlOptions } from './rawHtml/parseHtml.js';
|
|
22
23
|
export { safeHtmlAllowList } from './rawHtml/safeHtmlAllowList.js';
|
|
23
24
|
export type { HtmlAllowList } from './rawHtml/HtmlAllowList.js';
|
|
25
|
+
export { sanitizeHtml, type SanitizeHtmlOptions } from './rawHtml/sanitizeHtml.js';
|
|
26
|
+
export { filterContentNode } from './rawHtml/filterContentNode.js';
|
|
27
|
+
export { contentNodeToHtml } from './render/contentNodeToHtml.js';
|
|
24
28
|
export * from './components/WebRedirectComponent.jsx';
|
|
25
29
|
export * from './nbsp.js';
|
|
30
|
+
export { pop, dismissPop } from './pop.js';
|
|
26
31
|
export * from './browserStorage.js';
|
|
27
32
|
export { createElement } from './createElement.js';
|
|
28
33
|
export * from './createRef.js';
|
|
@@ -64,12 +69,15 @@ export * from './ContentNode.js';
|
|
|
64
69
|
export type { GenericObject } from './GenericObject.type.js';
|
|
65
70
|
export type { Instance } from './Instance/Instance.js';
|
|
66
71
|
export type { Key } from './Key.js';
|
|
72
|
+
export type { PopMessage } from './PopMessage.type.js';
|
|
67
73
|
export type { ReqRes, ReqResOrNull } from './ReqRes.js';
|
|
68
74
|
export type { Params } from './routing/Params.js';
|
|
69
75
|
export type { ParamsFromPath } from './routing/ParamsFromPath.js';
|
|
70
76
|
export type { RouteType, Route } from './routing/RouteType.js';
|
|
71
77
|
export { type RouteKey, type Path, type Path as RoutePath, StringIsPath, RouteKeyIsPath } from './routing/RouteTypes.js';
|
|
72
78
|
export type { Routes, CustomRoutes } from './routing/Routes.js';
|
|
79
|
+
export type { ErrorRouteType } from './routing/ErrorRouteType.js';
|
|
80
|
+
export { type TungstenErrorInfo, makeTungstenErrorInfo } from './routing/TungstenErrorInfo.js';
|
|
73
81
|
export type { RouteParams } from './routing/RouteParams.type.js';
|
|
74
82
|
export type { RouteData } from './routing/RouteData.js';
|
|
75
83
|
export type { RouteDataFunction } from './routing/RouteDataFunction.type.js';
|
package/dist/indexInner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexInner.d.ts","sourceRoot":"","sources":["../src/indexInner.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"indexInner.d.ts","sourceRoot":"","sources":["../src/indexInner.ts"],"names":[],"mappings":"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"}
|
package/dist/indexInner.js
CHANGED
|
@@ -21,12 +21,17 @@ export * from "./components/bindable/BindableTextarea.js";
|
|
|
21
21
|
export * from "./components/GoToComponent.js";
|
|
22
22
|
export * from "./components/Lazy.js";
|
|
23
23
|
export * from "./components/Link.js";
|
|
24
|
+
export * from "./components/PopMessages.js";
|
|
24
25
|
export * from "./components/RawHtml.js";
|
|
25
26
|
export * from "./components/RouteRedirectComponent.js";
|
|
26
27
|
export { parseHtml } from "./rawHtml/parseHtml.js";
|
|
27
28
|
export { safeHtmlAllowList } from "./rawHtml/safeHtmlAllowList.js";
|
|
29
|
+
export { sanitizeHtml } from "./rawHtml/sanitizeHtml.js";
|
|
30
|
+
export { filterContentNode } from "./rawHtml/filterContentNode.js";
|
|
31
|
+
export { contentNodeToHtml } from "./render/contentNodeToHtml.js";
|
|
28
32
|
export * from "./components/WebRedirectComponent.js";
|
|
29
33
|
export * from "./nbsp.js";
|
|
34
|
+
export { pop, dismissPop } from "./pop.js";
|
|
30
35
|
export * from "./browserStorage.js";
|
|
31
36
|
export { createElement } from "./createElement.js";
|
|
32
37
|
export * from "./createRef.js";
|
|
@@ -66,4 +71,5 @@ export * from "./components/Stylesheet.js";
|
|
|
66
71
|
export { TungstenError } from "./TungstenError.js";
|
|
67
72
|
export * from "./__deproxy.js";
|
|
68
73
|
export * from "./ContentNode.js"; // types and type guards
|
|
69
|
-
export { StringIsPath, RouteKeyIsPath } from "./routing/RouteTypes.js";
|
|
74
|
+
export { StringIsPath, RouteKeyIsPath } from "./routing/RouteTypes.js";
|
|
75
|
+
export { makeTungstenErrorInfo } from "./routing/TungstenErrorInfo.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeInstanceConfigFromFrameworkConfig.d.ts","sourceRoot":"","sources":["../src/makeInstanceConfigFromFrameworkConfig.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAEnE,wBAAgB,qCAAqC,CACjD,eAAe,EAAE,uBAAuB,EAAE,GAAG,GAAE,OAAe,GAC/D,cAAc,
|
|
1
|
+
{"version":3,"file":"makeInstanceConfigFromFrameworkConfig.d.ts","sourceRoot":"","sources":["../src/makeInstanceConfigFromFrameworkConfig.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAEnE,wBAAgB,qCAAqC,CACjD,eAAe,EAAE,uBAAuB,EAAE,GAAG,GAAE,OAAe,GAC/D,cAAc,CAWhB"}
|
|
@@ -5,7 +5,8 @@ export function makeInstanceConfigFromFrameworkConfig(frameworkConfig, dev = fal
|
|
|
5
5
|
useRootComponent: frameworkConfig.useRootComponent,
|
|
6
6
|
clientSideNav: frameworkConfig.clientSideNav,
|
|
7
7
|
siteBasePath: dev ? '' : frameworkConfig.siteBasePath,
|
|
8
|
-
staticSite: frameworkConfig.staticSite
|
|
8
|
+
staticSite: frameworkConfig.staticSite,
|
|
9
|
+
csr: frameworkConfig.csr
|
|
9
10
|
};
|
|
10
11
|
if ('sourceDir' in frameworkConfig) c.sourceDir = frameworkConfig.sourceDir;
|
|
11
12
|
return c;
|
package/dist/pop.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Instance } from './Instance/Instance.js';
|
|
2
|
+
export declare function registerPopInstance(newInstance: Instance): void;
|
|
3
|
+
export declare function dismissPop(id: number): void;
|
|
4
|
+
export declare function pop(text: string): void;
|
|
5
|
+
type PopFunction = typeof pop;
|
|
6
|
+
declare global {
|
|
7
|
+
var pop: PopFunction;
|
|
8
|
+
}
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=pop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pop.d.ts","sourceRoot":"","sources":["../src/pop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAStD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,QAAQ,GAAG,IAAI,CAE/D;AAQD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAO3C;AAID,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAatC;AAMD,KAAK,WAAW,GAAG,OAAO,GAAG,CAAA;AAE7B,OAAO,CAAC,MAAM,CAAC;IAEX,IAAI,GAAG,EAAE,WAAW,CAAA;CACvB"}
|
package/dist/pop.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { isServer } from "./isServer.js";
|
|
2
|
+
import { log, warn } from "./appOutput.js";
|
|
3
|
+
// Set once by PopMessages.clientInit, from this.__instance - one Instance per app, shared
|
|
4
|
+
// across the whole client lifetime, so no per-component proxy/subscription is needed here.
|
|
5
|
+
let instance = null;
|
|
6
|
+
export function registerPopInstance(newInstance) {
|
|
7
|
+
instance = newInstance;
|
|
8
|
+
}
|
|
9
|
+
let nextId = 0;
|
|
10
|
+
const AUTO_DISMISS_MS = 3000;
|
|
11
|
+
const LEAVE_MS = 200; // match .pop-message.leaving's transition duration in PopMessages.tsx
|
|
12
|
+
// Shared by pop()'s auto-dismiss and PopMessages' click-to-dismiss, so both leave the same way.
|
|
13
|
+
export function dismissPop(id) {
|
|
14
|
+
if (instance === null) return;
|
|
15
|
+
const {
|
|
16
|
+
popMessages
|
|
17
|
+
} = instance.internalStore;
|
|
18
|
+
popMessages.set(popMessages.get().map(message => message.id === id ? {
|
|
19
|
+
...message,
|
|
20
|
+
leaving: true
|
|
21
|
+
} : message));
|
|
22
|
+
setTimeout(() => {
|
|
23
|
+
popMessages.set(popMessages.get().filter(message => message.id !== id));
|
|
24
|
+
}, LEAVE_MS);
|
|
25
|
+
}
|
|
26
|
+
// Shows a dismissible banner via <PopMessages/> (an app mounts one in its Root). Also available
|
|
27
|
+
// as global.pop / window.pop for ad-hoc use outside component code, on server and client alike.
|
|
28
|
+
export function pop(text) {
|
|
29
|
+
if (isServer) {
|
|
30
|
+
log('pop: ' + text);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (instance === null) {
|
|
34
|
+
warn('pop() called before the app finished mounting; message dropped:', text);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const message = {
|
|
38
|
+
id: nextId++,
|
|
39
|
+
text
|
|
40
|
+
};
|
|
41
|
+
const {
|
|
42
|
+
popMessages
|
|
43
|
+
} = instance.internalStore;
|
|
44
|
+
popMessages.set([...popMessages.get(), message]);
|
|
45
|
+
setTimeout(() => dismissPop(message.id), AUTO_DISMISS_MS);
|
|
46
|
+
}
|
|
47
|
+
// Assigned at module load in both environments, so a pre-mount browser call hits pop()'s
|
|
48
|
+
// no-bridge branch instead of throwing.
|
|
49
|
+
globalThis.pop = pop;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ContentNode } from '../ContentNode.js';
|
|
2
|
+
import type { HtmlAllowList } from './HtmlAllowList.js';
|
|
3
|
+
/**
|
|
4
|
+
* Applies an allow list to a content tree that already exists, rather than
|
|
5
|
+
* one being built - the same decisions `parseHtml(html, { allowList })` makes
|
|
6
|
+
* while parsing, for a tree that did not come from parsing HTML at all (one
|
|
7
|
+
* rebuilt from storage, for instance) and so never had the chance to.
|
|
8
|
+
*
|
|
9
|
+
* A disallowed element is unwrapped, keeping its children in its place, so
|
|
10
|
+
* filtering a tag never costs the reader the words inside it - the same rule
|
|
11
|
+
* `parseHtml` applies. An element holding program text rather than prose
|
|
12
|
+
* (`<script>`, and anything on the same footing as `<script>` even under a
|
|
13
|
+
* permissive allow list) is dropped whole instead. `on*` props, `ref`, and
|
|
14
|
+
* `dangerouslySetInnerHTML` are always stripped - the tree-shape equivalent
|
|
15
|
+
* of what `parseHtml` refuses to produce in the first place - and a `href`/
|
|
16
|
+
* `src`/... value using an executable scheme (`javascript:`, `vbscript:`) or,
|
|
17
|
+
* on a navigating attribute, `data:` is dropped the same way.
|
|
18
|
+
*/
|
|
19
|
+
export declare function filterContentNode(node: ContentNode, allowList: HtmlAllowList): ContentNode;
|
|
20
|
+
//# sourceMappingURL=filterContentNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterContentNode.d.ts","sourceRoot":"","sources":["../../src/rawHtml/filterContentNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,mBAAmB,CAAA;AAI/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAyFvD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,GAAG,WAAW,CAE1F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ContentNodeIsComponent } from "../ContentNode.js";
|
|
2
|
+
import { $props, $type } from "../contentNodeSymbols.js";
|
|
3
|
+
import { StringIsHtmlEvent } from "../htmlEvents.js";
|
|
4
|
+
import { blockedUrl, makeAllowCheck, removalFor, urlAttributes } from "./parseHtml.js";
|
|
5
|
+
// The NodeProps equivalent of parseHtml's class->className, style->css
|
|
6
|
+
// rename: the allow list is written in terms of the HTML attribute name, but
|
|
7
|
+
// a content tree already carries Tungsten's prop names for these two.
|
|
8
|
+
const attributeCheckName = {
|
|
9
|
+
className: 'class',
|
|
10
|
+
css: 'style'
|
|
11
|
+
};
|
|
12
|
+
function filterProps(tag, props, allow) {
|
|
13
|
+
const filtered = {};
|
|
14
|
+
for (const key in props) {
|
|
15
|
+
if (key === 'children') continue;
|
|
16
|
+
const value = props[key];
|
|
17
|
+
// Tungsten reads these as event listeners, not attributes - same rule
|
|
18
|
+
// parseHtml applies to on* HTML attributes, expressed for prop names.
|
|
19
|
+
if (StringIsHtmlEvent(key)) continue;
|
|
20
|
+
// Raw markup that bypasses tree filtering entirely: parseHtml never
|
|
21
|
+
// produces this prop, so a tree in its shape should not carry it either.
|
|
22
|
+
if (key === 'dangerouslySetInnerHTML') continue;
|
|
23
|
+
if (key === 'ref') continue;
|
|
24
|
+
const checkName = (attributeCheckName[key] ?? key).toLowerCase();
|
|
25
|
+
if (!allow.attribute(tag, checkName)) continue;
|
|
26
|
+
if (checkName in urlAttributes && typeof value === 'string' && blockedUrl(checkName, value)) continue;
|
|
27
|
+
filtered[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return filtered;
|
|
30
|
+
}
|
|
31
|
+
// Matches toContentNode() in parseHtml.ts: zero children omits the prop,
|
|
32
|
+
// one is the value directly (not wrapped in an array), two or more is an
|
|
33
|
+
// array. Without this, an element that loses every child to filtering ends
|
|
34
|
+
// up with an empty-array `children` instead of no `children` prop at all -
|
|
35
|
+
// a shape parseHtml itself would never produce.
|
|
36
|
+
function normalizeChildren(children) {
|
|
37
|
+
if (!Array.isArray(children)) return children;
|
|
38
|
+
if (children.length === 0) return null;
|
|
39
|
+
if (children.length === 1) return children[0] ?? null;
|
|
40
|
+
return children;
|
|
41
|
+
}
|
|
42
|
+
function filter(node, allow) {
|
|
43
|
+
if (node === undefined || node === null || node === true || node === false) return node;
|
|
44
|
+
if (typeof node === 'string' || typeof node === 'number') return node;
|
|
45
|
+
if (Array.isArray(node)) {
|
|
46
|
+
const out = [];
|
|
47
|
+
for (const child of node) {
|
|
48
|
+
const filteredChild = filter(child, allow);
|
|
49
|
+
// Non-rendered values, whether the child already was one or
|
|
50
|
+
// filtering made it one (an unwrapped or dropped element that
|
|
51
|
+
// left nothing behind), contribute nothing to the array - never
|
|
52
|
+
// a stray null placeholder in a dropped element's place.
|
|
53
|
+
if (filteredChild === undefined || filteredChild === null || filteredChild === true || filteredChild === false) continue;
|
|
54
|
+
if (Array.isArray(filteredChild)) out.push(...filteredChild);else out.push(filteredChild);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
// Not authored markup - parseHtml never produces a component node, so a
|
|
59
|
+
// tree in its shape should not carry one either, but this is defensive
|
|
60
|
+
// rather than reachable: nothing that round-trips through storage (JSON)
|
|
61
|
+
// can carry a class or function reference.
|
|
62
|
+
if (ContentNodeIsComponent(node)) return node;
|
|
63
|
+
const tag = node[$type];
|
|
64
|
+
const removal = removalFor(tag, true, allow);
|
|
65
|
+
if (removal === 'drop') return null;
|
|
66
|
+
const children = normalizeChildren(filter(node[$props].children ?? null, allow));
|
|
67
|
+
if (removal === 'unwrap') return children ?? [];
|
|
68
|
+
return {
|
|
69
|
+
[$type]: tag,
|
|
70
|
+
[$props]: {
|
|
71
|
+
...filterProps(tag, node[$props], allow),
|
|
72
|
+
...(children === null ? {} : {
|
|
73
|
+
children
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Applies an allow list to a content tree that already exists, rather than
|
|
80
|
+
* one being built - the same decisions `parseHtml(html, { allowList })` makes
|
|
81
|
+
* while parsing, for a tree that did not come from parsing HTML at all (one
|
|
82
|
+
* rebuilt from storage, for instance) and so never had the chance to.
|
|
83
|
+
*
|
|
84
|
+
* A disallowed element is unwrapped, keeping its children in its place, so
|
|
85
|
+
* filtering a tag never costs the reader the words inside it - the same rule
|
|
86
|
+
* `parseHtml` applies. An element holding program text rather than prose
|
|
87
|
+
* (`<script>`, and anything on the same footing as `<script>` even under a
|
|
88
|
+
* permissive allow list) is dropped whole instead. `on*` props, `ref`, and
|
|
89
|
+
* `dangerouslySetInnerHTML` are always stripped - the tree-shape equivalent
|
|
90
|
+
* of what `parseHtml` refuses to produce in the first place - and a `href`/
|
|
91
|
+
* `src`/... value using an executable scheme (`javascript:`, `vbscript:`) or,
|
|
92
|
+
* on a navigating attribute, `data:` is dropped the same way.
|
|
93
|
+
*/
|
|
94
|
+
export function filterContentNode(node, allowList) {
|
|
95
|
+
return filter(node, makeAllowCheck(allowList));
|
|
96
|
+
}
|
|
@@ -18,6 +18,20 @@ export type ParseHtmlOptions = {
|
|
|
18
18
|
*/
|
|
19
19
|
allowList?: HtmlAllowList | undefined;
|
|
20
20
|
};
|
|
21
|
+
export type AllowCheck = {
|
|
22
|
+
tag: (name: string) => boolean;
|
|
23
|
+
attribute: (tag: string, name: string) => boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare function makeAllowCheck(allowList: HtmlAllowList | undefined): AllowCheck;
|
|
26
|
+
export declare const urlAttributes: Record<string, true>;
|
|
27
|
+
export declare function blockedUrl(attributeName: string, value: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whether an element survives, and if not, how it goes.
|
|
30
|
+
*
|
|
31
|
+
* Elements holding program text rather than prose are dropped whole — there is
|
|
32
|
+
* no reader's content inside them to preserve. Everything else is unwrapped.
|
|
33
|
+
*/
|
|
34
|
+
export declare function removalFor(name: string, sanitize: boolean, allow: AllowCheck): 'drop' | 'unwrap' | undefined;
|
|
21
35
|
/**
|
|
22
36
|
* Parses raw HTML into a Tungsten content tree.
|
|
23
37
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseHtml.d.ts","sourceRoot":"","sources":["../../src/rawHtml/parseHtml.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,mBAAmB,CAAA;AAKhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,MAAM,MAAM,gBAAgB,GAAG;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,CAAA;CACxC,CAAA;
|
|
1
|
+
{"version":3,"file":"parseHtml.d.ts","sourceRoot":"","sources":["../../src/rawHtml/parseHtml.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,mBAAmB,CAAA;AAKhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,MAAM,MAAM,gBAAgB,GAAG;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACrB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;IAC9B,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CACpD,CAAA;AAID,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,SAAS,GAAG,UAAU,CAe/E;AAiBD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAE9C,CAAA;AA2BD,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAOxE;AAgCD;;;;;GAKG;AACH,wBAAgB,UAAU,CACtB,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GACnD,MAAM,GAAG,QAAQ,GAAG,SAAS,CAK/B;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,WAAW,CAqGnF"}
|
|
@@ -6,7 +6,7 @@ const allowEverything = {
|
|
|
6
6
|
tag: () => true,
|
|
7
7
|
attribute: () => true
|
|
8
8
|
};
|
|
9
|
-
function makeAllowCheck(allowList) {
|
|
9
|
+
export function makeAllowCheck(allowList) {
|
|
10
10
|
if (allowList === undefined) return allowEverything;
|
|
11
11
|
const tags = new Set(allowList.tags);
|
|
12
12
|
const attributes = new Set(allowList.attributes);
|
|
@@ -21,7 +21,7 @@ function makeAllowCheck(allowList) {
|
|
|
21
21
|
}
|
|
22
22
|
// REGEX: on followed by at least one letter, e.g. onclick, onerror
|
|
23
23
|
const eventAttribute = /^on[a-z]/i;
|
|
24
|
-
const urlAttributes = {
|
|
24
|
+
export const urlAttributes = {
|
|
25
25
|
href: true,
|
|
26
26
|
src: true,
|
|
27
27
|
action: true,
|
|
@@ -56,7 +56,7 @@ function urlScheme(url) {
|
|
|
56
56
|
}
|
|
57
57
|
return '';
|
|
58
58
|
}
|
|
59
|
-
function blockedUrl(attributeName, value) {
|
|
59
|
+
export function blockedUrl(attributeName, value) {
|
|
60
60
|
const scheme = urlScheme(value);
|
|
61
61
|
if (scheme in executableSchemes) return true;
|
|
62
62
|
// data: URLs can carry a whole HTML document, so they are barred from
|
|
@@ -87,7 +87,7 @@ function attributesToProps(tag, attributes, sanitize, allow) {
|
|
|
87
87
|
* Elements holding program text rather than prose are dropped whole — there is
|
|
88
88
|
* no reader's content inside them to preserve. Everything else is unwrapped.
|
|
89
89
|
*/
|
|
90
|
-
function removalFor(name, sanitize, allow) {
|
|
90
|
+
export function removalFor(name, sanitize, allow) {
|
|
91
91
|
if (sanitize && name === 'script') return 'drop';
|
|
92
92
|
if (allow.tag(name)) return undefined;
|
|
93
93
|
return name in htmlRawTextTags ? 'drop' : 'unwrap';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HtmlAllowList } from './HtmlAllowList.js';
|
|
2
|
+
export type SanitizeHtmlOptions = {
|
|
3
|
+
/** Defaults to `safeHtmlAllowList`. Pass your own list to allow more or less. */
|
|
4
|
+
allowList?: HtmlAllowList;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Cleans untrusted HTML and returns it as a string, synchronously.
|
|
8
|
+
*
|
|
9
|
+
* `parseHtml()` already does the cleaning - this only adds the return trip,
|
|
10
|
+
* for a caller that needs the result as a string rather than a content tree:
|
|
11
|
+
* a paste handler cleaning a clipboard payload before it is inserted, or an
|
|
12
|
+
* editor cleaning its content before it is stored. Both happen at a rate
|
|
13
|
+
* `renderingNodeToHtml` (the async, component-aware server renderer) is the
|
|
14
|
+
* wrong shape for.
|
|
15
|
+
*/
|
|
16
|
+
export declare function sanitizeHtml(html: string, options?: SanitizeHtmlOptions): string;
|
|
17
|
+
//# sourceMappingURL=sanitizeHtml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizeHtml.d.ts","sourceRoot":"","sources":["../../src/rawHtml/sanitizeHtml.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAIvD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,iFAAiF;IACjF,SAAS,CAAC,EAAE,aAAa,CAAA;CAC5B,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAGpF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { contentNodeToHtml } from "../render/contentNodeToHtml.js";
|
|
2
|
+
import { parseHtml } from "./parseHtml.js";
|
|
3
|
+
import { safeHtmlAllowList } from "./safeHtmlAllowList.js";
|
|
4
|
+
/**
|
|
5
|
+
* Cleans untrusted HTML and returns it as a string, synchronously.
|
|
6
|
+
*
|
|
7
|
+
* `parseHtml()` already does the cleaning - this only adds the return trip,
|
|
8
|
+
* for a caller that needs the result as a string rather than a content tree:
|
|
9
|
+
* a paste handler cleaning a clipboard payload before it is inserted, or an
|
|
10
|
+
* editor cleaning its content before it is stored. Both happen at a rate
|
|
11
|
+
* `renderingNodeToHtml` (the async, component-aware server renderer) is the
|
|
12
|
+
* wrong shape for.
|
|
13
|
+
*/
|
|
14
|
+
export function sanitizeHtml(html, options = {}) {
|
|
15
|
+
const allowList = options.allowList ?? safeHtmlAllowList;
|
|
16
|
+
return contentNodeToHtml(parseHtml(html, {
|
|
17
|
+
allowList
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadData.d.ts","sourceRoot":"","sources":["../../src/render/HeadData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAE9D,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,IAAI,MAAM,EAAE,CAAA;AAE5C,MAAM,MAAM,QAAQ,GAAG;IACnB,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,mBAAmB,EAAE,aAAa,CAAC;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,sBAAsB,CAAC;IAC1C,YAAY,EAAE,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"HeadData.d.ts","sourceRoot":"","sources":["../../src/render/HeadData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAE9D,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,IAAI,MAAM,EAAE,CAAA;AAE5C,MAAM,MAAM,QAAQ,GAAG;IACnB,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,mBAAmB,EAAE,aAAa,CAAC;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,sBAAsB,CAAC;IAC1C,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE,OAAO,GAAG,QAAQ,CAAA;IACvB,GAAG,EAAE,OAAO,CAAA;CACf,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ContentNode } from '../ContentNode.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serialises a content tree to HTML, synchronously.
|
|
4
|
+
*
|
|
5
|
+
* `renderingNodeToHtml` (the server's real renderer) covers the general case -
|
|
6
|
+
* components, async data, `<head>` - and is async and internal because of it.
|
|
7
|
+
* This covers the subset that never needs any of that: plain HTML elements,
|
|
8
|
+
* text and arrays, the exact shape `parseHtml()` produces. Given a component
|
|
9
|
+
* node it throws rather than silently rendering nothing, since a caller
|
|
10
|
+
* reaching for the synchronous path has nothing that could resolve one.
|
|
11
|
+
*
|
|
12
|
+
* Attribute values are escaped, unlike `renderingNodeToHtml`'s - that renderer
|
|
13
|
+
* trusts values from application-authored JSX; this one exists specifically to
|
|
14
|
+
* round-trip untrusted markup back out as a string, so a value carrying `"`
|
|
15
|
+
* must not be able to break out of its attribute.
|
|
16
|
+
*/
|
|
17
|
+
export declare function contentNodeToHtml(node: ContentNode): string;
|
|
18
|
+
//# sourceMappingURL=contentNodeToHtml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentNodeToHtml.d.ts","sourceRoot":"","sources":["../../src/render/contentNodeToHtml.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAapD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CA+C3D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ContentNodeIsComponent } from "../ContentNode.js";
|
|
2
|
+
import { booleanAttributeValue } from "../booleanAttributeValue.js";
|
|
3
|
+
import { $props, $type } from "../contentNodeSymbols.js";
|
|
4
|
+
import { htmlEntities } from "../htmlEntities.js";
|
|
5
|
+
import { innerHtmlFromProps } from "../innerHtmlFromProps.js";
|
|
6
|
+
import { throwError } from "../throwError.js";
|
|
7
|
+
import { validChildren } from "../validChildren.js";
|
|
8
|
+
import { htmlMonoTags } from "./htmlMonoTags.js";
|
|
9
|
+
import { htmlSelfClosableTags } from "./htmlSelfClosableTags.js";
|
|
10
|
+
import { htmlVoidTags } from "./htmlVoidTags.js";
|
|
11
|
+
import { processProps } from "./processProps.js";
|
|
12
|
+
/**
|
|
13
|
+
* Serialises a content tree to HTML, synchronously.
|
|
14
|
+
*
|
|
15
|
+
* `renderingNodeToHtml` (the server's real renderer) covers the general case -
|
|
16
|
+
* components, async data, `<head>` - and is async and internal because of it.
|
|
17
|
+
* This covers the subset that never needs any of that: plain HTML elements,
|
|
18
|
+
* text and arrays, the exact shape `parseHtml()` produces. Given a component
|
|
19
|
+
* node it throws rather than silently rendering nothing, since a caller
|
|
20
|
+
* reaching for the synchronous path has nothing that could resolve one.
|
|
21
|
+
*
|
|
22
|
+
* Attribute values are escaped, unlike `renderingNodeToHtml`'s - that renderer
|
|
23
|
+
* trusts values from application-authored JSX; this one exists specifically to
|
|
24
|
+
* round-trip untrusted markup back out as a string, so a value carrying `"`
|
|
25
|
+
* must not be able to break out of its attribute.
|
|
26
|
+
*/
|
|
27
|
+
export function contentNodeToHtml(node) {
|
|
28
|
+
if (node === undefined || node === null || node === false || node === true) return '';
|
|
29
|
+
if (Array.isArray(node)) return node.map(contentNodeToHtml).join('');
|
|
30
|
+
if (typeof node === 'string' || typeof node === 'number') return htmlEntities(node.toString());
|
|
31
|
+
if (ContentNodeIsComponent(node)) {
|
|
32
|
+
throwError('contentNodeToHtml', `component nodes are not supported - encountered one of type ` + `${String(typeof node[$type] === 'string' ? node[$type] : node[$type].name)}.`);
|
|
33
|
+
}
|
|
34
|
+
const type = node[$type];
|
|
35
|
+
const {
|
|
36
|
+
children,
|
|
37
|
+
...restProps
|
|
38
|
+
} = node[$props];
|
|
39
|
+
const attribProps = processProps(restProps);
|
|
40
|
+
let attributes = '';
|
|
41
|
+
for (const key in attribProps) {
|
|
42
|
+
const value = attribProps[key];
|
|
43
|
+
if (typeof value === 'boolean') {
|
|
44
|
+
const attrValue = booleanAttributeValue(key, value);
|
|
45
|
+
if (attrValue !== null) attributes += attrValue === '' ? ` ${key}` : ` ${key}="${attrValue}"`;
|
|
46
|
+
} else if (value !== undefined && value !== null) {
|
|
47
|
+
attributes += ` ${key}="${htmlEntities(String(value))}"`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const innerHtml = innerHtmlFromProps(type, node[$props], validChildren(children));
|
|
51
|
+
if (innerHtml !== null) {
|
|
52
|
+
if (type in htmlVoidTags) {
|
|
53
|
+
throwError('contentNodeToHtml', `<${type}> is an HTML void type (cannot have children), but the node has dangerouslySetInnerHTML.`);
|
|
54
|
+
}
|
|
55
|
+
return `<${type}${attributes}>${innerHtml}</${type}>`;
|
|
56
|
+
}
|
|
57
|
+
if (validChildren(children)) {
|
|
58
|
+
if (type in htmlVoidTags) {
|
|
59
|
+
throwError('contentNodeToHtml', `<${type}> is an HTML void type (cannot have children), but the node has children.`);
|
|
60
|
+
}
|
|
61
|
+
return `<${type}${attributes}>${contentNodeToHtml(children)}</${type}>`;
|
|
62
|
+
}
|
|
63
|
+
if (type in htmlMonoTags) return `<${type}${attributes}>`;
|
|
64
|
+
if (type in htmlSelfClosableTags) return `<${type}${attributes} />`;
|
|
65
|
+
return `<${type}${attributes}></${type}>`;
|
|
66
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contentToHtml.d.ts","sourceRoot":"","sources":["../../src/render/contentToHtml.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EAAY,YAAY,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAMvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAI9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AAGrE,wBAAsB,aAAa,CAC/B,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EACpE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EACxC,MAAM,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EACnE,iBAAiB,GAAE,sBAAkC,EAAE,GAAG,UAAQ,GACnE,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"contentToHtml.d.ts","sourceRoot":"","sources":["../../src/render/contentToHtml.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EAAY,YAAY,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAMvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAI9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AAGrE,wBAAsB,aAAa,CAC/B,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EACpE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EACxC,MAAM,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EACnE,iBAAiB,GAAE,sBAAkC,EAAE,GAAG,UAAQ,GACnE,OAAO,CAAC,MAAM,CAAC,CAsDjB"}
|