@neetru/sdk 3.5.0 → 3.7.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/CHANGELOG.md +71 -1
- package/dist/ai.cjs +254 -391
- package/dist/ai.d.cts +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/ai.mjs +254 -391
- package/dist/auth.cjs +3560 -4993
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +3557 -4990
- package/dist/build-guard.cjs +101 -119
- package/dist/build-guard.mjs +91 -109
- package/dist/catalog.cjs +152 -224
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.mjs +152 -224
- package/dist/checkout.cjs +237 -320
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/checkout.mjs +236 -319
- package/dist/db-react.cjs +59 -87
- package/dist/db-react.d.cts +1 -1
- package/dist/db-react.d.ts +1 -1
- package/dist/db-react.mjs +56 -84
- package/dist/db.cjs +2055 -3013
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +2068 -3026
- package/dist/entitlements.cjs +12 -20
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/entitlements.mjs +12 -20
- package/dist/errors.cjs +9 -12
- package/dist/errors.d.cts +37 -2
- package/dist/errors.d.ts +37 -2
- package/dist/errors.mjs +8 -12
- package/dist/firestore-compat.cjs +241 -297
- package/dist/firestore-compat.d.cts +1 -1
- package/dist/firestore-compat.d.ts +1 -1
- package/dist/firestore-compat.mjs +215 -271
- package/dist/index.cjs +3627 -5135
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.mjs +3731 -5239
- package/dist/mobile.cjs +411 -0
- package/dist/mobile.d.cts +89 -0
- package/dist/mobile.d.ts +89 -0
- package/dist/mobile.mjs +409 -0
- package/dist/mocks.cjs +312 -447
- package/dist/mocks.d.cts +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.mjs +306 -441
- package/dist/notifications.cjs +226 -314
- package/dist/notifications.d.cts +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.mjs +225 -313
- package/dist/react.cjs +522 -693
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +512 -683
- package/dist/support.cjs +329 -325
- package/dist/support.d.cts +25 -3
- package/dist/support.d.ts +25 -3
- package/dist/support.mjs +328 -325
- package/dist/telemetry.cjs +197 -301
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.mjs +197 -301
- package/dist/{types-Du_iioJ7.d.cts → types-Bx4kTLmk.d.cts} +26 -0
- package/dist/{types-BPATkXYu.d.ts → types-Dx0IrOSF.d.ts} +26 -0
- package/dist/usage.cjs +163 -227
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/usage.mjs +163 -227
- package/dist/webhooks.cjs +258 -359
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/dist/webhooks.mjs +255 -356
- package/package.json +9 -3
- package/dist/ai.cjs.map +0 -1
- package/dist/ai.mjs.map +0 -1
- package/dist/auth.cjs.map +0 -1
- package/dist/auth.mjs.map +0 -1
- package/dist/build-guard.cjs.map +0 -1
- package/dist/build-guard.mjs.map +0 -1
- package/dist/catalog.cjs.map +0 -1
- package/dist/catalog.mjs.map +0 -1
- package/dist/checkout.cjs.map +0 -1
- package/dist/checkout.mjs.map +0 -1
- package/dist/db-react.cjs.map +0 -1
- package/dist/db-react.mjs.map +0 -1
- package/dist/db.cjs.map +0 -1
- package/dist/db.mjs.map +0 -1
- package/dist/entitlements.cjs.map +0 -1
- package/dist/entitlements.mjs.map +0 -1
- package/dist/errors.cjs.map +0 -1
- package/dist/errors.mjs.map +0 -1
- package/dist/firestore-compat.cjs.map +0 -1
- package/dist/firestore-compat.mjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/mocks.cjs.map +0 -1
- package/dist/mocks.mjs.map +0 -1
- package/dist/notifications.cjs.map +0 -1
- package/dist/notifications.mjs.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.mjs.map +0 -1
- package/dist/support.cjs.map +0 -1
- package/dist/support.mjs.map +0 -1
- package/dist/telemetry.cjs.map +0 -1
- package/dist/telemetry.mjs.map +0 -1
- package/dist/usage.cjs.map +0 -1
- package/dist/usage.mjs.map +0 -1
- package/dist/webhooks.cjs.map +0 -1
- package/dist/webhooks.mjs.map +0 -1
package/dist/ai.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
|
-
var
|
|
2
|
+
var u = class t extends Error {
|
|
3
3
|
code;
|
|
4
4
|
status;
|
|
5
5
|
requestId;
|
|
@@ -12,517 +12,380 @@ var NeetruError = class _NeetruError extends Error {
|
|
|
12
12
|
* para um `NeetruDbErrorCode` mais específico (recuperável vs não).
|
|
13
13
|
*/
|
|
14
14
|
reason;
|
|
15
|
-
constructor(
|
|
16
|
-
super(
|
|
17
|
-
this.name = "NeetruError";
|
|
18
|
-
this.code = code;
|
|
19
|
-
this.status = status;
|
|
20
|
-
this.requestId = requestId;
|
|
21
|
-
this.reason = reason;
|
|
22
|
-
Object.setPrototypeOf(this, _NeetruError.prototype);
|
|
15
|
+
constructor(e, r, s, n, i) {
|
|
16
|
+
super(r), this.name = "NeetruError", this.code = e, this.status = s, this.requestId = n, this.reason = i, Object.setPrototypeOf(this, t.prototype);
|
|
23
17
|
}
|
|
24
18
|
};
|
|
25
19
|
|
|
26
20
|
// src/http.ts
|
|
27
|
-
var
|
|
21
|
+
var z = {
|
|
28
22
|
// SDK major 3.x requer Core ≥ 2026.05.1 (suporte a X-Neetru-Version header,
|
|
29
23
|
// runTransaction write-after-read, verifyWebhookRequest, webhooks 3.0+)
|
|
30
24
|
3: "2026.05.1"
|
|
31
25
|
};
|
|
32
|
-
function
|
|
33
|
-
return
|
|
26
|
+
function b(t) {
|
|
27
|
+
return t.split("+")[0] ?? t;
|
|
34
28
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const pa = partsA[i] ?? 0;
|
|
41
|
-
const pb = partsB[i] ?? 0;
|
|
42
|
-
if (pa !== pb) return pa - pb;
|
|
29
|
+
function B(t, e) {
|
|
30
|
+
let r = b(t).split(".").map(Number), s = b(e).split(".").map(Number), n = Math.max(r.length, s.length);
|
|
31
|
+
for (let i = 0; i < n; i++) {
|
|
32
|
+
let a = r[i] ?? 0, o = s[i] ?? 0;
|
|
33
|
+
if (a !== o) return a - o;
|
|
43
34
|
}
|
|
44
35
|
return 0;
|
|
45
36
|
}
|
|
46
|
-
function
|
|
37
|
+
function G() {
|
|
47
38
|
try {
|
|
48
|
-
return "3.
|
|
39
|
+
return "3.7.0";
|
|
49
40
|
} catch {
|
|
50
|
-
return
|
|
41
|
+
return;
|
|
51
42
|
}
|
|
52
43
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return 3;
|
|
44
|
+
function J() {
|
|
45
|
+
let t = G();
|
|
46
|
+
return t ? parseInt(t.split(".")[0] ?? "3", 10) : 3;
|
|
57
47
|
}
|
|
58
|
-
var
|
|
59
|
-
function
|
|
60
|
-
if (!
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.warn(
|
|
70
|
-
`[Neetru SDK] Aten\xE7\xE3o: Core vers\xE3o "${coreVersion}" \xE9 anterior ao m\xEDnimo recomendado "${minCore}" para SDK major ${sdkMajor}. Alguns recursos podem n\xE3o funcionar corretamente. Atualize o Core para a vers\xE3o mais recente.`
|
|
71
|
-
);
|
|
72
|
-
}
|
|
48
|
+
var w = /* @__PURE__ */ new Set();
|
|
49
|
+
function E(t) {
|
|
50
|
+
if (!t) return;
|
|
51
|
+
let e = J(), r = z[e];
|
|
52
|
+
if (!r) return;
|
|
53
|
+
let s = b(t);
|
|
54
|
+
if (B(s, r) < 0) {
|
|
55
|
+
let n = `${e}:${s}`;
|
|
56
|
+
w.has(n) || (w.add(n), console.warn(
|
|
57
|
+
`[Neetru SDK] Aten\xE7\xE3o: Core vers\xE3o "${t}" \xE9 anterior ao m\xEDnimo recomendado "${r}" para SDK major ${e}. Alguns recursos podem n\xE3o funcionar corretamente. Atualize o Core para a vers\xE3o mais recente.`
|
|
58
|
+
));
|
|
73
59
|
}
|
|
74
60
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
if (status === 403) return "forbidden";
|
|
78
|
-
if (status === 404) return "not_found";
|
|
79
|
-
if (status === 409) return "conflict";
|
|
80
|
-
if (status === 422 || status === 400) return "validation_failed";
|
|
81
|
-
if (status === 429) return "rate_limited";
|
|
82
|
-
if (status >= 500) return "server_error";
|
|
83
|
-
return "unknown";
|
|
61
|
+
function x(t) {
|
|
62
|
+
return t === 401 ? "unauthorized" : t === 403 ? "forbidden" : t === 404 ? "not_found" : t === 409 ? "conflict" : t === 410 ? "gone" : t === 422 || t === 400 ? "validation_failed" : t === 429 ? "rate_limited" : t >= 500 ? "server_error" : "unknown";
|
|
84
63
|
}
|
|
85
64
|
|
|
86
65
|
// src/validators.ts
|
|
87
|
-
var
|
|
88
|
-
function
|
|
89
|
-
if (typeof
|
|
90
|
-
throw new
|
|
66
|
+
var k = /^[a-z0-9][a-z0-9_-]{0,62}$/i;
|
|
67
|
+
function A(t, e) {
|
|
68
|
+
if (typeof e != "string" || !k.test(e))
|
|
69
|
+
throw new u(
|
|
91
70
|
"validation_failed",
|
|
92
|
-
`${
|
|
71
|
+
`${t} must match ${k.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`
|
|
93
72
|
);
|
|
94
|
-
}
|
|
95
73
|
}
|
|
96
74
|
|
|
97
75
|
// src/ai.ts
|
|
98
|
-
var
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
var MAX_CONTENT_PARTS = 32;
|
|
102
|
-
var MAX_DATA_URL_LEN = 4194304;
|
|
103
|
-
var MAX_HTTPS_URL_LEN = 2048;
|
|
104
|
-
var DATA_IMAGE_URL_RE = /^data:image\/(?:png|jpe?g|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/;
|
|
105
|
-
var HTTPS_URL_RE = /^https:\/\/[^\s]+$/;
|
|
106
|
-
var IMAGE_DETAIL_VALUES = /* @__PURE__ */ new Set(["low", "high", "auto"]);
|
|
107
|
-
var AI_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant"]);
|
|
108
|
-
var MAX_MESSAGES = 100;
|
|
109
|
-
var MAX_MODEL_LEN = 128;
|
|
110
|
-
var MAX_TOKENS_CAP = 32768;
|
|
111
|
-
var MIN_TEMPERATURE = 0;
|
|
112
|
-
var MAX_TEMPERATURE = 2;
|
|
113
|
-
var MAX_TOTAL_CONTENT_PARTS = 200;
|
|
114
|
-
var MAX_TOTAL_IMAGES = 20;
|
|
115
|
-
var MAX_TOTAL_IMAGE_BYTES = 12 * 1024 * 1024;
|
|
116
|
-
var MAX_SCHEMA_JSON_LEN = 5e4;
|
|
117
|
-
var MAX_SCHEMA_DEPTH = 16;
|
|
118
|
-
var MAX_SCHEMA_KEYS = 500;
|
|
119
|
-
var FORBIDDEN_SCHEMA_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
120
|
-
var RESPONSE_FORMAT_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
121
|
-
function fail(msg) {
|
|
122
|
-
throw new NeetruError("validation_failed", msg);
|
|
76
|
+
var V = "/api/sdk/v1/ai/chat", T = 12e4, _ = 32768, R = 32, v = 4194304, S = 2048, Y = /^data:image\/(?:png|jpe?g|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/, Z = /^https:\/\/[^\s]+$/, Q = /* @__PURE__ */ new Set(["low", "high", "auto"]), ee = /* @__PURE__ */ new Set(["system", "user", "assistant"]), M = 100, j = 128, C = 32768, N = 0, I = 2, O = 200, P = 20, $ = 12 * 1024 * 1024, q = 5e4, F = 16, D = 500, te = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]), ne = /^[a-zA-Z0-9_-]+$/;
|
|
77
|
+
function c(t) {
|
|
78
|
+
throw new u("validation_failed", t);
|
|
123
79
|
}
|
|
124
|
-
function
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return !body.includes("=");
|
|
80
|
+
function re(t) {
|
|
81
|
+
if (t.length === 0 || t.length % 4 !== 0) return false;
|
|
82
|
+
let e = t.endsWith("==") ? 2 : t.endsWith("=") ? 1 : 0;
|
|
83
|
+
return !(e > 0 ? t.slice(0, t.length - e) : t).includes("=");
|
|
129
84
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return Math.max(0, Math.floor(b64.length * 3 / 4) - pad);
|
|
85
|
+
function se(t) {
|
|
86
|
+
let e = t.indexOf(",");
|
|
87
|
+
if (e === -1) return 0;
|
|
88
|
+
let r = t.slice(e + 1), s = r.endsWith("==") ? 2 : r.endsWith("=") ? 1 : 0;
|
|
89
|
+
return Math.max(0, Math.floor(r.length * 3 / 4) - s);
|
|
136
90
|
}
|
|
137
|
-
function
|
|
138
|
-
let
|
|
139
|
-
let
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (totalImages > MAX_TOTAL_IMAGES) {
|
|
152
|
-
return `ai: total images exceeds ${MAX_TOTAL_IMAGES} per request`;
|
|
153
|
-
}
|
|
154
|
-
const url = part.image_url?.url;
|
|
155
|
-
if (typeof url === "string" && url.startsWith("data:")) {
|
|
156
|
-
totalImageBytes += dataUrlDecodedBytes(url);
|
|
157
|
-
if (totalImageBytes > MAX_TOTAL_IMAGE_BYTES) {
|
|
158
|
-
return `ai: aggregate image bytes exceeds ${MAX_TOTAL_IMAGE_BYTES} per request`;
|
|
159
|
-
}
|
|
91
|
+
function ie(t) {
|
|
92
|
+
let e = 0, r = 0, s = 0;
|
|
93
|
+
for (let n of t) {
|
|
94
|
+
let i = n?.content;
|
|
95
|
+
if (Array.isArray(i))
|
|
96
|
+
for (let a of i) {
|
|
97
|
+
if (e++, e > O)
|
|
98
|
+
return `ai: total content parts exceeds ${O} per request`;
|
|
99
|
+
if (a && typeof a == "object" && a.type === "image_url") {
|
|
100
|
+
if (r++, r > P)
|
|
101
|
+
return `ai: total images exceeds ${P} per request`;
|
|
102
|
+
let o = a.image_url?.url;
|
|
103
|
+
if (typeof o == "string" && o.startsWith("data:") && (s += se(o), s > $))
|
|
104
|
+
return `ai: aggregate image bytes exceeds ${$} per request`;
|
|
160
105
|
}
|
|
161
106
|
}
|
|
162
|
-
}
|
|
163
107
|
}
|
|
164
108
|
return null;
|
|
165
109
|
}
|
|
166
|
-
function
|
|
167
|
-
if (
|
|
168
|
-
if (
|
|
110
|
+
function oe(t) {
|
|
111
|
+
if (t === void 0) return null;
|
|
112
|
+
if (t === null || typeof t != "object")
|
|
169
113
|
return "ai: responseFormat json_schema.schema must be an object";
|
|
170
|
-
|
|
171
|
-
let serialized;
|
|
114
|
+
let e;
|
|
172
115
|
try {
|
|
173
|
-
|
|
116
|
+
e = JSON.stringify(t);
|
|
174
117
|
} catch {
|
|
175
118
|
return "ai: responseFormat json_schema.schema is not serializable";
|
|
176
119
|
}
|
|
177
|
-
if (
|
|
178
|
-
if (
|
|
179
|
-
return `ai: responseFormat json_schema.schema exceeds ${
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
for (const item of node) {
|
|
188
|
-
const e = walk(item, depth + 1);
|
|
189
|
-
if (e) return e;
|
|
120
|
+
if (e === void 0) return "ai: responseFormat json_schema.schema is invalid";
|
|
121
|
+
if (e.length > q)
|
|
122
|
+
return `ai: responseFormat json_schema.schema exceeds ${q} serialized chars`;
|
|
123
|
+
let r = 0, s = (n, i) => {
|
|
124
|
+
if (i > F)
|
|
125
|
+
return `ai: responseFormat json_schema.schema exceeds max depth ${F}`;
|
|
126
|
+
if (Array.isArray(n)) {
|
|
127
|
+
for (let a of n) {
|
|
128
|
+
let o = s(a, i + 1);
|
|
129
|
+
if (o) return o;
|
|
190
130
|
}
|
|
191
131
|
return null;
|
|
192
132
|
}
|
|
193
|
-
if (
|
|
194
|
-
for (
|
|
195
|
-
if (
|
|
196
|
-
return `ai: responseFormat json_schema.schema has forbidden key: ${
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
const e = walk(node[key], depth + 1);
|
|
203
|
-
if (e) return e;
|
|
133
|
+
if (n && typeof n == "object")
|
|
134
|
+
for (let a of Object.getOwnPropertyNames(n)) {
|
|
135
|
+
if (te.has(a))
|
|
136
|
+
return `ai: responseFormat json_schema.schema has forbidden key: ${a}`;
|
|
137
|
+
if (r++, r > D)
|
|
138
|
+
return `ai: responseFormat json_schema.schema exceeds ${D} keys`;
|
|
139
|
+
let o = s(n[a], i + 1);
|
|
140
|
+
if (o) return o;
|
|
204
141
|
}
|
|
205
|
-
}
|
|
206
142
|
return null;
|
|
207
143
|
};
|
|
208
|
-
return
|
|
144
|
+
return s(t, 0);
|
|
209
145
|
}
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (!DATA_IMAGE_URL_RE.test(u)) {
|
|
218
|
-
fail("ai: image_url.url data: must be data:image/<png|jpeg|jpg|gif|webp>;base64,<...>");
|
|
219
|
-
}
|
|
220
|
-
const b64 = u.slice(u.indexOf(",") + 1);
|
|
221
|
-
if (!isStrictBase64Payload(b64)) {
|
|
222
|
-
fail("ai: image_url.url data: has invalid base64 (length/padding)");
|
|
223
|
-
}
|
|
146
|
+
function ae(t) {
|
|
147
|
+
(typeof t != "string" || t.length === 0) && c("ai: image_url.url must be a non-empty string");
|
|
148
|
+
let e = t;
|
|
149
|
+
if (e.startsWith("data:")) {
|
|
150
|
+
e.length > v && c(`ai: image_url.url (data:) exceeds ${v} chars`), Y.test(e) || c("ai: image_url.url data: must be data:image/<png|jpeg|jpg|gif|webp>;base64,<...>");
|
|
151
|
+
let r = e.slice(e.indexOf(",") + 1);
|
|
152
|
+
re(r) || c("ai: image_url.url data: has invalid base64 (length/padding)");
|
|
224
153
|
return;
|
|
225
154
|
}
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
if (!HTTPS_URL_RE.test(u)) fail("ai: image_url.url https: is invalid");
|
|
155
|
+
if (e.startsWith("https://")) {
|
|
156
|
+
e.length > S && c(`ai: image_url.url (https:) exceeds ${S} chars`), Z.test(e) || c("ai: image_url.url https: is invalid");
|
|
229
157
|
return;
|
|
230
158
|
}
|
|
231
|
-
|
|
159
|
+
c("ai: image_url.url must be a data:image/...;base64 or https:// URL (other schemes are rejected)");
|
|
232
160
|
}
|
|
233
|
-
function
|
|
234
|
-
if (typeof
|
|
235
|
-
|
|
236
|
-
if (content.length > MAX_TEXT_PART_LEN) fail(`ai: message content exceeds ${MAX_TEXT_PART_LEN} chars`);
|
|
161
|
+
function ce(t, e) {
|
|
162
|
+
if (typeof t == "string") {
|
|
163
|
+
t.length === 0 && c("ai: message content string must be non-empty"), t.length > _ && c(`ai: message content exceeds ${_} chars`);
|
|
237
164
|
return;
|
|
238
165
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const iu = part.image_url;
|
|
255
|
-
if (!iu || typeof iu !== "object") fail("ai: image_url part must have { image_url: { url } }");
|
|
256
|
-
validateImageUrl(iu.url);
|
|
257
|
-
const detail = iu.detail;
|
|
258
|
-
if (detail !== void 0 && (typeof detail !== "string" || !IMAGE_DETAIL_VALUES.has(detail))) {
|
|
259
|
-
fail("ai: image_url.detail must be 'low' | 'high' | 'auto'");
|
|
260
|
-
}
|
|
261
|
-
} else {
|
|
262
|
-
fail("ai: content part type must be 'text' or 'image_url'");
|
|
263
|
-
}
|
|
166
|
+
(!Array.isArray(t) || t.length === 0) && c("ai: message content must be a non-empty string or array of parts"), t.length > R && c(`ai: message content has more than ${R} parts`);
|
|
167
|
+
for (let r of t) {
|
|
168
|
+
(!r || typeof r != "object") && c("ai: each content part must be an object");
|
|
169
|
+
let s = r.type;
|
|
170
|
+
if (s === "text") {
|
|
171
|
+
let n = r.text;
|
|
172
|
+
(typeof n != "string" || n.length === 0) && c("ai: text part must have non-empty { text: string }"), n.length > _ && c(`ai: text part exceeds ${_} chars`);
|
|
173
|
+
} else if (s === "image_url") {
|
|
174
|
+
e !== "user" && c(`ai: image_url is only allowed in role 'user' messages (got '${e}')`);
|
|
175
|
+
let n = r.image_url;
|
|
176
|
+
(!n || typeof n != "object") && c("ai: image_url part must have { image_url: { url } }"), ae(n.url);
|
|
177
|
+
let i = n.detail;
|
|
178
|
+
i !== void 0 && (typeof i != "string" || !Q.has(i)) && c("ai: image_url.detail must be 'low' | 'high' | 'auto'");
|
|
179
|
+
} else
|
|
180
|
+
c("ai: content part type must be 'text' or 'image_url'");
|
|
264
181
|
}
|
|
265
182
|
}
|
|
266
|
-
function
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
if (typeof jso.description !== "string") fail("ai: responseFormat json_schema.description must be a string");
|
|
280
|
-
if (jso.description.length > 1e3) fail("ai: responseFormat json_schema.description exceeds 1000 chars");
|
|
281
|
-
}
|
|
282
|
-
if (jso.strict !== void 0 && typeof jso.strict !== "boolean") {
|
|
283
|
-
fail("ai: responseFormat json_schema.strict must be a boolean");
|
|
284
|
-
}
|
|
285
|
-
if (jso.schema !== void 0) {
|
|
286
|
-
const err = validateStructuredSchema(jso.schema);
|
|
287
|
-
if (err) fail(err);
|
|
183
|
+
function ue(t) {
|
|
184
|
+
(!t || typeof t != "object") && c("ai: responseFormat must be an object");
|
|
185
|
+
let e = t.type;
|
|
186
|
+
if (!(e === "text" || e === "json_object")) {
|
|
187
|
+
if (e === "json_schema") {
|
|
188
|
+
let r = t.json_schema;
|
|
189
|
+
(!r || typeof r != "object") && c("ai: responseFormat json_schema requires { json_schema: { name } }");
|
|
190
|
+
let s = r, n = s.name;
|
|
191
|
+
if ((typeof n != "string" || n.length === 0) && c("ai: responseFormat json_schema.name is required"), n.length > 64 && c("ai: responseFormat json_schema.name exceeds 64 chars"), ne.test(n) || c("ai: responseFormat json_schema.name must match a-zA-Z0-9_-"), s.description !== void 0 && (typeof s.description != "string" && c("ai: responseFormat json_schema.description must be a string"), s.description.length > 1e3 && c("ai: responseFormat json_schema.description exceeds 1000 chars")), s.strict !== void 0 && typeof s.strict != "boolean" && c("ai: responseFormat json_schema.strict must be a boolean"), s.schema !== void 0) {
|
|
192
|
+
let i = oe(s.schema);
|
|
193
|
+
i && c(i);
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
288
196
|
}
|
|
289
|
-
|
|
197
|
+
c("ai: responseFormat.type must be 'text' | 'json_object' | 'json_schema'");
|
|
290
198
|
}
|
|
291
|
-
fail("ai: responseFormat.type must be 'text' | 'json_object' | 'json_schema'");
|
|
292
199
|
}
|
|
293
|
-
function
|
|
294
|
-
if (!
|
|
295
|
-
throw new
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (
|
|
301
|
-
throw new
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
throw new NeetruError("validation_failed", `ai: messages exceeds ${MAX_MESSAGES} per request`);
|
|
308
|
-
}
|
|
309
|
-
for (const m of opts.messages) {
|
|
310
|
-
if (!m || typeof m !== "object" || typeof m.role !== "string" || !AI_ROLES.has(m.role)) {
|
|
311
|
-
throw new NeetruError(
|
|
200
|
+
function U(t, e, r) {
|
|
201
|
+
if (!e || typeof e != "object")
|
|
202
|
+
throw new u("validation_failed", "ai: options object is required");
|
|
203
|
+
if (typeof e.model != "string" || e.model.length === 0)
|
|
204
|
+
throw new u("validation_failed", "ai: model is required");
|
|
205
|
+
if (e.model.length > j)
|
|
206
|
+
throw new u("validation_failed", `ai: model exceeds ${j} chars`);
|
|
207
|
+
if (!Array.isArray(e.messages) || e.messages.length === 0)
|
|
208
|
+
throw new u("validation_failed", "ai: messages must be a non-empty array");
|
|
209
|
+
if (e.messages.length > M)
|
|
210
|
+
throw new u("validation_failed", `ai: messages exceeds ${M} per request`);
|
|
211
|
+
for (let o of e.messages) {
|
|
212
|
+
if (!o || typeof o != "object" || typeof o.role != "string" || !ee.has(o.role))
|
|
213
|
+
throw new u(
|
|
312
214
|
"validation_failed",
|
|
313
215
|
"ai: each message role must be 'system' | 'user' | 'assistant'"
|
|
314
216
|
);
|
|
315
|
-
|
|
316
|
-
validateAiContent(m.content, m.role);
|
|
217
|
+
ce(o.content, o.role);
|
|
317
218
|
}
|
|
318
|
-
|
|
319
|
-
if (
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
throw new NeetruError(
|
|
219
|
+
let s = ie(e.messages);
|
|
220
|
+
if (s) throw new u("validation_failed", s);
|
|
221
|
+
let n = e.productId ?? t.productId, i = e.tenantId ?? t.tenantId;
|
|
222
|
+
if (!n)
|
|
223
|
+
throw new u(
|
|
324
224
|
"validation_failed",
|
|
325
225
|
"ai: productId required (pass to options or set on createNeetruClient)"
|
|
326
226
|
);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
throw new NeetruError(
|
|
227
|
+
if (!i)
|
|
228
|
+
throw new u(
|
|
330
229
|
"validation_failed",
|
|
331
230
|
"ai: tenantId required (pass to options or set on createNeetruClient)"
|
|
332
231
|
);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
messages: opts.messages,
|
|
341
|
-
stream
|
|
232
|
+
A("productId", n), A("tenantId", i);
|
|
233
|
+
let a = {
|
|
234
|
+
productId: n,
|
|
235
|
+
tenantId: i,
|
|
236
|
+
model: e.model,
|
|
237
|
+
messages: e.messages,
|
|
238
|
+
stream: r
|
|
342
239
|
};
|
|
343
|
-
if (
|
|
344
|
-
if (!Number.isInteger(
|
|
345
|
-
throw new
|
|
240
|
+
if (e.maxTokens !== void 0) {
|
|
241
|
+
if (!Number.isInteger(e.maxTokens) || e.maxTokens <= 0 || e.maxTokens > C)
|
|
242
|
+
throw new u(
|
|
346
243
|
"validation_failed",
|
|
347
|
-
`ai: maxTokens must be a positive integer <= ${
|
|
244
|
+
`ai: maxTokens must be a positive integer <= ${C}`
|
|
348
245
|
);
|
|
349
|
-
|
|
350
|
-
body.maxTokens = opts.maxTokens;
|
|
246
|
+
a.maxTokens = e.maxTokens;
|
|
351
247
|
}
|
|
352
|
-
if (
|
|
353
|
-
if (typeof
|
|
354
|
-
throw new
|
|
248
|
+
if (e.temperature !== void 0) {
|
|
249
|
+
if (typeof e.temperature != "number" || !Number.isFinite(e.temperature) || e.temperature < N || e.temperature > I)
|
|
250
|
+
throw new u(
|
|
355
251
|
"validation_failed",
|
|
356
|
-
`ai: temperature must be a finite number between ${
|
|
252
|
+
`ai: temperature must be a finite number between ${N} and ${I}`
|
|
357
253
|
);
|
|
358
|
-
|
|
359
|
-
body.temperature = opts.temperature;
|
|
254
|
+
a.temperature = e.temperature;
|
|
360
255
|
}
|
|
361
|
-
|
|
362
|
-
validateResponseFormat(opts.responseFormat);
|
|
363
|
-
body.responseFormat = opts.responseFormat;
|
|
364
|
-
}
|
|
365
|
-
return body;
|
|
256
|
+
return e.responseFormat !== void 0 && (ue(e.responseFormat), a.responseFormat = e.responseFormat), a;
|
|
366
257
|
}
|
|
367
|
-
async function
|
|
258
|
+
async function X(t) {
|
|
368
259
|
try {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return JSON.parse(text);
|
|
260
|
+
let e = await t.text();
|
|
261
|
+
return e ? JSON.parse(e) : void 0;
|
|
372
262
|
} catch {
|
|
373
|
-
return
|
|
263
|
+
return;
|
|
374
264
|
}
|
|
375
265
|
}
|
|
376
|
-
function
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
return `${base}${p}`;
|
|
266
|
+
function de(t, e) {
|
|
267
|
+
let r = t.replace(/\/+$/, ""), s = e.startsWith("/") ? e : `/${e}`;
|
|
268
|
+
return `${r}${s}`;
|
|
380
269
|
}
|
|
381
|
-
async function
|
|
382
|
-
if (!
|
|
383
|
-
throw new
|
|
270
|
+
async function L(t, e, r, s) {
|
|
271
|
+
if (!t.apiKey)
|
|
272
|
+
throw new u(
|
|
384
273
|
"missing_api_key",
|
|
385
274
|
"ai requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var."
|
|
386
275
|
);
|
|
387
|
-
|
|
388
|
-
const url = joinUrl(config.baseUrl, AI_CHAT_PATH);
|
|
389
|
-
const headers = {
|
|
276
|
+
let n = de(t.baseUrl, V), a = { method: "POST", headers: {
|
|
390
277
|
"content-type": "application/json",
|
|
391
|
-
accept:
|
|
392
|
-
authorization: `Bearer ${
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (signal) init.signal = signal;
|
|
397
|
-
} else {
|
|
398
|
-
init.signal = signal ?? AbortSignal.timeout(AI_NONSTREAM_TIMEOUT_MS);
|
|
399
|
-
}
|
|
400
|
-
let res;
|
|
278
|
+
accept: s ? "text/event-stream" : "application/json",
|
|
279
|
+
authorization: `Bearer ${t.apiKey}`
|
|
280
|
+
}, body: JSON.stringify(e) };
|
|
281
|
+
s ? r && (a.signal = r) : a.signal = r ?? AbortSignal.timeout(T);
|
|
282
|
+
let o;
|
|
401
283
|
try {
|
|
402
|
-
|
|
403
|
-
} catch (
|
|
404
|
-
|
|
405
|
-
throw new
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (!
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const errField = parsed.error;
|
|
414
|
-
if (typeof errField === "string") {
|
|
415
|
-
message = errField;
|
|
416
|
-
} else if (errField && typeof errField === "object") {
|
|
417
|
-
if (typeof errField.code === "string") code = errField.code;
|
|
418
|
-
if (typeof errField.message === "string") message = errField.message;
|
|
419
|
-
}
|
|
284
|
+
o = await t.fetch(n, a);
|
|
285
|
+
} catch (d) {
|
|
286
|
+
let f = d instanceof DOMException && d.name === "TimeoutError" ? `Network error: timeout after ${T / 1e3}s` : d instanceof DOMException && d.name === "AbortError" ? "Network error: request aborted" : `Network error: ${d instanceof Error ? d.message : "fetch failed"}`;
|
|
287
|
+
throw new u("network_error", f);
|
|
288
|
+
}
|
|
289
|
+
let g = o.headers.get("x-request-id") ?? o.headers.get("x-correlation-id") ?? void 0;
|
|
290
|
+
if (!o.ok) {
|
|
291
|
+
let d = await X(o), f = x(o.status), m = `HTTP ${o.status}`;
|
|
292
|
+
if (d && typeof d == "object" && "error" in d) {
|
|
293
|
+
let l = d.error;
|
|
294
|
+
typeof l == "string" ? m = l : l && typeof l == "object" && (typeof l.code == "string" && (f = l.code), typeof l.message == "string" && (m = l.message));
|
|
420
295
|
}
|
|
421
|
-
throw new
|
|
296
|
+
throw new u(f, m, o.status, g);
|
|
422
297
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return res;
|
|
298
|
+
let h = o.headers.get("x-neetru-version");
|
|
299
|
+
return h && E(h), o;
|
|
426
300
|
}
|
|
427
|
-
function
|
|
301
|
+
function H(t) {
|
|
428
302
|
return {
|
|
429
|
-
provider:
|
|
430
|
-
usageWarning:
|
|
303
|
+
provider: t.headers.get("x-neetru-provider") ?? "",
|
|
304
|
+
usageWarning: t.headers.get("x-neetru-ai-usage-warning") === "1"
|
|
431
305
|
};
|
|
432
306
|
}
|
|
433
|
-
function
|
|
434
|
-
|
|
435
|
-
for (
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
307
|
+
function K(t) {
|
|
308
|
+
let e = [];
|
|
309
|
+
for (let s of t.split(`
|
|
310
|
+
`)) {
|
|
311
|
+
let n = s.replace(/\r$/, "");
|
|
312
|
+
if (n.startsWith("data:")) {
|
|
313
|
+
let i = n.slice(5);
|
|
314
|
+
i.startsWith(" ") && (i = i.slice(1)), e.push(i);
|
|
441
315
|
}
|
|
442
316
|
}
|
|
443
|
-
if (
|
|
444
|
-
|
|
445
|
-
|
|
317
|
+
if (e.length === 0) return null;
|
|
318
|
+
let r = e.join(`
|
|
319
|
+
`);
|
|
320
|
+
if (r === "[DONE]") return { done: true };
|
|
446
321
|
try {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
if (typeof content === "string" && content.length > 0) return { content };
|
|
450
|
-
return null;
|
|
322
|
+
let n = JSON.parse(r)?.choices?.[0]?.delta?.content;
|
|
323
|
+
return typeof n == "string" && n.length > 0 ? { content: n } : null;
|
|
451
324
|
} catch {
|
|
452
325
|
return null;
|
|
453
326
|
}
|
|
454
327
|
}
|
|
455
|
-
function
|
|
328
|
+
function ye(t) {
|
|
456
329
|
return {
|
|
457
|
-
async chat(
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const raw = await safeJson(res);
|
|
462
|
-
if (!raw || raw.ok !== true || !Array.isArray(raw.choices)) {
|
|
463
|
-
throw new NeetruError("invalid_response", "ai.chat response missing ok/choices");
|
|
464
|
-
}
|
|
330
|
+
async chat(e) {
|
|
331
|
+
let r = U(t, e, false), s = await L(t, r, e.signal, false), { provider: n, usageWarning: i } = H(s), a = await X(s);
|
|
332
|
+
if (!a || a.ok !== true || !Array.isArray(a.choices))
|
|
333
|
+
throw new u("invalid_response", "ai.chat response missing ok/choices");
|
|
465
334
|
return {
|
|
466
|
-
choices:
|
|
467
|
-
usage:
|
|
468
|
-
model:
|
|
469
|
-
provider:
|
|
470
|
-
usageWarning
|
|
335
|
+
choices: a.choices,
|
|
336
|
+
usage: a.usage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
337
|
+
model: a.model ?? e.model,
|
|
338
|
+
provider: a.provider ?? n ?? "",
|
|
339
|
+
usageWarning: i
|
|
471
340
|
};
|
|
472
341
|
},
|
|
473
|
-
stream(
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const meta = responsePromise.then(readMeta);
|
|
477
|
-
meta.catch(() => {
|
|
342
|
+
stream(e) {
|
|
343
|
+
let r = U(t, e, true), s = L(t, r, e.signal, true), n = s.then(H);
|
|
344
|
+
n.catch(() => {
|
|
478
345
|
});
|
|
479
|
-
async function*
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
const reader = stream.getReader();
|
|
486
|
-
const decoder = new TextDecoder();
|
|
487
|
-
let buffer = "";
|
|
346
|
+
async function* i() {
|
|
347
|
+
let o = (await s).body;
|
|
348
|
+
if (!o)
|
|
349
|
+
throw new u("invalid_response", "ai.stream: response has no body");
|
|
350
|
+
let g = o.getReader(), h = new TextDecoder(), d = "";
|
|
488
351
|
try {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
let
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
352
|
+
for (; ; ) {
|
|
353
|
+
let { done: m, value: l } = await g.read();
|
|
354
|
+
if (m) break;
|
|
355
|
+
d += h.decode(l, { stream: !0 });
|
|
356
|
+
let y;
|
|
357
|
+
for (; (y = d.indexOf(`
|
|
358
|
+
|
|
359
|
+
`)) !== -1; ) {
|
|
360
|
+
let W = d.slice(0, y);
|
|
361
|
+
d = d.slice(y + 2);
|
|
362
|
+
let p = K(W);
|
|
363
|
+
if (p && "done" in p) return;
|
|
364
|
+
p && "content" in p && (yield p.content);
|
|
500
365
|
}
|
|
501
366
|
}
|
|
502
|
-
|
|
503
|
-
if (
|
|
504
|
-
|
|
505
|
-
|
|
367
|
+
let f = d.trim();
|
|
368
|
+
if (f) {
|
|
369
|
+
let m = K(f);
|
|
370
|
+
m && "content" in m && (yield m.content);
|
|
506
371
|
}
|
|
507
372
|
} finally {
|
|
508
373
|
try {
|
|
509
|
-
|
|
374
|
+
g.releaseLock();
|
|
510
375
|
} catch {
|
|
511
376
|
}
|
|
512
377
|
try {
|
|
513
|
-
await
|
|
378
|
+
await o.cancel();
|
|
514
379
|
} catch {
|
|
515
380
|
}
|
|
516
381
|
}
|
|
517
382
|
}
|
|
518
383
|
return {
|
|
519
|
-
meta,
|
|
520
|
-
[Symbol.asyncIterator]:
|
|
384
|
+
meta: n,
|
|
385
|
+
[Symbol.asyncIterator]: i
|
|
521
386
|
};
|
|
522
387
|
}
|
|
523
388
|
};
|
|
524
389
|
}
|
|
525
390
|
|
|
526
|
-
export { createAiNamespace };
|
|
527
|
-
//# sourceMappingURL=ai.mjs.map
|
|
528
|
-
//# sourceMappingURL=ai.mjs.map
|
|
391
|
+
export { ye as createAiNamespace };
|