@onyx.dev/onyx-database 1.1.0 → 1.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.
@@ -11,6 +11,7 @@ var process__default = /*#__PURE__*/_interopDefault(process);
11
11
 
12
12
  // src/config/defaults.ts
13
13
  var DEFAULT_BASE_URL = "https://api.onyx.dev";
14
+ var DEFAULT_AI_BASE_URL = "https://ai.onyx.dev";
14
15
  var sanitizeBaseUrl = (u) => u.replace(/\/+$/, "");
15
16
 
16
17
  // src/errors/config-error.ts
@@ -69,6 +70,7 @@ function readEnv(targetId) {
69
70
  if (targetId && envId !== targetId) return {};
70
71
  const res = dropUndefined({
71
72
  baseUrl: pick("ONYX_DATABASE_BASE_URL"),
73
+ aiBaseUrl: pick("ONYX_AI_BASE_URL"),
72
74
  databaseId: envId,
73
75
  apiKey: pick("ONYX_DATABASE_API_KEY"),
74
76
  apiSecret: pick("ONYX_DATABASE_API_SECRET")
@@ -205,6 +207,7 @@ async function resolveConfig(input) {
205
207
  }
206
208
  const merged = {
207
209
  baseUrl: DEFAULT_BASE_URL,
210
+ aiBaseUrl: DEFAULT_AI_BASE_URL,
208
211
  ...dropUndefined(home),
209
212
  ...dropUndefined(project),
210
213
  ...dropUndefined(cfgPath),
@@ -213,6 +216,7 @@ async function resolveConfig(input) {
213
216
  };
214
217
  dbg("merged (pre-validate):", mask(merged));
215
218
  const baseUrl = sanitizeBaseUrl(merged.baseUrl ?? DEFAULT_BASE_URL);
219
+ const aiBaseUrl = sanitizeBaseUrl(merged.aiBaseUrl ?? DEFAULT_AI_BASE_URL);
216
220
  const databaseId = merged.databaseId ?? "";
217
221
  const apiKey = merged.apiKey ?? "";
218
222
  const apiSecret = merged.apiSecret ?? "";
@@ -248,6 +252,7 @@ async function resolveConfig(input) {
248
252
  }
249
253
  const resolved = {
250
254
  baseUrl,
255
+ aiBaseUrl,
251
256
  databaseId,
252
257
  apiKey,
253
258
  apiSecret,
@@ -258,6 +263,7 @@ async function resolveConfig(input) {
258
263
  };
259
264
  const source = {
260
265
  databaseId: input?.databaseId ? "explicit config" : env.databaseId ? "env" : cfgPath.databaseId ? "env ONYX_CONFIG_PATH" : project.databaseId ? "project file" : home.databaseId ? "home profile" : "unknown",
266
+ aiBaseUrl: input?.aiBaseUrl ? "explicit config" : env.aiBaseUrl ? "env" : cfgPath.aiBaseUrl ? "env ONYX_CONFIG_PATH" : project.aiBaseUrl ? "project file" : home.aiBaseUrl ? "home profile" : "default",
261
267
  apiKey: input?.apiKey ? "explicit config" : env.apiKey ? "env" : cfgPath.apiKey ? "env ONYX_CONFIG_PATH" : project.apiKey ? "project file" : home.apiKey ? "home profile" : "unknown",
262
268
  apiSecret: input?.apiSecret ? "explicit config" : env.apiSecret ? "env" : cfgPath.apiSecret ? "env ONYX_CONFIG_PATH" : project.apiSecret ? "project file" : home.apiSecret ? "home profile" : "unknown"
263
269
  };
@@ -277,6 +283,7 @@ async function resolveConfigWithSource(input) {
277
283
  const base = await resolveConfig(input);
278
284
  const sources = {
279
285
  baseUrl: input?.baseUrl ? "explicit config" : env.baseUrl ? "env" : cfgPath.baseUrl ? "env ONYX_CONFIG_PATH" : project.baseUrl ? "project file" : home.baseUrl ? "home profile" : "default",
286
+ aiBaseUrl: input?.aiBaseUrl ? "explicit config" : env.aiBaseUrl ? "env" : cfgPath.aiBaseUrl ? "env ONYX_CONFIG_PATH" : project.aiBaseUrl ? "project file" : home.aiBaseUrl ? "home profile" : "default",
280
287
  databaseId: input?.databaseId ? "explicit config" : env.databaseId ? "env" : cfgPath.databaseId ? "env ONYX_CONFIG_PATH" : project.databaseId ? "project file" : home.databaseId ? "home profile" : "unknown",
281
288
  apiKey: input?.apiKey ? "explicit config" : env.apiKey ? "env" : cfgPath.apiKey ? "env ONYX_CONFIG_PATH" : project.apiKey ? "project file" : home.apiKey ? "home profile" : "unknown",
282
289
  apiSecret: input?.apiSecret ? "explicit config" : env.apiSecret ? "env" : cfgPath.apiSecret ? "env ONYX_CONFIG_PATH" : project.apiSecret ? "project file" : home.apiSecret ? "home profile" : "unknown",
@@ -1399,6 +1406,7 @@ var OnyxDatabaseImpl = class {
1399
1406
  cfgPromise;
1400
1407
  resolved = null;
1401
1408
  http = null;
1409
+ aiHttp = null;
1402
1410
  streams = /* @__PURE__ */ new Set();
1403
1411
  requestLoggingEnabled;
1404
1412
  responseLoggingEnabled;
@@ -1433,6 +1441,30 @@ var OnyxDatabaseImpl = class {
1433
1441
  databaseId: this.resolved.databaseId
1434
1442
  };
1435
1443
  }
1444
+ async ensureAiClient() {
1445
+ if (!this.resolved) {
1446
+ this.resolved = await this.cfgPromise;
1447
+ }
1448
+ if (!this.aiHttp) {
1449
+ this.aiHttp = new HttpClient({
1450
+ baseUrl: this.resolved.aiBaseUrl,
1451
+ apiKey: this.resolved.apiKey,
1452
+ apiSecret: this.resolved.apiSecret,
1453
+ fetchImpl: this.resolved.fetch,
1454
+ requestLoggingEnabled: this.requestLoggingEnabled,
1455
+ responseLoggingEnabled: this.responseLoggingEnabled,
1456
+ retryEnabled: this.resolved.retryEnabled,
1457
+ maxRetries: this.resolved.maxRetries,
1458
+ retryInitialDelayMs: this.resolved.retryInitialDelayMs
1459
+ });
1460
+ }
1461
+ return {
1462
+ http: this.aiHttp,
1463
+ fetchImpl: this.resolved.fetch,
1464
+ aiBaseUrl: this.resolved.aiBaseUrl,
1465
+ databaseId: this.resolved.databaseId
1466
+ };
1467
+ }
1436
1468
  registerStream(handle) {
1437
1469
  this.streams.add(handle);
1438
1470
  return {
@@ -1445,7 +1477,34 @@ var OnyxDatabaseImpl = class {
1445
1477
  }
1446
1478
  };
1447
1479
  }
1480
+ getRequestLoggingEnabled() {
1481
+ return this.requestLoggingEnabled;
1482
+ }
1483
+ getResponseLoggingEnabled() {
1484
+ return this.responseLoggingEnabled;
1485
+ }
1448
1486
  /** -------- IOnyxDatabase -------- */
1487
+ chat() {
1488
+ return new AiChatClientImpl(
1489
+ () => this.ensureAiClient(),
1490
+ (handle) => this.registerStream(handle),
1491
+ () => this.requestLoggingEnabled,
1492
+ () => this.responseLoggingEnabled
1493
+ );
1494
+ }
1495
+ async getModels() {
1496
+ const { http } = await this.ensureAiClient();
1497
+ return http.request("GET", "/v1/models");
1498
+ }
1499
+ async getModel(modelId) {
1500
+ const { http } = await this.ensureAiClient();
1501
+ const path2 = `/v1/models/${encodeURIComponent(modelId)}`;
1502
+ return http.request("GET", path2);
1503
+ }
1504
+ async requestScriptApproval(input) {
1505
+ const { http } = await this.ensureAiClient();
1506
+ return http.request("POST", "/api/script-approvals", input);
1507
+ }
1449
1508
  from(table) {
1450
1509
  return new QueryBuilderImpl(this, String(table), this.defaultPartition);
1451
1510
  }
@@ -1995,6 +2054,153 @@ var CascadeBuilderImpl = class {
1995
2054
  return this.db.delete(table, primaryKey, opts);
1996
2055
  }
1997
2056
  };
2057
+ var AiChatClientImpl = class {
2058
+ constructor(resolveAiClient, registerStream, requestLoggingEnabled, responseLoggingEnabled) {
2059
+ this.resolveAiClient = resolveAiClient;
2060
+ this.registerStream = registerStream;
2061
+ this.requestLoggingEnabled = requestLoggingEnabled;
2062
+ this.responseLoggingEnabled = responseLoggingEnabled;
2063
+ }
2064
+ normalizeEventData(rawEvent) {
2065
+ const lines = rawEvent.split("\n");
2066
+ const dataLines = [];
2067
+ for (const line of lines) {
2068
+ const trimmed = line.trim();
2069
+ if (!trimmed || trimmed.startsWith(":")) continue;
2070
+ if (trimmed.startsWith("data:")) {
2071
+ dataLines.push(trimmed.slice(5).trim());
2072
+ } else {
2073
+ dataLines.push(trimmed);
2074
+ }
2075
+ }
2076
+ if (!dataLines.length) return null;
2077
+ const joined = dataLines.join("\n").trim();
2078
+ return joined.length > 0 ? joined : null;
2079
+ }
2080
+ logRequest(url, body, headers) {
2081
+ if (!this.requestLoggingEnabled()) return;
2082
+ console.log(`POST ${url}`);
2083
+ if (body != null) {
2084
+ const serialized = typeof body === "string" ? body : JSON.stringify(body);
2085
+ console.log(serialized);
2086
+ }
2087
+ const headerLog = { ...headers };
2088
+ if (headerLog["x-onyx-secret"]) headerLog["x-onyx-secret"] = "[REDACTED]";
2089
+ console.log("Headers:", headerLog);
2090
+ }
2091
+ logResponse(status, statusText, raw) {
2092
+ if (!this.responseLoggingEnabled()) return;
2093
+ const statusLine = `${status} ${statusText}`.trim();
2094
+ console.log(statusLine);
2095
+ if (raw && raw.trim().length > 0) {
2096
+ console.log(raw);
2097
+ }
2098
+ }
2099
+ toOnyxError(status, statusText, raw) {
2100
+ let parsed = raw;
2101
+ try {
2102
+ parsed = parseJsonAllowNaN(raw);
2103
+ } catch {
2104
+ }
2105
+ const message = typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "object" && typeof parsed.error?.message === "string" ? String(parsed.error.message) : `${status} ${statusText}`;
2106
+ return new OnyxHttpError(message, status, statusText, parsed, raw);
2107
+ }
2108
+ async create(request, options) {
2109
+ const body = { ...request, stream: !!request.stream };
2110
+ const { http, fetchImpl, aiBaseUrl, databaseId } = await this.resolveAiClient();
2111
+ const params = new URLSearchParams();
2112
+ const scopedDb = options?.databaseId ?? databaseId;
2113
+ if (scopedDb) params.append("databaseId", scopedDb);
2114
+ const path2 = `/v1/chat/completions${params.size ? `?${params.toString()}` : ""}`;
2115
+ if (!body.stream) {
2116
+ return http.request("POST", path2, body);
2117
+ }
2118
+ const url = `${aiBaseUrl}${path2}`;
2119
+ const headers = http.headers({ Accept: "text/event-stream" });
2120
+ this.logRequest(url, body, headers);
2121
+ const res = await fetchImpl(url, {
2122
+ method: "POST",
2123
+ headers,
2124
+ body: JSON.stringify(body)
2125
+ });
2126
+ if (!res.ok) {
2127
+ const raw = await res.text();
2128
+ this.logResponse(res.status, res.statusText, raw);
2129
+ throw this.toOnyxError(res.status, res.statusText, raw);
2130
+ }
2131
+ this.logResponse(res.status, res.statusText);
2132
+ const bodyStream = res.body;
2133
+ const reader = bodyStream && typeof bodyStream.getReader === "function" ? bodyStream.getReader() : null;
2134
+ if (!reader) {
2135
+ throw new OnyxHttpError(
2136
+ "Streaming response body is not readable",
2137
+ res.status,
2138
+ res.statusText,
2139
+ null,
2140
+ ""
2141
+ );
2142
+ }
2143
+ let canceled = false;
2144
+ const handle = {
2145
+ cancel: () => {
2146
+ if (canceled) return;
2147
+ canceled = true;
2148
+ try {
2149
+ reader.cancel?.();
2150
+ } catch {
2151
+ }
2152
+ }
2153
+ };
2154
+ const registered = this.registerStream(handle);
2155
+ const normalizeEvent = (rawEvent) => this.normalizeEventData(rawEvent);
2156
+ const stream = {
2157
+ async *[Symbol.asyncIterator]() {
2158
+ const decoder = new TextDecoder("utf-8");
2159
+ let buffer = "";
2160
+ try {
2161
+ while (!canceled) {
2162
+ const { done, value } = await reader.read();
2163
+ if (done) break;
2164
+ if (value) {
2165
+ buffer += decoder.decode(value, { stream: true });
2166
+ }
2167
+ let splitIndex = buffer.indexOf("\n\n");
2168
+ while (splitIndex !== -1) {
2169
+ const rawEvent = buffer.slice(0, splitIndex);
2170
+ buffer = buffer.slice(splitIndex + 2);
2171
+ const data = normalizeEvent(rawEvent);
2172
+ if (data === "[DONE]") return;
2173
+ if (data) {
2174
+ try {
2175
+ yield parseJsonAllowNaN(data);
2176
+ } catch {
2177
+ }
2178
+ }
2179
+ splitIndex = buffer.indexOf("\n\n");
2180
+ }
2181
+ }
2182
+ buffer += decoder.decode();
2183
+ const remaining = buffer.trim();
2184
+ if (remaining && remaining !== "[DONE]") {
2185
+ const data = normalizeEvent(remaining);
2186
+ if (data && data !== "[DONE]") {
2187
+ try {
2188
+ yield parseJsonAllowNaN(data);
2189
+ } catch {
2190
+ }
2191
+ }
2192
+ }
2193
+ } finally {
2194
+ registered.cancel();
2195
+ }
2196
+ },
2197
+ cancel() {
2198
+ registered.cancel();
2199
+ }
2200
+ };
2201
+ return stream;
2202
+ }
2203
+ };
1998
2204
  function createOnyxFacade(resolveConfig2) {
1999
2205
  let cachedCfg = null;
2000
2206
  function resolveConfigWithCache(config) {