@plasius/chatbot 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatbotClientError = void 0;
4
+ exports.getChatbotUsage = getChatbotUsage;
5
+ exports.sendChatbotMessage = sendChatbotMessage;
6
+ class ChatbotClientError extends Error {
7
+ constructor(status, message, code, usage) {
8
+ super(message);
9
+ this.name = "ChatbotClientError";
10
+ this.status = status;
11
+ this.code = code;
12
+ this.usage = usage;
13
+ }
14
+ }
15
+ exports.ChatbotClientError = ChatbotClientError;
16
+ const DEFAULT_ENDPOINT = "/ai/chatbot";
17
+ const DEFAULT_CSRF_COOKIE_NAME = "csrf-token";
18
+ const DEFAULT_CSRF_HEADER_NAME = "x-csrf-token";
19
+ function resolveFetch(fetchFn) {
20
+ const resolved = fetchFn ?? (typeof fetch !== "undefined" ? fetch : undefined);
21
+ if (!resolved) {
22
+ throw new Error("No fetch implementation is available.");
23
+ }
24
+ return resolved;
25
+ }
26
+ async function resolveHeaders(headers) {
27
+ if (!headers)
28
+ return undefined;
29
+ if (typeof headers === "function") {
30
+ return await headers();
31
+ }
32
+ return headers;
33
+ }
34
+ function readCookie(name) {
35
+ if (typeof document === "undefined" || typeof document.cookie !== "string") {
36
+ return undefined;
37
+ }
38
+ const entry = document.cookie
39
+ .split(";")
40
+ .map((part) => part.trim())
41
+ .find((value) => value.startsWith(`${name}=`));
42
+ if (!entry)
43
+ return undefined;
44
+ const [, rawValue = ""] = entry.split("=");
45
+ try {
46
+ return decodeURIComponent(rawValue);
47
+ }
48
+ catch {
49
+ return rawValue;
50
+ }
51
+ }
52
+ function normalizeUsage(value) {
53
+ if (!value || typeof value !== "object")
54
+ return undefined;
55
+ const usage = value;
56
+ if (typeof usage.limit !== "number" ||
57
+ typeof usage.used !== "number" ||
58
+ typeof usage.remaining !== "number" ||
59
+ typeof usage.exhausted !== "boolean") {
60
+ return undefined;
61
+ }
62
+ return {
63
+ limit: usage.limit,
64
+ used: usage.used,
65
+ remaining: usage.remaining,
66
+ exhausted: usage.exhausted,
67
+ };
68
+ }
69
+ async function parseBody(response) {
70
+ const contentType = response.headers.get("content-type") ?? "";
71
+ if (contentType.includes("application/json")) {
72
+ return await response.json();
73
+ }
74
+ const text = await response.text();
75
+ if (!text)
76
+ return undefined;
77
+ try {
78
+ return JSON.parse(text);
79
+ }
80
+ catch {
81
+ return text;
82
+ }
83
+ }
84
+ function normalizeError(status, body) {
85
+ const payload = body && typeof body === "object" ? body : undefined;
86
+ const fallbackMessage = status === 401
87
+ ? "Sign in to use chatbot."
88
+ : status === 429
89
+ ? "Chatbot usage limit reached."
90
+ : "Chatbot request failed.";
91
+ const message = payload?.message ?? fallbackMessage;
92
+ return new ChatbotClientError(status, message, payload?.error, payload?.usage);
93
+ }
94
+ async function ensureCsrfToken(fetcher, endpoint, options, baseHeaders) {
95
+ const cookieName = options.csrfCookieName ?? DEFAULT_CSRF_COOKIE_NAME;
96
+ const existing = readCookie(cookieName);
97
+ if (existing || options.bootstrapCsrf === false) {
98
+ return existing;
99
+ }
100
+ await fetcher(endpoint, {
101
+ method: "GET",
102
+ credentials: options.credentials ?? "include",
103
+ headers: baseHeaders,
104
+ });
105
+ return readCookie(cookieName);
106
+ }
107
+ async function getChatbotUsage(options = {}) {
108
+ const fetcher = resolveFetch(options.fetchFn);
109
+ const endpoint = options.endpoint ?? DEFAULT_ENDPOINT;
110
+ const customHeaders = await resolveHeaders(options.headers);
111
+ const response = await fetcher(endpoint, {
112
+ method: "GET",
113
+ credentials: options.credentials ?? "include",
114
+ headers: {
115
+ Accept: "application/json",
116
+ ...(customHeaders ?? {}),
117
+ },
118
+ });
119
+ const body = await parseBody(response);
120
+ if (!response.ok) {
121
+ throw normalizeError(response.status, body);
122
+ }
123
+ if (!body || typeof body !== "object") {
124
+ throw new Error("Invalid chatbot usage response.");
125
+ }
126
+ const usage = normalizeUsage(body.usage);
127
+ if (!usage) {
128
+ throw new Error("Invalid chatbot usage response.");
129
+ }
130
+ return { usage };
131
+ }
132
+ async function sendChatbotMessage(payload, options = {}) {
133
+ const fetcher = resolveFetch(options.fetchFn);
134
+ const endpoint = options.endpoint ?? DEFAULT_ENDPOINT;
135
+ const customHeaders = await resolveHeaders(options.headers);
136
+ const baseHeaders = {
137
+ Accept: "application/json",
138
+ "Content-Type": "application/json",
139
+ ...(customHeaders ?? {}),
140
+ };
141
+ const csrfToken = await ensureCsrfToken(fetcher, endpoint, options, baseHeaders);
142
+ const csrfHeader = options.csrfHeaderName ?? DEFAULT_CSRF_HEADER_NAME;
143
+ const requestHeaders = csrfToken
144
+ ? {
145
+ ...baseHeaders,
146
+ [csrfHeader]: csrfToken,
147
+ }
148
+ : baseHeaders;
149
+ const response = await fetcher(endpoint, {
150
+ method: "POST",
151
+ credentials: options.credentials ?? "include",
152
+ headers: requestHeaders,
153
+ body: JSON.stringify({
154
+ message: payload.message,
155
+ history: payload.history ?? [],
156
+ systemPrompt: payload.systemPrompt,
157
+ }),
158
+ });
159
+ const body = await parseBody(response);
160
+ if (!response.ok) {
161
+ throw normalizeError(response.status, body);
162
+ }
163
+ if (!body || typeof body !== "object") {
164
+ throw new Error("Invalid chatbot response.");
165
+ }
166
+ const content = body;
167
+ const reply = content.reply;
168
+ const model = content.model;
169
+ const usage = normalizeUsage(content.usage);
170
+ if (typeof reply !== "string" || typeof model !== "string" || !usage) {
171
+ throw new Error("Invalid chatbot response.");
172
+ }
173
+ return { reply, model, usage };
174
+ }
@@ -1,2 +1,3 @@
1
1
  export { default as ChatBot } from "./chatbot.js";
