@mademi_dev/chatemi 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/LICENSE +21 -0
- package/README.md +451 -0
- package/dist/api.d.ts +43 -0
- package/dist/assets/styles.css +2 -0
- package/dist/chatemi.js +1626 -0
- package/dist/chatemi.umd.cjs +1 -0
- package/dist/components/ChatEmiLauncher.d.ts +3 -0
- package/dist/components/ChatEmiMessenger.d.ts +3 -0
- package/dist/context.d.ts +42 -0
- package/dist/index.d.ts +8 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/mongodb.d.ts +23 -0
- package/dist/server/mongodb.js +58 -0
- package/dist/socket.d.ts +33 -0
- package/dist/types.d.ts +364 -0
- package/docs/BACKEND_CONTRACT.md +305 -0
- package/docs/IMPLEMENTATION_GUIDE.md +306 -0
- package/examples/nextjs-chat-widget/README.md +46 -0
- package/examples/nextjs-chat-widget/app/api/chat/conversations/route.ts +30 -0
- package/examples/nextjs-chat-widget/app/api/chat/socket-events/route.ts +44 -0
- package/examples/nextjs-chat-widget/app/components/ChatWidget.tsx +35 -0
- package/examples/nextjs-chat-widget/app/layout.tsx +20 -0
- package/examples/nextjs-chat-widget/app/lib/chatemi-config.ts +52 -0
- package/examples/nextjs-chat-widget/app/lib/chatemi-mongo.ts +27 -0
- package/examples/nextjs-chat-widget/app/page.tsx +11 -0
- package/package.json +77 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
|
|
3
|
+
export async function GET() {
|
|
4
|
+
return NextResponse.json({
|
|
5
|
+
messageCreated: {
|
|
6
|
+
type: "message.created",
|
|
7
|
+
payload: {
|
|
8
|
+
id: "message_1",
|
|
9
|
+
conversationId: "conversation_1",
|
|
10
|
+
sender: {
|
|
11
|
+
id: "user_1",
|
|
12
|
+
name: "Ava",
|
|
13
|
+
avatarUrl: "https://example.com/ava.png"
|
|
14
|
+
},
|
|
15
|
+
text: "Hello from ChatEmi",
|
|
16
|
+
status: "sent",
|
|
17
|
+
createdAt: new Date().toISOString()
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
notification: {
|
|
21
|
+
type: "notification",
|
|
22
|
+
payload: {
|
|
23
|
+
id: "notification_1",
|
|
24
|
+
kind: "message",
|
|
25
|
+
title: "Ava",
|
|
26
|
+
body: "Hello from ChatEmi",
|
|
27
|
+
conversationId: "conversation_1",
|
|
28
|
+
messageId: "message_1",
|
|
29
|
+
read: false,
|
|
30
|
+
createdAt: new Date().toISOString()
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
receipt: {
|
|
34
|
+
type: "message.receipt",
|
|
35
|
+
payload: {
|
|
36
|
+
conversationId: "conversation_1",
|
|
37
|
+
messageIds: ["message_1"],
|
|
38
|
+
userId: "user_2",
|
|
39
|
+
status: "read",
|
|
40
|
+
at: new Date().toISOString()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ChatEmiLauncher, ChatEmiProvider } from "chatemi";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import { createChatEmiConfig } from "../lib/chatemi-config";
|
|
6
|
+
|
|
7
|
+
export function ChatWidget() {
|
|
8
|
+
const config = useMemo(() => createChatEmiConfig(), []);
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<ChatEmiProvider config={config}>
|
|
12
|
+
<ChatEmiLauncher
|
|
13
|
+
defaultOpen={false}
|
|
14
|
+
markNotificationsReadOnOpen
|
|
15
|
+
placement="bottom-right"
|
|
16
|
+
showNotificationList
|
|
17
|
+
subtitle="We are here to help"
|
|
18
|
+
theme="glass"
|
|
19
|
+
title="Messages"
|
|
20
|
+
initialSize={{
|
|
21
|
+
width: 460,
|
|
22
|
+
height: 720
|
|
23
|
+
}}
|
|
24
|
+
minSize={{
|
|
25
|
+
width: 360,
|
|
26
|
+
height: 520
|
|
27
|
+
}}
|
|
28
|
+
maxSize={{
|
|
29
|
+
width: 960,
|
|
30
|
+
height: 860
|
|
31
|
+
}}
|
|
32
|
+
/>
|
|
33
|
+
</ChatEmiProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "chatemi/styles.css";
|
|
2
|
+
import type { Metadata } from "next";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { ChatWidget } from "./components/ChatWidget";
|
|
5
|
+
|
|
6
|
+
export const metadata: Metadata = {
|
|
7
|
+
title: "ChatEmi Next.js example",
|
|
8
|
+
description: "A Next.js app using the ChatEmi launcher widget."
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
12
|
+
return (
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<body>
|
|
15
|
+
{children}
|
|
16
|
+
<ChatWidget />
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ChatEmiConfig } from "chatemi";
|
|
2
|
+
|
|
3
|
+
export function createChatEmiConfig(): ChatEmiConfig {
|
|
4
|
+
return {
|
|
5
|
+
apiBaseUrl: requiredPublicEnv("NEXT_PUBLIC_CHAT_API_URL"),
|
|
6
|
+
socketUrl: process.env.NEXT_PUBLIC_CHAT_SOCKET_URL,
|
|
7
|
+
token: () => localStorage.getItem("access_token") ?? undefined,
|
|
8
|
+
theme: "glass",
|
|
9
|
+
notifications: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
browser: true,
|
|
12
|
+
showWhenOpen: false,
|
|
13
|
+
maxStored: 100
|
|
14
|
+
},
|
|
15
|
+
userDirectory: {
|
|
16
|
+
baseUrl: requiredPublicEnv("NEXT_PUBLIC_IDENTITY_API_URL"),
|
|
17
|
+
searchPath: "/users/search",
|
|
18
|
+
userPath: (userId) => `/users/${encodeURIComponent(userId)}`,
|
|
19
|
+
headers: () => {
|
|
20
|
+
const identityToken = localStorage.getItem("identity_token");
|
|
21
|
+
return identityToken ? { Authorization: `Bearer ${identityToken}` } : {};
|
|
22
|
+
},
|
|
23
|
+
mapUser: (rawUser) => {
|
|
24
|
+
const user = rawUser as {
|
|
25
|
+
id: string;
|
|
26
|
+
displayName?: string;
|
|
27
|
+
name?: string;
|
|
28
|
+
username?: string;
|
|
29
|
+
avatarUrl?: string;
|
|
30
|
+
photoUrl?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
id: user.id,
|
|
35
|
+
name: user.displayName ?? user.name ?? user.username ?? "Unknown user",
|
|
36
|
+
username: user.username,
|
|
37
|
+
avatarUrl: user.avatarUrl ?? user.photoUrl
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function requiredPublicEnv(name: string): string {
|
|
45
|
+
const value = process.env[name];
|
|
46
|
+
|
|
47
|
+
if (!value) {
|
|
48
|
+
throw new Error(`Missing ${name}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createChatEmiMongoConnection } from "chatemi/server";
|
|
2
|
+
|
|
3
|
+
let connectionPromise: ReturnType<typeof createChatEmiMongoConnection> | undefined;
|
|
4
|
+
|
|
5
|
+
export function getChatEmiMongo() {
|
|
6
|
+
if (!connectionPromise) {
|
|
7
|
+
connectionPromise = createChatEmiMongoConnection({
|
|
8
|
+
uri: requiredServerEnv("MONGODB_URI"),
|
|
9
|
+
databaseName: process.env.MONGODB_DB ?? "chatemi",
|
|
10
|
+
clientOptions: {
|
|
11
|
+
appName: "chatemi-nextjs-example"
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return connectionPromise;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function requiredServerEnv(name: string): string {
|
|
20
|
+
const value = process.env[name];
|
|
21
|
+
|
|
22
|
+
if (!value) {
|
|
23
|
+
throw new Error(`Missing ${name}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export default function HomePage() {
|
|
2
|
+
return (
|
|
3
|
+
<main style={{ minHeight: "100vh", padding: 48 }}>
|
|
4
|
+
<h1>ChatEmi widget example</h1>
|
|
5
|
+
<p>
|
|
6
|
+
Open the floating chat button. The provider stays connected in the background,
|
|
7
|
+
so notification badges continue to update when the modal is closed.
|
|
8
|
+
</p>
|
|
9
|
+
</main>
|
|
10
|
+
);
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mademi_dev/chatemi",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A React messaging kit with API clients, realtime socket support, hooks, provider state, and default Telegram-style UI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/chatemi.umd.cjs",
|
|
7
|
+
"module": "dist/chatemi.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/chatemi.js",
|
|
13
|
+
"require": "./dist/chatemi.umd.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./server": {
|
|
16
|
+
"types": "./dist/server/index.d.ts",
|
|
17
|
+
"import": "./dist/server/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./styles.css": "./dist/assets/styles.css"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"docs",
|
|
24
|
+
"examples",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"sideEffects": [
|
|
29
|
+
"**/*.css"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc --noEmit && vite build && tsc -p tsconfig.build.json && tsc -p tsconfig.server.json",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/mademi-dev/ChatEmi.git"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"react",
|
|
42
|
+
"chat",
|
|
43
|
+
"messaging",
|
|
44
|
+
"messenger",
|
|
45
|
+
"websocket",
|
|
46
|
+
"socket",
|
|
47
|
+
"telegram",
|
|
48
|
+
"ui"
|
|
49
|
+
],
|
|
50
|
+
"author": "",
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/mademi-dev/ChatEmi/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/mademi-dev/ChatEmi#readme",
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"mongodb": ">=7.0.0",
|
|
58
|
+
"react": ">=18.0.0",
|
|
59
|
+
"react-dom": ">=18.0.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"mongodb": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@types/node": "^26.0.0",
|
|
68
|
+
"@types/react": "^19.2.17",
|
|
69
|
+
"@types/react-dom": "^19.2.3",
|
|
70
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
71
|
+
"mongodb": "^7.3.0",
|
|
72
|
+
"react": "^19.2.7",
|
|
73
|
+
"react-dom": "^19.2.7",
|
|
74
|
+
"typescript": "^6.0.3",
|
|
75
|
+
"vite": "^8.0.16"
|
|
76
|
+
}
|
|
77
|
+
}
|