@uranotools/urano-social 0.0.0-stage → 0.2.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.
Files changed (37) hide show
  1. package/.env.example +6 -0
  2. package/LICENSE +21 -0
  3. package/README.md +192 -2
  4. package/dist/client/createUranoChat.d.ts +16 -0
  5. package/dist/client/createUranoChat.js +226 -0
  6. package/dist/client/index.d.ts +5 -0
  7. package/dist/client/index.js +10 -0
  8. package/dist/client/sse.d.ts +3 -0
  9. package/dist/client/sse.js +108 -0
  10. package/dist/client/submitContactForm.d.ts +30 -0
  11. package/dist/client/submitContactForm.js +65 -0
  12. package/dist/crypto.d.ts +5 -0
  13. package/dist/crypto.js +75 -0
  14. package/dist/flavors/UranoSocialChatElement.d.ts +13 -0
  15. package/dist/flavors/UranoSocialChatElement.js +178 -0
  16. package/dist/flavors/UranoSocialContactFormElement.d.ts +9 -0
  17. package/dist/flavors/UranoSocialContactFormElement.js +98 -0
  18. package/dist/flavors/styles.css +257 -0
  19. package/dist/index.d.ts +12 -0
  20. package/dist/index.js +26 -0
  21. package/dist/react/UranoSocialChat.d.ts +38 -0
  22. package/dist/react/UranoSocialChat.js +118 -0
  23. package/dist/react/UranoSocialContactForm.d.ts +15 -0
  24. package/dist/react/UranoSocialContactForm.js +48 -0
  25. package/dist/react/index.d.ts +4 -0
  26. package/dist/react/index.js +8 -0
  27. package/dist/server/index.d.ts +3 -0
  28. package/dist/server/index.js +13 -0
  29. package/dist/server/proxy.d.ts +16 -0
  30. package/dist/server/proxy.js +207 -0
  31. package/dist/server/visitorCookie.d.ts +11 -0
  32. package/dist/server/visitorCookie.js +43 -0
  33. package/dist/server/websocket.d.ts +21 -0
  34. package/dist/server/websocket.js +130 -0
  35. package/dist/types.d.ts +64 -0
  36. package/dist/types.js +2 -0
  37. package/package.json +91 -4
