@iyulab/chat-components 0.13.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/README.md +1 -0
- package/dist/_virtual/_glob-assets_raw/alert-triangle-fill.svg.4cfc4305.js +4 -0
- package/dist/_virtual/_glob-assets_raw/arrows-sort.svg.dda43a85.js +4 -0
- package/dist/_virtual/_glob-assets_raw/code.svg.c69bc144.js +4 -0
- package/dist/_virtual/_glob-assets_raw/download.svg.bce82177.js +4 -0
- package/dist/_virtual/_glob-assets_raw/external-link.svg.a9f7f02d.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file-code.svg.0e706f93.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file-music.svg.b9970203.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file-spreadsheet.svg.8c03bdfa.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file-text.svg.85bdd923.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file-type-pdf.svg.bc12db6d.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file-zip.svg.76dde660.js +4 -0
- package/dist/_virtual/_glob-assets_raw/file.svg.28f5d6f1.js +4 -0
- package/dist/_virtual/_glob-assets_raw/photo.svg.cc273cc1.js +4 -0
- package/dist/_virtual/_glob-assets_raw/player-stop-fill.svg.5378b752.js +4 -0
- package/dist/_virtual/_glob-assets_raw/send.svg.02326253.js +4 -0
- package/dist/_virtual/_glob-assets_raw/sort-ascending-letters.svg.14a3df67.js +4 -0
- package/dist/_virtual/_glob-assets_raw/sort-descending-letters.svg.3e03647c.js +4 -0
- package/dist/_virtual/_glob-assets_raw/video.svg.c183f03c.js +4 -0
- package/dist/_virtual/_glob-assets_raw/world.svg.cd9903c8.js +4 -0
- package/dist/components/UDataElement.d.ts +2 -0
- package/dist/components/UDataElement.js +9 -1
- package/dist/components/blocks/UCodeBlock.js +1 -0
- package/dist/components/blocks/UElementBlock.d.ts +12 -16
- package/dist/components/blocks/UElementBlock.js +23 -31
- package/dist/components/blocks/UFileBlock.js +1 -0
- package/dist/components/blocks/UMarkedBlock.d.ts +10 -1
- package/dist/components/blocks/UMarkedBlock.js +43 -13
- package/dist/components/blocks/UMarkedBlock.styles.js +10 -0
- package/dist/components/blocks/UTableBlock.js +1 -0
- package/dist/components/prompt/UPrompt.js +3 -1
- package/dist/components/references/URefCard.js +3 -1
- package/dist/components/references/URefTag.js +3 -1
- package/dist/components-extra/UChartBlock.js +4 -0
- package/dist/components-extra/UImagesBlock.d.ts +3 -0
- package/dist/components-extra/UImagesBlock.js +18 -3
- package/dist/components-extra/UImagesBlock.styles.js +19 -0
- package/dist/components-extra/UMapBlock.js +3 -0
- package/dist/components-extra/UVideoBlock.js +3 -0
- package/dist/extra.d.ts +7 -1
- package/dist/extra.js +12 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -2
- package/dist/utilities/ElementRegistry.d.ts +13 -0
- package/dist/utilities/ElementRegistry.js +33 -0
- package/dist/utilities/HtmlPlaceholder.d.ts +8 -0
- package/dist/utilities/HtmlPlaceholder.js +13 -1
- package/dist/utilities/PromptBuilder.d.ts +3 -0
- package/dist/utilities/PromptBuilder.js +5 -0
- package/dist/utilities/icons.js +52 -0
- package/dist/utilities/imageSources.d.ts +25 -0
- package/dist/utilities/imageSources.js +61 -0
- package/dist/utilities/messages.d.ts +1 -1
- package/dist/utilities/messages.js +6 -2
- package/dist/utilities/sanitizers.d.ts +10 -1
- package/dist/utilities/sanitizers.js +16 -5
- package/package.json +4 -2
- package/skills/iyulab-chat-components/SKILL.md +1 -0
- package/skills/iyulab-chat-components/references/components/element-block.md +5 -6
- package/skills/iyulab-chat-components/references/components/images-block.md +1 -0
- package/skills/iyulab-chat-components/references/components/marked-block.md +17 -0
- package/skills/iyulab-chat-components/references/extra-system.md +4 -4
- package/skills/iyulab-chat-components/references/security.md +23 -0
|
@@ -76,18 +76,29 @@ var HREF_STRIP_CHARS_REGEX = /[\u0000-\u001F\u007F\s]+/g;
|
|
|
76
76
|
/** href/src에서 차단해야 하는 위험 protocol */
|
|
77
77
|
var HREF_UNSAFE_PROTOCOL_REGEX = /^(?:javascript|data|vbscript):/i;
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
79
|
+
* URL 의 프로토콜을 검사해 안전한 URL 문자열을 돌려줍니다 — HTML escape 는 하지 않습니다.
|
|
80
|
+
* Lit 의 속성 바인딩처럼 escape 를 스스로 하는 자리에서 씁니다(두 번 escape 하면 `&` 가 `&` 가 된다).
|
|
81
|
+
* 위험한 URL(javascript:/data:/vbscript:, protocol-relative)은 `#` 가 됩니다.
|
|
80
82
|
*
|
|
81
83
|
* 예:
|
|
82
|
-
*
|
|
84
|
+
* html`<a href=${sanitizeHref(url)}>`
|
|
83
85
|
*/
|
|
84
|
-
function
|
|
86
|
+
function sanitizeHref(value) {
|
|
85
87
|
let normalized = value.replace(ZERO_WIDTH_STRICT_REGEX, "").trim();
|
|
86
88
|
if (HREF_STRIP_CHARS_REGEX.test(normalized)) normalized = normalized.replace(HREF_STRIP_CHARS_REGEX, "");
|
|
87
89
|
normalized = normalized.replace(/\\/g, "/");
|
|
88
90
|
if (normalized.startsWith("//")) return "#";
|
|
89
91
|
if (HREF_UNSAFE_PROTOCOL_REGEX.test(normalized)) return "#";
|
|
90
|
-
return
|
|
92
|
+
return normalized;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* href / src attribute용 문자열 처리 — HTML 문자열을 직접 조립하는 자리에서 씁니다.
|
|
96
|
+
*
|
|
97
|
+
* 예:
|
|
98
|
+
* <a href="{value}">
|
|
99
|
+
*/
|
|
100
|
+
function escapeHtmlHref(value) {
|
|
101
|
+
return escapeHtmlAttr(sanitizeHref(value));
|
|
91
102
|
}
|
|
92
103
|
//#endregion
|
|
93
|
-
export { escapeHtmlAttr, escapeHtmlHref, escapeHtmlText, stripZeroWidth };
|
|
104
|
+
export { escapeHtmlAttr, escapeHtmlHref, escapeHtmlText, sanitizeHref, stripZeroWidth };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/chat-components",
|
|
3
3
|
"description": "llm chat components for building chat interfaces",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.1",
|
|
5
5
|
"author": "iyulab",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
"./src/extra.ts",
|
|
39
39
|
"./dist/index.js",
|
|
40
40
|
"./src/index.ts",
|
|
41
|
+
"./dist/utilities/icons.js",
|
|
42
|
+
"./src/utilities/icons.ts",
|
|
41
43
|
"./dist/react/index.js"
|
|
42
44
|
],
|
|
43
45
|
"exports": {
|
|
@@ -67,7 +69,7 @@
|
|
|
67
69
|
"marked": "^18.0.6"
|
|
68
70
|
},
|
|
69
71
|
"peerDependencies": {
|
|
70
|
-
"@iyulab/components": ">=1.
|
|
72
|
+
"@iyulab/components": ">=1.51.0",
|
|
71
73
|
"@lit/react": ">=1.0.8",
|
|
72
74
|
"chart.js": ">=4.5.1",
|
|
73
75
|
"react": ">=18.0.0"
|
|
@@ -31,6 +31,7 @@ import '@iyulab/chat-components/dist/components/prompt/UPrompt.js';
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
> For detailed setup and usage patterns, see [./references/usage.md](./references/usage.md).
|
|
34
|
+
> Model output is untrusted — see [./references/security.md](./references/security.md) for what each input may contain.
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
@@ -6,7 +6,7 @@ import '@iyulab/chat-components/dist/components/blocks/UElementBlock.js';
|
|
|
6
6
|
|
|
7
7
|
**Tag:** `u-element-block`
|
|
8
8
|
|
|
9
|
-
Dynamic
|
|
9
|
+
Dynamic block renderer. Creates the registered block specified by `tag`, binds the schema's `properties` to it, and shows a skeleton placeholder while `loading`. Used internally by `u-marked-block` to render `block-json` code fences (see [../extra-system.md](../extra-system.md)) — you generally don't create it directly.
|
|
10
10
|
|
|
11
11
|
Extends `UDataElement`, so `tag`/`properties` can also be injected via a `<script type="application/json">` slot.
|
|
12
12
|
|
|
@@ -43,15 +43,14 @@ This is converted to `<u-element-block tag="u-images-block" ...>` via `UElementB
|
|
|
43
43
|
|
|
44
44
|
| Property | Type | Default | Reflect | Description |
|
|
45
45
|
|----------|------|---------|---------|-------------|
|
|
46
|
-
| `tag` | `string` | `undefined` | — |
|
|
47
|
-
| `properties` | `Record<string, unknown>` | `undefined` | — |
|
|
46
|
+
| `tag` | `string` | `undefined` | — | Block tag to render. Must be a registered block (`registerElementBlock` or `ElementPromptBuilder.add`) whose element is defined |
|
|
47
|
+
| `properties` | `Record<string, unknown>` | `undefined` | — | Values to bind. Only names listed in the block schema's `properties` are assigned |
|
|
48
48
|
| `loading` | `boolean` | `false` | ✓ | Shows a skeleton placeholder instead of the element |
|
|
49
|
-
| `blacklist` | `string[]` | `['innerHTML', 'outerHTML', 'textContent', 'innerText', 'outerText', 'srcdoc']` | — | Property names blocked from binding for XSS prevention |
|
|
50
49
|
|
|
51
50
|
## Error Handling
|
|
52
51
|
|
|
53
|
-
If `tag` is missing
|
|
52
|
+
If `tag` is missing or not a registered block, or `properties` is not an object or fails to assign, `u-element-block` does **not** show an error card — it renders nothing and logs to the console (`[u-element-block] ...`). While `loading` is `true`, JSON parse failures from the underlying `UDataElement` are silently ignored too, since incomplete streamed JSON is expected mid-stream.
|
|
54
53
|
|
|
55
54
|
## Security
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
`tag` and `properties` usually come from model output, so they are treated as untrusted. Only registered blocks are created, and only the property names in the block's schema are assigned — any other key (for example `style`) is dropped and logged. See [../extra-system.md](../extra-system.md#security).
|
|
@@ -71,3 +71,4 @@ interface ImageSlide {
|
|
|
71
71
|
| Carousel | Up to 3 slides visible; draggable |
|
|
72
72
|
| Lightbox | Full-screen modal on image click |
|
|
73
73
|
| Keyboard | `←` `→` to navigate, `Esc` to close |
|
|
74
|
+
| Image origin policy | `setAllowedImagePrefixes()` applies — a blocked item shows its alt text and is not requested (see [../security.md](../security.md)) |
|
|
@@ -65,8 +65,25 @@ Vendored from GitHub's markdown theme — light values shown, dark auto-applies
|
|
|
65
65
|
| `--base-size-4` / `-8` / `-16` / `-24` / `-40` | Spacing scale used throughout (margins, padding, gaps) |
|
|
66
66
|
| `--base-text-weight-normal` / `-medium` / `-semibold` | Font-weight scale (body / table header / heading) |
|
|
67
67
|
|
|
68
|
+
## CSS Parts
|
|
69
|
+
|
|
70
|
+
| Part | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `image-blocked` | Alt text shown in place of an image the image origin policy blocked (see Images) |
|
|
73
|
+
|
|
74
|
+
## Images
|
|
75
|
+
|
|
76
|
+
Markdown images (table cells included) follow the page-wide image origin policy set with
|
|
77
|
+
`setAllowedImagePrefixes()`. A blocked image is not requested; its alt text is shown in a
|
|
78
|
+
`part="image-blocked"` span (`Image blocked: …`, localized). See [../security.md](../security.md).
|
|
79
|
+
|
|
68
80
|
## ReferenceCitation Type
|
|
69
81
|
|
|
82
|
+
A citation is drawn at `endIndex` in the markdown source. While a response streams, a citation whose
|
|
83
|
+
`endIndex` is past the text received so far is held until that text arrives; a negative or non-integer
|
|
84
|
+
index is ignored. If `endIndex` falls inside a link URL, an image, or inline code, the citation is drawn
|
|
85
|
+
right after that element; inside a fenced code block it is dropped.
|
|
86
|
+
|
|
70
87
|
```ts
|
|
71
88
|
interface ReferenceCitation {
|
|
72
89
|
startIndex: number; // Start character index in the markdown text
|
|
@@ -76,20 +76,20 @@ const def: ElementSchema = {
|
|
|
76
76
|
ElementPromptBuilder.instance.add(def);
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
The element just needs to accept standard property assignments — `u-element-block`
|
|
79
|
+
The element just needs to accept standard property assignments. `add()` also registers the schema as a renderable block — `u-element-block` assigns only the names in the schema's `properties`. If you write your own prompt instead, call `registerElementBlock(def)` (exported from `@iyulab/chat-components`).
|
|
80
80
|
|
|
81
81
|
## Error Handling
|
|
82
82
|
|
|
83
|
-
If the LLM outputs a `tag` that isn't registered (e.g. missing `@iyulab/chat-components/extra` import, or a custom extra's element isn't defined yet), `u-element-block` does **not** show an error card — it renders nothing and logs to the console instead. Genuine data errors (invalid `properties`, assignment failures) are also console-only.
|
|
83
|
+
If the LLM outputs a `tag` that isn't a registered block (e.g. missing `@iyulab/chat-components/extra` import, or a custom extra's schema was never registered or its element isn't defined yet), `u-element-block` does **not** show an error card — it renders nothing and logs to the console instead. Genuine data errors (invalid `properties`, assignment failures) are also console-only.
|
|
84
84
|
|
|
85
85
|
## Security
|
|
86
86
|
|
|
87
|
-
`u-element-block`
|
|
87
|
+
`block-json` is model output and is treated as untrusted. `u-element-block` creates only registered blocks (`ElementPromptBuilder.add()` or `registerElementBlock()`; built-in extras register on import) and assigns only the property names in the block's schema `properties` — other keys, including `style`, are dropped and logged. Custom extras should accept data only; if a property is rendered as HTML, sanitize it inside the element.
|
|
88
88
|
|
|
89
89
|
## `ElementPromptBuilder` API
|
|
90
90
|
|
|
91
91
|
| Method | Description |
|
|
92
92
|
|--------|-------------|
|
|
93
93
|
| `ElementPromptBuilder.instance` | Singleton accessor |
|
|
94
|
-
| `.add(definition: ElementSchema)` | Register a custom extra (throws on tag conflict) |
|
|
94
|
+
| `.add(definition: ElementSchema)` | Register a custom extra (throws on tag conflict). Also registers it as a renderable block |
|
|
95
95
|
| `.build(): string` | Generate system prompt instruction string |
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Security model
|
|
2
|
+
|
|
3
|
+
Model output is **untrusted** (prompt injection can put third-party text in any response). What each input
|
|
4
|
+
is trusted to contain:
|
|
5
|
+
|
|
6
|
+
| Input | Treated as | Handling |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| `u-marked-block` `value` | untrusted | Raw HTML shown as text · link/image URLs protocol-checked (`javascript:`/`data:`/`vbscript:`/`//host` → `#`) · code fences escaped · table cells same rules |
|
|
9
|
+
| `block-json` fences | untrusted | Only registered blocks; only the schema's property names are assigned |
|
|
10
|
+
| `refs` | untrusted | Text rendered as text · URLs protocol-checked in `u-ref-tag` and `u-ref-card` |
|
|
11
|
+
| `u-table-block` cell `text` bound directly | **trusted HTML** | Sanitize before binding. `block-json` cannot reach it |
|
|
12
|
+
| Your custom block | your element's contract | The schema allows names, not content — sanitize HTML-rendered properties inside the element |
|
|
13
|
+
|
|
14
|
+
Requests: markdown images and `u-images-block` load the `http:`/`https:` URL the model writes as soon as they
|
|
15
|
+
render (an image URL can carry data out). When the model reads content you do not control, call
|
|
16
|
+
`setAllowedImagePrefixes([location.origin + '/', 'https://cdn.example.com/images/'])` before rendering —
|
|
17
|
+
images outside the list are not requested and show their alt text (`Image blocked: …`). Prefixes match the
|
|
18
|
+
resolved absolute URL; prefer paths to whole domains (open redirects). `data:image/…` is always shown (no
|
|
19
|
+
request). Default: all allowed. Add CSP `img-src` as a second layer.
|
|
20
|
+
`u-map-block` (OpenStreetMap iframe) and `u-video-block` (YouTube/Vimeo/direct) embed external content.
|
|
21
|
+
`u-ref-card` requests no favicon by default.
|
|
22
|
+
|
|
23
|
+
Do not insert model output with `innerHTML` yourself; route it through `u-marked-block`.
|