@neetru/sdk 3.6.0 → 3.8.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +66 -1
  3. package/dist/ai.cjs +298 -391
  4. package/dist/ai.d.cts +1 -1
  5. package/dist/ai.d.ts +1 -1
  6. package/dist/ai.mjs +298 -391
  7. package/dist/auth.cjs +3717 -5005
  8. package/dist/auth.d.cts +1 -1
  9. package/dist/auth.d.ts +1 -1
  10. package/dist/auth.mjs +3714 -5002
  11. package/dist/build-guard.cjs +101 -119
  12. package/dist/build-guard.mjs +91 -109
  13. package/dist/catalog.cjs +220 -225
  14. package/dist/catalog.d.cts +1 -1
  15. package/dist/catalog.d.ts +1 -1
  16. package/dist/catalog.mjs +220 -225
  17. package/dist/checkout.cjs +307 -323
  18. package/dist/checkout.d.cts +1 -1
  19. package/dist/checkout.d.ts +1 -1
  20. package/dist/checkout.mjs +306 -322
  21. package/dist/db-react.cjs +59 -87
  22. package/dist/db-react.d.cts +1 -1
  23. package/dist/db-react.d.ts +1 -1
  24. package/dist/db-react.mjs +56 -84
  25. package/dist/db.cjs +2128 -3014
  26. package/dist/db.d.cts +1 -1
  27. package/dist/db.d.ts +1 -1
  28. package/dist/db.mjs +2141 -3027
  29. package/dist/entitlements.cjs +19 -20
  30. package/dist/entitlements.d.cts +1 -1
  31. package/dist/entitlements.d.ts +1 -1
  32. package/dist/entitlements.mjs +19 -20
  33. package/dist/errors.cjs +16 -12
  34. package/dist/errors.d.cts +59 -3
  35. package/dist/errors.d.ts +59 -3
  36. package/dist/errors.mjs +15 -12
  37. package/dist/firestore-compat.cjs +241 -297
  38. package/dist/firestore-compat.d.cts +1 -1
  39. package/dist/firestore-compat.d.ts +1 -1
  40. package/dist/firestore-compat.mjs +215 -271
  41. package/dist/index.cjs +3942 -5134
  42. package/dist/index.d.cts +181 -5
  43. package/dist/index.d.ts +181 -5
  44. package/dist/index.mjs +4040 -5239
  45. package/dist/mobile.cjs +459 -344
  46. package/dist/mobile.d.cts +59 -4
  47. package/dist/mobile.d.ts +59 -4
  48. package/dist/mobile.mjs +459 -344
  49. package/dist/mocks.cjs +319 -447
  50. package/dist/mocks.d.cts +1 -1
  51. package/dist/mocks.d.ts +1 -1
  52. package/dist/mocks.mjs +313 -441
  53. package/dist/notifications.cjs +296 -317
  54. package/dist/notifications.d.cts +1 -1
  55. package/dist/notifications.d.ts +1 -1
  56. package/dist/notifications.mjs +295 -316
  57. package/dist/react.cjs +557 -707
  58. package/dist/react.d.cts +1 -1
  59. package/dist/react.d.ts +1 -1
  60. package/dist/react.mjs +547 -697
  61. package/dist/support.cjs +402 -328
  62. package/dist/support.d.cts +29 -3
  63. package/dist/support.d.ts +29 -3
  64. package/dist/support.mjs +401 -328
  65. package/dist/telemetry.cjs +267 -304
  66. package/dist/telemetry.d.cts +1 -1
  67. package/dist/telemetry.d.ts +1 -1
  68. package/dist/telemetry.mjs +267 -304
  69. package/dist/{types-Du_iioJ7.d.cts → types-D-9bjlM0.d.cts} +74 -1
  70. package/dist/{types-BPATkXYu.d.ts → types-bVztFQTI.d.ts} +74 -1
  71. package/dist/usage.cjs +233 -230
  72. package/dist/usage.d.cts +1 -1
  73. package/dist/usage.d.ts +1 -1
  74. package/dist/usage.mjs +233 -230
  75. package/dist/webhooks.cjs +328 -362
  76. package/dist/webhooks.d.cts +1 -1
  77. package/dist/webhooks.d.ts +1 -1
  78. package/dist/webhooks.mjs +325 -359
  79. package/package.json +5 -3
  80. package/dist/ai.cjs.map +0 -1
  81. package/dist/ai.mjs.map +0 -1
  82. package/dist/auth.cjs.map +0 -1
  83. package/dist/auth.mjs.map +0 -1
  84. package/dist/build-guard.cjs.map +0 -1
  85. package/dist/build-guard.mjs.map +0 -1
  86. package/dist/catalog.cjs.map +0 -1
  87. package/dist/catalog.mjs.map +0 -1
  88. package/dist/checkout.cjs.map +0 -1
  89. package/dist/checkout.mjs.map +0 -1
  90. package/dist/db-react.cjs.map +0 -1
  91. package/dist/db-react.mjs.map +0 -1
  92. package/dist/db.cjs.map +0 -1
  93. package/dist/db.mjs.map +0 -1
  94. package/dist/entitlements.cjs.map +0 -1
  95. package/dist/entitlements.mjs.map +0 -1
  96. package/dist/errors.cjs.map +0 -1
  97. package/dist/errors.mjs.map +0 -1
  98. package/dist/firestore-compat.cjs.map +0 -1
  99. package/dist/firestore-compat.mjs.map +0 -1
  100. package/dist/index.cjs.map +0 -1
  101. package/dist/index.mjs.map +0 -1
  102. package/dist/mobile.cjs.map +0 -1
  103. package/dist/mobile.mjs.map +0 -1
  104. package/dist/mocks.cjs.map +0 -1
  105. package/dist/mocks.mjs.map +0 -1
  106. package/dist/notifications.cjs.map +0 -1
  107. package/dist/notifications.mjs.map +0 -1
  108. package/dist/react.cjs.map +0 -1
  109. package/dist/react.mjs.map +0 -1
  110. package/dist/support.cjs.map +0 -1
  111. package/dist/support.mjs.map +0 -1
  112. package/dist/telemetry.cjs.map +0 -1
  113. package/dist/telemetry.mjs.map +0 -1
  114. package/dist/usage.cjs.map +0 -1
  115. package/dist/usage.mjs.map +0 -1
  116. package/dist/webhooks.cjs.map +0 -1
  117. package/dist/webhooks.mjs.map +0 -1
