@neetru/sdk 3.1.9 → 3.1.11

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.
Files changed (51) hide show
  1. package/dist/ai.cjs +304 -0
  2. package/dist/ai.cjs.map +1 -0
  3. package/dist/ai.d.cts +3 -0
  4. package/dist/ai.d.ts +3 -0
  5. package/dist/ai.mjs +302 -0
  6. package/dist/ai.mjs.map +1 -0
  7. package/dist/auth.cjs +283 -1
  8. package/dist/auth.cjs.map +1 -1
  9. package/dist/auth.d.cts +1 -1
  10. package/dist/auth.d.ts +1 -1
  11. package/dist/auth.mjs +283 -1
  12. package/dist/auth.mjs.map +1 -1
  13. package/dist/catalog.d.cts +1 -1
  14. package/dist/catalog.d.ts +1 -1
  15. package/dist/checkout.d.cts +1 -1
  16. package/dist/checkout.d.ts +1 -1
  17. package/dist/db-react.d.cts +1 -1
  18. package/dist/db-react.d.ts +1 -1
  19. package/dist/db.d.cts +1 -1
  20. package/dist/db.d.ts +1 -1
  21. package/dist/entitlements.d.cts +1 -1
  22. package/dist/entitlements.d.ts +1 -1
  23. package/dist/firestore-compat.d.cts +1 -1
  24. package/dist/firestore-compat.d.ts +1 -1
  25. package/dist/index.cjs +286 -2
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +3 -3
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.mjs +285 -3
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/mocks.cjs +52 -0
  32. package/dist/mocks.cjs.map +1 -1
  33. package/dist/mocks.d.cts +20 -2
  34. package/dist/mocks.d.ts +20 -2
  35. package/dist/mocks.mjs +52 -1
  36. package/dist/mocks.mjs.map +1 -1
  37. package/dist/notifications.d.cts +1 -1
  38. package/dist/notifications.d.ts +1 -1
  39. package/dist/react.d.cts +1 -1
  40. package/dist/react.d.ts +1 -1
  41. package/dist/support.d.cts +1 -1
  42. package/dist/support.d.ts +1 -1
  43. package/dist/telemetry.d.cts +1 -1
  44. package/dist/telemetry.d.ts +1 -1
  45. package/dist/{types-DDiVzgCT.d.cts → types-Cog9S-tC.d.cts} +84 -1
  46. package/dist/{types-HWDOUmlC.d.ts → types-dagUxKYz.d.ts} +84 -1
  47. package/dist/usage.d.cts +1 -1
  48. package/dist/usage.d.ts +1 -1
  49. package/dist/webhooks.d.cts +1 -1
  50. package/dist/webhooks.d.ts +1 -1
  51. package/package.json +6 -1
package/dist/auth.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { G as NeetruClientConfig, B as NeetruClient } from './types-DDiVzgCT.cjs';
1
+ import { S as NeetruClientConfig, R as NeetruClient } from './types-Cog9S-tC.cjs';
2
2
  import 'drizzle-orm/node-postgres';
3
3
  import './errors.cjs';
4
4
 
package/dist/auth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { G as NeetruClientConfig, B as NeetruClient } from './types-HWDOUmlC.js';
1
+ import { S as NeetruClientConfig, R as NeetruClient } from './types-dagUxKYz.js';
2
2
  import 'drizzle-orm/node-postgres';
3
3
  import './errors.js';
4
4
 
package/dist/auth.mjs CHANGED
@@ -5497,6 +5497,235 @@ var MockNotifications = class {
5497
5497
  }
5498
5498
  };
5499
5499
 
