@mailoo/chat 0.0.0-stage → 1.32.2
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/LICENSE +16 -0
- package/README.md +150 -2
- package/dist/chat-message-Dw6tKBEb.d.cts +10 -0
- package/dist/chat-message-Dw6tKBEb.d.ts +10 -0
- package/dist/chunk-2Y37RYEL.js +141 -0
- package/dist/chunk-2Y37RYEL.js.map +1 -0
- package/dist/chunk-4TNHJERE.js +19 -0
- package/dist/chunk-4TNHJERE.js.map +1 -0
- package/dist/chunk-77E6HUHY.js +41 -0
- package/dist/chunk-77E6HUHY.js.map +1 -0
- package/dist/chunk-AU6EFFLV.js +431 -0
- package/dist/chunk-AU6EFFLV.js.map +1 -0
- package/dist/chunk-QZ7HWQDO.js +839 -0
- package/dist/chunk-QZ7HWQDO.js.map +1 -0
- package/dist/client/index.cjs +1658 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +33 -0
- package/dist/client/index.d.ts +33 -0
- package/dist/client/index.js +597 -0
- package/dist/client/index.js.map +1 -0
- package/dist/hooks/index.cjs +751 -0
- package/dist/hooks/index.cjs.map +1 -0
- package/dist/hooks/index.d.cts +79 -0
- package/dist/hooks/index.d.ts +79 -0
- package/dist/hooks/index.js +32 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.cjs +213 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/mailoo-site-chat-widget-C7B797Lu.d.ts +130 -0
- package/dist/mailoo-site-chat-widget-h_cBqsJw.d.cts +130 -0
- package/dist/routes/index.cjs +204 -0
- package/dist/routes/index.cjs.map +1 -0
- package/dist/routes/index.d.cts +30 -0
- package/dist/routes/index.d.ts +30 -0
- package/dist/routes/index.js +174 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/shared-glVmghqk.d.cts +40 -0
- package/dist/shared-glVmghqk.d.ts +40 -0
- package/dist/styles/widget.css +122 -0
- package/dist/welcome-presets/index.cjs +479 -0
- package/dist/welcome-presets/index.cjs.map +1 -0
- package/dist/welcome-presets/index.d.cts +53 -0
- package/dist/welcome-presets/index.d.ts +53 -0
- package/dist/welcome-presets/index.js +38 -0
- package/dist/welcome-presets/index.js.map +1 -0
- package/dist/welcome-presets/parse.cjs +44 -0
- package/dist/welcome-presets/parse.cjs.map +1 -0
- package/dist/welcome-presets/parse.d.cts +11 -0
- package/dist/welcome-presets/parse.d.ts +11 -0
- package/dist/welcome-presets/parse.js +9 -0
- package/dist/welcome-presets/parse.js.map +1 -0
- package/dist/widget-config-B5Tf7gqn.d.cts +32 -0
- package/dist/widget-config-B5Tf7gqn.d.ts +32 -0
- package/package.json +85 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Mailoo Integrator Use License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mailoo
|
|
4
|
+
|
|
5
|
+
Permission is granted to use, install, and distribute this software in
|
|
6
|
+
unmodified form, including as a dependency of an application.
|
|
7
|
+
|
|
8
|
+
Modification of this software is not permitted.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
11
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
12
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
13
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
14
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
15
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
16
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,151 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@mailoo/chat`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
JSBOX visitor chat: BFF route factories, headless hooks, and a floating widget.
|
|
4
|
+
|
|
5
|
+
Install from npm together with `@mailoo/next-core`. Peer: `@heroicons/react`.
|
|
6
|
+
Inside this monorepo, `apps/web` uses `workspace:*`.
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Env: `MAILOO_CHAT_INTEGRATION_{API,API_KEY,PROJECT_UID,ID}`
|
|
11
|
+
- Optional: `MAILOO_CHAT_WS_ORIGIN` (public API host for WSS), `MAILOO_CHAT_WELCOME_MESSAGE`
|
|
12
|
+
- Browser opens WebSocket **directly** to Mailoo API (`/api/v1/chat/visitor-ws`). Ingress must support Upgrade.
|
|
13
|
+
|
|
14
|
+
## Routes (no Auth.js coupling)
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import {
|
|
18
|
+
createChatSubmitHandler,
|
|
19
|
+
createChatMessagesHandler,
|
|
20
|
+
createChatStatusHandler,
|
|
21
|
+
createChatWidgetConfigHandler,
|
|
22
|
+
} from '@mailoo/chat/routes'
|
|
23
|
+
|
|
24
|
+
export const POST = createChatSubmitHandler({
|
|
25
|
+
// optional: inject session email
|
|
26
|
+
resolveSender: async () => {
|
|
27
|
+
const session = await auth()
|
|
28
|
+
return session?.user?.email
|
|
29
|
+
? { email: session.user.email, name: session.user.name ?? undefined }
|
|
30
|
+
: null
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
export const GET = createChatMessagesHandler()
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Status (optional): `createChatStatusHandler()` → `GET /api/v1/webhooks/chat/status`.
|
|
38
|
+
Widget-config (optional BFF): `createChatWidgetConfigHandler()`.
|
|
39
|
+
|
|
40
|
+
Config helpers from `@mailoo/chat`: `getMailooChatIntegrationConfig`,
|
|
41
|
+
`getMailooChatWebSocketOrigin`, `fetchMailooChatIntegrationStatus`,
|
|
42
|
+
`fetchMailooChatWidgetConfig` (null on failure), `resolveMailooChatHostConfig`.
|
|
43
|
+
|
|
44
|
+
## Default floating widget (recommended)
|
|
45
|
+
|
|
46
|
+
Server Component layout:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { resolveMailooChatHostConfig } from '@mailoo/chat'
|
|
50
|
+
import { MailooSiteChatShell } from '@mailoo/chat/client'
|
|
51
|
+
import { auth } from '@/auth'
|
|
52
|
+
|
|
53
|
+
const session = await auth()
|
|
54
|
+
const chat = await resolveMailooChatHostConfig({
|
|
55
|
+
locale,
|
|
56
|
+
isAuthenticated: Boolean(session?.user?.email),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
{chat ? <MailooSiteChatShell chat={chat} /> : null}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`resolveMailooChatHostConfig` returns `null` when env is incomplete or
|
|
63
|
+
widget-config cannot load (HTTP errors, network, invalid payload). It **never
|
|
64
|
+
throws** — hosts must keep the page HTTP 200 and simply omit the chat shell.
|
|
65
|
+
When resolve succeeds it **always** loads JSBOX `config.chatWidget` (brand,
|
|
66
|
+
topics, position, welcome, privacy, operators) as `widgetConfig`. Call
|
|
67
|
+
`openMailooSiteChat()` from any client component to open the panel.
|
|
68
|
+
|
|
69
|
+
## Hooks
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import {
|
|
73
|
+
useMailooChatSession,
|
|
74
|
+
useMailooChatSubmit,
|
|
75
|
+
useMailooChatMessages,
|
|
76
|
+
useMailooChatStatus,
|
|
77
|
+
} from '@mailoo/chat/hooks'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`useMailooChatSession` owns session storage, guest profile, send, poll (`since`),
|
|
81
|
+
and visitor WebSocket. Pass `enabled` to gate realtime (the widget uses panel open).
|
|
82
|
+
|
|
83
|
+
## Widget (custom / headless UI)
|
|
84
|
+
|
|
85
|
+
Host CSS **must** import the widget shell (position + launcher do not rely on
|
|
86
|
+
host Tailwind scanning this package). Prefer a path PostCSS can resolve
|
|
87
|
+
(monorepo relative or package export):
|
|
88
|
+
|
|
89
|
+
```css
|
|
90
|
+
/* monorepo */
|
|
91
|
+
@import '../../../packages/chat/src/styles/widget.css';
|
|
92
|
+
/* or published package */
|
|
93
|
+
@import '@mailoo/chat/styles';
|
|
94
|
+
/* Tailwind v4: also scan package sources if you style with utilities */
|
|
95
|
+
@source '../node_modules/@mailoo/chat/src/**/*.{ts,tsx}';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { MailooSiteChatWidget } from '@mailoo/chat/client'
|
|
100
|
+
|
|
101
|
+
;<MailooSiteChatWidget
|
|
102
|
+
apiOrigin={wsOrigin}
|
|
103
|
+
projectUid={projectUid}
|
|
104
|
+
integrationId={integrationId}
|
|
105
|
+
welcomeMessage={welcome}
|
|
106
|
+
locale={locale}
|
|
107
|
+
isAuthenticated={isAuthenticated}
|
|
108
|
+
widgetConfig={widgetConfig}
|
|
109
|
+
/>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Prefer `resolveMailooChatHostConfig` + `MailooSiteChatShell` so brand/topics are
|
|
113
|
+
not omitted. For a custom UI, pass `widgetConfig` from
|
|
114
|
+
`fetchMailooChatWidgetConfig` (or BFF `…/widget-config`). Brand colors
|
|
115
|
+
(`brandPrimary` / `brandOnPrimary`), welcome title/tagline, topics, operators,
|
|
116
|
+
and launcher `position` come from the JSBOX dashboard **Widget** tab.
|
|
117
|
+
|
|
118
|
+
Optional: `className` / `panelClassName` / `launcherClassName`, controlled
|
|
119
|
+
`open` / `onOpenChange`, `labels`, endpoint overrides, host `position`
|
|
120
|
+
override (wins over `widgetConfig.position`), `zIndex`,
|
|
121
|
+
`onSessionCreated` / `onMessageSent` / `onError` / `onFault`, and small render
|
|
122
|
+
slots.
|
|
123
|
+
|
|
124
|
+
### Chat unavailable / rate limit
|
|
125
|
+
|
|
126
|
+
On submit or message poll, the package classifies **429** as `rate_limited` and
|
|
127
|
+
network / **502** / **503** / other **5xx** as `unavailable`, stops polling, and
|
|
128
|
+
shows a built-in panel (not raw API text). Pass an integrator action or custom
|
|
129
|
+
UI via `MailooSiteChatShell` / `MailooSiteChatWidget`:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<MailooSiteChatShell
|
|
133
|
+
chat={chat}
|
|
134
|
+
unavailableAction={{ type: 'mailto', email: 'support@example.com' }}
|
|
135
|
+
// or: { type: 'link', href: '/support', label: 'Contact support' }
|
|
136
|
+
// or: renderUnavailable={({ fault, labels, retry }) => …}
|
|
137
|
+
/>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Headless: `useMailooChatSession` exposes `fault`, `onFault`, and
|
|
141
|
+
`retryAfterFault`. Widget-config load still **fail-fast** before mount — this
|
|
142
|
+
panel is only for post-mount send/poll failures.
|
|
143
|
+
|
|
144
|
+
## Welcome presets
|
|
145
|
+
|
|
146
|
+
- **Client barrel** `@mailoo/chat/welcome-presets` — Provider, Switcher, renderers
|
|
147
|
+
(`'use client'`). Safe to import as components from Server Components; do **not**
|
|
148
|
+
call exported functions from the server. Optional around `MailooSiteChatShell`.
|
|
149
|
+
- **Server-safe parse** `@mailoo/chat/welcome-presets/parse` — `parseMailooChatWelcomePreset`
|
|
150
|
+
and related types only (no `'use client'`). Use this from RSC / env helpers
|
|
151
|
+
(e.g. `MAILOO_CHAT_WELCOME_PRESET`).
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import { unstable_rethrow } from "next/navigation";
|
|
3
|
+
import {
|
|
4
|
+
defaultMailooLogger,
|
|
5
|
+
readMailooIntegrationConfig
|
|
6
|
+
} from "@mailoo/next-core";
|
|
7
|
+
function getMailooChatIntegrationConfig() {
|
|
8
|
+
return readMailooIntegrationConfig({
|
|
9
|
+
prefix: "MAILOO_CHAT_INTEGRATION",
|
|
10
|
+
allowApiBaseUrlFallback: true
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function getMailooChatWebSocketOrigin() {
|
|
14
|
+
const explicit = process.env.MAILOO_CHAT_WS_ORIGIN?.trim();
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return explicit.replace(/\/$/, "");
|
|
17
|
+
}
|
|
18
|
+
const chatCfg = getMailooChatIntegrationConfig();
|
|
19
|
+
if (chatCfg?.apiBaseUrl) {
|
|
20
|
+
return chatCfg.apiBaseUrl.replace(/\/$/, "");
|
|
21
|
+
}
|
|
22
|
+
const chatApi = process.env.MAILOO_CHAT_INTEGRATION_API?.trim();
|
|
23
|
+
if (chatApi) {
|
|
24
|
+
return chatApi.replace(/\/$/, "");
|
|
25
|
+
}
|
|
26
|
+
const api = process.env.API_BASE_URL?.trim();
|
|
27
|
+
if (api) {
|
|
28
|
+
return api.replace(/\/$/, "");
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
async function fetchMailooChatIntegrationStatus() {
|
|
33
|
+
const cfg = getMailooChatIntegrationConfig();
|
|
34
|
+
if (!cfg) return null;
|
|
35
|
+
try {
|
|
36
|
+
const url = `${cfg.apiBaseUrl}/api/v1/webhooks/chat/${cfg.projectUid}/${cfg.integrationId}/status`;
|
|
37
|
+
const response = await fetch(url, {
|
|
38
|
+
method: "GET",
|
|
39
|
+
headers: {
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
"X-API-Key": cfg.apiKey
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) return null;
|
|
45
|
+
const data = await response.json();
|
|
46
|
+
if (typeof data.status !== "string" || typeof data.name !== "string" || typeof data.type !== "string" || typeof data.lastActivity !== "string") {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
status: data.status,
|
|
51
|
+
name: data.name,
|
|
52
|
+
type: data.type,
|
|
53
|
+
lastActivity: data.lastActivity
|
|
54
|
+
};
|
|
55
|
+
} catch (error) {
|
|
56
|
+
unstable_rethrow(error);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function fetchMailooChatWidgetConfig(locale) {
|
|
61
|
+
const cfg = getMailooChatIntegrationConfig();
|
|
62
|
+
if (!cfg) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const url = new URL(
|
|
67
|
+
`${cfg.apiBaseUrl}/api/v1/webhooks/chat/${cfg.projectUid}/${cfg.integrationId}/widget-config`
|
|
68
|
+
);
|
|
69
|
+
url.searchParams.set("locale", locale);
|
|
70
|
+
const response = await fetch(url.toString(), {
|
|
71
|
+
method: "GET",
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
"X-API-Key": cfg.apiKey
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
defaultMailooLogger.warn?.(
|
|
79
|
+
`Failed to fetch chat widget config: HTTP ${response.status}`
|
|
80
|
+
);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const data = await response.json();
|
|
84
|
+
if (!data.widget || !Array.isArray(data.widget.topics)) {
|
|
85
|
+
defaultMailooLogger.warn?.(
|
|
86
|
+
"Failed to fetch chat widget config: invalid response (missing widget.topics)"
|
|
87
|
+
);
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
...data.widget,
|
|
92
|
+
topics: data.widget.topics,
|
|
93
|
+
operators: Array.isArray(data.widget.operators) ? data.widget.operators : []
|
|
94
|
+
};
|
|
95
|
+
} catch (error) {
|
|
96
|
+
unstable_rethrow(error);
|
|
97
|
+
defaultMailooLogger.logException?.(
|
|
98
|
+
error,
|
|
99
|
+
"Failed to fetch chat widget config"
|
|
100
|
+
);
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function resolveMailooChatHostConfig(opts) {
|
|
105
|
+
try {
|
|
106
|
+
const server = getMailooChatIntegrationConfig();
|
|
107
|
+
if (!server) return null;
|
|
108
|
+
const apiOrigin = getMailooChatWebSocketOrigin();
|
|
109
|
+
if (!apiOrigin) return null;
|
|
110
|
+
const locale = opts.locale.trim() || "en";
|
|
111
|
+
const widgetConfig = await fetchMailooChatWidgetConfig(locale);
|
|
112
|
+
if (!widgetConfig) return null;
|
|
113
|
+
const welcomeOverride = process.env.MAILOO_CHAT_WELCOME_MESSAGE?.trim();
|
|
114
|
+
const welcomeMessage = welcomeOverride || widgetConfig.welcomeTagline?.trim() || "";
|
|
115
|
+
return {
|
|
116
|
+
apiOrigin,
|
|
117
|
+
projectUid: server.projectUid,
|
|
118
|
+
integrationId: server.integrationId,
|
|
119
|
+
welcomeMessage,
|
|
120
|
+
locale,
|
|
121
|
+
isAuthenticated: Boolean(opts.isAuthenticated),
|
|
122
|
+
widgetConfig
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
unstable_rethrow(error);
|
|
126
|
+
defaultMailooLogger.logException?.(
|
|
127
|
+
error,
|
|
128
|
+
"resolveMailooChatHostConfig failed"
|
|
129
|
+
);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
getMailooChatIntegrationConfig,
|
|
136
|
+
getMailooChatWebSocketOrigin,
|
|
137
|
+
fetchMailooChatIntegrationStatus,
|
|
138
|
+
fetchMailooChatWidgetConfig,
|
|
139
|
+
resolveMailooChatHostConfig
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=chunk-2Y37RYEL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { unstable_rethrow } from 'next/navigation'\nimport {\n defaultMailooLogger,\n readMailooIntegrationConfig,\n type MailooIntegrationConfig,\n} from '@mailoo/next-core'\nimport type { MailooChatWidgetConfig } from './lib/widget-config.js'\n\nexport type MailooChatIntegrationConfig = MailooIntegrationConfig\n\nexport function getMailooChatIntegrationConfig(): MailooChatIntegrationConfig | null {\n return readMailooIntegrationConfig({\n prefix: 'MAILOO_CHAT_INTEGRATION',\n allowApiBaseUrlFallback: true,\n })\n}\n\n/**\n * Base URL the browser uses for Mailoo chat WebSockets (ws/wss).\n * Precedence: MAILOO_CHAT_WS_ORIGIN → chat API base → API_BASE_URL.\n * The host must expose WebSocket upgrade on the public API hostname.\n */\nexport function getMailooChatWebSocketOrigin(): string | null {\n const explicit = process.env.MAILOO_CHAT_WS_ORIGIN?.trim()\n if (explicit) {\n return explicit.replace(/\\/$/, '')\n }\n const chatCfg = getMailooChatIntegrationConfig()\n if (chatCfg?.apiBaseUrl) {\n return chatCfg.apiBaseUrl.replace(/\\/$/, '')\n }\n const chatApi = process.env.MAILOO_CHAT_INTEGRATION_API?.trim()\n if (chatApi) {\n return chatApi.replace(/\\/$/, '')\n }\n const api = process.env.API_BASE_URL?.trim()\n if (api) {\n return api.replace(/\\/$/, '')\n }\n return null\n}\n\nexport type MailooChatIntegrationStatus = {\n status: string\n name: string\n type: string\n lastActivity: string\n}\n\nexport type { MailooChatWidgetConfig } from './lib/widget-config.js'\nexport {\n chatWidgetCssVariables,\n isMailooChatLauncherPosition,\n mailooChatLauncherRootClassNames,\n resolveMailooChatLauncherPosition,\n MAILOO_CHAT_LAUNCHER_POSITIONS,\n type MailooChatLauncherPosition,\n type MailooChatWidgetOperator,\n type MailooChatWidgetTopic,\n} from './lib/widget-config.js'\n\n/**\n * Server-side status check against Mailoo (API key from env).\n * Returns null when chat is not configured or the request fails.\n */\nexport async function fetchMailooChatIntegrationStatus(): Promise<MailooChatIntegrationStatus | null> {\n const cfg = getMailooChatIntegrationConfig()\n if (!cfg) return null\n try {\n const url = `${cfg.apiBaseUrl}/api/v1/webhooks/chat/${cfg.projectUid}/${cfg.integrationId}/status`\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': cfg.apiKey,\n },\n })\n if (!response.ok) return null\n const data = (await response.json()) as Partial<MailooChatIntegrationStatus>\n if (\n typeof data.status !== 'string' ||\n typeof data.name !== 'string' ||\n typeof data.type !== 'string' ||\n typeof data.lastActivity !== 'string'\n ) {\n return null\n }\n return {\n status: data.status,\n name: data.name,\n type: data.type,\n lastActivity: data.lastActivity,\n }\n } catch (error) {\n unstable_rethrow(error)\n return null\n }\n}\n\n/**\n * Server-side widget config from Mailoo API (brand, operators, topics, privacy).\n * Returns null when env is missing, the request fails, or the payload is invalid.\n * Never throws — hosts must not 500 the page when chat bootstrap fails.\n */\nexport async function fetchMailooChatWidgetConfig(\n locale: string\n): Promise<MailooChatWidgetConfig | null> {\n const cfg = getMailooChatIntegrationConfig()\n if (!cfg) {\n return null\n }\n try {\n const url = new URL(\n `${cfg.apiBaseUrl}/api/v1/webhooks/chat/${cfg.projectUid}/${cfg.integrationId}/widget-config`\n )\n url.searchParams.set('locale', locale)\n const response = await fetch(url.toString(), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': cfg.apiKey,\n },\n })\n if (!response.ok) {\n defaultMailooLogger.warn?.(\n `Failed to fetch chat widget config: HTTP ${response.status}`\n )\n return null\n }\n const data = (await response.json()) as {\n widget?: MailooChatWidgetConfig\n }\n if (!data.widget || !Array.isArray(data.widget.topics)) {\n defaultMailooLogger.warn?.(\n 'Failed to fetch chat widget config: invalid response (missing widget.topics)'\n )\n return null\n }\n return {\n ...data.widget,\n topics: data.widget.topics,\n operators: Array.isArray(data.widget.operators)\n ? data.widget.operators\n : [],\n }\n } catch (error) {\n unstable_rethrow(error)\n defaultMailooLogger.logException?.(\n error,\n 'Failed to fetch chat widget config'\n )\n return null\n }\n}\n\n/** Props for {@link MailooSiteChatShell} / floating widget host. */\nexport type MailooChatHostConfig = {\n apiOrigin: string\n projectUid: string\n integrationId: string\n welcomeMessage: string\n locale: string\n isAuthenticated: boolean\n /** Always present when resolve succeeds — brand, topics, position, etc. */\n widgetConfig: MailooChatWidgetConfig\n}\n\n/**\n * Default host resolve: env + public JSBOX widget-config.\n * Returns null when chat env is incomplete or widget-config cannot load\n * (do not mount the widget). Never throws — page hosts must stay HTTP 200.\n */\nexport async function resolveMailooChatHostConfig(opts: {\n locale: string\n isAuthenticated?: boolean\n}): Promise<MailooChatHostConfig | null> {\n try {\n const server = getMailooChatIntegrationConfig()\n if (!server) return null\n\n const apiOrigin = getMailooChatWebSocketOrigin()\n if (!apiOrigin) return null\n\n const locale = opts.locale.trim() || 'en'\n const widgetConfig = await fetchMailooChatWidgetConfig(locale)\n if (!widgetConfig) return null\n\n const welcomeOverride = process.env.MAILOO_CHAT_WELCOME_MESSAGE?.trim()\n const welcomeMessage =\n welcomeOverride || widgetConfig.welcomeTagline?.trim() || ''\n\n return {\n apiOrigin,\n projectUid: server.projectUid,\n integrationId: server.integrationId,\n welcomeMessage,\n locale,\n isAuthenticated: Boolean(opts.isAuthenticated),\n widgetConfig,\n }\n } catch (error) {\n unstable_rethrow(error)\n defaultMailooLogger.logException?.(\n error,\n 'resolveMailooChatHostConfig failed'\n )\n return null\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/welcome-presets/types.ts
|
|
2
|
+
function parseMailooChatWelcomePreset(value) {
|
|
3
|
+
const trimmed = value?.trim();
|
|
4
|
+
if (trimmed === "builtin" || trimmed === "team" || trimmed === "assistant") {
|
|
5
|
+
return trimmed;
|
|
6
|
+
}
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
function normalizeLegacyWelcomePresetId(value) {
|
|
10
|
+
if (value === "delinea") return "team";
|
|
11
|
+
if (value === "mia") return "assistant";
|
|
12
|
+
return parseMailooChatWelcomePreset(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
parseMailooChatWelcomePreset,
|
|
17
|
+
normalizeLegacyWelcomePresetId
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-4TNHJERE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/welcome-presets/types.ts"],"sourcesContent":["export type MailooChatWelcomePresetId = 'builtin' | 'team' | 'assistant'\n\nexport type MailooChatWelcomePresetOption = {\n id: MailooChatWelcomePresetId\n label: string\n description: string\n}\n\nexport function parseMailooChatWelcomePreset(\n value: string | undefined | null\n): MailooChatWelcomePresetId | null {\n const trimmed = value?.trim()\n if (trimmed === 'builtin' || trimmed === 'team' || trimmed === 'assistant') {\n return trimmed\n }\n return null\n}\n\n/** Maps legacy preset ids from earlier builds (localStorage only). */\nexport function normalizeLegacyWelcomePresetId(\n value: string\n): MailooChatWelcomePresetId | null {\n if (value === 'delinea') return 'team'\n if (value === 'mia') return 'assistant'\n return parseMailooChatWelcomePreset(value)\n}\n"],"mappings":";AAQO,SAAS,6BACd,OACkC;AAClC,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,YAAY,aAAa,YAAY,UAAU,YAAY,aAAa;AAC1E,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,+BACd,OACkC;AAClC,MAAI,UAAU,UAAW,QAAO;AAChC,MAAI,UAAU,MAAO,QAAO;AAC5B,SAAO,6BAA6B,KAAK;AAC3C;","names":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/lib/widget-config.ts
|
|
2
|
+
var MAILOO_CHAT_LAUNCHER_POSITIONS = [
|
|
3
|
+
"bottom-right",
|
|
4
|
+
"bottom-left",
|
|
5
|
+
"top-right",
|
|
6
|
+
"top-left",
|
|
7
|
+
"middle-right",
|
|
8
|
+
"middle-left"
|
|
9
|
+
];
|
|
10
|
+
function isMailooChatLauncherPosition(value) {
|
|
11
|
+
return typeof value === "string" && MAILOO_CHAT_LAUNCHER_POSITIONS.includes(value);
|
|
12
|
+
}
|
|
13
|
+
function resolveMailooChatLauncherPosition(prop, config) {
|
|
14
|
+
if (prop) return prop;
|
|
15
|
+
if (config?.position && isMailooChatLauncherPosition(config.position)) {
|
|
16
|
+
return config.position;
|
|
17
|
+
}
|
|
18
|
+
return "bottom-right";
|
|
19
|
+
}
|
|
20
|
+
function mailooChatLauncherRootClassNames(position) {
|
|
21
|
+
const parts = ["mailoo-chat-root"];
|
|
22
|
+
if (position.endsWith("-left")) parts.push("mailoo-chat-root--left");
|
|
23
|
+
if (position.startsWith("top-")) parts.push("mailoo-chat-root--top");
|
|
24
|
+
if (position.startsWith("middle-")) parts.push("mailoo-chat-root--middle");
|
|
25
|
+
return parts.join(" ");
|
|
26
|
+
}
|
|
27
|
+
function chatWidgetCssVariables(config) {
|
|
28
|
+
return {
|
|
29
|
+
["--mailoo-chat-brand"]: config?.brandPrimary ?? "#2563EB",
|
|
30
|
+
["--mailoo-chat-brand-on"]: config?.brandOnPrimary ?? "#FFFFFF"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
MAILOO_CHAT_LAUNCHER_POSITIONS,
|
|
36
|
+
isMailooChatLauncherPosition,
|
|
37
|
+
resolveMailooChatLauncherPosition,
|
|
38
|
+
mailooChatLauncherRootClassNames,
|
|
39
|
+
chatWidgetCssVariables
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=chunk-77E6HUHY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/widget-config.ts"],"sourcesContent":["import type { CSSProperties } from 'react'\n\nexport type MailooChatWidgetTopic = {\n id: string\n label: string\n action: 'start_chat' | 'external_url'\n externalUrl?: string\n}\n\nexport type MailooChatWidgetOperator = {\n userId: string\n name: string | null\n image: string | null\n online: boolean\n}\n\nexport const MAILOO_CHAT_LAUNCHER_POSITIONS = [\n 'bottom-right',\n 'bottom-left',\n 'top-right',\n 'top-left',\n 'middle-right',\n 'middle-left',\n] as const\n\nexport type MailooChatLauncherPosition =\n (typeof MAILOO_CHAT_LAUNCHER_POSITIONS)[number]\n\nexport type MailooChatWidgetConfig = {\n brandPrimary?: string\n brandOnPrimary?: string\n welcomeTitle?: string\n welcomeTagline?: string\n privacyPolicyUrl?: string\n position?: MailooChatLauncherPosition\n topics: MailooChatWidgetTopic[]\n operators: MailooChatWidgetOperator[]\n}\n\nexport function isMailooChatLauncherPosition(\n value: unknown\n): value is MailooChatLauncherPosition {\n return (\n typeof value === 'string' &&\n (MAILOO_CHAT_LAUNCHER_POSITIONS as readonly string[]).includes(value)\n )\n}\n\nexport function resolveMailooChatLauncherPosition(\n prop: MailooChatLauncherPosition | undefined,\n config: Pick<MailooChatWidgetConfig, 'position'> | null | undefined\n): MailooChatLauncherPosition {\n if (prop) return prop\n if (config?.position && isMailooChatLauncherPosition(config.position)) {\n return config.position\n }\n return 'bottom-right'\n}\n\nexport function mailooChatLauncherRootClassNames(\n position: MailooChatLauncherPosition\n): string {\n const parts = ['mailoo-chat-root']\n if (position.endsWith('-left')) parts.push('mailoo-chat-root--left')\n if (position.startsWith('top-')) parts.push('mailoo-chat-root--top')\n if (position.startsWith('middle-')) parts.push('mailoo-chat-root--middle')\n return parts.join(' ')\n}\n\nexport function chatWidgetCssVariables(\n config: Pick<\n MailooChatWidgetConfig,\n 'brandPrimary' | 'brandOnPrimary'\n > | null | undefined\n): CSSProperties {\n return {\n ['--mailoo-chat-brand' as string]: config?.brandPrimary ?? '#2563EB',\n ['--mailoo-chat-brand-on' as string]: config?.brandOnPrimary ?? '#FFFFFF',\n }\n}\n"],"mappings":";AAgBO,IAAM,iCAAiC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAgBO,SAAS,6BACd,OACqC;AACrC,SACE,OAAO,UAAU,YAChB,+BAAqD,SAAS,KAAK;AAExE;AAEO,SAAS,kCACd,MACA,QAC4B;AAC5B,MAAI,KAAM,QAAO;AACjB,MAAI,QAAQ,YAAY,6BAA6B,OAAO,QAAQ,GAAG;AACrE,WAAO,OAAO;AAAA,EAChB;AACA,SAAO;AACT;AAEO,SAAS,iCACd,UACQ;AACR,QAAM,QAAQ,CAAC,kBAAkB;AACjC,MAAI,SAAS,SAAS,OAAO,EAAG,OAAM,KAAK,wBAAwB;AACnE,MAAI,SAAS,WAAW,MAAM,EAAG,OAAM,KAAK,uBAAuB;AACnE,MAAI,SAAS,WAAW,SAAS,EAAG,OAAM,KAAK,0BAA0B;AACzE,SAAO,MAAM,KAAK,GAAG;AACvB;AAEO,SAAS,uBACd,QAIe;AACf,SAAO;AAAA,IACL,CAAC,qBAA+B,GAAG,QAAQ,gBAAgB;AAAA,IAC3D,CAAC,wBAAkC,GAAG,QAAQ,kBAAkB;AAAA,EAClE;AACF;","names":[]}
|