@aiassist-secure/core 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/dist/index.mjs ADDED
@@ -0,0 +1,314 @@
1
+ // src/types.ts
2
+ var AiAssistError = class extends Error {
3
+ constructor(message, status, code) {
4
+ super(message);
5
+ this.name = "AiAssistError";
6
+ this.status = status;
7
+ this.code = code;
8
+ }
9
+ };
10
+ var AuthenticationError = class extends AiAssistError {
11
+ constructor(message = "Invalid API key") {
12
+ super(message, 401, "invalid_api_key");
13
+ this.name = "AuthenticationError";
14
+ }
15
+ };
16
+ var RateLimitError = class extends AiAssistError {
17
+ constructor(message = "Rate limit exceeded", retryAfter) {
18
+ super(message, 429, "rate_limit_exceeded");
19
+ this.name = "RateLimitError";
20
+ this.retryAfter = retryAfter;
21
+ }
22
+ };
23
+ var APIError = class extends AiAssistError {
24
+ constructor(message, status, code) {
25
+ super(message, status, code);
26
+ this.name = "APIError";
27
+ }
28
+ };
29
+
30
+ // src/client.ts
31
+ var DEFAULT_BASE_URL = "https://api.aiassist.net";
32
+ var DEFAULT_TIMEOUT = 3e4;
33
+ var DEFAULT_MAX_RETRIES = 3;
34
+ var VERSION = "1.0.0";
35
+ function normalizeRole(role) {
36
+ if (role === "assistant" || role === "ai") return "ai";
37
+ if (role === "human") return "human";
38
+ if (role === "system") return "system";
39
+ return "user";
40
+ }
41
+ var AiAssistClient = class {
42
+ constructor(options) {
43
+ this.apiKey = options.apiKey;
44
+ this.baseURL = options.baseURL ?? DEFAULT_BASE_URL;
45
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
46
+ this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
47
+ this.defaultHeaders = options.defaultHeaders ?? {};
48
+ this.chat = new ChatAPI(this);
49
+ this.models = new ModelsAPI(this);
50
+ this.workspaces = new WorkspacesAPI(this);
51
+ }
52
+ getHeaders() {
53
+ return {
54
+ "Content-Type": "application/json",
55
+ "X-API-Key": this.apiKey,
56
+ "Authorization": `Bearer ${this.apiKey}`,
57
+ "User-Agent": `aiassist-js/${VERSION}`,
58
+ ...this.defaultHeaders
59
+ };
60
+ }
61
+ async request(method, path, options) {
62
+ const url = `${this.baseURL}${path}`;
63
+ const headers = { ...this.getHeaders(), ...options?.headers };
64
+ let lastError = null;
65
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
66
+ try {
67
+ const controller = new AbortController();
68
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
69
+ const response = await fetch(url, {
70
+ method,
71
+ headers,
72
+ body: options?.body ? JSON.stringify(options.body) : void 0,
73
+ signal: controller.signal
74
+ });
75
+ clearTimeout(timeoutId);
76
+ if (response.status === 401) {
77
+ throw new AuthenticationError();
78
+ }
79
+ if (response.status === 429) {
80
+ const retryAfter = parseInt(response.headers.get("Retry-After") ?? "5", 10);
81
+ if (attempt < this.maxRetries - 1) {
82
+ await this.sleep(retryAfter * 1e3);
83
+ continue;
84
+ }
85
+ throw new RateLimitError("Rate limit exceeded", retryAfter);
86
+ }
87
+ if (!response.ok) {
88
+ const errorData = await response.json().catch(() => ({}));
89
+ throw new APIError(
90
+ errorData.detail ?? `HTTP ${response.status}`,
91
+ response.status,
92
+ errorData.code
93
+ );
94
+ }
95
+ return await response.json();
96
+ } catch (error) {
97
+ lastError = error;
98
+ if (error instanceof AiAssistError) {
99
+ throw error;
100
+ }
101
+ if (attempt < this.maxRetries - 1) {
102
+ await this.sleep(Math.pow(2, attempt) * 1e3);
103
+ continue;
104
+ }
105
+ }
106
+ }
107
+ throw new APIError(`Request failed: ${lastError?.message}`);
108
+ }
109
+ async requestSilent(method, path, options) {
110
+ try {
111
+ await this.request(method, path, options);
112
+ } catch {
113
+ }
114
+ }
115
+ async *stream(method, path, body) {
116
+ const url = `${this.baseURL}${path}`;
117
+ const headers = this.getHeaders();
118
+ const response = await fetch(url, {
119
+ method,
120
+ headers,
121
+ body: JSON.stringify(body)
122
+ });
123
+ if (!response.ok) {
124
+ if (response.status === 401) throw new AuthenticationError();
125
+ if (response.status === 429) throw new RateLimitError();
126
+ const errorData = await response.json().catch(() => ({}));
127
+ throw new APIError(errorData.detail ?? `HTTP ${response.status}`, response.status);
128
+ }
129
+ const reader = response.body?.getReader();
130
+ if (!reader) throw new APIError("Response body is not readable");
131
+ const decoder = new TextDecoder();
132
+ let buffer = "";
133
+ while (true) {
134
+ const { done, value } = await reader.read();
135
+ if (done) break;
136
+ buffer += decoder.decode(value, { stream: true });
137
+ const lines = buffer.split("\n");
138
+ buffer = lines.pop() ?? "";
139
+ for (const line of lines) {
140
+ if (line.startsWith("data: ")) {
141
+ const data = line.slice(6);
142
+ if (data === "[DONE]") return;
143
+ try {
144
+ yield JSON.parse(data);
145
+ } catch {
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ sleep(ms) {
152
+ return new Promise((resolve) => setTimeout(resolve, ms));
153
+ }
154
+ };
155
+ var ChatAPI = class {
156
+ constructor(client) {
157
+ this.completions = new ChatCompletionsAPI(client);
158
+ }
159
+ };
160
+ var ChatCompletionsAPI = class {
161
+ constructor(client) {
162
+ this.client = client;
163
+ }
164
+ async create(params) {
165
+ if (params.stream) {
166
+ return this.client.stream("POST", "/v1/chat/completions", params);
167
+ }
168
+ return this.client.request("POST", "/v1/chat/completions", {
169
+ body: params
170
+ });
171
+ }
172
+ };
173
+ var ModelsAPI = class {
174
+ constructor(client) {
175
+ this.client = client;
176
+ }
177
+ async list() {
178
+ const response = await this.client.request("GET", "/v1/models");
179
+ return response.data;
180
+ }
181
+ };
182
+ var WorkspacesAPI = class {
183
+ constructor(client) {
184
+ this.client = client;
185
+ }
186
+ /**
187
+ * Create a new workspace with optional system prompt and context.
188
+ *
189
+ * @param params - Workspace creation options
190
+ * @returns Workspace and initial messages
191
+ */
192
+ async create(params) {
193
+ const body = {};
194
+ if (params?.initial_message) body.initial_message = params.initial_message;
195
+ if (params?.client_id) body.client_id = params.client_id;
196
+ if (params?.system_prompt) body.system_prompt = params.system_prompt;
197
+ if (params?.context) body.context = params.context;
198
+ if (params?.metadata) body.metadata = params.metadata;
199
+ const data = await this.client.request("POST", "/api/workspaces", { body });
200
+ return {
201
+ workspace: {
202
+ id: data.workspace.id,
203
+ mode: data.workspace.mode,
204
+ status: data.workspace.status || "active"
205
+ },
206
+ messages: (data.messages || []).map((m) => ({
207
+ id: m.id,
208
+ role: normalizeRole(m.role),
209
+ content: m.content,
210
+ created_at: m.created_at
211
+ }))
212
+ };
213
+ }
214
+ /**
215
+ * Get workspace by ID.
216
+ */
217
+ async get(workspaceId) {
218
+ const data = await this.client.request("GET", `/api/workspaces/${workspaceId}`);
219
+ const ws = data.workspace || data;
220
+ return {
221
+ id: ws.id,
222
+ mode: ws.mode || "ai",
223
+ status: ws.status || "active"
224
+ };
225
+ }
226
+ /**
227
+ * Get workspace by client ID.
228
+ * Returns null if not found.
229
+ */
230
+ async getByClientId(clientId) {
231
+ try {
232
+ const data = await this.client.request("GET", `/api/workspaces/by-client/${clientId}`);
233
+ return {
234
+ workspace: data.workspace ? {
235
+ id: data.workspace.id,
236
+ mode: data.workspace.mode,
237
+ status: "active"
238
+ } : null,
239
+ messages: (data.messages || []).map((m) => ({
240
+ id: m.id,
241
+ role: normalizeRole(m.role),
242
+ content: m.content,
243
+ created_at: m.created_at
244
+ })),
245
+ exists: data.exists
246
+ };
247
+ } catch (error) {
248
+ if (error instanceof APIError && error.status === 404) {
249
+ return { workspace: null, messages: [], exists: false };
250
+ }
251
+ throw error;
252
+ }
253
+ }
254
+ /**
255
+ * Send a message to a workspace.
256
+ * Returns user message, AI/human responses, mode, and shadow mode approval status.
257
+ */
258
+ async sendMessage(workspaceId, content) {
259
+ const data = await this.client.request("POST", `/api/workspaces/${workspaceId}/messages`, {
260
+ body: { content }
261
+ });
262
+ return {
263
+ user_message: {
264
+ id: data.user_message.id,
265
+ role: "user",
266
+ content: data.user_message.content,
267
+ created_at: data.user_message.created_at
268
+ },
269
+ responses: data.responses.map((r) => ({
270
+ id: r.id,
271
+ role: normalizeRole(r.role),
272
+ content: r.content,
273
+ created_at: r.created_at
274
+ })),
275
+ mode: data.mode,
276
+ pending_approval: data.pending_approval
277
+ };
278
+ }
279
+ /**
280
+ * Get all messages in a workspace.
281
+ */
282
+ async getMessages(workspaceId) {
283
+ const data = await this.client.request("GET", `/api/workspaces/${workspaceId}/messages`);
284
+ return (data.messages || []).map((m) => ({
285
+ id: m.id,
286
+ role: normalizeRole(m.role),
287
+ content: m.content,
288
+ created_at: m.created_at
289
+ }));
290
+ }
291
+ /**
292
+ * Send typing preview to workspace (for real-time typing indicators).
293
+ * Fails silently - non-critical operation.
294
+ */
295
+ async sendTypingPreview(workspaceId, text) {
296
+ await this.client.requestSilent("POST", `/api/workspaces/${workspaceId}/typing`, {
297
+ body: { text }
298
+ });
299
+ }
300
+ /**
301
+ * End a conversation/workspace.
302
+ * Fails silently - non-critical operation.
303
+ */
304
+ async endConversation(workspaceId) {
305
+ await this.client.requestSilent("POST", `/api/workspaces/${workspaceId}/end`, {});
306
+ }
307
+ };
308
+ export {
309
+ APIError,
310
+ AiAssistClient,
311
+ AiAssistError,
312
+ AuthenticationError,
313
+ RateLimitError
314
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@aiassist-secure/core",
3
+ "version": "1.0.0",
4
+ "description": "AiAssist Secure TypeScript SDK - Framework-agnostic API client",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
20
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
21
+ "typecheck": "tsc --noEmit"
22
+ },
23
+ "devDependencies": {
24
+ "tsup": "^8.0.0",
25
+ "typescript": "^5.0.0"
26
+ },
27
+ "keywords": [
28
+ "aiassist",
29
+ "aiassist-secure",
30
+ "ai",
31
+ "llm",
32
+ "openai",
33
+ "groq",
34
+ "chat",
35
+ "api",
36
+ "sdk"
37
+ ],
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/aiassistsecure/aiassist-js"
42
+ },
43
+ "homepage": "https://aiassist.net",
44
+ "bugs": {
45
+ "url": "https://github.com/aiassistsecure/aiassist-js/issues"
46
+ },
47
+ "engines": {
48
+ "node": ">=18.0.0"
49
+ }
50
+ }