2
+ export * from "./client.js";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,cAAc,aAAa,CAAC"}
package/dist-cjs/index.js CHANGED
@@ -1,4 +1,18 @@
1
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
18
  };
@@ -6,3 +20,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
20
  exports.ChatBot = void 0;
7
21
  var chatbot_js_1 = require("./chatbot.js");
8
22
  Object.defineProperty(exports, "ChatBot", { enumerable: true, get: function () { return __importDefault(chatbot_js_1).default; } });
23
+ __exportStar(require("./client.js"), exports);
@@ -1,106 +1,139 @@
1
- /* src/components/Chatbot.css */
2
1
  .chatbotcontainer {
3
2
  display: flex;
4
3
  flex-direction: column;
5
- height: 100vh;
6
4
  width: 100%;
7
- max-width: 600px;
5
+ max-width: 720px;
8
6
  margin: 0 auto;
9
- border: 1px solid #ddd;
10
- border-radius: 8px;
11
- background: #f9f9f9;
7
+ border: 1px solid #d1d7e0;
8
+ border-radius: 12px;
9
+ background: #f7f9fc;
10
+ min-height: 70vh;
11
+ overflow: hidden;
12
+ }
13
+
14
+ .header {
15
+ display: flex;
16
+ justify-content: space-between;
17
+ align-items: center;
18
+ padding: 12px 16px;
19
+ border-bottom: 1px solid #d1d7e0;
20
+ background: #eef3fb;
21
+ }
22
+
23
+ .title {
24
+ font-size: 16px;
25
+ font-weight: 700;
26
+ color: #1f2a3d;
27
+ }
28
+
29
+ .usage {
30
+ font-size: 13px;
31
+ font-weight: 600;
32
+ color: #4c5970;
33
+ }
34
+
35
+ .notice {
36
+ padding: 10px 16px;
37
+ font-size: 13px;
38
+ border-bottom: 1px solid #d1d7e0;
39
+ background: #fff8db;
40
+ color: #6f5200;
12
41
  }
13
42
 
14
43
  .messagesbox {
15
44
  flex: 1;
16
- padding: 10px;
45
+ padding: 12px;
17
46
  overflow-y: auto;
18
- background: #fff;
47
+ background: #ffffff;
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: 8px;
19
51
  }
20
52
 
21
53
  .message {
22
54
  display: flex;
23
- margin-bottom: 10px;
24
55
  }
25
56
 