5500
+ // src/ai.ts
5501
+ init_errors();
5502
+ init_http();
5503
+ var AI_CHAT_PATH = "/api/sdk/v1/ai/chat";
5504
+ var AI_NONSTREAM_TIMEOUT_MS = 12e4;
5505
+ function resolveAiBody(config, opts, stream) {
5506
+ if (!opts || typeof opts !== "object") {
5507
+ throw new NeetruError("validation_failed", "ai: options object is required");
5508
+ }
5509
+ if (typeof opts.model !== "string" || opts.model.length === 0) {
5510
+ throw new NeetruError("validation_failed", "ai: model is required");
5511
+ }
5512
+ if (!Array.isArray(opts.messages) || opts.messages.length === 0) {
5513
+ throw new NeetruError("validation_failed", "ai: messages must be a non-empty array");
5514
+ }
5515
+ for (const m of opts.messages) {
5516
+ if (!m || typeof m !== "object" || typeof m.role !== "string" || m.role.length === 0 || typeof m.content !== "string") {
5517
+ throw new NeetruError(
5518
+ "validation_failed",
5519
+ "ai: each message must be { role: string, content: string }"
5520
+ );
5521
+ }
5522
+ }
5523
+ const productId = opts.productId ?? config.productId;
5524
+ const tenantId = opts.tenantId ?? config.tenantId;
5525
+ if (!productId) {
5526
+ throw new NeetruError(
5527
+ "validation_failed",
5528
+ "ai: productId required (pass to options or set on createNeetruClient)"
5529
+ );
5530
+ }
5531
+ if (!tenantId) {
5532
+ throw new NeetruError(
5533
+ "validation_failed",
5534
+ "ai: tenantId required (pass to options or set on createNeetruClient)"
5535
+ );
5536
+ }
5537
+ assertValidSdkId("productId", productId);
5538
+ assertValidSdkId("tenantId", tenantId);
5539
+ const body = {
5540
+ productId,
5541
+ tenantId,
5542
+ model: opts.model,
5543
+ messages: opts.messages,
5544
+ stream
5545
+ };
5546
+ if (opts.maxTokens !== void 0) {
5547
+ if (!Number.isInteger(opts.maxTokens) || opts.maxTokens <= 0) {
5548
+ throw new NeetruError("validation_failed", "ai: maxTokens must be a positive integer");
5549
+ }
5550
+ body.maxTokens = opts.maxTokens;
5551
+ }
5552
+ if (opts.temperature !== void 0) {
5553
+ if (typeof opts.temperature !== "number" || !Number.isFinite(opts.temperature)) {
5554
+ throw new NeetruError("validation_failed", "ai: temperature must be a finite number");
5555
+ }
5556
+ body.temperature = opts.temperature;
5557
+ }
5558
+ return body;
5559
+ }
5560
+ async function safeJson2(res) {
5561
+ try {
5562
+ const text = await res.text();
5563
+ if (!text) return void 0;
5564
+ return JSON.parse(text);
5565
+ } catch {
5566
+ return void 0;
5567
+ }
5568
+ }
5569
+ function statusToCode2(status) {
5570
+ if (status === 401) return "unauthorized";
5571
+ if (status === 403) return "forbidden";
5572
+ if (status === 404) return "not_found";
5573
+ if (status === 409) return "conflict";
5574
+ if (status === 422 || status === 400) return "validation_failed";
5575
+ if (status === 429) return "rate_limited";
5576
+ if (status >= 500) return "server_error";
5577
+ return "unknown";
5578
+ }
5579
+ function joinUrl(baseUrl, path) {
5580
+ const base = baseUrl.replace(/\/+$/, "");
5581
+ const p = path.startsWith("/") ? path : `/${path}`;
5582
+ return `${base}${p}`;
5583
+ }
5584
+ async function aiFetch(config, body, signal, stream) {
5585
+ if (!config.apiKey) {
5586
+ throw new NeetruError(
5587
+ "missing_api_key",
5588
+ "ai requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var."
5589
+ );
5590
+ }
5591
+ const url = joinUrl(config.baseUrl, AI_CHAT_PATH);
5592
+ const headers = {
5593
+ "content-type": "application/json",
5594
+ accept: stream ? "text/event-stream" : "application/json",
5595
+ authorization: `Bearer ${config.apiKey}`
5596
+ };
5597
+ const init = { method: "POST", headers, body: JSON.stringify(body) };
5598
+ if (stream) {
5599
+ if (signal) init.signal = signal;
5600
+ } else {
5601
+ init.signal = signal ?? AbortSignal.timeout(AI_NONSTREAM_TIMEOUT_MS);
5602
+ }
5603
+ let res;
5604
+ try {
5605
+ res = await config.fetch(url, init);
5606
+ } catch (err) {
5607
+ const message = err instanceof DOMException && err.name === "TimeoutError" ? `Network error: timeout after ${AI_NONSTREAM_TIMEOUT_MS / 1e3}s` : err instanceof DOMException && err.name === "AbortError" ? "Network error: request aborted" : `Network error: ${err instanceof Error ? err.message : "fetch failed"}`;
5608
+ throw new NeetruError("network_error", message);
5609
+ }
5610
+ const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
5611
+ if (!res.ok) {
5612
+ const parsed = await safeJson2(res);
5613
+ let code = statusToCode2(res.status);
5614
+ let message = `HTTP ${res.status}`;
5615
+ if (parsed && typeof parsed === "object" && "error" in parsed) {
5616
+ const errField = parsed.error;
5617
+ if (typeof errField === "string") {
5618
+ message = errField;
5619
+ } else if (errField && typeof errField === "object") {
5620
+ if (typeof errField.code === "string") code = errField.code;
5621
+ if (typeof errField.message === "string") message = errField.message;
5622
+ }
5623
+ }
5624
+ throw new NeetruError(code, message, res.status, requestId);
5625
+ }
5626
+ const coreVersion = res.headers.get("x-neetru-version");
5627
+ if (coreVersion) checkCoreVersionCompat(coreVersion);
5628
+ return res;
5629
+ }
5630
+ function readMeta(res) {
5631
+ return {
5632
+ provider: res.headers.get("x-neetru-provider") ?? "",
5633
+ usageWarning: res.headers.get("x-neetru-ai-usage-warning") === "1"
5634
+ };
5635
+ }
5636
+ function parseSseData(rawEvent) {
5637
+ const dataLines = [];
5638
+ for (const line of rawEvent.split("\n")) {
5639
+ const trimmed = line.replace(/\r$/, "");
5640
+ if (trimmed.startsWith("data:")) {
5641
+ let v = trimmed.slice(5);
5642
+ if (v.startsWith(" ")) v = v.slice(1);
5643
+ dataLines.push(v);
5644
+ }
5645
+ }
5646
+ if (dataLines.length === 0) return null;
5647
+ const payload = dataLines.join("\n");
5648
+ if (payload === "[DONE]") return { done: true };
5649
+ try {
5650
+ const obj = JSON.parse(payload);
5651
+ const content = obj?.choices?.[0]?.delta?.content;
5652
+ if (typeof content === "string" && content.length > 0) return { content };
5653
+ return null;
5654
+ } catch {
5655
+ return null;
5656
+ }
5657
+ }
5658
+ function createAiNamespace(config) {
5659
+ return {
5660
+ async chat(opts) {
5661
+ const body = resolveAiBody(config, opts, false);
5662
+ const res = await aiFetch(config, body, opts.signal, false);
5663
+ const { provider: providerHeader, usageWarning } = readMeta(res);
5664
+ const raw = await safeJson2(res);
5665
+ if (!raw || raw.ok !== true || !Array.isArray(raw.choices)) {
5666
+ throw new NeetruError("invalid_response", "ai.chat response missing ok/choices");
5667
+ }
5668
+ return {
5669
+ choices: raw.choices,
5670
+ usage: raw.usage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
5671
+ model: raw.model ?? opts.model,
5672
+ provider: raw.provider ?? providerHeader ?? "",
5673
+ usageWarning
5674
+ };
5675
+ },
5676
+ stream(opts) {
5677
+ const body = resolveAiBody(config, opts, true);
5678
+ const responsePromise = aiFetch(config, body, opts.signal, true);
5679
+ const meta = responsePromise.then(readMeta);
5680
+ meta.catch(() => {
5681
+ });
5682
+ async function* iterate() {
5683
+ const res = await responsePromise;
5684
+ const stream = res.body;
5685
+ if (!stream) {
5686
+ throw new NeetruError("invalid_response", "ai.stream: response has no body");
5687
+ }
5688
+ const reader = stream.getReader();
5689
+ const decoder = new TextDecoder();
5690
+ let buffer = "";
5691
+ try {
5692
+ while (true) {
5693
+ const { done, value } = await reader.read();
5694
+ if (done) break;
5695
+ buffer += decoder.decode(value, { stream: true });
5696
+ let sep;
5697
+ while ((sep = buffer.indexOf("\n\n")) !== -1) {
5698
+ const rawEvent = buffer.slice(0, sep);
5699
+ buffer = buffer.slice(sep + 2);
5700
+ const parsed = parseSseData(rawEvent);
5701
+ if (parsed && "done" in parsed) return;
5702
+ if (parsed && "content" in parsed) yield parsed.content;
5703
+ }
5704
+ }
5705
+ const tail = buffer.trim();
5706
+ if (tail) {
5707
+ const parsed = parseSseData(tail);
5708
+ if (parsed && "content" in parsed) yield parsed.content;
5709
+ }
5710
+ } finally {
5711
+ try {
5712
+ reader.releaseLock();
5713
+ } catch {
5714
+ }
5715
+ try {
5716
+ await stream.cancel();
5717
+ } catch {
5718
+ }
5719
+ }
5720
+ }
5721
+ return {
5722
+ meta,
5723
+ [Symbol.asyncIterator]: iterate
5724
+ };
5725
+ }
5726
+ };
5727
+ }
5728
+
5500
5729
  // src/mocks.ts
