ocwi-core 0.1.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 ADDED
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes to OCWI are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+ OCWI uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ---
9
+
10
+ ## [0.1.1] – 2025-02-26
11
+
12
+ ### Initial public release
13
+
14
+ First publicly available version of OCWI.
15
+
16
+ #### Features
17
+
18
+ - Single-file IIFE bundle (`dist/ocwi.min.js`) — drop into any page via `<script>` tag
19
+ - Web Component (`<ocwi-chat>`) built with Lit, fully isolated in Shadow DOM
20
+ - Config layering: default → Luma remote → local overrides
21
+ - Luma integration: fetch remote UI config on init, cookie-based cache for instant load
22
+ - Dana integration: SSE streaming chat via Luma proxy; structured error event detection
23
+ - Automatic reconnect with exponential backoff when Dana or Luma is unavailable
24
+ - Connection status indicator (split dot: Luma left / Dana right)
25
+ - i18n: built-in `en`, `cs`, `de` dictionaries; runtime language switch; custom dictionary merge
26
+ - Full theming via CSS custom properties (`--ocwi-primary`, `--ocwi-bg`, etc.)
27
+ - Message actions: copy, edit (user), refresh (assistant)
28
+ - Configurable send keybind (`Enter`, `Shift+Enter`, `Ctrl+Enter`, `Alt+Enter`, `None`)
29
+ - Watermark support (image, repeat mode, position)
30
+ - Accessible: `aria-label`, keyboard navigation, focus management
31
+ - Mobile-responsive layout with safe-area inset support
32
+
33
+ #### API adapters
34
+
35
+ - `MockApi` — in-memory mock with simulated streaming (demo / development)
36
+ - `HttpApi` — real SSE streaming via `danaUrl`; SSE error detection; abort/stop support
package/LICENSE.md ADDED
@@ -0,0 +1,100 @@
1
+ # OCWI Sustainable Use License
2
+
3
+ Copyright (c) 2025-present, dana-luma-ocwi contributors
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute,
13
+ make available, and prepare derivative works of the software, in each
14
+ case subject to the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ **You may use or modify the software only for your own internal business
19
+ purposes, for non-commercial or personal use, or to embed the widget
20
+ into your own website or web application as a user-facing chat interface.**
21
+
22
+ **You may distribute the software or provide it to others only if you do
23
+ so free of charge and for non-commercial purposes.**
24
+
25
+ **You may not offer the software (or any substantially similar embeddable
26
+ AI chat widget product built on or derived from it) as a standalone
27
+ commercial product, hosted service, or SaaS offering — i.e. you may not
28
+ sell, license, or monetise the widget itself as the primary deliverable.**
29
+
30
+ You may not alter, remove, or obscure any licensing, copyright, or other
31
+ notices of the licensor in the software. Any use of the licensor's
32
+ trademarks is subject to applicable law.
33
+
34
+ ## Patents
35
+
36
+ The licensor grants you a license, under any patent claims the licensor
37
+ can license, or becomes able to license, to make, have made, use, sell,
38
+ offer for sale, import and have imported the software, in each case
39
+ subject to the limitations and conditions in this license. This license
40
+ does not cover any patent claims that you cause to be infringed by
41
+ modifications or additions to the software. If you or your company make
42
+ any written claim that the software infringes or contributes to
43
+ infringement of any patent, your patent license for the software granted
44
+ under these terms ends immediately. If your company makes such a claim,
45
+ your patent license ends immediately for work on behalf of your company.
46
+
47
+ ## Notices
48
+
49
+ You must ensure that anyone who gets a copy of any part of the software
50
+ from you also gets a copy of these terms. If you modify the software,
51
+ you must include in any modified copies of the software a prominent
52
+ notice stating that you have modified the software.
53
+
54
+ ## No Other Rights
55
+
56
+ These terms do not imply any licenses other than those expressly granted
57
+ in these terms.
58
+
59
+ ## Termination
60
+
61
+ If you use the software in violation of these terms, such use is not
62
+ licensed, and your license will automatically terminate. If the licensor
63
+ provides you with a notice of your violation, and you cease all violation
64
+ of this license no later than 30 days after you receive that notice, your
65
+ license will be reinstated retroactively. However, if you violate these
66
+ terms after such reinstatement, any additional violation of these terms
67
+ will cause your license to terminate automatically and permanently.
68
+
69
+ ## No Warranty
70
+
71
+ As far as the law allows, the software comes as is, without any warranty
72
+ or condition, and the licensor will not be liable to you for any damages
73
+ arising out of these terms or the use or nature of the software, under
74
+ any kind of legal claim.
75
+
76
+ ## Definitions
77
+
78
+ The **"licensor"** is the entity offering these terms.
79
+
80
+ The **"software"** is the OCWI project the licensor makes available under
81
+ these terms.
82
+
83
+ **"You"** refers to the individual or entity agreeing to these terms.
84
+
85
+ **"Your company"** is any legal entity, sole proprietorship, or other kind
86
+ of organization that you work for, plus all organizations that have
87
+ control over, are under the control of, or are under common control with
88
+ that organization.
89
+
90
+ **"Control"** means ownership of substantially all the assets of an entity,
91
+ or the power to direct its management and policies by vote, contract, or
92
+ otherwise. Control can be direct or indirect.
93
+
94
+ **"Your licenses"** are all the licenses granted to you for the software
95
+ under these terms.
96
+
97
+ **"Use"** means anything you do with the software requiring one of your
98
+ licenses.
99
+
100
+ **"Trademark"** means trademarks, service marks, and similar rights.
package/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # OCWI — Embeddable AI Chat Widget
2
+
3
+ [![npm](https://img.shields.io/npm/v/ocwi)](https://www.npmjs.com/package/ocwi)
4
+ [![license](https://img.shields.io/badge/license-Sustainable%20Use-blue)](LICENSE.md)
5
+ [![bundle](https://img.shields.io/badge/bundle-single%20file%20IIFE-green)](https://cdn.jsdelivr.net/npm/ocwi/dist/ocwi.min.js)
6
+
7
+ Framework-agnostic, single-file JS chat widget built with TypeScript and Lit.
8
+ Ships as one IIFE bundle — drop it into any web page with a single `<script>` tag.
9
+
10
+ **Key properties:**
11
+
12
+ - No React / Vue / Svelte — only [Lit](https://lit.dev/) (Web Components)
13
+ - Single JS file: `dist/ocwi.min.js` (Lit bundled in, ~50 kB gzip)
14
+ - Shadow DOM + CSS variables for full theme isolation
15
+ - Connects to **Luma** (config server) and streams AI responses from **Dana**
16
+ - Config layering: default → Luma remote → local overrides
17
+ - i18n with runtime language switch and custom dictionaries (`en`, `cs`, `de` built-in)
18
+ - Automatic reconnect with exponential backoff
19
+
20
+ ---
21
+
22
+ ## How it works
23
+
24
+ OCWI is the browser-side piece of a three-component system:
25
+
26
+ ```
27
+ ┌─────────────────────────────────────────────────────────┐
28
+ │ Browser │
29
+ │ │
30
+ │ ┌──────────────────────────────────────────────────┐ │
31
+ │ │ OCWI (Web Component — this package) │ │
32
+ │ │ Chat widget embedded into any web page │ │
33
+ │ └───────────────────┬──────────────────────────────┘ │
34
+ └───────────────────────│─────────────────────────────────┘
35
+ │ HTTPS (SSE stream + REST)
36
+
37
+ ┌───────────────────────────────────────────────────────────┐
38
+ │ Luma (Django / DRF backend) │
39
+ │ Agent config, auth, SSE proxy to Dana │
40
+ └───────────────────────┬───────────────────────────────────┘
41
+ │ HTTP (internal network)
42
+
43
+ ┌───────────────────────────────────────────────────────────┐
44
+ │ Dana (FastAPI / Python — AI backend) │
45
+ │ RAG pipeline, LLM integration, SSE streaming │
46
+ └───────────────────────────────────────────────────────────┘
47
+ ```
48
+
49
+ **OCWI** fetches its UI configuration (colors, agent name, language, …) from **Luma** at startup
50
+ and caches it in a cookie for instant subsequent loads. All chat messages are sent to **Luma**,
51
+ which proxies them to **Dana** and streams the AI response back over SSE.
52
+ Dana's URL is never exposed to the browser — Luma acts as the security boundary.
53
+
54
+ ---
55
+
56
+ ## Installation
57
+
58
+ ### CDN (recommended for most use cases)
59
+
60
+ ```html
61
+ <!-- jsDelivr (recommended) -->
62
+ <script src="https://cdn.jsdelivr.net/npm/ocwi/dist/ocwi.min.js"></script>
63
+
64
+ <!-- unpkg (alternative) -->
65
+ <script src="https://unpkg.com/ocwi/dist/ocwi.min.js"></script>
66
+ ```
67
+
68
+ Both CDNs serve the `latest` tag by default. To pin to a specific version:
69
+
70
+ ```html
71
+ <script src="https://cdn.jsdelivr.net/npm/ocwi@0.1.1/dist/ocwi.min.js"></script>
72
+ ```
73
+
74
+ ### npm
75
+
76
+ ```bash
77
+ npm install ocwi
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Quick start
83
+
84
+ ```html
85
+ <script src="https://cdn.jsdelivr.net/npm/ocwi/dist/ocwi.min.js"></script>
86
+ <div id="chat"></div>
87
+ <script>
88
+ const inst = window.OCWI('#chat', {
89
+ api: {
90
+ lumaUrl: 'https://your-luma-server.example.com/public/abc123'
91
+ }
92
+ });
93
+ </script>
94
+ ```
95
+
96
+ Without a `lumaUrl`, the widget starts in **demo mode** using a built-in mock API:
97
+
98
+ ```html
99
+ <script src="https://cdn.jsdelivr.net/npm/ocwi/dist/ocwi.min.js"></script>
100
+ <div id="chat"></div>
101
+ <script>
102
+ window.OCWI('#chat', {
103
+ ui: { name: 'Demo Assistant' },
104
+ theme: { primary: '#0ea5e9' },
105
+ locale: 'cs'
106
+ });
107
+ </script>
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Public API
113
+
114
+ ### `window.OCWI(target?, config?)`
115
+
116
+ Creates an `<ocwi-chat>` element, mounts it into the DOM and applies config.
117
+
118
+ | Parameter | Type | Description |
119
+ | --------- | --------------------------- | ------------------------------------------------------------------- |
120
+ | `target` | `string \| Element \| null` | CSS selector or Element to mount into. Defaults to `document.body`. |
121
+ | `config` | `Partial<OcwiConfig>` | Optional local config (merged last — highest priority). |
122
+
123
+ Returns the `<ocwi-chat>` element instance.
124
+
125
+ ### Instance methods
126
+
127
+ | Method | Description |
128
+ | ----------------------- | ------------------------------------------------------------------------- |
129
+ | `updateConfig(partial)` | Deep-merge partial config; live update (no reload). |
130
+ | `getState()` | Returns current widget state `{ messages, isStreaming, windowState, … }`. |
131
+ | `destroy()` | Cleans up all listeners and removes the element from DOM. |
132
+
133
+ ---
134
+
135
+ ## Configuration
136
+
137
+ ```typescript
138
+ window.OCWI('#chat', {
139
+ api: {
140
+ lumaUrl: 'https://luma.example.com/public/abc123', // Luma public link
141
+ danaUrl: 'https://dana.example.com', // Direct Dana URL (advanced, no proxy)
142
+ timeoutMs: 30000
143
+ },
144
+ locale: 'cs', // Top-level shortcut for i18n.lang
145
+ i18n: {
146
+ lang: 'cs',
147
+ dictionary: {
148
+ cs: { send: 'Odeslat' } // Override individual keys
149
+ }
150
+ },
151
+ theme: {
152
+ primary: '#0ea5e9',
153
+ ocwiWidth: '360px',
154
+ ocwiHeight: '520px',
155
+ ocwiRadius: '16px'
156
+ },
157
+ ui: {
158
+ name: 'Asistent',
159
+ placeholder: 'Napište zprávu…',
160
+ introductionMessage: 'Dobrý den! Jak vám mohu pomoci?',
161
+ position: 'bottom-right',
162
+ initialState: 'collapsed', // 'collapsed' | 'minimized' | 'expanded'
163
+ keybindForSend: 'Enter' // 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Alt+Enter' | 'None'
164
+ },
165
+ features: {
166
+ minimize: true,
167
+ close: true,
168
+ serverStatus: true,
169
+ messageCopy: true,
170
+ messageEdit: true,
171
+ messageRefresh: true,
172
+ sendButton: true,
173
+ stopButton: true,
174
+ placeholder: true
175
+ }
176
+ });
177
+ ```
178
+
179
+ ### `api`
180
+
181
+ | Field | Type | Description |
182
+ | ----------- | -------- | ------------------------------------------------------------------------------------------ |
183
+ | `lumaUrl` | `string` | Luma public link URL. Widget fetches UI config from here and routes all chat through Luma. |
184
+ | `danaUrl` | `string` | Direct Dana endpoint (bypasses Luma proxy — advanced use only). |
185
+ | `timeoutMs` | `number` | HTTP timeout in ms. Default: `30000`. |
186
+
187
+ ### `theme`
188
+
189
+ | Field | CSS variable | Example |
190
+ | ------------------------- | ------------------------------ | ------------ |
191
+ | `primary` | `--ocwi-primary` | `'#0ea5e9'` |
192
+ | `ocwiWidth` | `--ocwi-width` | `'360px'` |
193
+ | `ocwiHeight` | `--ocwi-height` | `'520px'` |
194
+ | `ocwiRadius` | `--ocwi-radius` | `'12px'` |
195
+ | `ocwiSpacing` | `--ocwi-spacing` | `'8px'` |
196
+ | `ocwiBg` | `--ocwi-bg` | `'#ffffff'` |
197
+ | `ocwiHeaderBg` | `--ocwi-header-bg` | `'#f9fafb'` |
198
+ | `ocwiHeaderText` | `--ocwi-header-text` | `'#111111'` |
199
+ | `ocwiBubbleUserBg` | `--ocwi-bubble-user-bg` | `'#2563eb'` |
200
+ | `ocwiBubbleUserText` | `--ocwi-bubble-user-text` | `'#ffffff'` |
201
+ | `ocwiBubbleAssistantBg` | `--ocwi-bubble-assistant-bg` | `'#f3f4f6'` |
202
+ | `ocwiBubbleAssistantText` | `--ocwi-bubble-assistant-text` | `'#1f2937'` |
203
+ | `ocwiInputBg` | `--ocwi-input-bg` | `'#ffffff'` |
204
+ | `ocwiSendBg` | `--ocwi-send-bg` | `'#2563eb'` |
205
+ | `ocwiFabBg` | `--ocwi-fab-bg` | `'#2563eb'` |
206
+ | `ocwiZIndex` | `--ocwi-z-index` | `2147480000` |
207
+ | `ocwiInputRows` | _(textarea rows)_ | `1` |
208
+
209
+ CSS variables can also be set directly on the host element from the outside:
210
+
211
+ ```js
212
+ document.querySelector('ocwi-chat').style.setProperty('--ocwi-primary', '#8b5cf6');
213
+ ```
214
+
215
+ ## HTTP (Dana) API contract
216
+
217
+ When `danaUrl` is configured, the widget POSTs to `<danaUrl>/api/chat`:
218
+
219
+ ```
220
+ POST https://dana.example.com/api/chat
221
+ Content-Type: application/json
222
+
223
+ {
224
+ "prompt": "Hello",
225
+ "conversationId": "c_01j…",
226
+ "clientMessageId": "u_01j…",
227
+ "rewriteFromMessageId": "u_01j…" // only on edit / refresh
228
+ }
229
+ ```
230
+
231
+ The response is an SSE stream. The widget reads chunks and accumulates them as the assistant message text. Dana signals errors via structured SSE events:
232
+
233
+ ```
234
+ data: {"error": "DANA_LLM_UNAVAILABLE"}\n\n
235
+ data: {"error": "DANA_LLM_AUTH"}\n\n
236
+ data: {"error": "DANA_LLM_TIMEOUT"}\n\n
237
+ data: {"error": "DANA_INTERNAL"}\n\n
238
+ ```
239
+
240
+ OCWI detects these events, aborts the stream, and displays a localised error message in the chat.
241
+
242
+ **In production, all traffic goes through Luma** — the `danaUrl` field is for advanced / self-hosted setups where you contact Dana directly.
243
+
244
+ ---
245
+
246
+ ## i18n
247
+
248
+ Built-in languages: `en` (default), `cs`, `de`.
249
+
250
+ ```js
251
+ window.OCWI('#chat', {
252
+ locale: 'cs',
253
+ i18n: {
254
+ dictionary: {
255
+ cs: { send: 'Pošli' } // override individual keys
256
+ }
257
+ }
258
+ });
259
+ ```
260
+
261
+ To add a new language entirely:
262
+
263
+ ```js
264
+ window.OCWI('#chat', {
265
+ locale: 'sk',
266
+ i18n: {
267
+ lang: 'sk',
268
+ dictionary: {
269
+ sk: {
270
+ send: 'Odoslať',
271
+ stop: 'Zastaviť'
272
+ // … add all keys (falls back to 'en' for missing ones)
273
+ }
274
+ }
275
+ }
276
+ });
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Accessibility
282
+
283
+ - Widget container has `role="region"` and `aria-label` with the agent name
284
+ - Textarea has `aria-label` (uses placeholder text)
285
+ - All icon buttons have `aria-label`
286
+ - Send button is focusable and keyboard-operable
287
+ - `Enter` submits (configurable), `Escape` clears the input
288
+
289
+ ---
290
+
291
+ ## Development
292
+
293
+ ```bash
294
+ npm install # install deps
295
+ npm run build # → dist/ocwi.min.js
296
+ npm run dev # watch mode
297
+ npm run lint # ESLint
298
+ npm run format # Prettier
299
+ ```
300
+
301
+ ---
302
+
303
+ ## License
304
+
305
+ OCWI is distributed under the [OCWI Sustainable Use License](LICENSE.md).
306
+ Source available. Free for personal, non-commercial, and internal business use.
307
+ Commercial redistribution or selling the widget as a standalone product requires a separate agreement.