26
- .message.user {
27
- justify-content: flex-end;
57
+ .user {
58
+ margin-left: auto;
28
59
  }
29
60
 
30
- .message.system {
31
- justify-content: flex-start;
61
+ .assistant,
62
+ .system {
63
+ margin-right: auto;
32
64
  }
33
65
 
34
66
  .bubble {
35
- max-width: 60%;
36
- padding: 10px 15px;
37
- border-radius: 15px;
67
+ max-width: 85%;
68
+ padding: 10px 12px;
69
+ border-radius: 12px;
70
+ line-height: 1.4;
71
+ word-break: break-word;
72
+ white-space: pre-wrap;
38
73
  font-size: 14px;
39
- line-height: 1.5;
40
- position: relative;
41
- word-wrap: break-word;
42
- }
43
-
44
- .message.user .bubble {
45
- background: #007bff;
46
- color: #fff;
47
- }
48
-
49
- .message.system .bubble {
50
- background: #e9ecef;
51
- color: #333;
52
- }
53
-
54
- .bubble::after {
55
- content: '';
56
- position: absolute;
57
- width: 0;
58
- height: 0;
59
- border-style: solid;
60
74
  }
61
75
 
62
- .message.user .bubble::after {
63
- right: -10px;
64
- top: 50%;
65
- border-width: 10px 0 10px 10px;
66
- border-color: transparent transparent transparent #007bff;
67
- transform: translateY(-50%);
76
+ .user .bubble {
77
+ background: #2463eb;
78
+ color: #ffffff;
68
79
  }
69
80
 
70
- .message.system .bubble::after {
71
- left: -10px;
72
- top: 50%;
73
- border-width: 10px 10px 10px 0;
74
- border-color: transparent #e9ecef transparent transparent;
75
- transform: translateY(-50%);
81
+ .assistant .bubble,
82
+ .system .bubble {
83
+ background: #edf2fa;
84
+ color: #182230;
76
85
  }
77
86
 
78
87
  .inputbox {
79
88
  display: flex;
80
89
  align-items: center;
90
+ gap: 8px;
81
91
  padding: 10px;
82
- border-top: 1px solid #ddd;
83
- background: #fff;
92
+ border-top: 1px solid #d1d7e0;
93
+ background: #f7f9fc;
94
+ position: relative;
84
95
  }
85
96
 
86
97
  .inputbox input {
87
98
  flex: 1;
88
- padding: 10px;
89
- border: 1px solid #ddd;
90
- border-radius: 20px;
99
+ border: 1px solid #c3cedf;
100
+ border-radius: 999px;
101
+ padding: 10px 14px;
91
102
  font-size: 14px;
92
103
  }
93
104
 
94
- .emojiicon, .sendicon {
95
- margin-left: 10px;
105
+ .inputbox input:disabled {
106
+ cursor: not-allowed;
107
+ opacity: 0.75;
108
+ background: #f1f4f9;
109
+ }
110
+
111
+ .iconButton {
112
+ width: 36px;
113
+ height: 36px;
114
+ display: inline-flex;
115
+ align-items: center;
116
+ justify-content: center;
117
+ border: 1px solid #c3cedf;
118
+ border-radius: 999px;
119
+ background: #ffffff;
96
120
  cursor: pointer;
97
- color: whitesmoke;
98
121
  }
99
122
 
100
- .emojiicon {
101
- font-size: 20px;
123
+ .iconButton:disabled {
124
+ cursor: not-allowed;
125
+ opacity: 0.6;
102
126
  }
103
127
 
128
+ .emojiicon,
104
129
  .sendicon {
105
- font-size: 20px;
106
- }
130
+ color: #2f4f95;
131
+ font-size: 16px;
132
+ }
133
+
134
+ .emojiPicker {
135
+ position: absolute;
136
+ right: 44px;
137
+ bottom: 52px;
138
+ z-index: 20;
139
+ }
@@ -0,0 +1,4 @@
1
+ # ADR Index
2
+
3
+ - [ADR-0001: Standalone @plasius/chatbot Package Scope](./adr-0001-chatbot-package-scope.md)
4
+ - [ADR-0002: Public Repository Governance Baseline](./adr-0002-public-repo-governance.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasius/chatbot",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "OpenAI Chatbot",
5
5
  "main": "./dist-cjs/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -38,7 +38,6 @@
38
38
  "react-icons": "^5.5.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "openai": "^5.19.1",
42
41
  "react": "^19.1.0"
43
42
  },
44
43
  "devDependencies": {
@@ -52,7 +51,6 @@
52
51
  "depcheck": "^1.4.7",
53
52
  "eslint": "^9.33.0",
54
53
  "npm-run-all": "^4.1.5",
55
- "openai": "^5.19.1",
56
54
  "react": "19.1.0",
57
55
  "react-dom": "19.1.0",
58
56
  "tsx": "^4.20.3",