@mitverse/mitbar-web 1.0.0

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/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # mitbar-web
2
+
3
+ **mitbar-web** is the browser bar (Node/npm package) you add to any website. It is always visible when enabled via frontend config and communicates with **mitbar-gateway** (Docker). The stack has two parts: **mitbar-web** (this package) and **mitbar-gateway** (WebSocket + HTTP server in Docker). Every message includes the **page address and title**. The UI includes **Build** and **Deploy** options.
4
+
5
+ ## Requirements
6
+
7
+ - **mitbar-gateway** running (Docker: `docker compose up -d mitbar-gateway`). See `../mitbar-gateway`.
8
+ - Optionally **script-writer** if the gateway forwards to it.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install mitbar-web
14
+ # or from repo
15
+ cd mitbar-web && npm run build
16
+ ```
17
+
18
+ ## Add to any website
19
+
20
+ ### 1. Frontend config (enable + gateway URL)
21
+
22
+ Either set a global config before loading the script, or use data attributes on the script tag.
23
+
24
+ **Option A – global config**
25
+
26
+ ```html
27
+ <script>
28
+ window.__MITBAR_CONFIG__ = {
29
+ enabled: true,
30
+ gatewayWsUrl: 'wss://barway.mitverse.com/ws' // default; omit to use this
31
+ };
32
+ </script>
33
+ <script src="https://your-cdn.com/mitbar-web/dist/mitbar.umd.cjs"></script>
34
+ ```
35
+
36
+ **Option B – data attributes**
37
+
38
+ ```html
39
+ <script
40
+ src="https://your-cdn.com/mitbar-web/dist/mitbar.umd.cjs"
41
+ data-mitbar-enabled="true"
42
+ data-mitbar-gateway-ws-url="wss://barway.mitverse.com/ws"
43
+ ></script>
44
+ ```
45
+
46
+ ### 2. ESM (e.g. Vite / React app)
47
+
48
+ ```ts
49
+ import { init } from 'mitbar-web';
50
+ init({
51
+ enabled: true,
52
+ gatewayWsUrl: 'wss://barway.mitverse.com/ws', // default when omitted
53
+ });
54
+ ```
55
+
56
+ ## Environment variables (MITBAR_ prefix)
57
+
58
+ Used by **mitbar-gateway** (see `../mitbar-gateway`). The browser bundle only uses the config above; optional build-time default:
59
+
60
+ | Variable | Description |
61
+ |----------|-------------|
62
+ | `MITBAR_GATEWAY_WS_URL` | Default WebSocket URL for the bar (optional; usually set per-site in frontend config). |
63
+
64
+ ## Message format
65
+
66
+ - The bar sends over WebSocket: `{ text, pageUrl, pageTitle, action: 'chat' | 'build' | 'deploy' }`.
67
+ - The gateway appends page context to the query and forwards to script-writer `POST /query`.
68
+ - script-writer handles the request and the gateway streams the response back to the bar.
69
+
70
+ ## Build
71
+
72
+ ```bash
73
+ npm run build
74
+ ```
75
+
76
+ Outputs in `dist/`:
77
+
78
+ - `mitbar.es.js` – ESM
79
+ - `mitbar.umd.cjs` – UMD (script tag / unpkg)
80
+
81
+ ## Deploy
82
+
83
+ Build and serve `dist/` from your CDN or static host. When `gatewayWsUrl` is not set, the bar uses **wss://barway.mitverse.com/ws**. Ensure the gateway is reachable (same origin or CORS/WS allowed).
package/dist/bar.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { MessageHandler } from './ws-client';
2
+
3
+ type WsClient = {
4
+ send: (payload: {
5
+ text: string;
6
+ pageUrl?: string;
7
+ pageTitle?: string;
8
+ action?: 'chat' | 'build' | 'deploy';
9
+ }) => void;
10
+ onMessage: (handler: MessageHandler) => () => void;
11
+ };
12
+ export declare function createBar(client: WsClient): void;
13
+ export {};
@@ -0,0 +1,19 @@
1
+ import { createBar } from './bar';
2
+ import { createWsClient } from './ws-client';
3
+
4
+ export interface MitbarConfig {
5
+ /** Show the bar. When false, bar is not rendered. */
6
+ enabled?: boolean;
7
+ /** WebSocket URL of mitbar-gateway. Defaults to wss://barway.mitverse.com/ws when not set. */
8
+ gatewayWsUrl?: string;
9
+ }
10
+ declare global {
11
+ interface Window {
12
+ __MITBAR_CONFIG__?: MitbarConfig;
13
+ }
14
+ }
15
+ /**
16
+ * Initialize and mount the bar. Call once after DOM ready (or use auto-init from script tag).
17
+ */
18
+ export declare function init(configOverride?: Partial<MitbarConfig>): void;
19
+ export { createBar, createWsClient };
@@ -0,0 +1,208 @@
1
+ const w = `
2
+ .mitbar-root {
3
+ position: fixed;
4
+ bottom: 0;
5
+ left: 0;
6
+ right: 0;
7
+ z-index: 2147483647;
8
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
9
+ font-size: 14px;
10
+ background: #1e293b;
11
+ color: #e2e8f0;
12
+ box-shadow: 0 -2px 10px rgba(0,0,0,0.2);
13
+ border-top: 1px solid #334155;
14
+ }
15
+ .mitbar-inner {
16
+ max-width: 100%;
17
+ padding: 8px 12px;
18
+ display: flex;
19
+ flex-wrap: wrap;
20
+ align-items: center;
21
+ gap: 8px;
22
+ }
23
+ .mitbar-input-wrap {
24
+ flex: 1;
25
+ min-width: 120px;
26
+ }
27
+ .mitbar-input {
28
+ width: 100%;
29
+ box-sizing: border-box;
30
+ padding: 6px 10px;
31
+ border: 1px solid #475569;
32
+ border-radius: 6px;
33
+ background: #0f172a;
34
+ color: #e2e8f0;
35
+ font: inherit;
36
+ }
37
+ .mitbar-input::placeholder { color: #94a3b8; }
38
+ .mitbar-input:focus {
39
+ outline: none;
40
+ border-color: #3b82f6;
41
+ }
42
+ .mitbar-btns {
43
+ display: flex;
44
+ gap: 6px;
45
+ flex-wrap: wrap;
46
+ }
47
+ .mitbar-btn {
48
+ padding: 6px 12px;
49
+ border: none;
50
+ border-radius: 6px;
51
+ font: inherit;
52
+ cursor: pointer;
53
+ background: #334155;
54
+ color: #e2e8f0;
55
+ }
56
+ .mitbar-btn:hover { background: #475569; }
57
+ .mitbar-btn--primary { background: #3b82f6; color: #fff; }
58
+ .mitbar-btn--primary:hover { background: #2563eb; }
59
+ .mitbar-btn--deploy { background: #059669; color: #fff; }
60
+ .mitbar-btn--deploy:hover { background: #047857; }
61
+ .mitbar-status {
62
+ font-size: 12px;
63
+ color: #94a3b8;
64
+ margin-left: auto;
65
+ }
66
+ .mitbar-reply {
67
+ width: 100%;
68
+ max-height: 120px;
69
+ overflow-y: auto;
70
+ padding: 8px 12px;
71
+ margin-top: 4px;
72
+ background: #0f172a;
73
+ border-radius: 6px;
74
+ border: 1px solid #334155;
75
+ font-size: 13px;
76
+ white-space: pre-wrap;
77
+ word-break: break-word;
78
+ }
79
+ .mitbar-reply--error { border-color: #dc2626; color: #fca5a5; }
80
+ .mitbar-reply:empty { display: none; }
81
+ `;
82
+ function h(d) {
83
+ if (typeof document > "u") return;
84
+ const e = document.createElement("style");
85
+ e.textContent = w, document.head.appendChild(e);
86
+ const n = document.createElement("div");
87
+ n.className = "mitbar-root", n.setAttribute("aria-label", "Mitbar");
88
+ const o = document.createElement("div");
89
+ o.className = "mitbar-inner";
90
+ const u = document.createElement("div");
91
+ u.className = "mitbar-input-wrap";
92
+ const c = document.createElement("input");
93
+ c.className = "mitbar-input", c.type = "text", c.placeholder = "Message for script-writer (page URL is sent automatically)…", c.setAttribute("aria-label", "Message"), u.appendChild(c);
94
+ const s = document.createElement("span");
95
+ s.className = "mitbar-status", s.textContent = "Connecting…";
96
+ const a = document.createElement("button");
97
+ a.className = "mitbar-btn mitbar-btn--primary", a.textContent = "Send", a.type = "button";
98
+ const b = document.createElement("button");
99
+ b.className = "mitbar-btn", b.textContent = "Build", b.type = "button";
100
+ const m = document.createElement("button");
101
+ m.className = "mitbar-btn mitbar-btn--deploy", m.textContent = "Deploy", m.type = "button";
102
+ const f = document.createElement("div");
103
+ f.className = "mitbar-reply", f.setAttribute("aria-live", "polite");
104
+ const t = document.createElement("div");
105
+ t.className = "mitbar-btns", t.append(a, b, m), o.append(u, t, s), n.appendChild(o), n.appendChild(f), document.body.appendChild(n);
106
+ const i = (r) => {
107
+ s.textContent = r;
108
+ }, p = (r, y) => {
109
+ f.textContent = r, f.classList.toggle("mitbar-reply--error", !!y);
110
+ };
111
+ d.onMessage((r) => {
112
+ r.type === "connected" ? i("Connected") : r.type === "disconnected" ? i("Disconnected") : r.type === "error" ? (i("Error"), p(r.error || "Error", !0)) : r.type === "output" && r.text && p(r.text, !1);
113
+ });
114
+ const l = (r) => {
115
+ const y = c.value.trim();
116
+ if (r === "chat" && !y) return;
117
+ const x = r === "chat" ? y : y || `Please ${r} the current project.`;
118
+ d.send({ text: x, action: r }), r === "chat" && (c.value = ""), p("Waiting for response…");
119
+ };
120
+ a.addEventListener("click", () => l("chat")), b.addEventListener("click", () => l("build")), m.addEventListener("click", () => l("deploy")), c.addEventListener("keydown", (r) => {
121
+ r.key === "Enter" && !r.shiftKey && (r.preventDefault(), l("chat"));
122
+ });
123
+ }
124
+ function E(d) {
125
+ let e = null, n = null;
126
+ const o = [], u = 3e3;
127
+ function c() {
128
+ return typeof window > "u" ? { pageUrl: "", pageTitle: "" } : {
129
+ pageUrl: window.location.href,
130
+ pageTitle: document.title || window.location.pathname || ""
131
+ };
132
+ }
133
+ function s() {
134
+ if (typeof WebSocket > "u") return null;
135
+ try {
136
+ const t = new WebSocket(d);
137
+ return t.onopen = () => {
138
+ a({ type: "connected" });
139
+ }, t.onmessage = (i) => {
140
+ try {
141
+ const p = JSON.parse(i.data);
142
+ a(p);
143
+ } catch {
144
+ a({ type: "output", text: String(i.data) });
145
+ }
146
+ }, t.onclose = () => {
147
+ a({ type: "disconnected" }), e = null, n = setTimeout(() => s(), u);
148
+ }, t.onerror = () => {
149
+ a({ type: "error", error: "WebSocket error" });
150
+ }, e = t, t;
151
+ } catch (t) {
152
+ return a({ type: "error", error: String(t) }), null;
153
+ }
154
+ }
155
+ function a(t) {
156
+ o.forEach((i) => {
157
+ try {
158
+ i(t);
159
+ } catch {
160
+ }
161
+ });
162
+ }
163
+ function b(t) {
164
+ const { pageUrl: i, pageTitle: p } = c(), l = {
165
+ text: (t.text || "").trim(),
166
+ pageUrl: t.pageUrl ?? i,
167
+ pageTitle: t.pageTitle ?? p,
168
+ action: t.action || "chat"
169
+ };
170
+ !l.text && l.action === "chat" || ((e == null ? void 0 : e.readyState) === WebSocket.OPEN ? e.send(JSON.stringify(l)) : (a({ type: "error", error: "Not connected. Reconnecting…" }), s(), (e == null ? void 0 : e.readyState) === WebSocket.OPEN && e.send(JSON.stringify(l))));
171
+ }
172
+ function m(t) {
173
+ return o.push(t), () => {
174
+ const i = o.indexOf(t);
175
+ i >= 0 && o.splice(i, 1);
176
+ };
177
+ }
178
+ function f() {
179
+ n && (clearTimeout(n), n = null), e && (e.close(), e = null);
180
+ }
181
+ return s(), { send: b, onMessage: m, connect: s, disconnect: f, getPageContext: c };
182
+ }
183
+ const S = "/ws", k = "wss://barway.mitverse.com/ws";
184
+ function v() {
185
+ const d = typeof window < "u" ? window : void 0;
186
+ if (!d) return {};
187
+ const e = d.__MITBAR_CONFIG__ || {}, n = document.currentScript, o = n ? {
188
+ enabled: n.getAttribute("data-mitbar-enabled") === "true" || n.getAttribute("data-mitbar-enabled") === "1",
189
+ gatewayWsUrl: n.getAttribute("data-mitbar-gateway-ws-url") || void 0
190
+ } : {};
191
+ return {
192
+ enabled: e.enabled ?? o.enabled ?? !1,
193
+ gatewayWsUrl: e.gatewayWsUrl ?? o.gatewayWsUrl ?? void 0
194
+ };
195
+ }
196
+ function g(d) {
197
+ const e = { ...v(), ...d };
198
+ if (!e.enabled) return;
199
+ const n = (e.gatewayWsUrl || "").trim() || k, o = n.includes("/") && !n.includes("?") && !n.endsWith("/") ? n : n.replace(/\/?$/, "") + S, u = E(o);
200
+ h(u);
201
+ }
202
+ typeof document < "u" && document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => g()) : typeof document < "u" && g();
203
+ export {
204
+ h as createBar,
205
+ E as createWsClient,
206
+ g as init
207
+ };
208
+ //# sourceMappingURL=mitbar.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mitbar.es.js","sources":["../src/bar.ts","../src/ws-client.ts","../src/index.ts"],"sourcesContent":["/**\n * Mitbar UI: fixed bar at bottom with input, Send, Build, Deploy, and reply area.\n */\n\nimport type { MessageHandler } from './ws-client';\n\ntype WsClient = {\n send: (payload: { text: string; pageUrl?: string; pageTitle?: string; action?: 'chat' | 'build' | 'deploy' }) => void;\n onMessage: (handler: MessageHandler) => () => void;\n};\n\nconst CSS = `\n.mitbar-root {\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 2147483647;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;\n font-size: 14px;\n background: #1e293b;\n color: #e2e8f0;\n box-shadow: 0 -2px 10px rgba(0,0,0,0.2);\n border-top: 1px solid #334155;\n}\n.mitbar-inner {\n max-width: 100%;\n padding: 8px 12px;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.mitbar-input-wrap {\n flex: 1;\n min-width: 120px;\n}\n.mitbar-input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 10px;\n border: 1px solid #475569;\n border-radius: 6px;\n background: #0f172a;\n color: #e2e8f0;\n font: inherit;\n}\n.mitbar-input::placeholder { color: #94a3b8; }\n.mitbar-input:focus {\n outline: none;\n border-color: #3b82f6;\n}\n.mitbar-btns {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n.mitbar-btn {\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n font: inherit;\n cursor: pointer;\n background: #334155;\n color: #e2e8f0;\n}\n.mitbar-btn:hover { background: #475569; }\n.mitbar-btn--primary { background: #3b82f6; color: #fff; }\n.mitbar-btn--primary:hover { background: #2563eb; }\n.mitbar-btn--deploy { background: #059669; color: #fff; }\n.mitbar-btn--deploy:hover { background: #047857; }\n.mitbar-status {\n font-size: 12px;\n color: #94a3b8;\n margin-left: auto;\n}\n.mitbar-reply {\n width: 100%;\n max-height: 120px;\n overflow-y: auto;\n padding: 8px 12px;\n margin-top: 4px;\n background: #0f172a;\n border-radius: 6px;\n border: 1px solid #334155;\n font-size: 13px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n.mitbar-reply--error { border-color: #dc2626; color: #fca5a5; }\n.mitbar-reply:empty { display: none; }\n`;\n\nexport function createBar(client: WsClient): void {\n if (typeof document === 'undefined') return;\n const style = document.createElement('style');\n style.textContent = CSS;\n document.head.appendChild(style);\n\n const root = document.createElement('div');\n root.className = 'mitbar-root';\n root.setAttribute('aria-label', 'Mitbar');\n\n const inner = document.createElement('div');\n inner.className = 'mitbar-inner';\n\n const inputWrap = document.createElement('div');\n inputWrap.className = 'mitbar-input-wrap';\n const input = document.createElement('input');\n input.className = 'mitbar-input';\n input.type = 'text';\n input.placeholder = 'Message for script-writer (page URL is sent automatically)…';\n input.setAttribute('aria-label', 'Message');\n inputWrap.appendChild(input);\n\n const status = document.createElement('span');\n status.className = 'mitbar-status';\n status.textContent = 'Connecting…';\n\n const btnSend = document.createElement('button');\n btnSend.className = 'mitbar-btn mitbar-btn--primary';\n btnSend.textContent = 'Send';\n btnSend.type = 'button';\n\n const btnBuild = document.createElement('button');\n btnBuild.className = 'mitbar-btn';\n btnBuild.textContent = 'Build';\n btnBuild.type = 'button';\n\n const btnDeploy = document.createElement('button');\n btnDeploy.className = 'mitbar-btn mitbar-btn--deploy';\n btnDeploy.textContent = 'Deploy';\n btnDeploy.type = 'button';\n\n const replyDiv = document.createElement('div');\n replyDiv.className = 'mitbar-reply';\n replyDiv.setAttribute('aria-live', 'polite');\n\n const btns = document.createElement('div');\n btns.className = 'mitbar-btns';\n btns.append(btnSend, btnBuild, btnDeploy);\n\n inner.append(inputWrap, btns, status);\n root.appendChild(inner);\n root.appendChild(replyDiv);\n document.body.appendChild(root);\n\n const setStatus = (text: string) => {\n status.textContent = text;\n };\n const setReply = (text: string, isError?: boolean) => {\n replyDiv.textContent = text;\n replyDiv.classList.toggle('mitbar-reply--error', !!isError);\n };\n\n client.onMessage((msg) => {\n if (msg.type === 'connected') setStatus('Connected');\n else if (msg.type === 'disconnected') setStatus('Disconnected');\n else if (msg.type === 'error') {\n setStatus('Error');\n setReply(msg.error || 'Error', true);\n } else if (msg.type === 'output' && msg.text) {\n setReply(msg.text, false);\n }\n });\n\n const send = (action: 'chat' | 'build' | 'deploy') => {\n const text = input.value.trim();\n if (action === 'chat' && !text) return;\n const payload = action === 'chat' ? text : (text || `Please ${action} the current project.`);\n client.send({ text: payload, action });\n if (action === 'chat') input.value = '';\n setReply('Waiting for response…');\n };\n\n btnSend.addEventListener('click', () => send('chat'));\n btnBuild.addEventListener('click', () => send('build'));\n btnDeploy.addEventListener('click', () => send('deploy'));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send('chat');\n }\n });\n}\n","/**\n * WebSocket client: sends { text, pageUrl, pageTitle } and receives { type, text? } from mitbar-gateway.\n */\n\nexport interface SendPayload {\n text: string;\n pageUrl?: string;\n pageTitle?: string;\n /** Optional: /build or /deploy for special actions */\n action?: 'chat' | 'build' | 'deploy';\n}\n\nexport interface IncomingMessage {\n type: string;\n text?: string;\n error?: string;\n}\n\nexport type MessageHandler = (msg: IncomingMessage) => void;\n\nexport function createWsClient(gatewayWsUrl: string) {\n let ws: WebSocket | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n const listeners: MessageHandler[] = [];\n const RECONNECT_MS = 3000;\n\n function getPageContext(): { pageUrl: string; pageTitle: string } {\n if (typeof window === 'undefined') return { pageUrl: '', pageTitle: '' };\n return {\n pageUrl: window.location.href,\n pageTitle: document.title || window.location.pathname || '',\n };\n }\n\n function connect(): WebSocket | null {\n if (typeof WebSocket === 'undefined') return null;\n try {\n const socket = new WebSocket(gatewayWsUrl);\n socket.onopen = () => {\n notify({ type: 'connected' });\n };\n socket.onmessage = (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data as string) as IncomingMessage;\n notify(data);\n } catch {\n notify({ type: 'output', text: String(event.data) });\n }\n };\n socket.onclose = () => {\n notify({ type: 'disconnected' });\n ws = null;\n reconnectTimer = setTimeout(() => connect(), RECONNECT_MS);\n };\n socket.onerror = () => {\n notify({ type: 'error', error: 'WebSocket error' });\n };\n ws = socket;\n return socket;\n } catch (e) {\n notify({ type: 'error', error: String(e) });\n return null;\n }\n }\n\n function notify(msg: IncomingMessage) {\n listeners.forEach((h) => {\n try {\n h(msg);\n } catch (_) {}\n });\n }\n\n function send(payload: SendPayload): void {\n const { pageUrl, pageTitle } = getPageContext();\n const body = {\n text: (payload.text || '').trim(),\n pageUrl: payload.pageUrl ?? pageUrl,\n pageTitle: payload.pageTitle ?? pageTitle,\n action: payload.action || 'chat',\n };\n if (!body.text && body.action === 'chat') return;\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(body));\n } else {\n notify({ type: 'error', error: 'Not connected. Reconnecting…' });\n connect();\n if (ws?.readyState === WebSocket.OPEN) ws.send(JSON.stringify(body));\n }\n }\n\n function onMessage(handler: MessageHandler): () => void {\n listeners.push(handler);\n return () => {\n const i = listeners.indexOf(handler);\n if (i >= 0) listeners.splice(i, 1);\n };\n }\n\n function disconnect(): void {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (ws) {\n ws.close();\n ws = null;\n }\n }\n\n connect();\n return { send, onMessage, connect, disconnect, getPageContext };\n}\n","/**\n * Mitbar – browser bar that talks to script-writer Docker agent via WebSocket gateway.\n * Add to any website; visibility and gateway URL are set via frontend config.\n * Every message includes the current page address and link.\n *\n * Config (one of):\n * - window.__MITBAR_CONFIG__ = { enabled: true, gatewayWsUrl: 'wss://...' }\n * - <script src=\"mitbar.js\" data-mitbar-enabled=\"true\" data-mitbar-gateway-ws-url=\"wss://...\"></script>\n *\n * When gatewayWsUrl is not set, defaults to wss://barway.mitverse.com/ws.\n * Build-time override: MITBAR_GATEWAY_WS_URL\n */\n\nimport { createBar } from './bar';\nimport { createWsClient } from './ws-client';\n\nexport interface MitbarConfig {\n /** Show the bar. When false, bar is not rendered. */\n enabled?: boolean;\n /** WebSocket URL of mitbar-gateway. Defaults to wss://barway.mitverse.com/ws when not set. */\n gatewayWsUrl?: string;\n}\n\ndeclare global {\n interface Window {\n __MITBAR_CONFIG__?: MitbarConfig;\n }\n}\n\nconst DEFAULT_WS_PATH = '/ws';\n/** Default gateway when none is configured (production Barway endpoint). */\nconst DEFAULT_GATEWAY_WS_URL = 'wss://barway.mitverse.com/ws';\n\nfunction getConfig(): MitbarConfig {\n const win = typeof window !== 'undefined' ? window : undefined;\n if (!win) return {};\n const fromWindow = win.__MITBAR_CONFIG__ || {};\n const script = document.currentScript as HTMLScriptElement | null;\n const fromData = script\n ? {\n enabled: script.getAttribute('data-mitbar-enabled') === 'true' || script.getAttribute('data-mitbar-enabled') === '1',\n gatewayWsUrl: script.getAttribute('data-mitbar-gateway-ws-url') || undefined,\n }\n : {};\n return {\n enabled: fromWindow.enabled ?? fromData.enabled ?? false,\n gatewayWsUrl: fromWindow.gatewayWsUrl ?? fromData.gatewayWsUrl ?? undefined,\n };\n}\n\n/**\n * Initialize and mount the bar. Call once after DOM ready (or use auto-init from script tag).\n */\nexport function init(configOverride?: Partial<MitbarConfig>): void {\n const config = { ...getConfig(), ...configOverride };\n if (!config.enabled) return;\n const gatewayWsUrl = (config.gatewayWsUrl || '').trim() || DEFAULT_GATEWAY_WS_URL;\n const wsUrl = gatewayWsUrl.includes('/') && !gatewayWsUrl.includes('?') && !gatewayWsUrl.endsWith('/')\n ? gatewayWsUrl\n : gatewayWsUrl.replace(/\\/?$/, '') + DEFAULT_WS_PATH;\n const client = createWsClient(wsUrl);\n createBar(client);\n}\n\nif (typeof document !== 'undefined' && document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => init());\n} else if (typeof document !== 'undefined') {\n init();\n}\n\nexport { createBar, createWsClient };\n"],"names":["CSS","createBar","client","style","root","inner","inputWrap","input","status","btnSend","btnBuild","btnDeploy","replyDiv","btns","setStatus","text","setReply","isError","msg","send","action","payload","e","createWsClient","gatewayWsUrl","ws","reconnectTimer","listeners","RECONNECT_MS","getPageContext","connect","socket","notify","event","data","h","pageUrl","pageTitle","body","onMessage","handler","disconnect","DEFAULT_WS_PATH","DEFAULT_GATEWAY_WS_URL","getConfig","win","fromWindow","script","fromData","init","configOverride","config","wsUrl"],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ (function(p,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(p=typeof globalThis<"u"?globalThis:p||self,g(p.Mitbar={}))})(this,function(p){"use strict";const g=`
2
+ .mitbar-root {
3
+ position: fixed;
4
+ bottom: 0;
5
+ left: 0;
6
+ right: 0;
7
+ z-index: 2147483647;
8
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
9
+ font-size: 14px;
10
+ background: #1e293b;
11
+ color: #e2e8f0;
12
+ box-shadow: 0 -2px 10px rgba(0,0,0,0.2);
13
+ border-top: 1px solid #334155;
14
+ }
15
+ .mitbar-inner {
16
+ max-width: 100%;
17
+ padding: 8px 12px;
18
+ display: flex;
19
+ flex-wrap: wrap;
20
+ align-items: center;
21
+ gap: 8px;
22
+ }
23
+ .mitbar-input-wrap {
24
+ flex: 1;
25
+ min-width: 120px;
26
+ }
27
+ .mitbar-input {
28
+ width: 100%;
29
+ box-sizing: border-box;
30
+ padding: 6px 10px;
31
+ border: 1px solid #475569;
32
+ border-radius: 6px;
33
+ background: #0f172a;
34
+ color: #e2e8f0;
35
+ font: inherit;
36
+ }
37
+ .mitbar-input::placeholder { color: #94a3b8; }
38
+ .mitbar-input:focus {
39
+ outline: none;
40
+ border-color: #3b82f6;
41
+ }
42
+ .mitbar-btns {
43
+ display: flex;
44
+ gap: 6px;
45
+ flex-wrap: wrap;
46
+ }
47
+ .mitbar-btn {
48
+ padding: 6px 12px;
49
+ border: none;
50
+ border-radius: 6px;
51
+ font: inherit;
52
+ cursor: pointer;
53
+ background: #334155;
54
+ color: #e2e8f0;
55
+ }
56
+ .mitbar-btn:hover { background: #475569; }
57
+ .mitbar-btn--primary { background: #3b82f6; color: #fff; }
58
+ .mitbar-btn--primary:hover { background: #2563eb; }
59
+ .mitbar-btn--deploy { background: #059669; color: #fff; }
60
+ .mitbar-btn--deploy:hover { background: #047857; }
61
+ .mitbar-status {
62
+ font-size: 12px;
63
+ color: #94a3b8;
64
+ margin-left: auto;
65
+ }
66
+ .mitbar-reply {
67
+ width: 100%;
68
+ max-height: 120px;
69
+ overflow-y: auto;
70
+ padding: 8px 12px;
71
+ margin-top: 4px;
72
+ background: #0f172a;
73
+ border-radius: 6px;
74
+ border: 1px solid #334155;
75
+ font-size: 13px;
76
+ white-space: pre-wrap;
77
+ word-break: break-word;
78
+ }
79
+ .mitbar-reply--error { border-color: #dc2626; color: #fca5a5; }
80
+ .mitbar-reply:empty { display: none; }
81
+ `;function w(d){if(typeof document>"u")return;const e=document.createElement("style");e.textContent=g,document.head.appendChild(e);const n=document.createElement("div");n.className="mitbar-root",n.setAttribute("aria-label","Mitbar");const o=document.createElement("div");o.className="mitbar-inner";const b=document.createElement("div");b.className="mitbar-input-wrap";const c=document.createElement("input");c.className="mitbar-input",c.type="text",c.placeholder="Message for script-writer (page URL is sent automatically)…",c.setAttribute("aria-label","Message"),b.appendChild(c);const s=document.createElement("span");s.className="mitbar-status",s.textContent="Connecting…";const a=document.createElement("button");a.className="mitbar-btn mitbar-btn--primary",a.textContent="Send",a.type="button";const f=document.createElement("button");f.className="mitbar-btn",f.textContent="Build",f.type="button";const m=document.createElement("button");m.className="mitbar-btn mitbar-btn--deploy",m.textContent="Deploy",m.type="button";const y=document.createElement("div");y.className="mitbar-reply",y.setAttribute("aria-live","polite");const t=document.createElement("div");t.className="mitbar-btns",t.append(a,f,m),o.append(b,t,s),n.appendChild(o),n.appendChild(y),document.body.appendChild(n);const i=r=>{s.textContent=r},u=(r,x)=>{y.textContent=r,y.classList.toggle("mitbar-reply--error",!!x)};d.onMessage(r=>{r.type==="connected"?i("Connected"):r.type==="disconnected"?i("Disconnected"):r.type==="error"?(i("Error"),u(r.error||"Error",!0)):r.type==="output"&&r.text&&u(r.text,!1)});const l=r=>{const x=c.value.trim();if(r==="chat"&&!x)return;const k=r==="chat"?x:x||`Please ${r} the current project.`;d.send({text:k,action:r}),r==="chat"&&(c.value=""),u("Waiting for response…")};a.addEventListener("click",()=>l("chat")),f.addEventListener("click",()=>l("build")),m.addEventListener("click",()=>l("deploy")),c.addEventListener("keydown",r=>{r.key==="Enter"&&!r.shiftKey&&(r.preventDefault(),l("chat"))})}function E(d){let e=null,n=null;const o=[],b=3e3;function c(){return typeof window>"u"?{pageUrl:"",pageTitle:""}:{pageUrl:window.location.href,pageTitle:document.title||window.location.pathname||""}}function s(){if(typeof WebSocket>"u")return null;try{const t=new WebSocket(d);return t.onopen=()=>{a({type:"connected"})},t.onmessage=i=>{try{const u=JSON.parse(i.data);a(u)}catch{a({type:"output",text:String(i.data)})}},t.onclose=()=>{a({type:"disconnected"}),e=null,n=setTimeout(()=>s(),b)},t.onerror=()=>{a({type:"error",error:"WebSocket error"})},e=t,t}catch(t){return a({type:"error",error:String(t)}),null}}function a(t){o.forEach(i=>{try{i(t)}catch{}})}function f(t){const{pageUrl:i,pageTitle:u}=c(),l={text:(t.text||"").trim(),pageUrl:t.pageUrl??i,pageTitle:t.pageTitle??u,action:t.action||"chat"};!l.text&&l.action==="chat"||((e==null?void 0:e.readyState)===WebSocket.OPEN?e.send(JSON.stringify(l)):(a({type:"error",error:"Not connected. Reconnecting…"}),s(),(e==null?void 0:e.readyState)===WebSocket.OPEN&&e.send(JSON.stringify(l))))}function m(t){return o.push(t),()=>{const i=o.indexOf(t);i>=0&&o.splice(i,1)}}function y(){n&&(clearTimeout(n),n=null),e&&(e.close(),e=null)}return s(),{send:f,onMessage:m,connect:s,disconnect:y,getPageContext:c}}const S="/ws",v="wss://barway.mitverse.com/ws";function C(){const d=typeof window<"u"?window:void 0;if(!d)return{};const e=d.__MITBAR_CONFIG__||{},n=document.currentScript,o=n?{enabled:n.getAttribute("data-mitbar-enabled")==="true"||n.getAttribute("data-mitbar-enabled")==="1",gatewayWsUrl:n.getAttribute("data-mitbar-gateway-ws-url")||void 0}:{};return{enabled:e.enabled??o.enabled??!1,gatewayWsUrl:e.gatewayWsUrl??o.gatewayWsUrl??void 0}}function h(d){const e={...C(),...d};if(!e.enabled)return;const n=(e.gatewayWsUrl||"").trim()||v,o=n.includes("/")&&!n.includes("?")&&!n.endsWith("/")?n:n.replace(/\/?$/,"")+S,b=E(o);w(b)}typeof document<"u"&&document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>h()):typeof document<"u"&&h(),p.createBar=w,p.createWsClient=E,p.init=h,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
82
+ //# sourceMappingURL=mitbar.umd.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mitbar.umd.cjs","sources":["../src/bar.ts","../src/ws-client.ts","../src/index.ts"],"sourcesContent":["/**\n * Mitbar UI: fixed bar at bottom with input, Send, Build, Deploy, and reply area.\n */\n\nimport type { MessageHandler } from './ws-client';\n\ntype WsClient = {\n send: (payload: { text: string; pageUrl?: string; pageTitle?: string; action?: 'chat' | 'build' | 'deploy' }) => void;\n onMessage: (handler: MessageHandler) => () => void;\n};\n\nconst CSS = `\n.mitbar-root {\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 2147483647;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;\n font-size: 14px;\n background: #1e293b;\n color: #e2e8f0;\n box-shadow: 0 -2px 10px rgba(0,0,0,0.2);\n border-top: 1px solid #334155;\n}\n.mitbar-inner {\n max-width: 100%;\n padding: 8px 12px;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.mitbar-input-wrap {\n flex: 1;\n min-width: 120px;\n}\n.mitbar-input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 10px;\n border: 1px solid #475569;\n border-radius: 6px;\n background: #0f172a;\n color: #e2e8f0;\n font: inherit;\n}\n.mitbar-input::placeholder { color: #94a3b8; }\n.mitbar-input:focus {\n outline: none;\n border-color: #3b82f6;\n}\n.mitbar-btns {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n.mitbar-btn {\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n font: inherit;\n cursor: pointer;\n background: #334155;\n color: #e2e8f0;\n}\n.mitbar-btn:hover { background: #475569; }\n.mitbar-btn--primary { background: #3b82f6; color: #fff; }\n.mitbar-btn--primary:hover { background: #2563eb; }\n.mitbar-btn--deploy { background: #059669; color: #fff; }\n.mitbar-btn--deploy:hover { background: #047857; }\n.mitbar-status {\n font-size: 12px;\n color: #94a3b8;\n margin-left: auto;\n}\n.mitbar-reply {\n width: 100%;\n max-height: 120px;\n overflow-y: auto;\n padding: 8px 12px;\n margin-top: 4px;\n background: #0f172a;\n border-radius: 6px;\n border: 1px solid #334155;\n font-size: 13px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n.mitbar-reply--error { border-color: #dc2626; color: #fca5a5; }\n.mitbar-reply:empty { display: none; }\n`;\n\nexport function createBar(client: WsClient): void {\n if (typeof document === 'undefined') return;\n const style = document.createElement('style');\n style.textContent = CSS;\n document.head.appendChild(style);\n\n const root = document.createElement('div');\n root.className = 'mitbar-root';\n root.setAttribute('aria-label', 'Mitbar');\n\n const inner = document.createElement('div');\n inner.className = 'mitbar-inner';\n\n const inputWrap = document.createElement('div');\n inputWrap.className = 'mitbar-input-wrap';\n const input = document.createElement('input');\n input.className = 'mitbar-input';\n input.type = 'text';\n input.placeholder = 'Message for script-writer (page URL is sent automatically)…';\n input.setAttribute('aria-label', 'Message');\n inputWrap.appendChild(input);\n\n const status = document.createElement('span');\n status.className = 'mitbar-status';\n status.textContent = 'Connecting…';\n\n const btnSend = document.createElement('button');\n btnSend.className = 'mitbar-btn mitbar-btn--primary';\n btnSend.textContent = 'Send';\n btnSend.type = 'button';\n\n const btnBuild = document.createElement('button');\n btnBuild.className = 'mitbar-btn';\n btnBuild.textContent = 'Build';\n btnBuild.type = 'button';\n\n const btnDeploy = document.createElement('button');\n btnDeploy.className = 'mitbar-btn mitbar-btn--deploy';\n btnDeploy.textContent = 'Deploy';\n btnDeploy.type = 'button';\n\n const replyDiv = document.createElement('div');\n replyDiv.className = 'mitbar-reply';\n replyDiv.setAttribute('aria-live', 'polite');\n\n const btns = document.createElement('div');\n btns.className = 'mitbar-btns';\n btns.append(btnSend, btnBuild, btnDeploy);\n\n inner.append(inputWrap, btns, status);\n root.appendChild(inner);\n root.appendChild(replyDiv);\n document.body.appendChild(root);\n\n const setStatus = (text: string) => {\n status.textContent = text;\n };\n const setReply = (text: string, isError?: boolean) => {\n replyDiv.textContent = text;\n replyDiv.classList.toggle('mitbar-reply--error', !!isError);\n };\n\n client.onMessage((msg) => {\n if (msg.type === 'connected') setStatus('Connected');\n else if (msg.type === 'disconnected') setStatus('Disconnected');\n else if (msg.type === 'error') {\n setStatus('Error');\n setReply(msg.error || 'Error', true);\n } else if (msg.type === 'output' && msg.text) {\n setReply(msg.text, false);\n }\n });\n\n const send = (action: 'chat' | 'build' | 'deploy') => {\n const text = input.value.trim();\n if (action === 'chat' && !text) return;\n const payload = action === 'chat' ? text : (text || `Please ${action} the current project.`);\n client.send({ text: payload, action });\n if (action === 'chat') input.value = '';\n setReply('Waiting for response…');\n };\n\n btnSend.addEventListener('click', () => send('chat'));\n btnBuild.addEventListener('click', () => send('build'));\n btnDeploy.addEventListener('click', () => send('deploy'));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send('chat');\n }\n });\n}\n","/**\n * WebSocket client: sends { text, pageUrl, pageTitle } and receives { type, text? } from mitbar-gateway.\n */\n\nexport interface SendPayload {\n text: string;\n pageUrl?: string;\n pageTitle?: string;\n /** Optional: /build or /deploy for special actions */\n action?: 'chat' | 'build' | 'deploy';\n}\n\nexport interface IncomingMessage {\n type: string;\n text?: string;\n error?: string;\n}\n\nexport type MessageHandler = (msg: IncomingMessage) => void;\n\nexport function createWsClient(gatewayWsUrl: string) {\n let ws: WebSocket | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n const listeners: MessageHandler[] = [];\n const RECONNECT_MS = 3000;\n\n function getPageContext(): { pageUrl: string; pageTitle: string } {\n if (typeof window === 'undefined') return { pageUrl: '', pageTitle: '' };\n return {\n pageUrl: window.location.href,\n pageTitle: document.title || window.location.pathname || '',\n };\n }\n\n function connect(): WebSocket | null {\n if (typeof WebSocket === 'undefined') return null;\n try {\n const socket = new WebSocket(gatewayWsUrl);\n socket.onopen = () => {\n notify({ type: 'connected' });\n };\n socket.onmessage = (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data as string) as IncomingMessage;\n notify(data);\n } catch {\n notify({ type: 'output', text: String(event.data) });\n }\n };\n socket.onclose = () => {\n notify({ type: 'disconnected' });\n ws = null;\n reconnectTimer = setTimeout(() => connect(), RECONNECT_MS);\n };\n socket.onerror = () => {\n notify({ type: 'error', error: 'WebSocket error' });\n };\n ws = socket;\n return socket;\n } catch (e) {\n notify({ type: 'error', error: String(e) });\n return null;\n }\n }\n\n function notify(msg: IncomingMessage) {\n listeners.forEach((h) => {\n try {\n h(msg);\n } catch (_) {}\n });\n }\n\n function send(payload: SendPayload): void {\n const { pageUrl, pageTitle } = getPageContext();\n const body = {\n text: (payload.text || '').trim(),\n pageUrl: payload.pageUrl ?? pageUrl,\n pageTitle: payload.pageTitle ?? pageTitle,\n action: payload.action || 'chat',\n };\n if (!body.text && body.action === 'chat') return;\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(body));\n } else {\n notify({ type: 'error', error: 'Not connected. Reconnecting…' });\n connect();\n if (ws?.readyState === WebSocket.OPEN) ws.send(JSON.stringify(body));\n }\n }\n\n function onMessage(handler: MessageHandler): () => void {\n listeners.push(handler);\n return () => {\n const i = listeners.indexOf(handler);\n if (i >= 0) listeners.splice(i, 1);\n };\n }\n\n function disconnect(): void {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (ws) {\n ws.close();\n ws = null;\n }\n }\n\n connect();\n return { send, onMessage, connect, disconnect, getPageContext };\n}\n","/**\n * Mitbar – browser bar that talks to script-writer Docker agent via WebSocket gateway.\n * Add to any website; visibility and gateway URL are set via frontend config.\n * Every message includes the current page address and link.\n *\n * Config (one of):\n * - window.__MITBAR_CONFIG__ = { enabled: true, gatewayWsUrl: 'wss://...' }\n * - <script src=\"mitbar.js\" data-mitbar-enabled=\"true\" data-mitbar-gateway-ws-url=\"wss://...\"></script>\n *\n * When gatewayWsUrl is not set, defaults to wss://barway.mitverse.com/ws.\n * Build-time override: MITBAR_GATEWAY_WS_URL\n */\n\nimport { createBar } from './bar';\nimport { createWsClient } from './ws-client';\n\nexport interface MitbarConfig {\n /** Show the bar. When false, bar is not rendered. */\n enabled?: boolean;\n /** WebSocket URL of mitbar-gateway. Defaults to wss://barway.mitverse.com/ws when not set. */\n gatewayWsUrl?: string;\n}\n\ndeclare global {\n interface Window {\n __MITBAR_CONFIG__?: MitbarConfig;\n }\n}\n\nconst DEFAULT_WS_PATH = '/ws';\n/** Default gateway when none is configured (production Barway endpoint). */\nconst DEFAULT_GATEWAY_WS_URL = 'wss://barway.mitverse.com/ws';\n\nfunction getConfig(): MitbarConfig {\n const win = typeof window !== 'undefined' ? window : undefined;\n if (!win) return {};\n const fromWindow = win.__MITBAR_CONFIG__ || {};\n const script = document.currentScript as HTMLScriptElement | null;\n const fromData = script\n ? {\n enabled: script.getAttribute('data-mitbar-enabled') === 'true' || script.getAttribute('data-mitbar-enabled') === '1',\n gatewayWsUrl: script.getAttribute('data-mitbar-gateway-ws-url') || undefined,\n }\n : {};\n return {\n enabled: fromWindow.enabled ?? fromData.enabled ?? false,\n gatewayWsUrl: fromWindow.gatewayWsUrl ?? fromData.gatewayWsUrl ?? undefined,\n };\n}\n\n/**\n * Initialize and mount the bar. Call once after DOM ready (or use auto-init from script tag).\n */\nexport function init(configOverride?: Partial<MitbarConfig>): void {\n const config = { ...getConfig(), ...configOverride };\n if (!config.enabled) return;\n const gatewayWsUrl = (config.gatewayWsUrl || '').trim() || DEFAULT_GATEWAY_WS_URL;\n const wsUrl = gatewayWsUrl.includes('/') && !gatewayWsUrl.includes('?') && !gatewayWsUrl.endsWith('/')\n ? gatewayWsUrl\n : gatewayWsUrl.replace(/\\/?$/, '') + DEFAULT_WS_PATH;\n const client = createWsClient(wsUrl);\n createBar(client);\n}\n\nif (typeof document !== 'undefined' && document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => init());\n} else if (typeof document !== 'undefined') {\n init();\n}\n\nexport { createBar, createWsClient };\n"],"names":["CSS","createBar","client","style","root","inner","inputWrap","input","status","btnSend","btnBuild","btnDeploy","replyDiv","btns","setStatus","text","setReply","isError","msg","send","action","payload","e","createWsClient","gatewayWsUrl","ws","reconnectTimer","listeners","RECONNECT_MS","getPageContext","connect","socket","notify","event","data","h","pageUrl","pageTitle","body","onMessage","handler","disconnect","DEFAULT_WS_PATH","DEFAULT_GATEWAY_WS_URL","getConfig","win","fromWindow","script","fromData","init","configOverride","config","wsUrl"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * WebSocket client: sends { text, pageUrl, pageTitle } and receives { type, text? } from mitbar-gateway.
3
+ */
4
+ export interface SendPayload {
5
+ text: string;
6
+ pageUrl?: string;
7
+ pageTitle?: string;
8
+ /** Optional: /build or /deploy for special actions */
9
+ action?: 'chat' | 'build' | 'deploy';
10
+ }
11
+ export interface IncomingMessage {
12
+ type: string;
13
+ text?: string;
14
+ error?: string;
15
+ }
16
+ export type MessageHandler = (msg: IncomingMessage) => void;
17
+ export declare function createWsClient(gatewayWsUrl: string): {
18
+ send: (payload: SendPayload) => void;
19
+ onMessage: (handler: MessageHandler) => () => void;
20
+ connect: () => WebSocket | null;
21
+ disconnect: () => void;
22
+ getPageContext: () => {
23
+ pageUrl: string;
24
+ pageTitle: string;
25
+ };
26
+ };
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@mitverse/mitbar-web",
3
+ "version": "1.0.0",
4
+ "description": "Browser bar that communicates with script-writer Docker agent (page context, Build, Deploy)",
5
+ "type": "module",
6
+ "main": "dist/mitbar.umd.cjs",
7
+ "module": "dist/mitbar.es.js",
8
+ "unpkg": "dist/mitbar.umd.cjs",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "peerDependencies": {
15
+ "react": "^18.0.0",
16
+ "react-dom": "^18.0.0",
17
+ "react-router-dom": "^6.0.0"
18
+ },
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "tsc && vite build",
22
+ "preview": "vite preview"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "^5.2.2",
26
+ "vite": "^5.0.8",
27
+ "vite-plugin-dts": "^3.7.0"
28
+ }
29
+ }