@@ -0,0 +1,257 @@
1
+ :root, .urano-social-host {
2
+ --us-bg: #0f1419;
3
+ --us-panel: #1a2332;
4
+ --us-border: #2a3a4f;
5
+ --us-text: #e8eef6;
6
+ --us-muted: #8fa3b8;
7
+ --us-accent: #3dba9a;
8
+ --us-accent-contrast: #06241c;
9
+ --us-user-bg: #243447;
10
+ --us-bot-bg: #15202b;
11
+ --us-danger: #e35d6a;
12
+ --us-radius: 14px;
13
+ --us-shadow: 0 18px 50px rgba(0, 0, 0, 0.35);
14
+ --us-font: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
15
+ --us-z: 2147483000;
16
+ }
17
+
18
+ .urano-social-host {
19
+ font-family: var(--us-font);
20
+ color: var(--us-text);
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ .urano-social-host *,
25
+ .urano-social-host *::before,
26
+ .urano-social-host *::after {
27
+ box-sizing: border-box;
28
+ }
29
+
30
+ .urano-social-launcher {
31
+ position: fixed;
32
+ right: 20px;
33
+ bottom: 20px;
34
+ z-index: var(--us-z);
35
+ width: 56px;
36
+ height: 56px;
37
+ border: 0;
38
+ border-radius: 999px;
39
+ background: var(--us-accent);
40
+ color: var(--us-accent-contrast);
41
+ font-size: 22px;
42
+ cursor: pointer;
43
+ box-shadow: var(--us-shadow);
44
+ }
45
+
46
+ .urano-social-panel {
47
+ display: flex;
48
+ flex-direction: column;
49
+ background: var(--us-panel);
50
+ border: 1px solid var(--us-border);
51
+ border-radius: var(--us-radius);
52
+ box-shadow: var(--us-shadow);
53
+ overflow: hidden;
54
+ }
55
+
56
+ .urano-social-host[data-flavor="floating"] .urano-social-panel {
57
+ position: fixed;
58
+ right: 20px;
59
+ bottom: 88px;
60
+ z-index: var(--us-z);
61
+ width: min(380px, calc(100vw - 24px));
62
+ height: min(560px, calc(100vh - 120px));
63
+ }
64
+
65
+ .urano-social-host[data-flavor="sidebar"] {
66
+ position: fixed;
67
+ top: 0;
68
+ right: 0;
69
+ z-index: var(--us-z);
70
+ height: 100vh;
71
+ width: min(380px, 100vw);
72
+ }
73
+
74
+ .urano-social-host[data-flavor="sidebar"] .urano-social-panel {
75
+ height: 100%;
76
+ border-radius: 0;
77
+ border-right: 0;
78
+ border-top: 0;
79
+ border-bottom: 0;
80
+ }
81
+
82
+ .urano-social-header {
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: space-between;
86
+ gap: 12px;
87
+ padding: 14px 16px;
88
+ border-bottom: 1px solid var(--us-border);
89
+ background: var(--us-bg);
90
+ }
91
+
92
+ .urano-social-header h2 {
93
+ margin: 0;
94
+ font-size: 15px;
95
+ font-weight: 600;
96
+ }
97
+
98
+ .urano-social-header button {
99
+ border: 0;
100
+ background: transparent;
101
+ color: var(--us-muted);
102
+ cursor: pointer;
103
+ font-size: 18px;
104
+ }
105
+
106
+ .urano-social-messages {
107
+ flex: 1;
108
+ overflow: auto;
109
+ padding: 16px;
110
+ display: flex;
111
+ flex-direction: column;
112
+ gap: 10px;
113
+ background: var(--us-bg);
114
+ }
115
+
116
+ .urano-social-empty {
117
+ margin: auto;
118
+ text-align: center;
119
+ color: var(--us-muted);
120
+ font-size: 14px;
121
+ padding: 24px;
122
+ }
123
+
124
+ .urano-social-bubble {
125
+ max-width: 85%;
126
+ padding: 10px 12px;
127
+ border-radius: 12px;
128
+ font-size: 14px;
129
+ line-height: 1.45;
130
+ white-space: pre-wrap;
131
+ word-break: break-word;
132
+ }
133
+
134
+ .urano-social-bubble[data-role="user"] {
135
+ align-self: flex-end;
136
+ background: var(--us-user-bg);
137
+ }
138
+
139
+ .urano-social-bubble[data-role="assistant"] {
140
+ align-self: flex-start;
141
+ background: var(--us-bot-bg);
142
+ border: 1px solid var(--us-border);
143
+ }
144
+
145
+ .urano-social-bubble[data-streaming="true"]::after {
146
+ content: "▍";
147
+ display: inline-block;
148
+ margin-left: 2px;
149
+ animation: us-blink 1s steps(2, jump-none) infinite;
150
+ }
151
+
152
+ @keyframes us-blink {
153
+ to { opacity: 0; }
154
+ }
155
+
156
+ .urano-social-composer {
157
+ display: flex;
158
+ gap: 8px;
159
+ padding: 12px;
160
+ border-top: 1px solid var(--us-border);
161
+ background: var(--us-panel);
162
+ }
163
+
164
+ .urano-social-composer input,
165
+ .urano-social-composer textarea {
166
+ flex: 1;
167
+ resize: none;
168
+ min-height: 42px;
169
+ max-height: 120px;
170
+ border-radius: 10px;
171
+ border: 1px solid var(--us-border);
172
+ background: var(--us-bg);
173
+ color: var(--us-text);
174
+ padding: 10px 12px;
175
+ font: inherit;
176
+ }
177
+
178
+ .urano-social-composer button {
179
+ border: 0;
180
+ border-radius: 10px;
181
+ background: var(--us-accent);
182
+ color: var(--us-accent-contrast);
183
+ padding: 0 14px;
184
+ font-weight: 600;
185
+ cursor: pointer;
186
+ }
187
+
188
+ .urano-social-composer button:disabled {
189
+ opacity: 0.55;
190
+ cursor: not-allowed;
191
+ }
192
+
193
+ .urano-social-error {
194
+ color: var(--us-danger);
195
+ font-size: 12px;
196
+ padding: 0 12px 8px;
197
+ }
198
+
199
+ .urano-social-host[data-open="false"] .urano-social-panel {
200
+ display: none;
201
+ }
202
+
203
+ .urano-social-host[data-flavor="sidebar"][data-open="false"] {
204
+ display: none;
205
+ }
206
+
207
+ /* Contact form (light DOM / React) */
208
+ .urano-social-contact {
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 10px;
212
+ padding: 16px;
213
+ max-width: 420px;
214
+ background: var(--us-panel, #1a2332);
215
+ border: 1px solid var(--us-border, #2a3a4f);
216
+ border-radius: var(--us-radius, 14px);
217
+ color: var(--us-text, #e8eef6);
218
+ font-family: var(--us-font, ui-sans-serif, system-ui, sans-serif);
219
+ }
220
+
221
+ .urano-social-contact h3 {
222
+ margin: 0 0 4px;
223
+ font-size: 16px;
224
+ }
225
+
226
+ .urano-social-contact label {
227
+ display: flex;
228
+ flex-direction: column;
229
+ gap: 4px;
230
+ font-size: 12px;
231
+ color: var(--us-muted, #8fa3b8);
232
+ }
233
+
234
+ .urano-social-contact input,
235
+ .urano-social-contact textarea {
236
+ border: 1px solid var(--us-border, #2a3a4f);
237
+ border-radius: 10px;
238
+ background: var(--us-bg, #0f1419);
239
+ color: var(--us-text, #e8eef6);
240
+ padding: 10px 12px;
241
+ font: inherit;
242
+ }
243
+
244
+ .urano-social-contact button {
245
+ border: 0;
246
+ border-radius: 10px;
247
+ background: var(--us-accent, #3dba9a);
248
+ color: var(--us-accent-contrast, #06241c);
249
+ padding: 10px 14px;
250
+ font-weight: 600;
251
+ cursor: pointer;
252
+ }
253
+
254
+ .urano-social-contact button:disabled {
255
+ opacity: 0.55;
256
+ cursor: not-allowed;
257
+ }
@@ -0,0 +1,12 @@
1
+ export { createUranoChat } from './client/createUranoChat';
2
+ export type { UranoChat } from './client/createUranoChat';
3
+ export { readSseStream, parseSseChunk } from './client/sse';
4
+ export { submitContactForm } from './client/submitContactForm';
5
+ export type { ContactFormPayload, ContactFormResult, SubmitContactFormOptions } from './client/submitContactForm';
6
+ export { createSocialProxy, socialProxyRoute } from './server/proxy';
7
+ export { attachSocialWebSocket, buildWsEnvelope } from './server/websocket';
8
+ export { registerUranoSocialChat, UranoSocialChatElement } from './flavors/UranoSocialChatElement';
9
+ export type { SocialFlavor } from './flavors/UranoSocialChatElement';
10
+ export { registerUranoSocialContactForm, UranoSocialContactFormElement } from './flavors/UranoSocialContactFormElement';
11
+ export { signHmacHex, verifyHmacHex, randomId } from './crypto';
12
+ export type { SocialProxyConfig, SocialClientMessage, SocialChatEvent, CreateUranoChatOptions, SocialSendOptions, SocialTransport, } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.randomId = exports.verifyHmacHex = exports.signHmacHex = exports.UranoSocialContactFormElement = exports.registerUranoSocialContactForm = exports.UranoSocialChatElement = exports.registerUranoSocialChat = exports.buildWsEnvelope = exports.attachSocialWebSocket = exports.socialProxyRoute = exports.createSocialProxy = exports.submitContactForm = exports.parseSseChunk = exports.readSseStream = exports.createUranoChat = void 0;
4
+ var createUranoChat_1 = require("./client/createUranoChat");
5
+ Object.defineProperty(exports, "createUranoChat", { enumerable: true, get: function () { return createUranoChat_1.createUranoChat; } });
6
+ var sse_1 = require("./client/sse");
7
+ Object.defineProperty(exports, "readSseStream", { enumerable: true, get: function () { return sse_1.readSseStream; } });
8
+ Object.defineProperty(exports, "parseSseChunk", { enumerable: true, get: function () { return sse_1.parseSseChunk; } });
9
+ var submitContactForm_1 = require("./client/submitContactForm");
10
+ Object.defineProperty(exports, "submitContactForm", { enumerable: true, get: function () { return submitContactForm_1.submitContactForm; } });
11
+ var proxy_1 = require("./server/proxy");
12
+ Object.defineProperty(exports, "createSocialProxy", { enumerable: true, get: function () { return proxy_1.createSocialProxy; } });
13
+ Object.defineProperty(exports, "socialProxyRoute", { enumerable: true, get: function () { return proxy_1.socialProxyRoute; } });
14
+ var websocket_1 = require("./server/websocket");
15
+ Object.defineProperty(exports, "attachSocialWebSocket", { enumerable: true, get: function () { return websocket_1.attachSocialWebSocket; } });
16
+ Object.defineProperty(exports, "buildWsEnvelope", { enumerable: true, get: function () { return websocket_1.buildWsEnvelope; } });
17
+ var UranoSocialChatElement_1 = require("./flavors/UranoSocialChatElement");
18
+ Object.defineProperty(exports, "registerUranoSocialChat", { enumerable: true, get: function () { return UranoSocialChatElement_1.registerUranoSocialChat; } });
19
+ Object.defineProperty(exports, "UranoSocialChatElement", { enumerable: true, get: function () { return UranoSocialChatElement_1.UranoSocialChatElement; } });
20
+ var UranoSocialContactFormElement_1 = require("./flavors/UranoSocialContactFormElement");
21
+ Object.defineProperty(exports, "registerUranoSocialContactForm", { enumerable: true, get: function () { return UranoSocialContactFormElement_1.registerUranoSocialContactForm; } });
22
+ Object.defineProperty(exports, "UranoSocialContactFormElement", { enumerable: true, get: function () { return UranoSocialContactFormElement_1.UranoSocialContactFormElement; } });
23
+ var crypto_1 = require("./crypto");
24
+ Object.defineProperty(exports, "signHmacHex", { enumerable: true, get: function () { return crypto_1.signHmacHex; } });
25
+ Object.defineProperty(exports, "verifyHmacHex", { enumerable: true, get: function () { return crypto_1.verifyHmacHex; } });
26
+ Object.defineProperty(exports, "randomId", { enumerable: true, get: function () { return crypto_1.randomId; } });
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { type UranoChat } from '../client/createUranoChat';
3
+ import type { SocialClientMessage } from '../types';
4
+ export type SocialFlavor = 'floating' | 'sidebar' | 'headless';
5
+ export interface UranoSocialChatProps {
6
+ flavor?: SocialFlavor;
7
+ endpoint?: string;
8
+ title?: string;
9
+ displayName?: string;
10
+ className?: string;
11
+ open?: boolean;
12
+ defaultOpen?: boolean;
13
+ onOpenChange?: (open: boolean) => void;
14
+ renderHeader?: (props: {
15
+ title: string;
16
+ onClose: () => void;
17
+ }) => React.ReactNode;
18
+ renderMessages?: (props: {
19
+ messages: SocialClientMessage[];
20
+ }) => React.ReactNode;
21
+ renderMessage?: (message: SocialClientMessage) => React.ReactNode;
22
+ renderComposer?: (props: {
23
+ disabled: boolean;
24
+ value: string;
25
+ onChange: (value: string) => void;
26
+ onSubmit: () => void;
27
+ }) => React.ReactNode;
28
+ renderLauncher?: (props: {
29
+ open: boolean;
30
+ onToggle: () => void;
31
+ }) => React.ReactNode;
32
+ renderEmpty?: () => React.ReactNode;
33
+ }
34
+ export declare function UranoSocialChat(props: UranoSocialChatProps): React.JSX.Element | null;
35
+ export declare function useUranoChat(options: {
36
+ endpoint?: string;
37
+ displayName?: string;
38
+ }): UranoChat;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.UranoSocialChat = UranoSocialChat;
37
+ exports.useUranoChat = useUranoChat;
38
+ const jsx_runtime_1 = require("react/jsx-runtime");
39
+ const react_1 = __importStar(require("react"));
40
+ const createUranoChat_1 = require("../client/createUranoChat");
41
+ function UranoSocialChat(props) {
42
+ const flavor = props.flavor || 'floating';
43
+ const [open, setOpen] = (0, react_1.useState)(props.open ?? props.defaultOpen ?? flavor === 'sidebar');
44
+ const [messages, setMessages] = (0, react_1.useState)([]);
45
+ const [streaming, setStreaming] = (0, react_1.useState)(false);
46
+ const [error, setError] = (0, react_1.useState)('');
47
+ const [draft, setDraft] = (0, react_1.useState)('');
48
+ const chatRef = (0, react_1.useRef)(null);
49
+ (0, react_1.useEffect)(() => {
50
+ if (props.open !== undefined)
51
+ setOpen(props.open);
52
+ }, [props.open]);
53
+ (0, react_1.useEffect)(() => {
54
+ const chat = (0, createUranoChat_1.createUranoChat)({
55
+ endpoint: props.endpoint || '/api/urano-social',
56
+ displayName: props.displayName,
57
+ onMessages: setMessages,
58
+ onError: (err) => setError(err.message),
59
+ onStatus: (status) => setStreaming(status.streaming),
60
+ });
61
+ chatRef.current = chat;
62
+ return () => chat.destroy();
63
+ }, [props.endpoint, props.displayName]);
64
+ const setOpenBoth = (next) => {
65
+ setOpen(next);
66
+ props.onOpenChange?.(next);
67
+ };
68
+ const onSubmit = async () => {
69
+ const text = draft.trim();
70
+ if (!text || !chatRef.current)
71
+ return;
72
+ setDraft('');
73
+ setError('');
74
+ try {
75
+ await chatRef.current.send(text);
76
+ }
77
+ catch (err) {
78
+ setError(err?.message || 'send_failed');
79
+ }
80
+ };
81
+ const header = props.renderHeader
82
+ ? props.renderHeader({ title: props.title || 'Atención al cliente', onClose: () => setOpenBoth(false) })
83
+ : ((0, jsx_runtime_1.jsxs)("div", { className: "urano-social-header", children: [(0, jsx_runtime_1.jsx)("h2", { children: props.title || 'Atención al cliente' }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setOpenBoth(false), "aria-label": "Cerrar", children: "\u00D7" })] }));
84
+ const messageList = props.renderMessages
85
+ ? props.renderMessages({ messages })
86
+ : ((0, jsx_runtime_1.jsx)("div", { className: "urano-social-messages", children: messages.length === 0
87
+ ? (props.renderEmpty?.() || (0, jsx_runtime_1.jsx)("div", { className: "urano-social-empty", children: "Escribe tu consulta y te atendemos." }))
88
+ : messages.map((m) => (props.renderMessage
89
+ ? (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: props.renderMessage(m) }, m.id)
90
+ : ((0, jsx_runtime_1.jsx)("div", { className: "urano-social-bubble", "data-role": m.role, "data-streaming": m.streaming ? 'true' : 'false', children: m.content }, m.id)))) }));
91
+ const composer = props.renderComposer
92
+ ? props.renderComposer({
93
+ disabled: streaming,
94
+ value: draft,
95
+ onChange: setDraft,
96
+ onSubmit,
97
+ })
98
+ : ((0, jsx_runtime_1.jsxs)("form", { className: "urano-social-composer", onSubmit: (e) => {
99
+ e.preventDefault();
100
+ void onSubmit();
101
+ }, children: [(0, jsx_runtime_1.jsx)("textarea", { rows: 1, value: draft, disabled: streaming, placeholder: "Escribe un mensaje\u2026", onChange: (e) => setDraft(e.target.value) }), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: streaming || !draft.trim(), children: "Enviar" })] }));
102
+ const launcher = flavor === 'floating'
103
+ ? (props.renderLauncher
104
+ ? props.renderLauncher({ open, onToggle: () => setOpenBoth(!open) })
105
+ : (0, jsx_runtime_1.jsx)("button", { type: "button", className: "urano-social-launcher", onClick: () => setOpenBoth(!open), children: "\uD83D\uDCAC" }))
106
+ : null;
107
+ if (flavor === 'headless')
108
+ return null;
109
+ return ((0, jsx_runtime_1.jsxs)("div", { className: ['urano-social-host', props.className].filter(Boolean).join(' '), "data-flavor": flavor, "data-open": String(open), children: [launcher, (0, jsx_runtime_1.jsxs)("div", { className: "urano-social-panel", children: [header, messageList, error ? (0, jsx_runtime_1.jsx)("div", { className: "urano-social-error", children: error }) : null, composer] })] }));
110
+ }
111
+ function useUranoChat(options) {
112
+ const chat = (0, react_1.useMemo)(() => (0, createUranoChat_1.createUranoChat)({
113
+ endpoint: options.endpoint,
114
+ displayName: options.displayName,
115
+ }), [options.endpoint, options.displayName]);
116
+ (0, react_1.useEffect)(() => () => chat.destroy(), [chat]);
117
+ return chat;
118
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ export interface UranoSocialContactFormProps {
3
+ endpoint?: string;
4
+ title?: string;
5
+ submitLabel?: string;
6
+ className?: string;
7
+ onSuccess?: (text: string) => void;
8
+ onError?: (error: string) => void;
9
+ renderFields?: (props: {
10
+ values: Record<string, string>;
11
+ setValue: (key: string, value: string) => void;
12
+ disabled: boolean;
13
+ }) => React.ReactNode;
14
+ }
15
+ export declare function UranoSocialContactForm(props: UranoSocialContactFormProps): React.JSX.Element;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UranoSocialContactForm = UranoSocialContactForm;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const submitContactForm_1 = require("../client/submitContactForm");
7
+ function UranoSocialContactForm(props) {
8
+ const [values, setValues] = (0, react_1.useState)({ name: '', email: '', subject: '', message: '' });
9
+ const [busy, setBusy] = (0, react_1.useState)(false);
10
+ const [error, setError] = (0, react_1.useState)('');
11
+ const [success, setSuccess] = (0, react_1.useState)('');
12
+ const setValue = (key, value) => {
13
+ setValues((prev) => ({ ...prev, [key]: value }));
14
+ };
15
+ const onSubmit = async (ev) => {
16
+ ev.preventDefault();
17
+ if (busy)
18
+ return;
19
+ setBusy(true);
20
+ setError('');
21
+ setSuccess('');
22
+ try {
23
+ const result = await (0, submitContactForm_1.submitContactForm)({
24
+ name: values.name,
25
+ email: values.email,
26
+ subject: values.subject,
27
+ message: values.message,
28
+ }, { endpoint: props.endpoint || '/api/urano-social', useGet: true });
29
+ if (!result.ok)
30
+ throw new Error(result.error || 'send_failed');
31
+ const msg = 'Enviado. Te responderemos por correo.';
32
+ setSuccess(msg);
33
+ props.onSuccess?.(result.text || msg);
34
+ setValues({ name: '', email: '', subject: '', message: '' });
35
+ }
36
+ catch (e) {
37
+ const msg = e?.message || 'send_failed';
38
+ setError(msg);
39
+ props.onError?.(msg);
40
+ }
41
+ finally {
42
+ setBusy(false);
43
+ }
44
+ };
45
+ return ((0, jsx_runtime_1.jsxs)("form", { className: ['urano-social-contact', props.className].filter(Boolean).join(' '), onSubmit: onSubmit, children: [(0, jsx_runtime_1.jsx)("h3", { children: props.title || 'Contáctanos' }), props.renderFields
46
+ ? props.renderFields({ values, setValue, disabled: busy })
47
+ : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("label", { children: ["Nombre", (0, jsx_runtime_1.jsx)("input", { value: values.name, disabled: busy, onChange: (e) => setValue('name', e.target.value) })] }), (0, jsx_runtime_1.jsxs)("label", { children: ["Email", (0, jsx_runtime_1.jsx)("input", { type: "email", required: true, value: values.email, disabled: busy, onChange: (e) => setValue('email', e.target.value) })] }), (0, jsx_runtime_1.jsxs)("label", { children: ["Asunto", (0, jsx_runtime_1.jsx)("input", { value: values.subject, disabled: busy, onChange: (e) => setValue('subject', e.target.value) })] }), (0, jsx_runtime_1.jsxs)("label", { children: ["Mensaje", (0, jsx_runtime_1.jsx)("textarea", { required: true, rows: 4, value: values.message, disabled: busy, onChange: (e) => setValue('message', e.target.value) })] })] })), error ? (0, jsx_runtime_1.jsx)("p", { className: "urano-social-error", children: error }) : null, success ? (0, jsx_runtime_1.jsx)("p", { style: { color: 'var(--us-accent, #3dba9a)', fontSize: 12 }, children: success }) : null, (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: busy, children: props.submitLabel || 'Enviar' })] }));
48
+ }
@@ -0,0 +1,4 @@
1
+ export { UranoSocialChat, useUranoChat } from './UranoSocialChat';
2
+ export type { UranoSocialChatProps, SocialFlavor } from './UranoSocialChat';
3
+ export { UranoSocialContactForm } from './UranoSocialContactForm';
4
+ export type { UranoSocialContactFormProps } from './UranoSocialContactForm';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UranoSocialContactForm = exports.useUranoChat = exports.UranoSocialChat = void 0;
4
+ var UranoSocialChat_1 = require("./UranoSocialChat");
5
+ Object.defineProperty(exports, "UranoSocialChat", { enumerable: true, get: function () { return UranoSocialChat_1.UranoSocialChat; } });
6
+ Object.defineProperty(exports, "useUranoChat", { enumerable: true, get: function () { return UranoSocialChat_1.useUranoChat; } });
7
+ var UranoSocialContactForm_1 = require("./UranoSocialContactForm");
8
+ Object.defineProperty(exports, "UranoSocialContactForm", { enumerable: true, get: function () { return UranoSocialContactForm_1.UranoSocialContactForm; } });
@@ -0,0 +1,3 @@
1
+ export { createSocialProxy, socialProxyRoute } from './proxy';
2
+ export { attachSocialWebSocket, buildWsEnvelope } from './websocket';
3
+ export { resolveVisitorId, parseCookies, DEFAULT_COOKIE_NAME } from './visitorCookie';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_COOKIE_NAME = exports.parseCookies = exports.resolveVisitorId = exports.buildWsEnvelope = exports.attachSocialWebSocket = exports.socialProxyRoute = exports.createSocialProxy = void 0;
4
+ var proxy_1 = require("./proxy");
5
+ Object.defineProperty(exports, "createSocialProxy", { enumerable: true, get: function () { return proxy_1.createSocialProxy; } });
6
+ Object.defineProperty(exports, "socialProxyRoute", { enumerable: true, get: function () { return proxy_1.socialProxyRoute; } });
7
+ var websocket_1 = require("./websocket");
8
+ Object.defineProperty(exports, "attachSocialWebSocket", { enumerable: true, get: function () { return websocket_1.attachSocialWebSocket; } });
9
+ Object.defineProperty(exports, "buildWsEnvelope", { enumerable: true, get: function () { return websocket_1.buildWsEnvelope; } });
10
+ var visitorCookie_1 = require("./visitorCookie");
11
+ Object.defineProperty(exports, "resolveVisitorId", { enumerable: true, get: function () { return visitorCookie_1.resolveVisitorId; } });
12
+ Object.defineProperty(exports, "parseCookies", { enumerable: true, get: function () { return visitorCookie_1.parseCookies; } });
13
+ Object.defineProperty(exports, "DEFAULT_COOKIE_NAME", { enumerable: true, get: function () { return visitorCookie_1.DEFAULT_COOKIE_NAME; } });
@@ -0,0 +1,16 @@
1
+ import type { SocialProxyConfig } from '../types';
2
+ export interface SocialProxyHandlers {
3
+ /** Fetch/Web-standard handler for App Router / Astro / edge-compatible hosts. */
4
+ handle: (request: Request) => Promise<Response>;
5
+ }
6
+ /**
7
+ * Creates a site-local proxy that signs webhook traffic with the server secret.
8
+ * The browser never receives WEBHOOK_SECRET.
9
+ */
10
+ export declare function createSocialProxy(partial?: Partial<SocialProxyConfig>): SocialProxyHandlers;
11
+ /** Convenience for Next.js App Router route handlers. */
12
+ export declare function socialProxyRoute(partial?: Partial<SocialProxyConfig>): {
13
+ GET: (request: Request) => Promise<Response>;
14
+ POST: (request: Request) => Promise<Response>;
15
+ OPTIONS: (request: Request) => Promise<Response>;
16
+ };