package/dist/support.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/errors.ts
2
- var NeetruError = class _NeetruError extends Error {
2
+ var i = class e extends Error {
3
3
  code;
4
4
  status;
5
5
  requestId;
@@ -12,293 +12,391 @@ 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(code, message, status, requestId, reason) {
16
- super(message);
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
+ /**
16
+ * 3.8.0: `x-correlation-id` da requisição que falhou. O SDK gera um UUID por
17
+ * chamada (ou usa o que o chamador passou) e manda no header; o Core grava o
18
+ * mesmo id nos logs/auditoria — cite-o ao abrir um ticket de suporte.
19
+ * `undefined` em erros que acontecem antes de qualquer requisição.
20
+ */
21
+ correlationId;
22
+ constructor(t, r, o, s, u, c) {
23
+ super(r), this.name = "NeetruError", this.code = t, this.status = o, this.requestId = s, this.reason = u, this.correlationId = c, Object.setPrototypeOf(this, e.prototype);
24
+ }
25
+ }, _ = class e extends i {
26
+ constructor(t, r, o, s, u) {
27
+ super("auth_required", t, o, s, r, u), this.name = "NeetruAuthRequiredError", Object.setPrototypeOf(this, e.prototype);
23
28
  }
24
29
  };
25
30
 
26
31
  // src/idempotency.ts
27
- function generateIdempotencyKey() {
28
- const cryptoObj = typeof globalThis !== "undefined" && "crypto" in globalThis ? globalThis.crypto : void 0;
29
- if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
30
- return cryptoObj.randomUUID();
31
- }
32
- throw new NeetruError(
32
+ function C() {
33
+ let e = typeof globalThis < "u" && "crypto" in globalThis ? globalThis.crypto : void 0;
34
+ if (e && typeof e.randomUUID == "function")
35
+ return e.randomUUID();
36
+ throw new i(
33
37
  "runtime_unsupported",
34
38
  "crypto.randomUUID not available in this runtime. SDK 3.0 requires Node \u226520 or modern browser/Edge."
35
39
  );
36
40
  }
37
41
 
42
+ // src/correlation.ts
43
+ var D = "x-correlation-id";
44
+ var Y = /^[A-Za-z0-9._:\-]+$/;
45
+ function U(e) {
46
+ return typeof e == "string" && e.length > 0 && e.length <= 128 && Y.test(e);
47
+ }
48
+ function J() {
49
+ let e = globalThis.crypto;
50
+ try {
51
+ if (e && typeof e.randomUUID == "function") return e.randomUUID();
52
+ } catch {
53
+ }
54
+ let t = new Uint8Array(16), r = false;
55
+ try {
56
+ e && typeof e.getRandomValues == "function" && (e.getRandomValues(t), r = !0);
57
+ } catch {
58
+ r = false;
59
+ }
60
+ if (!r)
61
+ for (let s = 0; s < t.length; s++) t[s] = Math.floor(Math.random() * 256);
62
+ t[6] = t[6] & 15 | 64, t[8] = t[8] & 63 | 128;
63
+ let o = Array.from(t, (s) => s.toString(16).padStart(2, "0")).join("");
64
+ return `${o.slice(0, 8)}-${o.slice(8, 12)}-${o.slice(12, 16)}-${o.slice(16, 20)}-${o.slice(20)}`;
65
+ }
66
+ function x(e, t) {
67
+ let r, o = {};
68
+ for (let [u, c] of Object.entries(e)) {
69
+ if (u.toLowerCase() === D) {
70
+ U(c) && (r = c);
71
+ continue;
72
+ }
73
+ o[u] = c;
74
+ }
75
+ let s = r ?? (U(t) ? t : void 0) ?? J();
76
+ return o[D] = s, { headers: o, correlationId: s };
77
+ }
78
+
79
+ // src/server-only-key.ts
80
+ function O() {
81
+ try {
82
+ let e = globalThis.navigator;
83
+ if (e && e.product === "ReactNative") return "react-native";
84
+ } catch {
85
+ }
86
+ try {
87
+ let e = globalThis;
88
+ if (typeof e.window < "u" && typeof e.document < "u") return "browser";
89
+ } catch {
90
+ }
91
+ return null;
92
+ }
93
+
38
94
  // src/http.ts
39
- var COMPAT_MATRIX = {
95
+ var W = {
40
96
  // SDK major 3.x requer Core ≥ 2026.05.1 (suporte a X-Neetru-Version header,
41
97
  // runTransaction write-after-read, verifyWebhookRequest, webhooks 3.0+)
42
98
  3: "2026.05.1"
43
99
  };
44
- function stripRevision(v) {
45
- return v.split("+")[0] ?? v;
100
+ function A(e) {
101
+ return e.split("+")[0] ?? e;
46
102
  }
47
- function compareCalVer(a, b) {
48
- const partsA = stripRevision(a).split(".").map(Number);
49
- const partsB = stripRevision(b).split(".").map(Number);
50
- const len = Math.max(partsA.length, partsB.length);
51
- for (let i = 0; i < len; i++) {
52
- const pa = partsA[i] ?? 0;
53
- const pb = partsB[i] ?? 0;
54
- if (pa !== pb) return pa - pb;
103
+ function Q(e, t) {
104
+ let r = A(e).split(".").map(Number), o = A(t).split(".").map(Number), s = Math.max(r.length, o.length);
105
+ for (let u = 0; u < s; u++) {
106
+ let c = r[u] ?? 0, n = o[u] ?? 0;
107
+ if (c !== n) return c - n;
55
108
  }
56
109
  return 0;
57
110
  }
58
- function readInjectedSdkVersion() {
111
+ function $() {
59
112
  try {
60
- return "3.6.0";
113
+ return "3.8.0";
61
114
  } catch {
62
- return void 0;
115
+ return;
63
116
  }
64
117
  }
65
- function getSdkMajor() {
66
- const ver = readInjectedSdkVersion();
67
- if (ver) return parseInt(ver.split(".")[0] ?? "3", 10);
68
- return 3;
118
+ function Z() {
119
+ let e = $();
120
+ return e ? parseInt(e.split(".")[0] ?? "3", 10) : 3;
69
121
  }
70
- var _warnedCoreTooOld = /* @__PURE__ */ new Set();
71
- function checkCoreVersionCompat(coreVersion) {
72
- if (!coreVersion) return;
73
- const sdkMajor = getSdkMajor();
74
- const minCore = COMPAT_MATRIX[sdkMajor];
75
- if (!minCore) return;
76
- const stripped = stripRevision(coreVersion);
77
- if (compareCalVer(stripped, minCore) < 0) {
78
- const key = `${sdkMajor}:${stripped}`;
79
- if (!_warnedCoreTooOld.has(key)) {
80
- _warnedCoreTooOld.add(key);
81
- console.warn(
82
- `[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.`
83
- );
84
- }
122
+ var M = /* @__PURE__ */ new Set();
123
+ function ee(e) {
124
+ if (!e) return;
125
+ let t = Z(), r = W[t];
126
+ if (!r) return;
127
+ let o = A(e);
128
+ if (Q(o, r) < 0) {
129
+ let s = `${t}:${o}`;
130
+ M.has(s) || (M.add(s), console.warn(
131
+ `[Neetru SDK] Aten\xE7\xE3o: Core vers\xE3o "${e}" \xE9 anterior ao m\xEDnimo recomendado "${r}" para SDK major ${t}. Alguns recursos podem n\xE3o funcionar corretamente. Atualize o Core para a vers\xE3o mais recente.`
132
+ ));
85
133
  }
86
134
  }
87
- var DEFAULT_RETRIES_READ = 2;
88
- var DEFAULT_RETRIES_WRITE = 0;
89
- var READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
90
- var RETRYABLE_CODES = /* @__PURE__ */ new Set([
135
+ function te() {
136
+ let e = "This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.";
137
+ return O() ? "Esta opera\xE7\xE3o exige a credencial nrt_ do produto, que \xE9 S\xD3 DE SERVIDOR. No navegador/app, chame a API do seu produto (ex.: https://<produto>.neetru.com/api/v1) com o token do usu\xE1rio \u2014 o backend do produto faz esta chamada com o SDK e a chave. (" + e + ")" : e;
138
+ }
139
+ var ne = 2, re = 0, oe = /* @__PURE__ */ new Set(["GET", "HEAD"]), ie = /* @__PURE__ */ new Set([
91
140
  "rate_limited",
92
141
  "server_error",
93
142
  "network_error"
94
143
  ]);
95
- function backoffMs(attempt) {
96
- const base = 200 * Math.pow(4, attempt);
97
- const jitter = base * 0.2 * (Math.random() * 2 - 1);
98
- return Math.max(50, Math.round(base + jitter));
144
+ function P(e) {
145
+ let t = 200 * Math.pow(4, e), r = t * 0.2 * (Math.random() * 2 - 1);
146
+ return Math.max(50, Math.round(t + r));
99
147
  }
100
- var MAX_RETRY_AFTER_MS = 6e4;
101
- function parseRetryAfter(value) {
102
- if (!value) return null;
103
- const secs = Number(value);
104
- if (Number.isFinite(secs) && secs >= 0) return Math.min(Math.round(secs * 1e3), MAX_RETRY_AFTER_MS);
105
- const dateMs = Date.parse(value);
106
- if (Number.isFinite(dateMs)) {
107
- const delta = dateMs - Date.now();
108
- if (delta > 0) return Math.min(delta, MAX_RETRY_AFTER_MS);
148
+ var q = 6e4;
149
+ function se(e) {
150
+ if (!e) return null;
151
+ let t = Number(e);
152
+ if (Number.isFinite(t) && t >= 0) return Math.min(Math.round(t * 1e3), q);
153
+ let r = Date.parse(e);
154
+ if (Number.isFinite(r)) {
155
+ let o = r - Date.now();
156
+ if (o > 0) return Math.min(o, q);
109
157
  }
110
158
  return null;
111
159
  }
112
- function sleep(ms) {
113
- return new Promise((resolve) => setTimeout(resolve, ms));
160
+ function K(e) {
161
+ return new Promise((t) => setTimeout(t, e));
114
162
  }
115
- function statusToCode(status) {
116
- if (status === 401) return "unauthorized";
117
- if (status === 403) return "forbidden";
118
- if (status === 404) return "not_found";
119
- if (status === 409) return "conflict";
120
- if (status === 422 || status === 400) return "validation_failed";
121
- if (status === 429) return "rate_limited";
122
- if (status >= 500) return "server_error";
123
- return "unknown";
163
+ function ae(e) {
164
+ return e === 401 ? "unauthorized" : e === 403 ? "forbidden" : e === 404 ? "not_found" : e === 409 ? "conflict" : e === 410 ? "gone" : e === 422 || e === 400 ? "validation_failed" : e === 429 ? "rate_limited" : e >= 500 ? "server_error" : "unknown";
124
165
  }
125
- function buildUrl(baseUrl, path, query) {
126
- const base = baseUrl.replace(/\/+$/, "");
127
- const p = path.startsWith("/") ? path : `/${path}`;
128
- const url = new URL(`${base}${p}`);
129
- if (query) {
130
- for (const [k, v] of Object.entries(query)) {
131
- if (v === void 0) continue;
132
- url.searchParams.set(k, String(v));
166
+ function de(e, t, r) {
167
+ let o = e.replace(/\/+$/, ""), s = t.startsWith("/") ? t : `/${t}`, u = new URL(`${o}${s}`);
168
+ if (r)
169
+ for (let [c, n] of Object.entries(r))
170
+ n !== void 0 && u.searchParams.set(c, String(n));
171
+ return u.toString();
172
+ }
173
+ async function j(e) {
174
+ let t = await e.text();
175
+ if (t)
176
+ try {
177
+ return JSON.parse(t);
178
+ } catch {
179
+ return;
133
180
  }
134
- }
135
- return url.toString();
136
181
  }
137
- async function safeJson(res) {
138
- const text = await res.text();
139
- if (!text) return void 0;
140
- try {
141
- return JSON.parse(text);
142
- } catch {
143
- return void 0;
182
+ async function v(e, t) {
183
+ let r = t.method ?? "GET", o = de(e.baseUrl, t.path, t.query), s = oe.has(r) ? ne : re, u = t.retries ?? s, { headers: c, correlationId: n } = x(
184
+ { accept: "application/json", ...t.headers },
185
+ t.correlationId
186
+ ), g = $();
187
+ if (g && (c["x-neetru-sdk-version"] = g), t.requireAuth) {
188
+ if (!e.apiKey)
189
+ throw new i("missing_api_key", te());
190
+ c.authorization = `Bearer ${e.apiKey}`;
144
191
  }
145
- }
146
- async function httpRequest(config, opts) {
147
- const method = opts.method ?? "GET";
148
- const url = buildUrl(config.baseUrl, opts.path, opts.query);
149
- const defaultRetries = READ_METHODS.has(method) ? DEFAULT_RETRIES_READ : DEFAULT_RETRIES_WRITE;
150
- const maxRetries = opts.retries ?? defaultRetries;
151
- const headers = {
152
- accept: "application/json",
153
- ...opts.headers
154
- };
155
- const sdkVersion = readInjectedSdkVersion();
156
- if (sdkVersion) {
157
- headers["x-neetru-sdk-version"] = sdkVersion;
192
+ if (t.idempotencyKey) {
193
+ let p = typeof t.idempotencyKey == "string" ? t.idempotencyKey : C();
194
+ c["idempotency-key"] = p;
158
195
  }
159
- if (opts.requireAuth) {
160
- if (!config.apiKey) {
161
- throw new NeetruError(
162
- "missing_api_key",
163
- "This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var."
196
+ let a = t.body !== void 0 && r !== "GET" && r !== "DELETE" ? JSON.stringify(t.body) : void 0;
197
+ a !== void 0 && (c["content-type"] = "application/json");
198
+ let l = null, f = t.deadlineMs != null ? Date.now() + t.deadlineMs : null;
199
+ for (let p = 0; p <= u; p++) {
200
+ if (f != null && Date.now() >= f)
201
+ throw l ?? new i(
202
+ "network_error",
203
+ "Deadline excedido antes de completar a request",
204
+ void 0,
205
+ void 0,
206
+ void 0,
207
+ n
164
208
  );
165
- }
166
- headers.authorization = `Bearer ${config.apiKey}`;
167
- }
168
- if (opts.idempotencyKey) {
169
- const key = typeof opts.idempotencyKey === "string" ? opts.idempotencyKey : generateIdempotencyKey();
170
- headers["idempotency-key"] = key;
171
- }
172
- const bodyString = opts.body !== void 0 && method !== "GET" && method !== "DELETE" ? JSON.stringify(opts.body) : void 0;
173
- if (bodyString !== void 0) {
174
- headers["content-type"] = "application/json";
175
- }
176
- let lastError = null;
177
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
178
- const init = { method, headers };
179
- if (bodyString !== void 0) init.body = bodyString;
180
- init.signal = AbortSignal.timeout(3e4);
181
- let res;
209
+ let E = { method: r, headers: c };
210
+ a !== void 0 && (E.body = a);
211
+ let z = f != null ? Math.max(1, Math.min(3e4, f - Date.now())) : 3e4;
212
+ E.signal = AbortSignal.timeout(z);
213
+ let m;
182
214
  try {
183
- res = await config.fetch(url, init);
184
- } catch (err2) {
185
- const message2 = err2 instanceof DOMException && err2.name === "TimeoutError" ? "Network error: timeout after 30s" : `Network error: ${err2 instanceof Error ? err2.message : "fetch failed"}`;
186
- lastError = new NeetruError("network_error", message2);
187
- if (attempt < maxRetries) {
188
- await sleep(backoffMs(attempt));
189
- continue;
215
+ m = await e.fetch(o, E);
216
+ } catch (d) {
217
+ let w = d instanceof DOMException && d.name === "TimeoutError" ? "Network error: timeout after 30s" : `Network error: ${d instanceof Error ? d.message : "fetch failed"}`;
218
+ if (l = new i("network_error", w, void 0, void 0, void 0, n), p < u) {
219
+ let N = P(p);
220
+ if (f == null || Date.now() + N < f) {
221
+ await K(N);
222
+ continue;
223
+ }
190
224
  }
191
- throw lastError;
225
+ throw l;
192
226
  }
193
- const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
194
- if (res.ok) {
195
- const coreVersion = res.headers.get("x-neetru-version");
196
- if (coreVersion) checkCoreVersionCompat(coreVersion);
197
- const parsed = await safeJson(res);
198
- return parsed;
227
+ let X = m.headers.get("x-request-id") ?? m.headers.get("x-correlation-id") ?? void 0;
228
+ if (m.ok) {
229
+ let d = m.headers.get("x-neetru-version");
230
+ return d && ee(d), await j(m);
199
231
  }
200
- const body = await safeJson(res);
201
- let code = statusToCode(res.status);
202
- let message = `HTTP ${res.status}`;
203
- let reason;
204
- if (body && typeof body === "object") {
205
- const errField = body.error;
206
- if (typeof errField === "string") {
207
- message = errField;
208
- } else if (errField && typeof errField === "object") {
209
- if (typeof errField.code === "string") code = errField.code;
210
- if (typeof errField.message === "string") message = errField.message;
211
- if (typeof errField.reason === "string") reason = errField.reason;
212
- } else {
213
- if (typeof body.code === "string") code = body.code;
214
- if (typeof body.message === "string") message = body.message;
215
- }
216
- if (typeof body.reason === "string") reason = body.reason;
232
+ let y = await j(m), k = ae(m.status), h = `HTTP ${m.status}`, S;
233
+ if (y && typeof y == "object") {
234
+ let d = y.error;
235
+ typeof d == "string" ? h = d : d && typeof d == "object" ? (typeof d.code == "string" && (k = d.code), typeof d.message == "string" && (h = d.message), typeof d.reason == "string" && (S = d.reason)) : (typeof y.code == "string" && (k = y.code), typeof y.message == "string" && (h = y.message)), typeof y.reason == "string" && (S = y.reason);
217
236
  }
218
- const err = new NeetruError(code, message, res.status, requestId, reason);
219
- lastError = err;
220
- const isRetryable = RETRYABLE_CODES.has(code);
221
- if (isRetryable && attempt < maxRetries) {
222
- const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
223
- const delay = retryAfter ?? backoffMs(attempt);
224
- await sleep(delay);
225
- continue;
237
+ if (m.status === 410) {
238
+ let d = m.headers.get("x-neetru-replacement");
239
+ h === `HTTP ${m.status}` && (h = `Endpoint ${t.path} foi removido do Core (HTTP 410 Gone) \u2014 atualize o @neetru/sdk e migre para a API substituta.`), d && !h.includes(d) && (h += ` Substituto: ${d}.`);
226
240
  }
227
- throw err;
241
+ let T = new i(k, h, m.status, X, S, n);
242
+ if (l = T, ie.has(k) && p < u) {
243
+ let w = se(m.headers.get("retry-after")) ?? P(p);
244
+ if (f == null || Date.now() + w < f) {
245
+ await K(w);
246
+ continue;
247
+ }
248
+ }
249
+ throw T;
228
250
  }
229
- throw lastError ?? new NeetruError("unknown", "unexpected httpRequest exit");
251
+ throw l ?? new i("unknown", "unexpected httpRequest exit", void 0, void 0, void 0, n);
230
252
  }
231
253
 
232
254
  // src/validators.ts
233
- var SDK_ID_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/i;
234
- function assertValidSdkId(field, value) {
235
- if (typeof value !== "string" || !SDK_ID_RE.test(value)) {
236
- throw new NeetruError(
255
+ var L = /^[a-z0-9][a-z0-9_-]{0,62}$/i;
256
+ function I(e, t) {
257
+ if (typeof t != "string" || !L.test(t))
258
+ throw new i(
237
259
  "validation_failed",
238
- `${field} must match ${SDK_ID_RE.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`
260
+ `${e} must match ${L.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`
239
261
  );
240
- }
241
262
  }
242
263
 
243
264
  // src/support.ts
244
- var VALID_SEVERITIES = ["low", "normal", "high", "urgent"];
245
- var VALID_STATUSES = ["open", "pending", "resolved", "closed"];
246
- function toTicket(raw) {
247
- if (!raw || typeof raw !== "object") {
248
- throw new NeetruError("invalid_response", "Ticket response is not an object");
249
- }
250
- const r = raw;
251
- if (typeof r.id !== "string") {
252
- throw new NeetruError("invalid_response", "Ticket missing id");
253
- }
254
- const firstAttachment = Array.isArray(r.attachments) && typeof r.attachments[0] === "string" ? r.attachments[0] : void 0;
265
+ var R = ["low", "normal", "high", "urgent"], ue = ["open", "pending", "resolved", "closed"], V = 50;
266
+ function F(e) {
267
+ if (!e || typeof e != "object")
268
+ throw new i("invalid_response", "Ticket response is not an object");
269
+ let t = e;
270
+ if (typeof t.id != "string")
271
+ throw new i("invalid_response", "Ticket missing id");
272
+ let r = Array.isArray(t.attachments) && typeof t.attachments[0] == "string" ? t.attachments[0] : void 0, o = typeof t.screenshotUrl == "string" ? t.screenshotUrl : r ?? null;
255
273
  return {
256
- id: r.id,
257
- subject: typeof r.subject === "string" ? r.subject : "",
258
- message: typeof r.message === "string" ? r.message : "",
259
- severity: VALID_SEVERITIES.includes(r.severity) ? r.severity : "normal",
260
- status: VALID_STATUSES.includes(r.status) ? r.status : "open",
261
- createdAt: typeof r.createdAt === "string" ? r.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
262
- updatedAt: typeof r.updatedAt === "string" ? r.updatedAt : void 0,
263
- productSlug: typeof r.productId === "string" ? r.productId : typeof r.productSlug === "string" ? r.productSlug : void 0,
264
- pageUrl: typeof r.pageUrl === "string" ? r.pageUrl : null,
265
- screenshotUrl: typeof r.screenshotUrl === "string" ? r.screenshotUrl : firstAttachment ?? null,
266
- resolvedAt: typeof r.resolvedAt === "string" ? r.resolvedAt : null,
267
- resolvedNotifiedAt: typeof r.resolvedNotifiedAt === "string" ? r.resolvedNotifiedAt : null,
268
- satisfactionAttempts: typeof r.satisfactionAttempts === "number" && Number.isFinite(r.satisfactionAttempts) ? r.satisfactionAttempts : 0,
269
- lastSatisfactionAttemptAt: typeof r.lastSatisfactionAttemptAt === "string" ? r.lastSatisfactionAttemptAt : null,
270
- satisfiedAt: typeof r.satisfiedAt === "string" ? r.satisfiedAt : null,
271
- rating: typeof r.rating === "number" && Number.isFinite(r.rating) ? r.rating : null,
272
- satisfactionComment: typeof r.satisfactionComment === "string" ? r.satisfactionComment : null
274
+ id: t.id,
275
+ subject: typeof t.subject == "string" ? t.subject : "",
276
+ message: typeof t.message == "string" ? t.message : "",
277
+ severity: R.includes(t.severity) ? t.severity : "normal",
278
+ status: ue.includes(t.status) ? t.status : "open",
279
+ createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
280
+ updatedAt: typeof t.updatedAt == "string" ? t.updatedAt : void 0,
281
+ productSlug: typeof t.productId == "string" ? t.productId : typeof t.productSlug == "string" ? t.productSlug : void 0,
282
+ pageUrl: typeof t.pageUrl == "string" ? t.pageUrl : null,
283
+ screenshotUrl: o,
284
+ // 3.7.0: a listagem do Core não traz mais `attachments` (screenshotUrl vem
285
+ // null) — `screenshotAttached` diz se o ticket tem print. Fallback: há URL.
286
+ screenshotAttached: typeof t.screenshotAttached == "boolean" ? t.screenshotAttached : o !== null,
287
+ resolvedAt: typeof t.resolvedAt == "string" ? t.resolvedAt : null,
288
+ resolvedNotifiedAt: typeof t.resolvedNotifiedAt == "string" ? t.resolvedNotifiedAt : null,
289
+ satisfactionAttempts: typeof t.satisfactionAttempts == "number" && Number.isFinite(t.satisfactionAttempts) ? t.satisfactionAttempts : 0,
290
+ lastSatisfactionAttemptAt: typeof t.lastSatisfactionAttemptAt == "string" ? t.lastSatisfactionAttemptAt : null,
291
+ satisfiedAt: typeof t.satisfiedAt == "string" ? t.satisfiedAt : null,
292
+ rating: typeof t.rating == "number" && Number.isFinite(t.rating) ? t.rating : null,
293
+ satisfactionComment: typeof t.satisfactionComment == "string" ? t.satisfactionComment : null
273
294
  };
274
295
  }
275
- function assertTicketId(ticketId) {
276
- if (!ticketId || typeof ticketId !== "string") {
277
- throw new NeetruError("validation_failed", "ticketId is required");
278
- }
296
+ function b(e) {
297
+ if (!e || typeof e != "string")
298
+ throw new i("validation_failed", "ticketId is required");
279
299
  }
280
- function assertValidComment(comment) {
281
- if (typeof comment === "string" && comment.length > 2e3) {
282
- throw new NeetruError("validation_failed", "comment max 2000 chars");
283
- }
300
+ function H(e) {
301
+ if (typeof e == "string" && e.length > 2e3)
302
+ throw new i("validation_failed", "comment max 2000 chars");
284
303
  }
285
- function resolveProductId(config, ...candidates) {
286
- for (const c of candidates) {
287
- if (typeof c === "string" && c.length > 0) {
288
- assertValidSdkId("productSlug", c);
289
- return c;
290
- }
291
- }
292
- if (config.productId) {
293
- assertValidSdkId("productId", config.productId);
294
- return config.productId;
295
- }
296
- throw new NeetruError(
304
+ function B(e, ...t) {
305
+ for (let r of t)
306
+ if (typeof r == "string" && r.length > 0)
307
+ return I("productSlug", r), r;
308
+ if (e.productId)
309
+ return I("productId", e.productId), e.productId;
310
+ throw new i(
297
311
  "validation_failed",
298
312
  "productId required (pass to input.productSlug or set on createNeetruClient)"
299
313
  );
300
314
  }
301
- function createSupportNamespace(config) {
315
+ var ce = "X-Neetru-End-User-Token", le = "Esta opera\xE7\xE3o de suporte exige um usu\xE1rio final logado: o Core s\xF3 mostra/altera os tickets do pr\xF3prio usu\xE1rio (header X-Neetru-End-User-Token com o id_token OIDC). Fa\xE7a login com client.auth.signIn() e tente de novo.", fe = "O Core exige a identidade do usu\xE1rio final para esta opera\xE7\xE3o (403 end_user_token_required) e nenhum id_token foi aceito. Fa\xE7a login com client.auth.signIn() e tente de novo.", pe = "O Core recusou o token do usu\xE1rio final (401 invalid_end_user_token \u2014 sess\xE3o expirada, usu\xE1rio inativo ou token que n\xE3o \xE9 id_token) e a renova\xE7\xE3o autom\xE1tica n\xE3o resolveu. Fa\xE7a login novamente com client.auth.signIn() e tente de novo.", me = "O id_token do usu\xE1rio final foi emitido para o client OIDC de OUTRO produto (403 end_user_token_product_mismatch). Confira se o login (client.auth / clientId OIDC) e a apiKey/productId do createNeetruClient s\xE3o do MESMO produto.";
316
+ function G(e) {
317
+ if (e instanceof i && !(e instanceof _)) {
318
+ if (e.code === "end_user_token_required")
319
+ throw new _(
320
+ fe,
321
+ "end_user_token_required",
322
+ e.status,
323
+ e.requestId,
324
+ e.correlationId
325
+ );
326
+ if (e.code === "invalid_end_user_token")
327
+ throw new _(
328
+ pe,
329
+ "invalid_end_user_token",
330
+ e.status,
331
+ e.requestId,
332
+ e.correlationId
333
+ );
334
+ if (e.code === "end_user_token_product_mismatch")
335
+ throw new i(
336
+ "forbidden",
337
+ me,
338
+ e.status,
339
+ e.requestId,
340
+ "end_user_token_product_mismatch",
341
+ e.correlationId
342
+ );
343
+ }
344
+ throw e;
345
+ }
346
+ function ge(e) {
347
+ return e instanceof i && e.code === "invalid_end_user_token";
348
+ }
349
+ function Ue(e, t = {}) {
350
+ async function r() {
351
+ try {
352
+ let n = await t.getEndUserToken?.();
353
+ return typeof n == "string" && n.length > 0 ? n : null;
354
+ } catch {
355
+ return null;
356
+ }
357
+ }
358
+ async function o() {
359
+ if (!t.refreshEndUserToken) return false;
360
+ try {
361
+ return await t.refreshEndUserToken() === !0;
362
+ } catch {
363
+ return false;
364
+ }
365
+ }
366
+ function s(n) {
367
+ return n ? { [ce]: n } : {};
368
+ }
369
+ async function u(n, g) {
370
+ let a = await r();
371
+ if (!a && n && await o() && (a = await r()), !a && n)
372
+ throw new _(le, "no_signed_in_user");
373
+ try {
374
+ return await g(s(a));
375
+ } catch (l) {
376
+ if (a && ge(l) && await o()) {
377
+ let f = await r();
378
+ if (f)
379
+ try {
380
+ return await g(s(f));
381
+ } catch (p) {
382
+ G(p);
383
+ }
384
+ }
385
+ G(l);
386
+ }
387
+ }
388
+ async function c(n, g = {}) {
389
+ await u(
390
+ true,
391
+ (a) => v(e, {
392
+ method: "POST",
393
+ path: n,
394
+ requireAuth: !0,
395
+ headers: a,
396
+ ...g
397
+ })
398
+ );
399
+ }
302
400
  return {
303
401
  /**
304
402
  * Cria um ticket de suporte. Requer Bearer auth. `productSlug` no input
@@ -306,85 +404,75 @@ function createSupportNamespace(config) {
306
404
  *
307
405
  * Endpoint canonical: `POST /api/sdk/v1/support/tickets`.
308
406
  */
309
- async createTicket(input) {
310
- if (!input || typeof input !== "object") {
311
- throw new NeetruError("validation_failed", "input is required");
312
- }
313
- if (!input.subject || typeof input.subject !== "string") {
314
- throw new NeetruError("validation_failed", "subject is required");
315
- }
316
- if (input.subject.length > 200) {
317
- throw new NeetruError("validation_failed", "subject max 200 chars");
318
- }
319
- if (!input.message || typeof input.message !== "string") {
320
- throw new NeetruError("validation_failed", "message is required");
321
- }
322
- if (input.message.length > 1e4) {
323
- throw new NeetruError("validation_failed", "message max 10000 chars");
324
- }
325
- if (input.severity && !VALID_SEVERITIES.includes(input.severity)) {
326
- throw new NeetruError(
407
+ async createTicket(n) {
408
+ if (!n || typeof n != "object")
409
+ throw new i("validation_failed", "input is required");
410
+ if (!n.subject || typeof n.subject != "string")
411
+ throw new i("validation_failed", "subject is required");
412
+ if (n.subject.length > 200)
413
+ throw new i("validation_failed", "subject max 200 chars");
414
+ if (!n.message || typeof n.message != "string")
415
+ throw new i("validation_failed", "message is required");
416
+ if (n.message.length > 1e4)
417
+ throw new i("validation_failed", "message max 10000 chars");
418
+ if (n.severity && !R.includes(n.severity))
419
+ throw new i(
327
420
  "validation_failed",
328
- `severity must be one of ${VALID_SEVERITIES.join(", ")}`
421
+ `severity must be one of ${R.join(", ")}`
329
422
  );
330
- }
331
- const productId = resolveProductId(config, input.productSlug);
332
- const body = {
333
- productId,
334
- subject: input.subject,
335
- message: input.message,
336
- severity: input.severity ?? "normal"
423
+ let a = {
424
+ productId: B(e, n.productSlug),
425
+ subject: n.subject,
426
+ message: n.message,
427
+ severity: n.severity ?? "normal"
337
428
  };
338
- if (input.metadata && typeof input.metadata === "object") {
339
- body.metadata = input.metadata;
340
- }
341
- if (typeof input.pageUrl === "string") {
342
- body.pageUrl = input.pageUrl;
343
- }
344
- if (typeof input.screenshotBase64 === "string") {
345
- body.screenshotBase64 = input.screenshotBase64;
346
- }
347
- if (typeof input.consoleLogs === "string") {
348
- body.consoleLogs = input.consoleLogs;
349
- }
350
- const raw = await httpRequest(config, {
351
- method: "POST",
352
- path: "/api/sdk/v1/support/tickets",
353
- body,
354
- requireAuth: true,
355
- idempotencyKey: true
356
- });
357
- const candidate = raw && typeof raw === "object" && "ticket" in raw ? raw.ticket : raw;
358
- return toTicket(candidate);
429
+ n.metadata && typeof n.metadata == "object" && (a.metadata = n.metadata), typeof n.pageUrl == "string" && (a.pageUrl = n.pageUrl), typeof n.screenshotBase64 == "string" && (a.screenshotBase64 = n.screenshotBase64), typeof n.consoleLogs == "string" && (a.consoleLogs = n.consoleLogs);
430
+ let l = await u(
431
+ false,
432
+ (p) => v(e, {
433
+ method: "POST",
434
+ path: "/api/sdk/v1/support/tickets",
435
+ body: a,
436
+ requireAuth: !0,
437
+ idempotencyKey: !0,
438
+ headers: p
439
+ })
440
+ ), f = l && typeof l == "object" && "ticket" in l ? l.ticket : l;
441
+ return F(f);
359
442
  },
360
443
  /**
361
444
  * Lista tickets do customer no produto atual. `productSlug` no contexto.
362
445
  *
363
446
  * Endpoint canonical: `GET /api/sdk/v1/support/tickets?productId=...`.
364
447
  */
365
- async listMyTickets(options) {
366
- const productId = resolveProductId(config, options?.productSlug);
367
- const raw = await httpRequest(config, {
368
- method: "GET",
369
- path: "/api/sdk/v1/support/tickets",
370
- query: { productId },
371
- requireAuth: true
372
- });
373
- const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && "tickets" in raw ? raw.tickets ?? [] : [];
374
- return list.map(toTicket);
448
+ async listMyTickets(n) {
449
+ let g = B(e, n?.productSlug), a = n?.limit;
450
+ if (a !== void 0 && (!Number.isInteger(a) || a < 1 || a > V))
451
+ throw new i(
452
+ "validation_failed",
453
+ `limit must be an integer 1-${V} (Core default 20)`
454
+ );
455
+ let l = await u(
456
+ true,
457
+ (p) => v(e, {
458
+ method: "GET",
459
+ path: "/api/sdk/v1/support/tickets",
460
+ query: { productId: g, limit: a },
461
+ requireAuth: !0,
462
+ headers: p
463
+ })
464
+ );
465
+ return (Array.isArray(l) ? l : l && typeof l == "object" && "tickets" in l ? l.tickets ?? [] : []).map(F);
375
466
  },
376
467
  /**
377
468
  * 3.4: marca a notificação de resolução como vista (`resolvedNotifiedAt`,
378
469
  * idempotente no Core). Endpoint canonical:
379
470
  * `POST /api/sdk/v1/support/tickets/{id}/resolved-seen`.
380
471
  */
381
- async markResolvedSeen(ticketId) {
382
- assertTicketId(ticketId);
383
- await httpRequest(config, {
384
- method: "POST",
385
- path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/resolved-seen`,
386
- requireAuth: true
387
- });
472
+ async markResolvedSeen(n) {
473
+ b(n), await c(
474
+ `/api/sdk/v1/support/tickets/${encodeURIComponent(n)}/resolved-seen`
475
+ );
388
476
  },
389
477
  /**
390
478
  * 3.4: registra uma tentativa de exibição do modal de satisfação
@@ -392,61 +480,46 @@ function createSupportNamespace(config) {
392
480
  * resposta. Endpoint canonical:
393
481
  * `POST /api/sdk/v1/support/tickets/{id}/satisfaction-attempt`.
394
482
  */
395
- async recordSatisfactionAttempt(ticketId) {
396
- assertTicketId(ticketId);
397
- await httpRequest(config, {
398
- method: "POST",
399
- path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/satisfaction-attempt`,
400
- requireAuth: true,
483
+ async recordSatisfactionAttempt(n) {
484
+ b(n), await c(
485
+ `/api/sdk/v1/support/tickets/${encodeURIComponent(n)}/satisfaction-attempt`,
401
486
  // Incrementa satisfactionAttempts += 1 no Core — sem idempotencyKey,
402
487
  // um retry de rede infla o contador (mesmo padrão de createTicket acima).
403
- idempotencyKey: true
404
- });
488
+ { idempotencyKey: true }
489
+ );
405
490
  },
406
491
  /**
407
492
  * 3.4: envia (ou pula) a avaliação de satisfação (CSAT 1-5). Endpoint
408
493
  * canonical: `POST /api/sdk/v1/support/tickets/{id}/satisfaction`.
409
494
  */
410
- async submitSatisfaction(input) {
411
- if (!input || typeof input !== "object") {
412
- throw new NeetruError("validation_failed", "input is required");
413
- }
414
- assertTicketId(input.ticketId);
415
- if (input.rating !== null && input.rating !== void 0) {
416
- if (!Number.isInteger(input.rating) || input.rating < 1 || input.rating > 5) {
417
- throw new NeetruError("validation_failed", "rating must be an integer 1-5 or null");
495
+ async submitSatisfaction(n) {
496
+ if (!n || typeof n != "object")
497
+ throw new i("validation_failed", "input is required");
498
+ if (b(n.ticketId), n.rating !== null && n.rating !== void 0 && (!Number.isInteger(n.rating) || n.rating < 1 || n.rating > 5))
499
+ throw new i("validation_failed", "rating must be an integer 1-5 or null");
500
+ H(n.comment), await c(
501
+ `/api/sdk/v1/support/tickets/${encodeURIComponent(n.ticketId)}/satisfaction`,
502
+ {
503
+ body: {
504
+ rating: n.rating ?? null,
505
+ comment: n.comment ?? null,
506
+ skipped: n.skipped
507
+ }
418
508
  }
419
- }
420
- assertValidComment(input.comment);
421
- await httpRequest(config, {
422
- method: "POST",
423
- path: `/api/sdk/v1/support/tickets/${encodeURIComponent(input.ticketId)}/satisfaction`,
424
- body: {
425
- rating: input.rating ?? null,
426
- comment: input.comment ?? null,
427
- skipped: input.skipped
428
- },
429
- requireAuth: true
430
- });
509
+ );
431
510
  },
432
511
  /**
433
512
  * 3.4: contesta um ticket resolvido — reabre e zera o ciclo de
434
513
  * satisfação/notificação. Endpoint canonical:
435
514
  * `POST /api/sdk/v1/support/tickets/{id}/contest`.
436
515
  */
437
- async contestTicket(ticketId, opts) {
438
- assertTicketId(ticketId);
439
- assertValidComment(opts?.comment);
440
- await httpRequest(config, {
441
- method: "POST",
442
- path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/contest`,
443
- body: { comment: opts?.comment ?? void 0 },
444
- requireAuth: true
445
- });
516
+ async contestTicket(n, g) {
517
+ b(n), H(g?.comment), await c(
518
+ `/api/sdk/v1/support/tickets/${encodeURIComponent(n)}/contest`,
519
+ { body: { comment: g?.comment ?? void 0 } }
520
+ );
446
521
  }
447
522
  };
448
523
  }
449
524
 
450
- export { createSupportNamespace };
451
- //# sourceMappingURL=support.mjs.map
452
- //# sourceMappingURL=support.mjs.map
525
+ export { ce as END_USER_TOKEN_HEADER, Ue as createSupportNamespace };