5501
5730
  init_errors();
5502
5731
  var DEV_FIXTURE_USER = Object.freeze({
@@ -5782,6 +6011,57 @@ var MockEntitlements = class {
5782
6011
  this._denied.clear();
5783
6012
  }
5784
6013
  };
6014
+ var MockAi = class {
6015
+ _calls = [];
6016
+ _reply(opts) {
6017
+ const last = [...opts.messages].reverse().find((m) => m.role === "user") ?? opts.messages[opts.messages.length - 1];
6018
+ const content = last?.content ?? "";
6019
+ return content ? `mock-reply: ${content}` : "mock-reply";
6020
+ }
6021
+ async chat(opts) {
6022
+ if (!opts || typeof opts.model !== "string" || opts.model.length === 0) {
6023
+ throw new NeetruError("validation_failed", "ai: model is required");
6024
+ }
6025
+ if (!Array.isArray(opts.messages) || opts.messages.length === 0) {
6026
+ throw new NeetruError("validation_failed", "ai: messages must be a non-empty array");
6027
+ }
6028
+ this._calls.push({ model: opts.model, messages: opts.messages, stream: false });
6029
+ const text = this._reply(opts);
6030
+ const promptTokens = opts.messages.reduce((n, m) => n + (m.content?.length ?? 0), 0);
6031
+ const completionTokens = text.length;
6032
+ return {
6033
+ choices: [{ message: { role: "assistant", content: text }, finish_reason: "stop" }],
6034
+ usage: {
6035
+ prompt_tokens: promptTokens,
6036
+ completion_tokens: completionTokens,
6037
+ total_tokens: promptTokens + completionTokens
6038
+ },
6039
+ model: opts.model,
6040
+ provider: "mock",
6041
+ usageWarning: false
6042
+ };
6043
+ }
6044
+ stream(opts) {
6045
+ if (!opts || typeof opts.model !== "string" || opts.model.length === 0) {
6046
+ throw new NeetruError("validation_failed", "ai: model is required");
6047
+ }
6048
+ if (!Array.isArray(opts.messages) || opts.messages.length === 0) {
6049
+ throw new NeetruError("validation_failed", "ai: messages must be a non-empty array");
6050
+ }
6051
+ this._calls.push({ model: opts.model, messages: opts.messages, stream: true });
6052
+ const text = this._reply(opts);
6053
+ const parts = text.match(/\S+\s*/g) ?? [text];
6054
+ const meta = Promise.resolve({ provider: "mock", usageWarning: false });
6055
+ async function* iterate() {
6056
+ for (const p of parts) yield p;
6057
+ }
6058
+ return { meta, [Symbol.asyncIterator]: iterate };
6059
+ }
6060
+ /** Test helper — histórico de chamadas. */
6061
+ __getCalls() {
6062
+ return this._calls;
6063
+ }
6064
+ };
5785
6065
 
5786
6066
  // src/auth.ts
5787
6067
  function readEnvApiKey() {
@@ -6223,6 +6503,7 @@ function createNeetruClient(config = {}) {
6223
6503
  const db = config.mocks?.db ?? createNeetruDb(resolved, config.db);
6224
6504
  const webhooks = config.mocks?.webhooks ?? (isDev ? new MockWebhooks() : createWebhooksNamespace(resolved));
6225
6505
  const notifications = config.mocks?.notifications ?? (isDev ? new MockNotifications() : createNotificationsNamespace(resolved));
6506
+ const ai = config.mocks?.ai ?? (isDev ? new MockAi() : createAiNamespace(resolved));
6226
6507
  const client = Object.freeze({
6227
6508
  config: resolved,
6228
6509
  auth,
@@ -6234,7 +6515,8 @@ function createNeetruClient(config = {}) {
6234
6515
  db,
6235
6516
  checkout: createCheckoutNamespace(resolved),
6236
6517
  webhooks,
6237
- notifications
6518
+ notifications,
6519
+ ai
6238
6520
  });
6239
6521
  return client;
6240
6522
  }