@convosite/client 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Convosite
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,170 @@
1
- # Temporary Holding Version
1
+ # @convosite/client
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Framework-agnostic JavaScript and TypeScript client for building Convosite conversational experiences. It has no runtime dependencies and uses the platform `fetch` API, so it works in browsers, Node 18+, React, Next.js, Vue, Nuxt, Svelte, SvelteKit, Astro, Bun and other modern JavaScript runtimes.
4
+
5
+ Convosite's client-side runtime is intentionally small: developers define **blocks** and **endpoints** through the CLI, content is managed as **knowledge** inside Convosite, and applications consume conversations and invoke public endpoint actions. Knowledge is retrieved internally by the conversation runtime and is not exposed as a headless CMS API.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @convosite/client
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```ts
16
+ import { createConvosite } from '@convosite/client';
17
+
18
+ const convosite = createConvosite({
19
+ site: 'YOUR_SITE_ULID',
20
+ });
21
+
22
+ const conversation = convosite.conversations.create();
23
+
24
+ for await (const event of conversation.send('What services do you offer?')) {
25
+ console.log(event);
26
+ }
27
+ ```
28
+
29
+ Production defaults to `https://app.convosite.io/api`. No API token belongs in frontend code. Protected site variables remain server-side and can be used by endpoint actions without being exposed to the browser.
30
+
31
+ ## Conversations
32
+
33
+ Conversations are streamed from the Convosite runtime as NDJSON. The SDK parses the stream and manages the `X-Conversation-Session` header automatically.
34
+
35
+ ```ts
36
+ const conversation = convosite.conversations.create();
37
+
38
+ for await (const event of conversation.send('Help me choose the right service.')) {
39
+ if (event.type === 'field_delta') {
40
+ console.log(event.path, event.delta);
41
+ }
42
+
43
+ if (event.type === 'field_complete') {
44
+ console.log(event.path, event.value);
45
+ }
46
+
47
+ if (event.type === 'conversation_usage') {
48
+ console.log(event.user_turns, event.max_user_turns);
49
+ }
50
+
51
+ if (event.type === 'complete') {
52
+ console.log('Turn complete');
53
+ }
54
+ }
55
+
56
+ // Continues the same server-side conversation.
57
+ for await (const event of conversation.send('Tell me more.')) {
58
+ console.log(event);
59
+ }
60
+
61
+ await conversation.end();
62
+ ```
63
+
64
+ Use `conversation.sessionId` to inspect the current session. `conversation.reset()` forgets the session locally without ending it on the server.
65
+
66
+ ### Manage session IDs yourself
67
+
68
+ ```ts
69
+ for await (const event of convosite.conversations.send('Hello', {
70
+ sessionId: 'SESSION_UUID',
71
+ })) {
72
+ console.log(event);
73
+ }
74
+
75
+ await convosite.conversations.end('SESSION_UUID');
76
+ ```
77
+
78
+ ## Actions
79
+
80
+ Invoke an endpoint defined by the developer and pushed through `@convosite/cli`:
81
+
82
+ ```ts
83
+ await convosite.actions.run('ENDPOINT_ULID', {
84
+ name: 'Joe',
85
+ email: 'joe@example.com',
86
+ message: 'Hello',
87
+ });
88
+ ```
89
+
90
+ Only public input is sent by the client. Site variables such as API tokens remain server-side and are resolved by Convosite when the endpoint action runs.
91
+
92
+ ## Knowledge
93
+
94
+ Knowledge is intentionally not exposed by this package. Knowledge and Knowledge Items are managed in Convosite and indexed for retrieval. The conversation runtime uses that knowledge when generating conversational experiences.
95
+
96
+ This keeps application code focused on conversations rather than turning Knowledge into another public content API.
97
+
98
+ ## Cancellation
99
+
100
+ Actions and conversation streams accept an `AbortSignal`:
101
+
102
+ ```ts
103
+ const controller = new AbortController();
104
+
105
+ for await (const event of convosite.conversations.send('Hello', {
106
+ signal: controller.signal,
107
+ })) {
108
+ console.log(event);
109
+ }
110
+
111
+ controller.abort();
112
+ ```
113
+
114
+ ## SSR and custom fetch
115
+
116
+ A custom `fetch` can be supplied for framework runtimes, instrumentation or tests:
117
+
118
+ ```ts
119
+ const convosite = createConvosite({
120
+ site: 'YOUR_SITE_ULID',
121
+ fetch: customFetch,
122
+ });
123
+ ```
124
+
125
+ ## Errors
126
+
127
+ ```ts
128
+ import { ConvositeError } from '@convosite/client';
129
+
130
+ try {
131
+ await convosite.actions.run('ENDPOINT_ULID', {});
132
+ } catch (error) {
133
+ if (error instanceof ConvositeError) {
134
+ console.log(error.status);
135
+ console.log(error.code);
136
+ console.log(error.message);
137
+ console.log(error.details);
138
+ console.log(error.requestId);
139
+ }
140
+ }
141
+ ```
142
+
143
+ Validation errors are available through `details`. Conversation error codes such as `conversation_ended` and `conversation_limit_reached` are exposed through `code` when returned by the runtime.
144
+
145
+ ## Raw request escape hatch
146
+
147
+ For public Laravel API endpoints that are not yet wrapped by the SDK:
148
+
149
+ ```ts
150
+ const data = await convosite.request('/some/runtime/endpoint');
151
+ ```
152
+
153
+ The path is relative to `baseUrl` and uses the same error handling, timeout and configured headers as actions.
154
+
155
+ ## Configuration
156
+
157
+ ```ts
158
+ const convosite = createConvosite({
159
+ site: 'YOUR_SITE_ULID',
160
+ baseUrl: 'https://app.convosite.io/api',
161
+ conversationUrl: 'https://app.convosite.io/api',
162
+ timeout: 30_000,
163
+ headers: {},
164
+ fetch: globalThis.fetch,
165
+ });
166
+ ```
167
+
168
+ `baseUrl` is used for actions and raw requests. `conversationUrl` is used for streamed conversations and defaults to `baseUrl`.
169
+
170
+ The timeout applies to normal JSON requests. Conversation streams intentionally have no fixed SDK timeout; use an `AbortSignal` when needed.
package/dist/index.cjs ADDED
@@ -0,0 +1,317 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ConvositeError: () => ConvositeError,
24
+ createConvosite: () => createConvosite
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/errors.ts
29
+ var ConvositeError = class extends Error {
30
+ status;
31
+ code;
32
+ details;
33
+ requestId;
34
+ constructor(options) {
35
+ super(options.message, options.cause === void 0 ? void 0 : { cause: options.cause });
36
+ this.name = "ConvositeError";
37
+ this.status = options.status ?? 0;
38
+ this.code = options.code ?? null;
39
+ this.details = options.details ?? null;
40
+ this.requestId = options.requestId ?? null;
41
+ }
42
+ };
43
+
44
+ // src/http.ts
45
+ function normalizeBaseUrl(value) {
46
+ return value.replace(/\/+$/, "");
47
+ }
48
+ function joinUrl(base, path) {
49
+ if (/^https?:\/\//i.test(path)) return path;
50
+ return `${normalizeBaseUrl(base)}/${path.replace(/^\/+/, "")}`;
51
+ }
52
+ function encodeSegment(value) {
53
+ return encodeURIComponent(value);
54
+ }
55
+ function timeoutSignal(signal, timeout) {
56
+ if (timeout <= 0) return signal ? { signal, cleanup: () => void 0 } : { cleanup: () => void 0 };
57
+ const controller = new AbortController();
58
+ const timer = setTimeout(() => controller.abort(new DOMException("Request timed out.", "TimeoutError")), timeout);
59
+ const abort = () => controller.abort(signal?.reason);
60
+ if (signal) {
61
+ if (signal.aborted) abort();
62
+ else signal.addEventListener("abort", abort, { once: true });
63
+ }
64
+ return {
65
+ signal: controller.signal,
66
+ cleanup: () => {
67
+ clearTimeout(timer);
68
+ signal?.removeEventListener("abort", abort);
69
+ }
70
+ };
71
+ }
72
+ async function responseBody(response) {
73
+ const text = await response.text();
74
+ if (!text) return null;
75
+ try {
76
+ return JSON.parse(text);
77
+ } catch {
78
+ return text;
79
+ }
80
+ }
81
+ function errorFrom(response, body) {
82
+ const object = body && typeof body === "object" ? body : {};
83
+ const message = typeof object.message === "string" ? object.message : `Convosite request failed with status ${response.status}.`;
84
+ const code = typeof object.error === "string" ? object.error : null;
85
+ const details = object.errors ?? body;
86
+ return new ConvositeError({
87
+ message,
88
+ status: response.status,
89
+ code,
90
+ details,
91
+ requestId: response.headers.get("X-Request-ID")
92
+ });
93
+ }
94
+ var HttpClient = class {
95
+ constructor(fetcher, baseUrl, headers, timeout) {
96
+ this.fetcher = fetcher;
97
+ this.baseUrl = baseUrl;
98
+ this.headers = headers;
99
+ this.timeout = timeout;
100
+ }
101
+ fetcher;
102
+ baseUrl;
103
+ headers;
104
+ timeout;
105
+ async api(path, init = {}) {
106
+ const response = await this.fetch(path, init, true);
107
+ const body = await responseBody(response);
108
+ if (!response.ok) throw errorFrom(response, body);
109
+ if (!body || typeof body !== "object" || !("success" in body)) {
110
+ throw new ConvositeError({ message: "Convosite returned an invalid API response.", status: response.status, details: body });
111
+ }
112
+ const envelope = body;
113
+ if (envelope.success !== true) {
114
+ throw new ConvositeError({ message: envelope.message || "Convosite request failed.", status: response.status, details: envelope.errors });
115
+ }
116
+ return envelope.data;
117
+ }
118
+ async raw(path, options = {}) {
119
+ const { parseAs = "json", ...init } = options;
120
+ const response = await this.fetch(path, init, true);
121
+ if (!response.ok) throw errorFrom(response, await responseBody(response));
122
+ if (parseAs === "response") return response;
123
+ if (parseAs === "text") return await response.text();
124
+ if (response.status === 204) return void 0;
125
+ return await response.json();
126
+ }
127
+ async fetch(path, init = {}, useTimeout = false) {
128
+ const headers = new Headers(this.headers);
129
+ new Headers(init.headers).forEach((value, key) => headers.set(key, value));
130
+ const timed = useTimeout ? timeoutSignal(init.signal ?? void 0, this.timeout) : timeoutSignal(init.signal ?? void 0, 0);
131
+ try {
132
+ const requestInit = { ...init, headers };
133
+ if (timed.signal) requestInit.signal = timed.signal;
134
+ return await this.fetcher(joinUrl(this.baseUrl, path), requestInit);
135
+ } catch (cause) {
136
+ if (cause instanceof ConvositeError) throw cause;
137
+ const aborted = timed.signal?.aborted;
138
+ throw new ConvositeError({
139
+ message: aborted ? "Convosite request was aborted." : "Unable to connect to Convosite.",
140
+ code: aborted ? "request_aborted" : "network_error",
141
+ cause
142
+ });
143
+ } finally {
144
+ timed.cleanup();
145
+ }
146
+ }
147
+ };
148
+ async function workerError(response) {
149
+ return errorFrom(response, await responseBody(response));
150
+ }
151
+
152
+ // src/conversations.ts
153
+ async function* parseNdjson(response) {
154
+ if (!response.body) throw new ConvositeError({ message: "Conversation response did not contain a stream.", status: response.status });
155
+ const reader = response.body.getReader();
156
+ const decoder = new TextDecoder();
157
+ let buffer = "";
158
+ try {
159
+ while (true) {
160
+ const { value, done } = await reader.read();
161
+ buffer += decoder.decode(value, { stream: !done });
162
+ let newline;
163
+ while ((newline = buffer.indexOf("\n")) !== -1) {
164
+ const line = buffer.slice(0, newline).trim();
165
+ buffer = buffer.slice(newline + 1);
166
+ if (line) yield parseEvent(line);
167
+ }
168
+ if (done) break;
169
+ }
170
+ const tail = buffer.trim();
171
+ if (tail) yield parseEvent(tail);
172
+ } finally {
173
+ reader.releaseLock();
174
+ }
175
+ }
176
+ function parseEvent(line) {
177
+ try {
178
+ const event = JSON.parse(line);
179
+ if (!event || typeof event !== "object" || typeof event.type !== "string") {
180
+ throw new Error("Event has no type.");
181
+ }
182
+ return event;
183
+ } catch (cause) {
184
+ throw new ConvositeError({ message: "Conversation stream contained an invalid event.", code: "invalid_stream", details: line, cause });
185
+ }
186
+ }
187
+ var ConversationsClient = class {
188
+ constructor(fetcher, baseUrl, siteId) {
189
+ this.fetcher = fetcher;
190
+ this.baseUrl = baseUrl;
191
+ this.siteId = siteId;
192
+ }
193
+ fetcher;
194
+ baseUrl;
195
+ siteId;
196
+ create(sessionId) {
197
+ let currentSession = sessionId?.trim() || null;
198
+ const client = this;
199
+ return {
200
+ get sessionId() {
201
+ return currentSession;
202
+ },
203
+ async *send(query, options = {}) {
204
+ const stream = client.send(query, { ...options, ...currentSession ? { sessionId: currentSession } : {} }, (id) => {
205
+ currentSession = id;
206
+ });
207
+ yield* stream;
208
+ },
209
+ async end(options = {}) {
210
+ if (!currentSession) return { ended: false };
211
+ const result = await client.end(currentSession, options);
212
+ if (result.ended) currentSession = null;
213
+ return result;
214
+ },
215
+ reset() {
216
+ currentSession = null;
217
+ }
218
+ };
219
+ }
220
+ async *send(query, options = {}, onSession) {
221
+ const trimmed = query.trim();
222
+ if (!trimmed) throw new ConvositeError({ message: "Conversation query is required.", code: "validation_error" });
223
+ const headers = new Headers({ "Content-Type": "application/json", "Accept": "application/x-ndjson" });
224
+ if (options.sessionId) headers.set("X-Conversation-Session", options.sessionId);
225
+ let response;
226
+ try {
227
+ const init = { method: "POST", headers, body: JSON.stringify({ query: trimmed }) };
228
+ if (options.signal) init.signal = options.signal;
229
+ response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}`), init);
230
+ } catch (cause) {
231
+ throw new ConvositeError({ message: options.signal?.aborted ? "Conversation request was aborted." : "Unable to connect to Convosite conversations.", code: options.signal?.aborted ? "request_aborted" : "network_error", cause });
232
+ }
233
+ if (!response.ok) throw await workerError(response);
234
+ const session = response.headers.get("X-Conversation-Session");
235
+ if (session) onSession?.(session);
236
+ yield* parseNdjson(response);
237
+ }
238
+ async end(sessionId, options = {}) {
239
+ const headers = new Headers({ "Accept": "application/json", "X-Conversation-Session": sessionId });
240
+ let response;
241
+ try {
242
+ const init = { method: "POST", headers };
243
+ if (options.signal) init.signal = options.signal;
244
+ response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}/end`), init);
245
+ } catch (cause) {
246
+ throw new ConvositeError({ message: options.signal?.aborted ? "Conversation request was aborted." : "Unable to connect to Convosite conversations.", code: options.signal?.aborted ? "request_aborted" : "network_error", cause });
247
+ }
248
+ if (!response.ok) throw await workerError(response);
249
+ return await response.json();
250
+ }
251
+ };
252
+
253
+ // src/client.ts
254
+ var DEFAULT_BASE_URL = "https://app.convosite.io/api";
255
+ function createConvosite(config) {
256
+ if (!config || typeof config.site !== "string" || !config.site.trim()) {
257
+ throw new ConvositeError({
258
+ message: "A Convosite site ID is required.",
259
+ code: "invalid_config"
260
+ });
261
+ }
262
+ const fetcher = config.fetch ?? globalThis.fetch?.bind(globalThis);
263
+ if (!fetcher) {
264
+ throw new ConvositeError({
265
+ message: "No fetch implementation is available.",
266
+ code: "invalid_config"
267
+ });
268
+ }
269
+ const siteId = config.site.trim();
270
+ const site = encodeSegment(siteId);
271
+ const baseUrl = normalizeBaseUrl(config.baseUrl ?? DEFAULT_BASE_URL);
272
+ const conversationUrl = normalizeBaseUrl(config.conversationUrl ?? baseUrl);
273
+ const http = new HttpClient(
274
+ fetcher,
275
+ baseUrl,
276
+ config.headers ?? {},
277
+ config.timeout ?? 3e4
278
+ );
279
+ const conversations = new ConversationsClient(fetcher, conversationUrl, siteId);
280
+ const requestOptions = (options) => options?.signal ? { signal: options.signal } : {};
281
+ return {
282
+ actions: {
283
+ run: (endpointId, input, options) => {
284
+ if (typeof endpointId !== "string" || !endpointId.trim()) {
285
+ throw new ConvositeError({
286
+ message: "An endpoint ID is required.",
287
+ code: "validation_error"
288
+ });
289
+ }
290
+ return http.api(
291
+ `/actions/${site}/${encodeSegment(endpointId.trim())}`,
292
+ {
293
+ method: "POST",
294
+ headers: {
295
+ "Content-Type": "application/json",
296
+ Accept: "application/json"
297
+ },
298
+ body: JSON.stringify(input),
299
+ ...requestOptions(options)
300
+ }
301
+ );
302
+ }
303
+ },
304
+ conversations: {
305
+ create: (sessionId) => conversations.create(sessionId),
306
+ send: (query, options) => conversations.send(query, options),
307
+ end: (sessionId, options) => conversations.end(sessionId, options)
308
+ },
309
+ request: (path, options = {}) => http.raw(path, options)
310
+ };
311
+ }
312
+ // Annotate the CommonJS export names for ESM import in node:
313
+ 0 && (module.exports = {
314
+ ConvositeError,
315
+ createConvosite
316
+ });
317
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/conversations.ts","../src/client.ts"],"sourcesContent":["export { createConvosite } from './client';\nexport { ConvositeError } from './errors';\nexport type {\n ActionResponse,\n Conversation,\n ConversationCompleteEvent,\n ConversationEndResponse,\n ConversationErrorEvent,\n ConversationEvent,\n ConversationFieldEvent,\n ConversationSendOptions,\n ConversationUsageEvent,\n ConvositeClient,\n ConvositeConfig,\n Fetch,\n JsonPrimitive,\n JsonValue,\n RawRequestOptions,\n RequestOptions,\n} from './types';\n","export class ConvositeError extends Error {\n readonly status: number;\n readonly code: string | null;\n readonly details: unknown;\n readonly requestId: string | null;\n\n constructor(options: {\n message: string;\n status?: number;\n code?: string | null;\n details?: unknown;\n requestId?: string | null;\n cause?: unknown;\n }) {\n super(options.message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = 'ConvositeError';\n this.status = options.status ?? 0;\n this.code = options.code ?? null;\n this.details = options.details ?? null;\n this.requestId = options.requestId ?? null;\n }\n}\n","import { ConvositeError } from './errors';\nimport type { Fetch, RawRequestOptions } from './types';\n\ninterface ApiEnvelope<T> {\n success: boolean;\n message: string;\n data: T;\n errors: unknown;\n}\n\nexport function normalizeBaseUrl(value: string): string {\n return value.replace(/\\/+$/, '');\n}\n\nexport function joinUrl(base: string, path: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n return `${normalizeBaseUrl(base)}/${path.replace(/^\\/+/, '')}`;\n}\n\nexport function encodeSegment(value: string): string {\n return encodeURIComponent(value);\n}\n\nfunction timeoutSignal(signal: AbortSignal | undefined, timeout: number): { signal?: AbortSignal; cleanup: () => void } {\n if (timeout <= 0) return signal ? { signal, cleanup: () => undefined } : { cleanup: () => undefined };\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException('Request timed out.', 'TimeoutError')), timeout);\n const abort = () => controller.abort(signal?.reason);\n if (signal) {\n if (signal.aborted) abort();\n else signal.addEventListener('abort', abort, { once: true });\n }\n return {\n signal: controller.signal,\n cleanup: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n },\n };\n}\n\nasync function responseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!text) return null;\n try { return JSON.parse(text); } catch { return text; }\n}\n\nfunction errorFrom(response: Response, body: unknown): ConvositeError {\n const object = body && typeof body === 'object' ? body as Record<string, unknown> : {};\n const message = typeof object.message === 'string' ? object.message : `Convosite request failed with status ${response.status}.`;\n const code = typeof object.error === 'string' ? object.error : null;\n const details = object.errors ?? body;\n return new ConvositeError({\n message,\n status: response.status,\n code,\n details,\n requestId: response.headers.get('X-Request-ID'),\n });\n}\n\nexport class HttpClient {\n constructor(\n private readonly fetcher: Fetch,\n private readonly baseUrl: string,\n private readonly headers: HeadersInit,\n private readonly timeout: number,\n ) {}\n\n async api<T>(path: string, init: RequestInit = {}): Promise<T> {\n const response = await this.fetch(path, init, true);\n const body = await responseBody(response);\n if (!response.ok) throw errorFrom(response, body);\n if (!body || typeof body !== 'object' || !('success' in body)) {\n throw new ConvositeError({ message: 'Convosite returned an invalid API response.', status: response.status, details: body });\n }\n const envelope = body as ApiEnvelope<T>;\n if (envelope.success !== true) {\n throw new ConvositeError({ message: envelope.message || 'Convosite request failed.', status: response.status, details: envelope.errors });\n }\n return envelope.data;\n }\n\n async raw<T>(path: string, options: RawRequestOptions = {}): Promise<T> {\n const { parseAs = 'json', ...init } = options;\n const response = await this.fetch(path, init, true);\n if (!response.ok) throw errorFrom(response, await responseBody(response));\n if (parseAs === 'response') return response as T;\n if (parseAs === 'text') return await response.text() as T;\n if (response.status === 204) return undefined as T;\n return await response.json() as T;\n }\n\n async fetch(path: string, init: RequestInit = {}, useTimeout = false): Promise<Response> {\n const headers = new Headers(this.headers);\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\n const timed = useTimeout ? timeoutSignal(init.signal ?? undefined, this.timeout) : timeoutSignal(init.signal ?? undefined, 0);\n try {\n const requestInit: RequestInit = { ...init, headers };\n if (timed.signal) requestInit.signal = timed.signal;\n return await this.fetcher(joinUrl(this.baseUrl, path), requestInit);\n } catch (cause) {\n if (cause instanceof ConvositeError) throw cause;\n const aborted = timed.signal?.aborted;\n throw new ConvositeError({\n message: aborted ? 'Convosite request was aborted.' : 'Unable to connect to Convosite.',\n code: aborted ? 'request_aborted' : 'network_error',\n cause,\n });\n } finally {\n timed.cleanup();\n }\n }\n}\n\nexport async function workerError(response: Response): Promise<ConvositeError> {\n return errorFrom(response, await responseBody(response));\n}\n","import { ConvositeError } from './errors';\nimport { encodeSegment, joinUrl, workerError } from './http';\nimport type {\n Conversation,\n ConversationEndResponse,\n ConversationEvent,\n ConversationSendOptions,\n Fetch,\n RequestOptions,\n} from './types';\n\nasync function* parseNdjson(response: Response): AsyncGenerator<ConversationEvent> {\n if (!response.body) throw new ConvositeError({ message: 'Conversation response did not contain a stream.', status: response.status });\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n while (true) {\n const { value, done } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (line) yield parseEvent(line);\n }\n if (done) break;\n }\n const tail = buffer.trim();\n if (tail) yield parseEvent(tail);\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction parseEvent(line: string): ConversationEvent {\n try {\n const event = JSON.parse(line) as unknown;\n if (!event || typeof event !== 'object' || typeof (event as { type?: unknown }).type !== 'string') {\n throw new Error('Event has no type.');\n }\n return event as ConversationEvent;\n } catch (cause) {\n throw new ConvositeError({ message: 'Conversation stream contained an invalid event.', code: 'invalid_stream', details: line, cause });\n }\n}\n\nexport class ConversationsClient {\n constructor(\n private readonly fetcher: Fetch,\n private readonly baseUrl: string,\n private readonly siteId: string,\n ) {}\n\n create(sessionId?: string): Conversation {\n let currentSession = sessionId?.trim() || null;\n const client = this;\n return {\n get sessionId() { return currentSession; },\n async *send(query: string, options: RequestOptions = {}) {\n const stream = client.send(query, { ...options, ...(currentSession ? { sessionId: currentSession } : {}) }, (id) => { currentSession = id; });\n yield* stream;\n },\n async end(options: RequestOptions = {}) {\n if (!currentSession) return { ended: false };\n const result = await client.end(currentSession, options);\n if (result.ended) currentSession = null;\n return result;\n },\n reset() { currentSession = null; },\n };\n }\n\n async *send(\n query: string,\n options: ConversationSendOptions = {},\n onSession?: (sessionId: string) => void,\n ): AsyncGenerator<ConversationEvent> {\n const trimmed = query.trim();\n if (!trimmed) throw new ConvositeError({ message: 'Conversation query is required.', code: 'validation_error' });\n const headers = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/x-ndjson' });\n if (options.sessionId) headers.set('X-Conversation-Session', options.sessionId);\n let response: Response;\n try {\n const init: RequestInit = { method: 'POST', headers, body: JSON.stringify({ query: trimmed }) };\n if (options.signal) init.signal = options.signal;\n response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}`), init);\n } catch (cause) {\n throw new ConvositeError({ message: options.signal?.aborted ? 'Conversation request was aborted.' : 'Unable to connect to Convosite conversations.', code: options.signal?.aborted ? 'request_aborted' : 'network_error', cause });\n }\n if (!response.ok) throw await workerError(response);\n const session = response.headers.get('X-Conversation-Session');\n if (session) onSession?.(session);\n yield* parseNdjson(response);\n }\n\n async end(sessionId: string, options: RequestOptions = {}): Promise<ConversationEndResponse> {\n const headers = new Headers({ 'Accept': 'application/json', 'X-Conversation-Session': sessionId });\n let response: Response;\n try {\n const init: RequestInit = { method: 'POST', headers };\n if (options.signal) init.signal = options.signal;\n response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}/end`), init);\n } catch (cause) {\n throw new ConvositeError({ message: options.signal?.aborted ? 'Conversation request was aborted.' : 'Unable to connect to Convosite conversations.', code: options.signal?.aborted ? 'request_aborted' : 'network_error', cause });\n }\n if (!response.ok) throw await workerError(response);\n return await response.json() as ConversationEndResponse;\n }\n}\n","import { ConversationsClient } from './conversations';\nimport { ConvositeError } from './errors';\nimport { encodeSegment, HttpClient, normalizeBaseUrl } from './http';\nimport type {\n ActionResponse,\n ConvositeClient,\n ConvositeConfig,\n RawRequestOptions,\n RequestOptions,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://app.convosite.io/api';\n\nexport function createConvosite(config: ConvositeConfig): ConvositeClient {\n if (!config || typeof config.site !== 'string' || !config.site.trim()) {\n throw new ConvositeError({\n message: 'A Convosite site ID is required.',\n code: 'invalid_config',\n });\n }\n\n const fetcher = config.fetch ?? globalThis.fetch?.bind(globalThis);\n if (!fetcher) {\n throw new ConvositeError({\n message: 'No fetch implementation is available.',\n code: 'invalid_config',\n });\n }\n\n const siteId = config.site.trim();\n const site = encodeSegment(siteId);\n const baseUrl = normalizeBaseUrl(config.baseUrl ?? DEFAULT_BASE_URL);\n const conversationUrl = normalizeBaseUrl(config.conversationUrl ?? baseUrl);\n const http = new HttpClient(\n fetcher,\n baseUrl,\n config.headers ?? {},\n config.timeout ?? 30_000,\n );\n const conversations = new ConversationsClient(fetcher, conversationUrl, siteId);\n\n const requestOptions = (options?: RequestOptions): RequestInit =>\n options?.signal ? { signal: options.signal } : {};\n\n return {\n actions: {\n run: (endpointId, input, options) => {\n if (typeof endpointId !== 'string' || !endpointId.trim()) {\n throw new ConvositeError({\n message: 'An endpoint ID is required.',\n code: 'validation_error',\n });\n }\n\n return http.api<ActionResponse>(\n `/actions/${site}/${encodeSegment(endpointId.trim())}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(input),\n ...requestOptions(options),\n },\n );\n },\n },\n conversations: {\n create: (sessionId) => conversations.create(sessionId),\n send: (query, options) => conversations.send(query, options),\n end: (sessionId, options) => conversations.end(sessionId, options),\n },\n request: <T = unknown>(path: string, options: RawRequestOptions = {}) =>\n http.raw<T>(path, options),\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,110 @@
1
+ type JsonPrimitive = string | number | boolean | null;
2
+ type JsonValue = JsonPrimitive | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ interface ActionResponse {
6
+ message: string;
7
+ }
8
+ interface RequestOptions {
9
+ signal?: AbortSignal;
10
+ }
11
+ interface RawRequestOptions extends RequestInit {
12
+ /** Parse successful responses as JSON by default. */
13
+ parseAs?: 'json' | 'text' | 'response';
14
+ }
15
+ interface ConversationSendOptions extends RequestOptions {
16
+ sessionId?: string;
17
+ }
18
+ type ConversationFieldEvent = {
19
+ type: 'field_delta';
20
+ path: string;
21
+ delta: string;
22
+ value?: unknown;
23
+ [key: string]: unknown;
24
+ } | {
25
+ type: 'field_complete';
26
+ path: string;
27
+ value: unknown;
28
+ [key: string]: unknown;
29
+ } | {
30
+ type: 'field';
31
+ path: string;
32
+ value?: unknown;
33
+ delta?: string;
34
+ [key: string]: unknown;
35
+ };
36
+ interface ConversationUsageEvent {
37
+ type: 'conversation_usage';
38
+ user_turns: number;
39
+ max_user_turns: number;
40
+ reached_limit: boolean;
41
+ [key: string]: unknown;
42
+ }
43
+ interface ConversationCompleteEvent {
44
+ type: 'complete';
45
+ [key: string]: unknown;
46
+ }
47
+ interface ConversationErrorEvent {
48
+ type: 'error';
49
+ message: string;
50
+ request_id?: string;
51
+ [key: string]: unknown;
52
+ }
53
+ type ConversationEvent = ConversationFieldEvent | ConversationUsageEvent | ConversationCompleteEvent | ConversationErrorEvent | ({
54
+ type: string;
55
+ } & Record<string, unknown>);
56
+ interface ConversationEndResponse {
57
+ ended: boolean;
58
+ }
59
+ interface Conversation {
60
+ readonly sessionId: string | null;
61
+ send(query: string, options?: RequestOptions): AsyncIterable<ConversationEvent>;
62
+ end(options?: RequestOptions): Promise<ConversationEndResponse>;
63
+ reset(): void;
64
+ }
65
+ type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
66
+ interface ConvositeConfig {
67
+ /** Site ULID used by the Convosite runtime. */
68
+ site: string;
69
+ /** Laravel public API base. Defaults to https://app.convosite.io/api. */
70
+ baseUrl?: string;
71
+ /** Conversations Worker base. Defaults to baseUrl. */
72
+ conversationUrl?: string;
73
+ /** Custom fetch implementation for SSR runtimes, tests, proxies, etc. */
74
+ fetch?: Fetch;
75
+ /** Headers applied to Laravel API requests. */
76
+ headers?: HeadersInit;
77
+ /** Timeout for non-streaming requests in milliseconds. Defaults to 30000. Set 0 to disable. */
78
+ timeout?: number;
79
+ }
80
+ interface ConvositeClient {
81
+ readonly actions: {
82
+ run<TInput extends Record<string, unknown> = Record<string, unknown>>(endpointId: string, input: TInput, options?: RequestOptions): Promise<ActionResponse>;
83
+ };
84
+ readonly conversations: {
85
+ create(sessionId?: string): Conversation;
86
+ send(query: string, options?: ConversationSendOptions): AsyncIterable<ConversationEvent>;
87
+ end(sessionId: string, options?: RequestOptions): Promise<ConversationEndResponse>;
88
+ };
89
+ /** Escape hatch for public Laravel API endpoints not yet wrapped by the SDK. */
90
+ request<T = unknown>(path: string, options?: RawRequestOptions): Promise<T>;
91
+ }
92
+
93
+ declare function createConvosite(config: ConvositeConfig): ConvositeClient;
94
+
95
+ declare class ConvositeError extends Error {
96
+ readonly status: number;
97
+ readonly code: string | null;
98
+ readonly details: unknown;
99
+ readonly requestId: string | null;
100
+ constructor(options: {
101
+ message: string;
102
+ status?: number;
103
+ code?: string | null;
104
+ details?: unknown;
105
+ requestId?: string | null;
106
+ cause?: unknown;
107
+ });
108
+ }
109
+
110
+ export { type ActionResponse, type Conversation, type ConversationCompleteEvent, type ConversationEndResponse, type ConversationErrorEvent, type ConversationEvent, type ConversationFieldEvent, type ConversationSendOptions, type ConversationUsageEvent, type ConvositeClient, type ConvositeConfig, ConvositeError, type Fetch, type JsonPrimitive, type JsonValue, type RawRequestOptions, type RequestOptions, createConvosite };
@@ -0,0 +1,110 @@
1
+ type JsonPrimitive = string | number | boolean | null;
2
+ type JsonValue = JsonPrimitive | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ interface ActionResponse {
6
+ message: string;
7
+ }
8
+ interface RequestOptions {
9
+ signal?: AbortSignal;
10
+ }
11
+ interface RawRequestOptions extends RequestInit {
12
+ /** Parse successful responses as JSON by default. */
13
+ parseAs?: 'json' | 'text' | 'response';
14
+ }
15
+ interface ConversationSendOptions extends RequestOptions {
16
+ sessionId?: string;
17
+ }
18
+ type ConversationFieldEvent = {
19
+ type: 'field_delta';
20
+ path: string;
21
+ delta: string;
22
+ value?: unknown;
23
+ [key: string]: unknown;
24
+ } | {
25
+ type: 'field_complete';
26
+ path: string;
27
+ value: unknown;
28
+ [key: string]: unknown;
29
+ } | {
30
+ type: 'field';
31
+ path: string;
32
+ value?: unknown;
33
+ delta?: string;
34
+ [key: string]: unknown;
35
+ };
36
+ interface ConversationUsageEvent {
37
+ type: 'conversation_usage';
38
+ user_turns: number;
39
+ max_user_turns: number;
40
+ reached_limit: boolean;
41
+ [key: string]: unknown;
42
+ }
43
+ interface ConversationCompleteEvent {
44
+ type: 'complete';
45
+ [key: string]: unknown;
46
+ }
47
+ interface ConversationErrorEvent {
48
+ type: 'error';
49
+ message: string;
50
+ request_id?: string;
51
+ [key: string]: unknown;
52
+ }
53
+ type ConversationEvent = ConversationFieldEvent | ConversationUsageEvent | ConversationCompleteEvent | ConversationErrorEvent | ({
54
+ type: string;
55
+ } & Record<string, unknown>);
56
+ interface ConversationEndResponse {
57
+ ended: boolean;
58
+ }
59
+ interface Conversation {
60
+ readonly sessionId: string | null;
61
+ send(query: string, options?: RequestOptions): AsyncIterable<ConversationEvent>;
62
+ end(options?: RequestOptions): Promise<ConversationEndResponse>;
63
+ reset(): void;
64
+ }
65
+ type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
66
+ interface ConvositeConfig {
67
+ /** Site ULID used by the Convosite runtime. */
68
+ site: string;
69
+ /** Laravel public API base. Defaults to https://app.convosite.io/api. */
70
+ baseUrl?: string;
71
+ /** Conversations Worker base. Defaults to baseUrl. */
72
+ conversationUrl?: string;
73
+ /** Custom fetch implementation for SSR runtimes, tests, proxies, etc. */
74
+ fetch?: Fetch;
75
+ /** Headers applied to Laravel API requests. */
76
+ headers?: HeadersInit;
77
+ /** Timeout for non-streaming requests in milliseconds. Defaults to 30000. Set 0 to disable. */
78
+ timeout?: number;
79
+ }
80
+ interface ConvositeClient {
81
+ readonly actions: {
82
+ run<TInput extends Record<string, unknown> = Record<string, unknown>>(endpointId: string, input: TInput, options?: RequestOptions): Promise<ActionResponse>;
83
+ };
84
+ readonly conversations: {
85
+ create(sessionId?: string): Conversation;
86
+ send(query: string, options?: ConversationSendOptions): AsyncIterable<ConversationEvent>;
87
+ end(sessionId: string, options?: RequestOptions): Promise<ConversationEndResponse>;
88
+ };
89
+ /** Escape hatch for public Laravel API endpoints not yet wrapped by the SDK. */
90
+ request<T = unknown>(path: string, options?: RawRequestOptions): Promise<T>;
91
+ }
92
+
93
+ declare function createConvosite(config: ConvositeConfig): ConvositeClient;
94
+
95
+ declare class ConvositeError extends Error {
96
+ readonly status: number;
97
+ readonly code: string | null;
98
+ readonly details: unknown;
99
+ readonly requestId: string | null;
100
+ constructor(options: {
101
+ message: string;
102
+ status?: number;
103
+ code?: string | null;
104
+ details?: unknown;
105
+ requestId?: string | null;
106
+ cause?: unknown;
107
+ });
108
+ }
109
+
110
+ export { type ActionResponse, type Conversation, type ConversationCompleteEvent, type ConversationEndResponse, type ConversationErrorEvent, type ConversationEvent, type ConversationFieldEvent, type ConversationSendOptions, type ConversationUsageEvent, type ConvositeClient, type ConvositeConfig, ConvositeError, type Fetch, type JsonPrimitive, type JsonValue, type RawRequestOptions, type RequestOptions, createConvosite };
package/dist/index.js ADDED
@@ -0,0 +1,289 @@
1
+ // src/errors.ts
2
+ var ConvositeError = class extends Error {
3
+ status;
4
+ code;
5
+ details;
6
+ requestId;
7
+ constructor(options) {
8
+ super(options.message, options.cause === void 0 ? void 0 : { cause: options.cause });
9
+ this.name = "ConvositeError";
10
+ this.status = options.status ?? 0;
11
+ this.code = options.code ?? null;
12
+ this.details = options.details ?? null;
13
+ this.requestId = options.requestId ?? null;
14
+ }
15
+ };
16
+
17
+ // src/http.ts
18
+ function normalizeBaseUrl(value) {
19
+ return value.replace(/\/+$/, "");
20
+ }
21
+ function joinUrl(base, path) {
22
+ if (/^https?:\/\//i.test(path)) return path;
23
+ return `${normalizeBaseUrl(base)}/${path.replace(/^\/+/, "")}`;
24
+ }
25
+ function encodeSegment(value) {
26
+ return encodeURIComponent(value);
27
+ }
28
+ function timeoutSignal(signal, timeout) {
29
+ if (timeout <= 0) return signal ? { signal, cleanup: () => void 0 } : { cleanup: () => void 0 };
30
+ const controller = new AbortController();
31
+ const timer = setTimeout(() => controller.abort(new DOMException("Request timed out.", "TimeoutError")), timeout);
32
+ const abort = () => controller.abort(signal?.reason);
33
+ if (signal) {
34
+ if (signal.aborted) abort();
35
+ else signal.addEventListener("abort", abort, { once: true });
36
+ }
37
+ return {
38
+ signal: controller.signal,
39
+ cleanup: () => {
40
+ clearTimeout(timer);
41
+ signal?.removeEventListener("abort", abort);
42
+ }
43
+ };
44
+ }
45
+ async function responseBody(response) {
46
+ const text = await response.text();
47
+ if (!text) return null;
48
+ try {
49
+ return JSON.parse(text);
50
+ } catch {
51
+ return text;
52
+ }
53
+ }
54
+ function errorFrom(response, body) {
55
+ const object = body && typeof body === "object" ? body : {};
56
+ const message = typeof object.message === "string" ? object.message : `Convosite request failed with status ${response.status}.`;
57
+ const code = typeof object.error === "string" ? object.error : null;
58
+ const details = object.errors ?? body;
59
+ return new ConvositeError({
60
+ message,
61
+ status: response.status,
62
+ code,
63
+ details,
64
+ requestId: response.headers.get("X-Request-ID")
65
+ });
66
+ }
67
+ var HttpClient = class {
68
+ constructor(fetcher, baseUrl, headers, timeout) {
69
+ this.fetcher = fetcher;
70
+ this.baseUrl = baseUrl;
71
+ this.headers = headers;
72
+ this.timeout = timeout;
73
+ }
74
+ fetcher;
75
+ baseUrl;
76
+ headers;
77
+ timeout;
78
+ async api(path, init = {}) {
79
+ const response = await this.fetch(path, init, true);
80
+ const body = await responseBody(response);
81
+ if (!response.ok) throw errorFrom(response, body);
82
+ if (!body || typeof body !== "object" || !("success" in body)) {
83
+ throw new ConvositeError({ message: "Convosite returned an invalid API response.", status: response.status, details: body });
84
+ }
85
+ const envelope = body;
86
+ if (envelope.success !== true) {
87
+ throw new ConvositeError({ message: envelope.message || "Convosite request failed.", status: response.status, details: envelope.errors });
88
+ }
89
+ return envelope.data;
90
+ }
91
+ async raw(path, options = {}) {
92
+ const { parseAs = "json", ...init } = options;
93
+ const response = await this.fetch(path, init, true);
94
+ if (!response.ok) throw errorFrom(response, await responseBody(response));
95
+ if (parseAs === "response") return response;
96
+ if (parseAs === "text") return await response.text();
97
+ if (response.status === 204) return void 0;
98
+ return await response.json();
99
+ }
100
+ async fetch(path, init = {}, useTimeout = false) {
101
+ const headers = new Headers(this.headers);
102
+ new Headers(init.headers).forEach((value, key) => headers.set(key, value));
103
+ const timed = useTimeout ? timeoutSignal(init.signal ?? void 0, this.timeout) : timeoutSignal(init.signal ?? void 0, 0);
104
+ try {
105
+ const requestInit = { ...init, headers };
106
+ if (timed.signal) requestInit.signal = timed.signal;
107
+ return await this.fetcher(joinUrl(this.baseUrl, path), requestInit);
108
+ } catch (cause) {
109
+ if (cause instanceof ConvositeError) throw cause;
110
+ const aborted = timed.signal?.aborted;
111
+ throw new ConvositeError({
112
+ message: aborted ? "Convosite request was aborted." : "Unable to connect to Convosite.",
113
+ code: aborted ? "request_aborted" : "network_error",
114
+ cause
115
+ });
116
+ } finally {
117
+ timed.cleanup();
118
+ }
119
+ }
120
+ };
121
+ async function workerError(response) {
122
+ return errorFrom(response, await responseBody(response));
123
+ }
124
+
125
+ // src/conversations.ts
126
+ async function* parseNdjson(response) {
127
+ if (!response.body) throw new ConvositeError({ message: "Conversation response did not contain a stream.", status: response.status });
128
+ const reader = response.body.getReader();
129
+ const decoder = new TextDecoder();
130
+ let buffer = "";
131
+ try {
132
+ while (true) {
133
+ const { value, done } = await reader.read();
134
+ buffer += decoder.decode(value, { stream: !done });
135
+ let newline;
136
+ while ((newline = buffer.indexOf("\n")) !== -1) {
137
+ const line = buffer.slice(0, newline).trim();
138
+ buffer = buffer.slice(newline + 1);
139
+ if (line) yield parseEvent(line);
140
+ }
141
+ if (done) break;
142
+ }
143
+ const tail = buffer.trim();
144
+ if (tail) yield parseEvent(tail);
145
+ } finally {
146
+ reader.releaseLock();
147
+ }
148
+ }
149
+ function parseEvent(line) {
150
+ try {
151
+ const event = JSON.parse(line);
152
+ if (!event || typeof event !== "object" || typeof event.type !== "string") {
153
+ throw new Error("Event has no type.");
154
+ }
155
+ return event;
156
+ } catch (cause) {
157
+ throw new ConvositeError({ message: "Conversation stream contained an invalid event.", code: "invalid_stream", details: line, cause });
158
+ }
159
+ }
160
+ var ConversationsClient = class {
161
+ constructor(fetcher, baseUrl, siteId) {
162
+ this.fetcher = fetcher;
163
+ this.baseUrl = baseUrl;
164
+ this.siteId = siteId;
165
+ }
166
+ fetcher;
167
+ baseUrl;
168
+ siteId;
169
+ create(sessionId) {
170
+ let currentSession = sessionId?.trim() || null;
171
+ const client = this;
172
+ return {
173
+ get sessionId() {
174
+ return currentSession;
175
+ },
176
+ async *send(query, options = {}) {
177
+ const stream = client.send(query, { ...options, ...currentSession ? { sessionId: currentSession } : {} }, (id) => {
178
+ currentSession = id;
179
+ });
180
+ yield* stream;
181
+ },
182
+ async end(options = {}) {
183
+ if (!currentSession) return { ended: false };
184
+ const result = await client.end(currentSession, options);
185
+ if (result.ended) currentSession = null;
186
+ return result;
187
+ },
188
+ reset() {
189
+ currentSession = null;
190
+ }
191
+ };
192
+ }
193
+ async *send(query, options = {}, onSession) {
194
+ const trimmed = query.trim();
195
+ if (!trimmed) throw new ConvositeError({ message: "Conversation query is required.", code: "validation_error" });
196
+ const headers = new Headers({ "Content-Type": "application/json", "Accept": "application/x-ndjson" });
197
+ if (options.sessionId) headers.set("X-Conversation-Session", options.sessionId);
198
+ let response;
199
+ try {
200
+ const init = { method: "POST", headers, body: JSON.stringify({ query: trimmed }) };
201
+ if (options.signal) init.signal = options.signal;
202
+ response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}`), init);
203
+ } catch (cause) {
204
+ throw new ConvositeError({ message: options.signal?.aborted ? "Conversation request was aborted." : "Unable to connect to Convosite conversations.", code: options.signal?.aborted ? "request_aborted" : "network_error", cause });
205
+ }
206
+ if (!response.ok) throw await workerError(response);
207
+ const session = response.headers.get("X-Conversation-Session");
208
+ if (session) onSession?.(session);
209
+ yield* parseNdjson(response);
210
+ }
211
+ async end(sessionId, options = {}) {
212
+ const headers = new Headers({ "Accept": "application/json", "X-Conversation-Session": sessionId });
213
+ let response;
214
+ try {
215
+ const init = { method: "POST", headers };
216
+ if (options.signal) init.signal = options.signal;
217
+ response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}/end`), init);
218
+ } catch (cause) {
219
+ throw new ConvositeError({ message: options.signal?.aborted ? "Conversation request was aborted." : "Unable to connect to Convosite conversations.", code: options.signal?.aborted ? "request_aborted" : "network_error", cause });
220
+ }
221
+ if (!response.ok) throw await workerError(response);
222
+ return await response.json();
223
+ }
224
+ };
225
+
226
+ // src/client.ts
227
+ var DEFAULT_BASE_URL = "https://app.convosite.io/api";
228
+ function createConvosite(config) {
229
+ if (!config || typeof config.site !== "string" || !config.site.trim()) {
230
+ throw new ConvositeError({
231
+ message: "A Convosite site ID is required.",
232
+ code: "invalid_config"
233
+ });
234
+ }
235
+ const fetcher = config.fetch ?? globalThis.fetch?.bind(globalThis);
236
+ if (!fetcher) {
237
+ throw new ConvositeError({
238
+ message: "No fetch implementation is available.",
239
+ code: "invalid_config"
240
+ });
241
+ }
242
+ const siteId = config.site.trim();
243
+ const site = encodeSegment(siteId);
244
+ const baseUrl = normalizeBaseUrl(config.baseUrl ?? DEFAULT_BASE_URL);
245
+ const conversationUrl = normalizeBaseUrl(config.conversationUrl ?? baseUrl);
246
+ const http = new HttpClient(
247
+ fetcher,
248
+ baseUrl,
249
+ config.headers ?? {},
250
+ config.timeout ?? 3e4
251
+ );
252
+ const conversations = new ConversationsClient(fetcher, conversationUrl, siteId);
253
+ const requestOptions = (options) => options?.signal ? { signal: options.signal } : {};
254
+ return {
255
+ actions: {
256
+ run: (endpointId, input, options) => {
257
+ if (typeof endpointId !== "string" || !endpointId.trim()) {
258
+ throw new ConvositeError({
259
+ message: "An endpoint ID is required.",
260
+ code: "validation_error"
261
+ });
262
+ }
263
+ return http.api(
264
+ `/actions/${site}/${encodeSegment(endpointId.trim())}`,
265
+ {
266
+ method: "POST",
267
+ headers: {
268
+ "Content-Type": "application/json",
269
+ Accept: "application/json"
270
+ },
271
+ body: JSON.stringify(input),
272
+ ...requestOptions(options)
273
+ }
274
+ );
275
+ }
276
+ },
277
+ conversations: {
278
+ create: (sessionId) => conversations.create(sessionId),
279
+ send: (query, options) => conversations.send(query, options),
280
+ end: (sessionId, options) => conversations.end(sessionId, options)
281
+ },
282
+ request: (path, options = {}) => http.raw(path, options)
283
+ };
284
+ }
285
+ export {
286
+ ConvositeError,
287
+ createConvosite
288
+ };
289
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/conversations.ts","../src/client.ts"],"sourcesContent":["export class ConvositeError extends Error {\n readonly status: number;\n readonly code: string | null;\n readonly details: unknown;\n readonly requestId: string | null;\n\n constructor(options: {\n message: string;\n status?: number;\n code?: string | null;\n details?: unknown;\n requestId?: string | null;\n cause?: unknown;\n }) {\n super(options.message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = 'ConvositeError';\n this.status = options.status ?? 0;\n this.code = options.code ?? null;\n this.details = options.details ?? null;\n this.requestId = options.requestId ?? null;\n }\n}\n","import { ConvositeError } from './errors';\nimport type { Fetch, RawRequestOptions } from './types';\n\ninterface ApiEnvelope<T> {\n success: boolean;\n message: string;\n data: T;\n errors: unknown;\n}\n\nexport function normalizeBaseUrl(value: string): string {\n return value.replace(/\\/+$/, '');\n}\n\nexport function joinUrl(base: string, path: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n return `${normalizeBaseUrl(base)}/${path.replace(/^\\/+/, '')}`;\n}\n\nexport function encodeSegment(value: string): string {\n return encodeURIComponent(value);\n}\n\nfunction timeoutSignal(signal: AbortSignal | undefined, timeout: number): { signal?: AbortSignal; cleanup: () => void } {\n if (timeout <= 0) return signal ? { signal, cleanup: () => undefined } : { cleanup: () => undefined };\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException('Request timed out.', 'TimeoutError')), timeout);\n const abort = () => controller.abort(signal?.reason);\n if (signal) {\n if (signal.aborted) abort();\n else signal.addEventListener('abort', abort, { once: true });\n }\n return {\n signal: controller.signal,\n cleanup: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n },\n };\n}\n\nasync function responseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!text) return null;\n try { return JSON.parse(text); } catch { return text; }\n}\n\nfunction errorFrom(response: Response, body: unknown): ConvositeError {\n const object = body && typeof body === 'object' ? body as Record<string, unknown> : {};\n const message = typeof object.message === 'string' ? object.message : `Convosite request failed with status ${response.status}.`;\n const code = typeof object.error === 'string' ? object.error : null;\n const details = object.errors ?? body;\n return new ConvositeError({\n message,\n status: response.status,\n code,\n details,\n requestId: response.headers.get('X-Request-ID'),\n });\n}\n\nexport class HttpClient {\n constructor(\n private readonly fetcher: Fetch,\n private readonly baseUrl: string,\n private readonly headers: HeadersInit,\n private readonly timeout: number,\n ) {}\n\n async api<T>(path: string, init: RequestInit = {}): Promise<T> {\n const response = await this.fetch(path, init, true);\n const body = await responseBody(response);\n if (!response.ok) throw errorFrom(response, body);\n if (!body || typeof body !== 'object' || !('success' in body)) {\n throw new ConvositeError({ message: 'Convosite returned an invalid API response.', status: response.status, details: body });\n }\n const envelope = body as ApiEnvelope<T>;\n if (envelope.success !== true) {\n throw new ConvositeError({ message: envelope.message || 'Convosite request failed.', status: response.status, details: envelope.errors });\n }\n return envelope.data;\n }\n\n async raw<T>(path: string, options: RawRequestOptions = {}): Promise<T> {\n const { parseAs = 'json', ...init } = options;\n const response = await this.fetch(path, init, true);\n if (!response.ok) throw errorFrom(response, await responseBody(response));\n if (parseAs === 'response') return response as T;\n if (parseAs === 'text') return await response.text() as T;\n if (response.status === 204) return undefined as T;\n return await response.json() as T;\n }\n\n async fetch(path: string, init: RequestInit = {}, useTimeout = false): Promise<Response> {\n const headers = new Headers(this.headers);\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\n const timed = useTimeout ? timeoutSignal(init.signal ?? undefined, this.timeout) : timeoutSignal(init.signal ?? undefined, 0);\n try {\n const requestInit: RequestInit = { ...init, headers };\n if (timed.signal) requestInit.signal = timed.signal;\n return await this.fetcher(joinUrl(this.baseUrl, path), requestInit);\n } catch (cause) {\n if (cause instanceof ConvositeError) throw cause;\n const aborted = timed.signal?.aborted;\n throw new ConvositeError({\n message: aborted ? 'Convosite request was aborted.' : 'Unable to connect to Convosite.',\n code: aborted ? 'request_aborted' : 'network_error',\n cause,\n });\n } finally {\n timed.cleanup();\n }\n }\n}\n\nexport async function workerError(response: Response): Promise<ConvositeError> {\n return errorFrom(response, await responseBody(response));\n}\n","import { ConvositeError } from './errors';\nimport { encodeSegment, joinUrl, workerError } from './http';\nimport type {\n Conversation,\n ConversationEndResponse,\n ConversationEvent,\n ConversationSendOptions,\n Fetch,\n RequestOptions,\n} from './types';\n\nasync function* parseNdjson(response: Response): AsyncGenerator<ConversationEvent> {\n if (!response.body) throw new ConvositeError({ message: 'Conversation response did not contain a stream.', status: response.status });\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n while (true) {\n const { value, done } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (line) yield parseEvent(line);\n }\n if (done) break;\n }\n const tail = buffer.trim();\n if (tail) yield parseEvent(tail);\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction parseEvent(line: string): ConversationEvent {\n try {\n const event = JSON.parse(line) as unknown;\n if (!event || typeof event !== 'object' || typeof (event as { type?: unknown }).type !== 'string') {\n throw new Error('Event has no type.');\n }\n return event as ConversationEvent;\n } catch (cause) {\n throw new ConvositeError({ message: 'Conversation stream contained an invalid event.', code: 'invalid_stream', details: line, cause });\n }\n}\n\nexport class ConversationsClient {\n constructor(\n private readonly fetcher: Fetch,\n private readonly baseUrl: string,\n private readonly siteId: string,\n ) {}\n\n create(sessionId?: string): Conversation {\n let currentSession = sessionId?.trim() || null;\n const client = this;\n return {\n get sessionId() { return currentSession; },\n async *send(query: string, options: RequestOptions = {}) {\n const stream = client.send(query, { ...options, ...(currentSession ? { sessionId: currentSession } : {}) }, (id) => { currentSession = id; });\n yield* stream;\n },\n async end(options: RequestOptions = {}) {\n if (!currentSession) return { ended: false };\n const result = await client.end(currentSession, options);\n if (result.ended) currentSession = null;\n return result;\n },\n reset() { currentSession = null; },\n };\n }\n\n async *send(\n query: string,\n options: ConversationSendOptions = {},\n onSession?: (sessionId: string) => void,\n ): AsyncGenerator<ConversationEvent> {\n const trimmed = query.trim();\n if (!trimmed) throw new ConvositeError({ message: 'Conversation query is required.', code: 'validation_error' });\n const headers = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/x-ndjson' });\n if (options.sessionId) headers.set('X-Conversation-Session', options.sessionId);\n let response: Response;\n try {\n const init: RequestInit = { method: 'POST', headers, body: JSON.stringify({ query: trimmed }) };\n if (options.signal) init.signal = options.signal;\n response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}`), init);\n } catch (cause) {\n throw new ConvositeError({ message: options.signal?.aborted ? 'Conversation request was aborted.' : 'Unable to connect to Convosite conversations.', code: options.signal?.aborted ? 'request_aborted' : 'network_error', cause });\n }\n if (!response.ok) throw await workerError(response);\n const session = response.headers.get('X-Conversation-Session');\n if (session) onSession?.(session);\n yield* parseNdjson(response);\n }\n\n async end(sessionId: string, options: RequestOptions = {}): Promise<ConversationEndResponse> {\n const headers = new Headers({ 'Accept': 'application/json', 'X-Conversation-Session': sessionId });\n let response: Response;\n try {\n const init: RequestInit = { method: 'POST', headers };\n if (options.signal) init.signal = options.signal;\n response = await this.fetcher(joinUrl(this.baseUrl, `/conversations/${encodeSegment(this.siteId)}/end`), init);\n } catch (cause) {\n throw new ConvositeError({ message: options.signal?.aborted ? 'Conversation request was aborted.' : 'Unable to connect to Convosite conversations.', code: options.signal?.aborted ? 'request_aborted' : 'network_error', cause });\n }\n if (!response.ok) throw await workerError(response);\n return await response.json() as ConversationEndResponse;\n }\n}\n","import { ConversationsClient } from './conversations';\nimport { ConvositeError } from './errors';\nimport { encodeSegment, HttpClient, normalizeBaseUrl } from './http';\nimport type {\n ActionResponse,\n ConvositeClient,\n ConvositeConfig,\n RawRequestOptions,\n RequestOptions,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://app.convosite.io/api';\n\nexport function createConvosite(config: ConvositeConfig): ConvositeClient {\n if (!config || typeof config.site !== 'string' || !config.site.trim()) {\n throw new ConvositeError({\n message: 'A Convosite site ID is required.',\n code: 'invalid_config',\n });\n }\n\n const fetcher = config.fetch ?? globalThis.fetch?.bind(globalThis);\n if (!fetcher) {\n throw new ConvositeError({\n message: 'No fetch implementation is available.',\n code: 'invalid_config',\n });\n }\n\n const siteId = config.site.trim();\n const site = encodeSegment(siteId);\n const baseUrl = normalizeBaseUrl(config.baseUrl ?? DEFAULT_BASE_URL);\n const conversationUrl = normalizeBaseUrl(config.conversationUrl ?? baseUrl);\n const http = new HttpClient(\n fetcher,\n baseUrl,\n config.headers ?? {},\n config.timeout ?? 30_000,\n );\n const conversations = new ConversationsClient(fetcher, conversationUrl, siteId);\n\n const requestOptions = (options?: RequestOptions): RequestInit =>\n options?.signal ? { signal: options.signal } : {};\n\n return {\n actions: {\n run: (endpointId, input, options) => {\n if (typeof endpointId !== 'string' || !endpointId.trim()) {\n throw new ConvositeError({\n message: 'An endpoint ID is required.',\n code: 'validation_error',\n });\n }\n\n return http.api<ActionResponse>(\n `/actions/${site}/${encodeSegment(endpointId.trim())}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(input),\n ...requestOptions(options),\n },\n );\n },\n },\n conversations: {\n create: (sessionId) => conversations.create(sessionId),\n send: (query, options) => conversations.send(query, options),\n end: (sessionId, options) => conversations.end(sessionId, options),\n },\n request: <T = unknown>(path: string, options: RawRequestOptions = {}) =>\n http.raw<T>(path, options),\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,46 @@
1
1
  {
2
2
  "name": "@convosite/client",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Framework-agnostic JavaScript and TypeScript client for building Convosite conversational experiences.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/index.cjs"
21
+ }
22
+ },
23
+ "scripts": {
24
+ "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
25
+ "build": "npm run clean && tsup src/index.ts --format esm,cjs --dts --sourcemap --clean",
26
+ "test": "vitest run",
27
+ "typecheck": "tsc --noEmit",
28
+ "check": "npm run typecheck && npm test && npm run build",
29
+ "prepublishOnly": "npm run check"
30
+ },
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
34
+ "devDependencies": {
35
+ "tsup": "^8.5.0",
36
+ "typescript": "^5.9.3",
37
+ "vitest": "^3.2.4"
38
+ },
39
+ "keywords": [
40
+ "convosite",
41
+ "conversational-ui",
42
+ "conversational-ai",
43
+ "sdk",
44
+ "typescript"
45
+ ]
46
+ }