@juspay/svelte-ui-components 2.136.1 → 2.136.7
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/BrandLoader/BrandLoader.svelte +9 -2
- package/dist/Button/Button.svelte +3 -1
- package/dist/Carousel/Carousel.svelte +50 -6
- package/dist/Chat/types.d.ts +5 -0
- package/dist/ChatMessage/ChatMessage.svelte +114 -3
- package/dist/ChatMessage/properties.d.ts +12 -0
- package/dist/ChatMessageList/ChatMessageList.svelte +1 -0
- package/dist/Choicebox/Choicebox.svelte +55 -0
- package/dist/Choicebox/properties.d.ts +1 -0
- package/dist/Input/Input.svelte +18 -7
- package/dist/InputButton/InputButton.svelte +7 -3
- package/dist/MarkdownText/MarkdownText.svelte +138 -0
- package/dist/MarkdownText/MarkdownText.svelte.d.ts +4 -0
- package/dist/MarkdownText/markdown.d.ts +6 -0
- package/dist/MarkdownText/markdown.js +105 -0
- package/dist/MarkdownText/properties.d.ts +27 -0
- package/dist/SoundKit/properties.js +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist-wc/index.js +15264 -11926
- package/package.json +5 -1
- /package/dist/{soundKit → MarkdownText}/properties.js +0 -0
- /package/dist/{soundKit/soundKit.d.ts → SoundKit/SoundKit.d.ts} +0 -0
- /package/dist/{soundKit/soundKit.js → SoundKit/SoundKit.js} +0 -0
- /package/dist/{soundKit → SoundKit}/properties.d.ts +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Marked } from 'marked';
|
|
2
|
+
/**
|
|
3
|
+
* Chat content comes from models and users, not from the app's own templates,
|
|
4
|
+
* so the output must be safe without asking consumers to run a sanitizer:
|
|
5
|
+
* raw HTML never passes through (it renders as escaped text), and only these
|
|
6
|
+
* URL protocols survive on links. Everything else in the output is built by
|
|
7
|
+
* marked from markdown syntax alone.
|
|
8
|
+
*/
|
|
9
|
+
const SAFE_LINK_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);
|
|
10
|
+
const SAFE_IMAGE_PROTOCOLS = new Set(['http:', 'https:']);
|
|
11
|
+
/**
|
|
12
|
+
* Character references that decode to an ASCII control character, plus the two
|
|
13
|
+
* named forms HTML defines for tab and newline. These are the smuggling vector:
|
|
14
|
+
* `jav	ascript:` is not a scheme to `new URL()`, so it reads as a harmless
|
|
15
|
+
* relative path -- but the browser decodes the reference back to a tab when it
|
|
16
|
+
* parses the attribute, and the WHATWG URL parser strips tabs and newlines from
|
|
17
|
+
* INSIDE a scheme, leaving `javascript:`. The validator and the browser
|
|
18
|
+
* therefore disagree about the same string, which is the whole bug.
|
|
19
|
+
*/
|
|
20
|
+
const NUMERIC_REFERENCE = /&#(x[0-9a-f]+|[0-9]+);?/gi;
|
|
21
|
+
const NAMED_WHITESPACE_REFERENCE = /&(tab|newline);/gi;
|
|
22
|
+
// Matching control characters is the entire point: these are exactly what the
|
|
23
|
+
// URL parser silently removes, and what an attacker smuggles in as a character
|
|
24
|
+
// reference to hide a scheme.
|
|
25
|
+
// eslint-disable-next-line no-control-regex
|
|
26
|
+
const STRIPPED_BY_URL_PARSER = /[\u0000-\u0020\u007f]/g;
|
|
27
|
+
/**
|
|
28
|
+
* Normalise an href the way the BROWSER will see it, then check the protocol.
|
|
29
|
+
* Decoding first and stripping second is what closes the gap: whatever survives
|
|
30
|
+
* this is what the URL parser is actually handed at click time.
|
|
31
|
+
*/
|
|
32
|
+
function normaliseForProtocolCheck(href) {
|
|
33
|
+
return href
|
|
34
|
+
.replace(NUMERIC_REFERENCE, (_match, code) => String.fromCodePoint(code[0].toLowerCase() === 'x' ? parseInt(code.slice(1), 16) : parseInt(code, 10)))
|
|
35
|
+
.replace(NAMED_WHITESPACE_REFERENCE, ' ')
|
|
36
|
+
.replace(STRIPPED_BY_URL_PARSER, '');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Relative URLs resolve against the placeholder base and come out `https:`, so
|
|
40
|
+
* they are allowed without a special case.
|
|
41
|
+
*/
|
|
42
|
+
function hasSafeProtocol(href, allowList) {
|
|
43
|
+
try {
|
|
44
|
+
return allowList.has(new URL(normaliseForProtocolCheck(href), 'https://relative.invalid').protocol);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function escapeHtml(value) {
|
|
51
|
+
return value
|
|
52
|
+
.replace(/&/g, '&')
|
|
53
|
+
.replace(/</g, '<')
|
|
54
|
+
.replace(/>/g, '>')
|
|
55
|
+
.replace(/"/g, '"')
|
|
56
|
+
.replace(/'/g, ''');
|
|
57
|
+
}
|
|
58
|
+
const sanitizingRenderer = {
|
|
59
|
+
html(token) {
|
|
60
|
+
return escapeHtml(token.text);
|
|
61
|
+
},
|
|
62
|
+
link(token) {
|
|
63
|
+
if (hasSafeProtocol(token.href, SAFE_LINK_PROTOCOLS)) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return escapeHtml(token.text);
|
|
67
|
+
},
|
|
68
|
+
image(token) {
|
|
69
|
+
if (hasSafeProtocol(token.href, SAFE_IMAGE_PROTOCOLS)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return escapeHtml(token.text);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
/* Safe to share across SSR requests: each instance's configuration (renderer,
|
|
76
|
+
gfm, breaks) is fixed at construction and parse() takes no per-request state,
|
|
77
|
+
so the cache only ever holds config-immutable parsers keyed by option shape. */
|
|
78
|
+
const instances = new Map();
|
|
79
|
+
/* External links open in a new tab with `rel="noopener noreferrer"` — the same
|
|
80
|
+
default the library's Button/Card apply to `target="_blank"` anchors. The
|
|
81
|
+
default renderer never emits `target`, so the regex can only annotate, never
|
|
82
|
+
duplicate; relative, mailto: and tel: links keep same-tab navigation. */
|
|
83
|
+
const EXTERNAL_ANCHOR_PATTERN = /<a href="(https?:\/\/[^"]*)"/g;
|
|
84
|
+
function annotateExternalLinks(html) {
|
|
85
|
+
return html.replace(EXTERNAL_ANCHOR_PATTERN, '<a href="$1" target="_blank" rel="noopener noreferrer"');
|
|
86
|
+
}
|
|
87
|
+
function instanceFor(options) {
|
|
88
|
+
const breaks = options.breaks === true;
|
|
89
|
+
const key = breaks ? 'breaks' : 'default';
|
|
90
|
+
let instance = instances.get(key);
|
|
91
|
+
if (!instance) {
|
|
92
|
+
instance = new Marked({ gfm: true, breaks, renderer: sanitizingRenderer });
|
|
93
|
+
instances.set(key, instance);
|
|
94
|
+
}
|
|
95
|
+
return instance;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Markdown → HTML with the sanitizing pipeline above. Pure string transform —
|
|
99
|
+
* no DOM involved — so it renders identically on server and client.
|
|
100
|
+
*/
|
|
101
|
+
export function renderMarkdown(markdown, options = {}) {
|
|
102
|
+
const instance = instanceFor(options);
|
|
103
|
+
const output = options.inline === true ? instance.parseInline(markdown) : instance.parse(markdown);
|
|
104
|
+
return typeof output === 'string' ? annotateExternalLinks(output) : '';
|
|
105
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type MarkdownTextProperties = OptionalMarkdownTextProperties & MandatoryMarkdownTextProperties;
|
|
2
|
+
export type MandatoryMarkdownTextProperties = {
|
|
3
|
+
/**
|
|
4
|
+
* Markdown source. Rendered through the library's sanitized-by-construction
|
|
5
|
+
* pipeline: raw HTML (block and inline) is escaped and shown as text, and
|
|
6
|
+
* link/image URLs outside the safe-protocol allow-list are stripped while
|
|
7
|
+
* their text is kept.
|
|
8
|
+
*/
|
|
9
|
+
markdown: string;
|
|
10
|
+
};
|
|
11
|
+
export type OptionalMarkdownTextProperties = {
|
|
12
|
+
/** Render single newlines as `<br>` (GFM "breaks" mode). */
|
|
13
|
+
breaks?: boolean;
|
|
14
|
+
testId?: string;
|
|
15
|
+
classes?: string;
|
|
16
|
+
};
|
|
17
|
+
export type RenderMarkdownOptions = {
|
|
18
|
+
/** Render single newlines as `<br>` (GFM "breaks" mode). */
|
|
19
|
+
breaks?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Parse as inline markdown: no block elements (`<p>`, lists, tables) are
|
|
22
|
+
* produced, so the output can sit inside an existing `<p>` or `<span>`.
|
|
23
|
+
* The same sanitization applies — inline raw HTML is escaped and unsafe
|
|
24
|
+
* link/image protocols are stripped.
|
|
25
|
+
*/
|
|
26
|
+
inline?: boolean;
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,8 @@ export { default as Chat } from './Chat/Chat.svelte';
|
|
|
86
86
|
export { default as ChatHeader } from './ChatHeader/ChatHeader.svelte';
|
|
87
87
|
export { default as ChatMessage } from './ChatMessage/ChatMessage.svelte';
|
|
88
88
|
export { default as ChatMessageList } from './ChatMessageList/ChatMessageList.svelte';
|
|
89
|
+
export { default as MarkdownText } from './MarkdownText/MarkdownText.svelte';
|
|
90
|
+
export { renderMarkdown } from './MarkdownText/markdown';
|
|
89
91
|
export { default as ChatComposer } from './ChatComposer/ChatComposer.svelte';
|
|
90
92
|
export { default as ChatSuggestions } from './ChatSuggestions/ChatSuggestions.svelte';
|
|
91
93
|
export { default as ChatToolStatus } from './ChatToolStatus/ChatToolStatus.svelte';
|
|
@@ -152,7 +154,7 @@ export type * from './ThemeSwitcher/properties';
|
|
|
152
154
|
export type * from './ThinkingIndicator/properties';
|
|
153
155
|
export type * from './ToolCallLog/properties';
|
|
154
156
|
export type * from './TaskList/properties';
|
|
155
|
-
export type * from './
|
|
157
|
+
export type * from './SoundKit/properties';
|
|
156
158
|
export type * from './Book/properties';
|
|
157
159
|
export type * from './Browser/properties';
|
|
158
160
|
export type * from './Phone/properties';
|
|
@@ -187,6 +189,7 @@ export type * from './SpeechToText/types';
|
|
|
187
189
|
export type * from './ChatHeader/properties';
|
|
188
190
|
export type * from './ChatMessage/properties';
|
|
189
191
|
export type * from './ChatMessageList/properties';
|
|
192
|
+
export type * from './MarkdownText/properties';
|
|
190
193
|
export type * from './ChatComposer/properties';
|
|
191
194
|
export type * from './ChatSuggestions/properties';
|
|
192
195
|
export type * from './ChatToolStatus/properties';
|
|
@@ -197,6 +200,6 @@ export type * from './Draggable/properties';
|
|
|
197
200
|
export type * from './MediaPlayer/properties';
|
|
198
201
|
export type * from './MediaUpload/properties';
|
|
199
202
|
export type * from './Gallery/properties';
|
|
200
|
-
export { createSoundKit } from './
|
|
203
|
+
export { createSoundKit } from './SoundKit/SoundKit';
|
|
201
204
|
export { validateInput, lockBodyScroll, unlockBodyScroll } from './utils';
|
|
202
205
|
export { formatNumberIndian } from './_chart/format';
|
package/dist/index.js
CHANGED
|
@@ -86,6 +86,8 @@ export { default as Chat } from './Chat/Chat.svelte';
|
|
|
86
86
|
export { default as ChatHeader } from './ChatHeader/ChatHeader.svelte';
|
|
87
87
|
export { default as ChatMessage } from './ChatMessage/ChatMessage.svelte';
|
|
88
88
|
export { default as ChatMessageList } from './ChatMessageList/ChatMessageList.svelte';
|
|
89
|
+
export { default as MarkdownText } from './MarkdownText/MarkdownText.svelte';
|
|
90
|
+
export { renderMarkdown } from './MarkdownText/markdown';
|
|
89
91
|
export { default as ChatComposer } from './ChatComposer/ChatComposer.svelte';
|
|
90
92
|
export { default as ChatSuggestions } from './ChatSuggestions/ChatSuggestions.svelte';
|
|
91
93
|
export { default as ChatToolStatus } from './ChatToolStatus/ChatToolStatus.svelte';
|
|
@@ -100,6 +102,6 @@ export { default as Gallery } from './Gallery/Gallery.svelte';
|
|
|
100
102
|
export { ChatController } from './Chat/controller.svelte';
|
|
101
103
|
export { partyOf } from './Chat/roles';
|
|
102
104
|
export { SpeechToTextController } from './SpeechToText/controller.svelte';
|
|
103
|
-
export { createSoundKit } from './
|
|
105
|
+
export { createSoundKit } from './SoundKit/SoundKit';
|
|
104
106
|
export { validateInput, lockBodyScroll, unlockBodyScroll } from './utils';
|
|
105
107
|
export { formatNumberIndian } from './_chart/format';
|