@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/mocks.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // src/errors.ts
4
- var NeetruError = class _NeetruError extends Error {
4
+ var l = class m extends Error {
5
5
  code;
6
6
  status;
7
7
  requestId;
@@ -14,24 +14,24 @@ var NeetruError = class _NeetruError extends Error {
14
14
  * para um `NeetruDbErrorCode` mais específico (recuperável vs não).
15
15
  */
16
16
  reason;
17
- constructor(code, message, status, requestId, reason) {
18
- super(message);
19
- this.name = "NeetruError";
20
- this.code = code;
21
- this.status = status;
22
- this.requestId = requestId;
23
- this.reason = reason;
24
- Object.setPrototypeOf(this, _NeetruError.prototype);
17
+ /**
18
+ * 3.8.0: `x-correlation-id` da requisição que falhou. O SDK gera um UUID por
19
+ * chamada (ou usa o que o chamador passou) e manda no header; o Core grava o
20
+ * mesmo id nos logs/auditoria — cite-o ao abrir um ticket de suporte.
21
+ * `undefined` em erros que acontecem antes de qualquer requisição.
22
+ */
23
+ correlationId;
24
+ constructor(e, r, i, o, a, c) {
25
+ super(r), this.name = "NeetruError", this.code = e, this.status = i, this.requestId = o, this.reason = a, this.correlationId = c, Object.setPrototypeOf(this, m.prototype);
25
26
  }
26
27
  };
27
28
 
28
29
  // src/db-errors.ts
29
- var RETRYABLE_CODES = /* @__PURE__ */ new Set([
30
+ var U = /* @__PURE__ */ new Set([
30
31
  "db_unavailable",
31
32
  "db_conflict",
32
33
  "db_timeout"
33
- ]);
34
- var NeetruDbError = class _NeetruDbError extends NeetruError {
34
+ ]), _ = class m extends l {
35
35
  /** Código de erro fechado — específico de DB. */
36
36
  code;
37
37
  /**
@@ -44,79 +44,60 @@ var NeetruDbError = class _NeetruDbError extends NeetruError {
44
44
  * Nunca deve ser exibido ao usuário final.
45
45
  */
46
46
  dbId;
47
- constructor(code, message, dbId) {
48
- super(code, message);
49
- this.name = "NeetruDbError";
50
- this.code = code;
51
- this.retryable = RETRYABLE_CODES.has(code);
52
- this.dbId = dbId;
53
- Object.setPrototypeOf(this, _NeetruDbError.prototype);
47
+ constructor(e, r, i) {
48
+ super(e, r), this.name = "NeetruDbError", this.code = e, this.retryable = U.has(e), this.dbId = i, Object.setPrototypeOf(this, m.prototype);
54
49
  }
55
50
  };
56
51
 
57
52
  // src/runtime-env.ts
58
- function isProductionRuntime() {
53
+ function R() {
59
54
  try {
60
- if (typeof process !== "undefined" && process.env) {
55
+ if (typeof process < "u" && process.env)
61
56
  return process.env.NODE_ENV === "production";
62
- }
63
57
  } catch {
64
58
  }
65
59
  return false;
66
60
  }
67
61
 
68
62
  // src/mocks.ts
69
- var DEV_FIXTURE_USER = Object.freeze({
63
+ var x = Object.freeze({
70
64
  uid: "dev-fixture-uid-0001",
71
65
  email: "dev@neetru.local",
72
66
  emailVerified: true,
73
67
  displayName: "Dev Fixture",
74
68
  isCustomer: true,
75
69
  isStaff: false
76
- });
77
- var MockAuth = class {
70
+ }), A = class {
78
71
  _user;
79
72
  _listeners;
80
73
  _allowUnsignedDecode;
81
- constructor(initialUser = null, options) {
82
- this._user = initialUser;
83
- this._listeners = /* @__PURE__ */ new Set();
84
- this._allowUnsignedDecode = options?.allowUnsignedDecode ?? false;
85
- if (this._allowUnsignedDecode && isProductionRuntime()) {
86
- throw new NeetruError(
74
+ constructor(e = null, r) {
75
+ if (this._user = e, this._listeners = /* @__PURE__ */ new Set(), this._allowUnsignedDecode = r?.allowUnsignedDecode ?? false, this._allowUnsignedDecode && R())
76
+ throw new l(
87
77
  "invalid_config",
88
78
  "MockAuth com allowUnsignedDecode=true \xE9 PROIBIDO em produ\xE7\xE3o (NODE_ENV=production): decodificar JWT sem verificar assinatura \xE9 bypass de autentica\xE7\xE3o. Este modo existe exclusivamente para testes."
89
79
  );
90
- }
91
- if (this._allowUnsignedDecode) {
92
- const isTestEnv = typeof process !== "undefined" && (process.env?.NODE_ENV === "test" || process.env?.VITEST === "true" || process.env?.VITEST != null);
93
- if (!isTestEnv && typeof console !== "undefined") {
94
- console.warn(
95
- "[neetru-sdk] MockAuth.verifyToken est\xE1 em modo allowUnsignedDecode=true: tokens N\xC3O t\xEAm assinatura verificada. Este modo \xE9 exclusivo para testes \u2014 NUNCA use como security boundary em c\xF3digo deployado."
96
- );
97
- }
98
- }
80
+ this._allowUnsignedDecode && !(typeof process < "u" && (process.env?.NODE_ENV === "test" || process.env?.VITEST === "true" || process.env?.VITEST != null)) && typeof console < "u" && console.warn(
81
+ "[neetru-sdk] MockAuth.verifyToken est\xE1 em modo allowUnsignedDecode=true: tokens N\xC3O t\xEAm assinatura verificada. Este modo \xE9 exclusivo para testes \u2014 NUNCA use como security boundary em c\xF3digo deployado."
82
+ );
99
83
  }
100
- async signIn(_options) {
101
- if (!this._user) this._user = { ...DEV_FIXTURE_USER };
102
- this._notify();
103
- return this._user;
84
+ async signIn(e) {
85
+ return this._user || (this._user = { ...x }), this._notify(), this._user;
104
86
  }
105
87
  async signOut() {
106
- this._user = null;
107
- this._notify();
88
+ this._user = null, this._notify();
108
89
  }
109
90
  getUser() {
110
91
  return this._user;
111
92
  }
112
- onAuthStateChanged(listener) {
113
- this._listeners.add(listener);
93
+ onAuthStateChanged(e) {
94
+ this._listeners.add(e);
114
95
  try {
115
- listener(this._user);
96
+ e(this._user);
116
97
  } catch {
117
98
  }
118
99
  return () => {
119
- this._listeners.delete(listener);
100
+ this._listeners.delete(e);
120
101
  };
121
102
  }
122
103
  /**
@@ -129,52 +110,46 @@ var MockAuth = class {
129
110
  *
130
111
  * Para simular falhas ou resultados customizados, use `__mockVerifyToken(fn)`.
131
112
  */
132
- async verifyToken(token) {
133
- if (this._verifyTokenOverride) {
134
- return this._verifyTokenOverride(token);
135
- }
136
- if (!token) {
137
- throw new NeetruError("token_invalid_signature", "Token inv\xE1lido: string vazia");
138
- }
139
- if (!this._allowUnsignedDecode) {
140
- throw new NeetruError(
113
+ async verifyToken(e) {
114
+ if (this._verifyTokenOverride)
115
+ return this._verifyTokenOverride(e);
116
+ if (!e)
117
+ throw new l("token_invalid_signature", "Token inv\xE1lido: string vazia");
118
+ if (!this._allowUnsignedDecode)
119
+ throw new l(
141
120
  "unauthorized",
142
121
  "MockAuth.verifyToken n\xE3o verifica assinaturas JWT e N\xC3O deve ser usado como security boundary em c\xF3digo deployado. Em testes, use new MockAuth(user, { allowUnsignedDecode: true }) para habilitar decodifica\xE7\xE3o sem assinatura, ou __mockVerifyToken(fn) para injetar resultado customizado."
143
122
  );
144
- }
145
123
  try {
146
- const parts = token.split(".");
147
- if (parts.length === 3) {
148
- const b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
149
- const pad = "=".repeat((4 - b64.length % 4) % 4);
150
- const decoded = JSON.parse(
151
- typeof atob === "function" ? atob(b64 + pad) : Buffer.from(b64 + pad, "base64").toString("utf-8")
124
+ let r = e.split(".");
125
+ if (r.length === 3) {
126
+ let i = r[1].replace(/-/g, "+").replace(/_/g, "/"), o = "=".repeat((4 - i.length % 4) % 4), a = JSON.parse(
127
+ typeof atob == "function" ? atob(i + o) : Buffer.from(i + o, "base64").toString("utf-8")
152
128
  );
153
- if (typeof decoded.sub === "string") {
129
+ if (typeof a.sub == "string")
154
130
  return {
155
- uid: decoded.sub,
156
- email: typeof decoded.email === "string" ? decoded.email : "",
157
- emailVerified: typeof decoded.email_verified === "boolean" ? decoded.email_verified : void 0,
158
- displayName: typeof decoded.name === "string" ? decoded.name : void 0,
159
- photoURL: typeof decoded.picture === "string" ? decoded.picture : void 0,
160
- isStaff: decoded.is_staff === true,
161
- isCustomer: decoded.is_customer === true,
162
- tenantId: typeof decoded.tenant_id === "string" ? decoded.tenant_id : void 0,
163
- ...decoded
131
+ uid: a.sub,
132
+ email: typeof a.email == "string" ? a.email : "",
133
+ emailVerified: typeof a.email_verified == "boolean" ? a.email_verified : void 0,
134
+ displayName: typeof a.name == "string" ? a.name : void 0,
135
+ photoURL: typeof a.picture == "string" ? a.picture : void 0,
136
+ isStaff: a.is_staff === !0,
137
+ isCustomer: a.is_customer === !0,
138
+ tenantId: typeof a.tenant_id == "string" ? a.tenant_id : void 0,
139
+ ...a
164
140
  };
165
- }
166
141
  }
167
142
  } catch {
168
143
  }
169
144
  if (this._user) return this._user;
170
- throw new NeetruError("token_invalid_signature", "Nenhum user mock dispon\xEDvel e JWT sem sub v\xE1lido");
145
+ throw new l("token_invalid_signature", "Nenhum user mock dispon\xEDvel e JWT sem sub v\xE1lido");
171
146
  }
172
147
  /**
173
148
  * Mock de `handleRedirectCallback` (Bug 2 / 3.1.3) — não há redirect real no
174
149
  * mock, então retorna `null` por default. Use `__setPendingCallback(result)`
175
150
  * em testes pra simular um retorno do IdP.
176
151
  */
177
- async handleRedirectCallback(_currentUrl) {
152
+ async handleRedirectCallback(e) {
178
153
  return this._pendingCallback;
179
154
  }
180
155
  /**
@@ -183,7 +158,7 @@ var MockAuth = class {
183
158
  * contrato "no-op seguro em todo page load" da implementação real). O login
184
159
  * mock acontece direto via `signIn()`.
185
160
  */
186
- async completeSignIn(_currentUrl) {
161
+ async completeSignIn(e) {
187
162
  return null;
188
163
  }
189
164
  /**
@@ -196,12 +171,12 @@ var MockAuth = class {
196
171
  _pendingCallback = null;
197
172
  _idToken = null;
198
173
  /** Test helper — simula o material devolvido por um callback OIDC. */
199
- __setPendingCallback(result) {
200
- this._pendingCallback = result;
174
+ __setPendingCallback(e) {
175
+ this._pendingCallback = e;
201
176
  }
202
177
  /** Test helper — injeta o id_token cru retornado por `getIdToken`. */
203
- __setIdToken(token) {
204
- this._idToken = token;
178
+ __setIdToken(e) {
179
+ this._idToken = e;
205
180
  }
206
181
  _verifyTokenOverride = null;
207
182
  /**
@@ -214,75 +189,63 @@ var MockAuth = class {
214
189
  * mock.__mockVerifyToken(async () => { throw new NeetruError('token_expired', '...'); });
215
190
  * ```
216
191
  */
217
- __mockVerifyToken(fn) {
218
- this._verifyTokenOverride = fn;
192
+ __mockVerifyToken(e) {
193
+ this._verifyTokenOverride = e;
219
194
  }
220
195
  /** Helper de tests — força um user state arbitrário. */
221
- __setUser(user) {
222
- this._user = user;
223
- this._notify();
196
+ __setUser(e) {
197
+ this._user = e, this._notify();
224
198
  }
225
199
  _notify() {
226
- for (const l of this._listeners) {
200
+ for (let e of this._listeners)
227
201
  try {
228
- l(this._user);
202
+ e(this._user);
229
203
  } catch {
230
204
  }
231
- }
232
205
  }
233
- };
234
- var MockUsage = class {
206
+ }, T = class {
235
207
  _reports = [];
236
208
  _quotas;
237
209
  _counters = /* @__PURE__ */ new Map();
238
- constructor(initialQuotas = {}) {
239
- this._quotas = new Map(Object.entries(initialQuotas));
240
- }
241
- async report(resource, qty = 1, options) {
242
- if (!resource) throw new Error("resource required");
243
- const safeQty = Number.isFinite(qty) && qty > 0 ? Math.floor(qty) : 1;
244
- const existing = this._counters.get(resource) ?? 0;
245
- const next = existing + safeQty;
246
- this._counters.set(resource, next);
247
- this._reports.push({
248
- resource,
249
- qty: safeQty,
250
- productId: options?.productId,
251
- tenantId: options?.tenantId,
210
+ constructor(e = {}) {
211
+ this._quotas = new Map(Object.entries(e));
212
+ }
213
+ async report(e, r = 1, i) {
214
+ if (!e) throw new Error("resource required");
215
+ let o = Number.isFinite(r) && r > 0 ? Math.floor(r) : 1, c = (this._counters.get(e) ?? 0) + o;
216
+ this._counters.set(e, c), this._reports.push({
217
+ resource: e,
218
+ qty: o,
219
+ productId: i?.productId,
220
+ tenantId: i?.tenantId,
252
221
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
253
222
  });
254
- const limitFixture = this._quotas.get(resource);
255
- const limit = limitFixture?.limit ?? -1;
223
+ let d = this._quotas.get(e)?.limit ?? -1;
256
224
  return {
257
225
  ok: true,
258
- counterId: `mock_${resource}`,
259
- value: next,
260
- limit,
261
- remaining: limit < 0 ? -1 : Math.max(0, limit - next),
262
- status: limit > 0 && next >= limit ? "read_only_overlimit" : "ok"
226
+ counterId: `mock_${e}`,
227
+ value: c,
228
+ limit: d,
229
+ remaining: d < 0 ? -1 : Math.max(0, d - c),
230
+ status: d > 0 && c >= d ? "read_only_overlimit" : "ok"
263
231
  };
264
232
  }
265
- async check(resource, _options) {
266
- const quota = this._quotas.get(resource);
267
- const used = this._counters.get(resource) ?? 0;
268
- if (!quota) {
233
+ async check(e, r) {
234
+ let i = this._quotas.get(e), o = this._counters.get(e) ?? 0;
235
+ if (!i)
269
236
  return { allowed: true, reason: "granted", limit: -1, remaining: -1, behavior: null };
270
- }
271
- const remaining = quota.limit < 0 ? -1 : Math.max(0, quota.limit - used);
272
- if (remaining === 0) {
273
- return {
274
- allowed: false,
275
- reason: "limit_exceeded",
276
- limit: quota.limit,
277
- remaining: 0,
278
- behavior: "readonly"
279
- };
280
- }
281
- return {
237
+ let a = i.limit < 0 ? -1 : Math.max(0, i.limit - o);
238
+ return a === 0 ? {
239
+ allowed: false,
240
+ reason: "limit_exceeded",
241
+ limit: i.limit,
242
+ remaining: 0,
243
+ behavior: "readonly"
244
+ } : {
282
245
  allowed: true,
283
246
  reason: "granted",
284
- limit: quota.limit,
285
- remaining,
247
+ limit: i.limit,
248
+ remaining: a,
286
249
  behavior: null
287
250
  };
288
251
  }
@@ -295,40 +258,37 @@ var MockUsage = class {
295
258
  return this.__getReports();
296
259
  }
297
260
  /** Test helper — substitui quota fixture. */
298
- __setQuota(metric, quota) {
299
- this._quotas.set(metric, quota);
261
+ __setQuota(e, r) {
262
+ this._quotas.set(e, r);
300
263
  }
301
264
  /** Test helper — limpa estado. */
302
265
  __reset() {
303
- this._reports = [];
304
- this._quotas.clear();
305
- this._counters.clear();
266
+ this._reports = [], this._quotas.clear(), this._counters.clear();
306
267
  }
307
- };
308
- var MockSupport = class {
268
+ }, P = class {
309
269
  _tickets = [];
310
270
  _ticketSeq = 0;
311
- async createTicket(input) {
312
- if (!input?.subject) throw new NeetruError("validation_failed", "subject required");
313
- if (!input?.message) throw new NeetruError("validation_failed", "message required");
314
- if (!input?.productSlug) {
315
- throw new NeetruError(
271
+ async createTicket(e) {
272
+ if (!e?.subject) throw new l("validation_failed", "subject required");
273
+ if (!e?.message) throw new l("validation_failed", "message required");
274
+ if (!e?.productSlug)
275
+ throw new l(
316
276
  "validation_failed",
317
277
  "productSlug required (3.0 breaking \u2014 pass to input or set on createNeetruClient)"
318
278
  );
319
- }
320
- const ticket = {
279
+ let r = {
321
280
  id: `mock-ticket-${++this._ticketSeq}`,
322
- subject: input.subject,
323
- message: input.message,
324
- severity: input.severity ?? "normal",
281
+ subject: e.subject,
282
+ message: e.message,
283
+ severity: e.severity ?? "normal",
325
284
  status: "open",
326
285
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
327
- productSlug: input.productSlug,
286
+ productSlug: e.productSlug,
328
287
  // 3.4 (product-feedback): espelha o contrato — campos novos nullable,
329
288
  // populados a partir do input quando fornecidos.
330
- pageUrl: typeof input.pageUrl === "string" ? input.pageUrl : null,
331
- screenshotUrl: typeof input.screenshotBase64 === "string" ? input.screenshotBase64 : null,
289
+ pageUrl: typeof e.pageUrl == "string" ? e.pageUrl : null,
290
+ screenshotUrl: typeof e.screenshotBase64 == "string" ? e.screenshotBase64 : null,
291
+ screenshotAttached: typeof e.screenshotBase64 == "string",
332
292
  resolvedAt: null,
333
293
  resolvedNotifiedAt: null,
334
294
  satisfactionAttempts: 0,
@@ -337,146 +297,116 @@ var MockSupport = class {
337
297
  rating: null,
338
298
  satisfactionComment: null
339
299
  };
340
- this._tickets.push(ticket);
341
- return ticket;
300
+ return this._tickets.push(r), r;
342
301
  }
343
- async listMyTickets(options) {
344
- if (options?.productSlug) {
345
- return this._tickets.filter((t) => t.productSlug === options.productSlug);
346
- }
347
- return [...this._tickets];
302
+ async listMyTickets(e) {
303
+ return e?.productSlug ? this._tickets.filter((r) => r.productSlug === e.productSlug) : [...this._tickets];
348
304
  }
349
- _find(ticketId) {
350
- if (!ticketId || typeof ticketId !== "string") {
351
- throw new NeetruError("validation_failed", "ticketId is required");
352
- }
353
- const ticket = this._tickets.find((t) => t.id === ticketId);
354
- if (!ticket) {
355
- throw new NeetruError("not_found", `ticket ${ticketId} not found`);
356
- }
357
- return ticket;
305
+ _find(e) {
306
+ if (!e || typeof e != "string")
307
+ throw new l("validation_failed", "ticketId is required");
308
+ let r = this._tickets.find((i) => i.id === e);
309
+ if (!r)
310
+ throw new l("not_found", `ticket ${e} not found`);
311
+ return r;
358
312
  }
359
313
  /** 3.4: espelha `markResolvedSeen` — idempotente (só seta se ainda null). */
360
- async markResolvedSeen(ticketId) {
361
- const ticket = this._find(ticketId);
362
- if (ticket.resolvedNotifiedAt === null) {
363
- ticket.resolvedNotifiedAt = (/* @__PURE__ */ new Date()).toISOString();
364
- }
314
+ async markResolvedSeen(e) {
315
+ let r = this._find(e);
316
+ r.resolvedNotifiedAt === null && (r.resolvedNotifiedAt = (/* @__PURE__ */ new Date()).toISOString());
365
317
  }
366
318
  /** 3.4: espelha `recordSatisfactionAttempt` — incrementa contador. */
367
- async recordSatisfactionAttempt(ticketId) {
368
- const ticket = this._find(ticketId);
369
- ticket.satisfactionAttempts += 1;
370
- ticket.lastSatisfactionAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
319
+ async recordSatisfactionAttempt(e) {
320
+ let r = this._find(e);
321
+ r.satisfactionAttempts += 1, r.lastSatisfactionAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
371
322
  }
372
323
  /** 3.4: espelha `submitSatisfaction` — terminal, seta `satisfiedAt`. */
373
- async submitSatisfaction(input) {
374
- if (!input || typeof input !== "object") {
375
- throw new NeetruError("validation_failed", "input is required");
376
- }
377
- if (input.rating !== null && input.rating !== void 0) {
378
- if (!Number.isInteger(input.rating) || input.rating < 1 || input.rating > 5) {
379
- throw new NeetruError("validation_failed", "rating must be an integer 1-5 or null");
380
- }
381
- }
382
- if (typeof input.comment === "string" && input.comment.length > 2e3) {
383
- throw new NeetruError("validation_failed", "comment max 2000 chars");
384
- }
385
- const ticket = this._find(input.ticketId);
386
- ticket.satisfiedAt = (/* @__PURE__ */ new Date()).toISOString();
387
- ticket.rating = input.rating ?? null;
388
- ticket.satisfactionComment = input.comment ?? null;
324
+ async submitSatisfaction(e) {
325
+ if (!e || typeof e != "object")
326
+ throw new l("validation_failed", "input is required");
327
+ if (e.rating !== null && e.rating !== void 0 && (!Number.isInteger(e.rating) || e.rating < 1 || e.rating > 5))
328
+ throw new l("validation_failed", "rating must be an integer 1-5 or null");
329
+ if (typeof e.comment == "string" && e.comment.length > 2e3)
330
+ throw new l("validation_failed", "comment max 2000 chars");
331
+ let r = this._find(e.ticketId);
332
+ r.satisfiedAt = (/* @__PURE__ */ new Date()).toISOString(), r.rating = e.rating ?? null, r.satisfactionComment = e.comment ?? null;
389
333
  }
390
334
  /** 3.4: espelha `contestTicket` — reabre e zera o ciclo de satisfação. */
391
- async contestTicket(ticketId, opts) {
392
- if (typeof opts?.comment === "string" && opts.comment.length > 2e3) {
393
- throw new NeetruError("validation_failed", "comment max 2000 chars");
394
- }
395
- const ticket = this._find(ticketId);
396
- ticket.status = "open";
397
- ticket.resolvedAt = null;
398
- ticket.resolvedNotifiedAt = null;
399
- ticket.satisfactionAttempts = 0;
400
- ticket.lastSatisfactionAttemptAt = null;
401
- ticket.satisfiedAt = null;
402
- ticket.rating = null;
403
- ticket.satisfactionComment = null;
335
+ async contestTicket(e, r) {
336
+ if (typeof r?.comment == "string" && r.comment.length > 2e3)
337
+ throw new l("validation_failed", "comment max 2000 chars");
338
+ let i = this._find(e);
339
+ i.status = "open", i.resolvedAt = null, i.resolvedNotifiedAt = null, i.satisfactionAttempts = 0, i.lastSatisfactionAttemptAt = null, i.satisfiedAt = null, i.rating = null, i.satisfactionComment = null;
404
340
  }
405
341
  /** Test helper. */
406
342
  __reset() {
407
- this._tickets = [];
408
- this._ticketSeq = 0;
343
+ this._tickets = [], this._ticketSeq = 0;
409
344
  }
410
- };
411
- var MockEntitlements = class {
345
+ }, D = class {
412
346
  _denied = /* @__PURE__ */ new Set();
413
- async check(productSlug, feature) {
414
- return !this._denied.has(`${productSlug}:${feature}`);
347
+ async check(e, r) {
348
+ return !this._denied.has(`${e}:${r}`);
415
349
  }
416
- async checkDetailed(productSlug, feature) {
417
- const allowed = await this.check(productSlug, feature);
350
+ async checkDetailed(e, r) {
351
+ let i = await this.check(e, r);
418
352
  return {
419
- allowed,
420
- productSlug,
421
- feature,
422
- reason: allowed ? "granted" : "mock_denied"
353
+ allowed: i,
354
+ productSlug: e,
355
+ feature: r,
356
+ reason: i ? "granted" : "mock_denied"
423
357
  };
424
358
  }
425
359
  /** Test helper. */
426
- __deny(productSlug, feature) {
427
- this._denied.add(`${productSlug}:${feature}`);
360
+ __deny(e, r) {
361
+ this._denied.add(`${e}:${r}`);
428
362
  }
429
363
  /** Test helper. */
430
364
  __reset() {
431
365
  this._denied.clear();
432
366
  }
433
- };
434
- var MockDb = class {
367
+ }, C = class {
435
368
  _store = /* @__PURE__ */ new Map();
436
369
  _fixtures;
437
- constructor(initialFixtures = {}) {
438
- this._fixtures = new Map(Object.entries(initialFixtures));
439
- }
440
- collection(name) {
441
- const _store = this._store;
442
- const _fixtures = this._fixtures;
443
- if (!_store.has(name)) {
444
- const init = _fixtures.get(name);
445
- _store.set(
446
- name,
447
- init ? new Map(Object.entries(init)) : /* @__PURE__ */ new Map()
370
+ constructor(e = {}) {
371
+ this._fixtures = new Map(Object.entries(e));
372
+ }
373
+ collection(e) {
374
+ let r = this._store, i = this._fixtures;
375
+ if (!r.has(e)) {
376
+ let s = i.get(e);
377
+ r.set(
378
+ e,
379
+ s ? new Map(Object.entries(s)) : /* @__PURE__ */ new Map()
448
380
  );
449
381
  }
450
- const coll = _store.get(name);
451
- const matchesFilter = (doc, f) => {
452
- const v = doc[f.field];
453
- switch (f.op) {
382
+ let o = r.get(e), a = (s, t) => {
383
+ let n = s[t.field];
384
+ switch (t.op) {
454
385
  case "==":
455
- return v === f.value;
386
+ return n === t.value;
456
387
  case "!=":
457
- return v !== f.value;
388
+ return n !== t.value;
458
389
  case "<":
459
- return typeof v === "number" && typeof f.value === "number" && v < f.value;
390
+ return typeof n == "number" && typeof t.value == "number" && n < t.value;
460
391
  case "<=":
461
- return typeof v === "number" && typeof f.value === "number" && v <= f.value;
392
+ return typeof n == "number" && typeof t.value == "number" && n <= t.value;
462
393
  case ">":
463
- return typeof v === "number" && typeof f.value === "number" && v > f.value;
394
+ return typeof n == "number" && typeof t.value == "number" && n > t.value;
464
395
  case ">=":
465
- return typeof v === "number" && typeof f.value === "number" && v >= f.value;
396
+ return typeof n == "number" && typeof t.value == "number" && n >= t.value;
466
397
  case "in":
467
- return Array.isArray(f.value) && f.value.includes(v);
398
+ return Array.isArray(t.value) && t.value.includes(n);
468
399
  case "array-contains":
469
- return Array.isArray(v) && v.includes(f.value);
400
+ return Array.isArray(n) && n.includes(t.value);
470
401
  case "not-in":
471
- return Array.isArray(f.value) && !f.value.includes(v);
402
+ return Array.isArray(t.value) && !t.value.includes(n);
472
403
  default:
473
404
  return true;
474
405
  }
475
- };
476
- let autoSeq = 0;
477
- function buildListResult(items) {
406
+ }, c = 0;
407
+ function y(s) {
478
408
  return {
479
- docs: items.map((d, i) => ({ id: d.id ?? String(i), data: d })),
409
+ docs: s.map((t, n) => ({ id: t.id ?? String(n), data: t })),
480
410
  nextCursor: null,
481
411
  fromCache: false,
482
412
  stale: false,
@@ -484,141 +414,111 @@ var MockDb = class {
484
414
  changes: []
485
415
  };
486
416
  }
487
- function buildGetResult(data, id) {
417
+ function d(s, t) {
488
418
  return {
489
- docs: [{ id, data }],
419
+ docs: [{ id: t, data: s }],
490
420
  fromCache: false,
491
421
  stale: false,
492
422
  hasPendingWrites: false,
493
423
  changes: []
494
424
  };
495
425
  }
496
- const ref = {
497
- async list(q) {
498
- let items = Array.from(coll.values());
499
- if (q?.where && q.where.length > 0) {
500
- items = items.filter(
501
- (doc) => q.where.every((f) => matchesFilter(doc, f))
502
- );
503
- }
504
- if (q?.orderBy) {
505
- const { field, direction } = q.orderBy;
506
- items = items.slice().sort((a, b) => {
507
- const av = a[field];
508
- const bv = b[field];
509
- const avs = av ?? "";
510
- const bvs = bv ?? "";
511
- const cmp = avs < bvs ? -1 : avs > bvs ? 1 : 0;
512
- return direction === "desc" ? -cmp : cmp;
426
+ let f = {
427
+ async list(s) {
428
+ let t = Array.from(o.values());
429
+ if (s?.where && s.where.length > 0 && (t = t.filter(
430
+ (u) => s.where.every((g) => a(u, g))
431
+ )), s?.orderBy) {
432
+ let { field: u, direction: g } = s.orderBy;
433
+ t = t.slice().sort((p, b) => {
434
+ let h = p[u], v = b[u], k = h ?? "", w = v ?? "", S = k < w ? -1 : k > w ? 1 : 0;
435
+ return g === "desc" ? -S : S;
513
436
  });
514
437
  }
515
- const limit = q?.limit ?? 20;
516
- items = items.slice(0, limit);
517
- return buildListResult(items);
438
+ let n = s?.limit ?? 20;
439
+ return t = t.slice(0, n), y(t);
518
440
  },
519
- async get(id) {
520
- const data = coll.get(id);
521
- if (!data) return null;
522
- return buildGetResult(data, id);
441
+ async get(s) {
442
+ let t = o.get(s);
443
+ return t ? d(t, s) : null;
523
444
  },
524
- async add(data) {
525
- const id = `mock-${++autoSeq}-${Math.random().toString(36).slice(2, 8)}`;
526
- coll.set(id, { ...data, id });
527
- return { ok: true, id };
445
+ async add(s) {
446
+ let t = `mock-${++c}-${Math.random().toString(36).slice(2, 8)}`;
447
+ return o.set(t, { ...s, id: t }), { ok: true, id: t };
528
448
  },
529
- async set(id, data) {
530
- coll.set(id, { ...data, id });
531
- return { ok: true };
449
+ async set(s, t) {
450
+ return o.set(s, { ...t, id: s }), { ok: true };
532
451
  },
533
- async update(id, data) {
534
- const cur = coll.get(id);
535
- if (!cur) {
536
- coll.set(id, { ...data, id });
537
- } else {
538
- coll.set(id, { ...cur, ...data });
539
- }
540
- return { ok: true };
452
+ async update(s, t) {
453
+ let n = o.get(s);
454
+ return n ? o.set(s, { ...n, ...t }) : o.set(s, { ...t, id: s }), { ok: true };
541
455
  },
542
- async remove(id) {
543
- coll.delete(id);
544
- return { ok: true };
456
+ async remove(s) {
457
+ return o.delete(s), { ok: true };
545
458
  },
546
- async batch(ops) {
547
- for (const op of ops) {
548
- const collMap = coll;
549
- if (op.kind === "add") {
550
- const id = `mock-batch-${++autoSeq}`;
551
- collMap.set(id, { ...op.data, id });
552
- } else if (op.kind === "set") {
553
- collMap.set(op.id, { ...op.data, id: op.id });
554
- } else if (op.kind === "update") {
555
- const cur = collMap.get(op.id);
556
- collMap.set(op.id, { ...cur ?? {}, ...op.data, id: op.id });
557
- } else if (op.kind === "remove") {
558
- collMap.delete(op.id);
559
- }
459
+ async batch(s) {
460
+ for (let t of s) {
461
+ let n = o;
462
+ if (t.kind === "add") {
463
+ let u = `mock-batch-${++c}`;
464
+ n.set(u, { ...t.data, id: u });
465
+ } else if (t.kind === "set")
466
+ n.set(t.id, { ...t.data, id: t.id });
467
+ else if (t.kind === "update") {
468
+ let u = n.get(t.id);
469
+ n.set(t.id, { ...u ?? {}, ...t.data, id: t.id });
470
+ } else t.kind === "remove" && n.delete(t.id);
560
471
  }
561
472
  return { ok: true };
562
473
  },
563
- onDoc(id, cb) {
564
- const data = coll.get(id);
565
- Promise.resolve().then(() => cb(data ? data : null));
566
- return () => {
474
+ onDoc(s, t) {
475
+ let n = o.get(s);
476
+ return Promise.resolve().then(() => t(n || null)), () => {
567
477
  };
568
478
  },
569
- onSnapshot(q, cb) {
570
- Promise.resolve().then(async () => {
571
- const snap = await ref.list(q);
572
- cb(snap);
573
- });
574
- return () => {
479
+ onSnapshot(s, t) {
480
+ return Promise.resolve().then(async () => {
481
+ let n = await f.list(s);
482
+ t(n);
483
+ }), () => {
575
484
  };
576
485
  },
577
- doc(id) {
486
+ doc(s) {
578
487
  return {
579
488
  get id() {
580
- return id;
489
+ return s;
581
490
  },
582
491
  get path() {
583
- return `${name}/${id}`;
492
+ return `${e}/${s}`;
584
493
  },
585
494
  get collection() {
586
- return name;
495
+ return e;
587
496
  },
588
497
  async get() {
589
- const data = coll.get(id);
590
- if (!data) return null;
591
- return buildGetResult(data, id);
498
+ let t = o.get(s);
499
+ return t ? d(t, s) : null;
592
500
  },
593
- async set(data) {
594
- coll.set(id, { ...data, id });
595
- return { ok: true };
501
+ async set(t) {
502
+ return o.set(s, { ...t, id: s }), { ok: true };
596
503
  },
597
- async update(data) {
598
- const cur = coll.get(id);
599
- if (!cur) {
600
- coll.set(id, { ...data, id });
601
- } else {
602
- coll.set(id, { ...cur, ...data });
603
- }
604
- return { ok: true };
504
+ async update(t) {
505
+ let n = o.get(s);
506
+ return n ? o.set(s, { ...n, ...t }) : o.set(s, { ...t, id: s }), { ok: true };
605
507
  },
606
508
  async remove() {
607
- coll.delete(id);
608
- return { ok: true };
509
+ return o.delete(s), { ok: true };
609
510
  },
610
- onSnapshot(cb) {
611
- const data = coll.get(id);
612
- Promise.resolve().then(
613
- () => cb(data ? buildGetResult(data, id) : null)
614
- );
615
- return () => {
511
+ onSnapshot(t) {
512
+ let n = o.get(s);
513
+ return Promise.resolve().then(
514
+ () => t(n ? d(n, s) : null)
515
+ ), () => {
616
516
  };
617
517
  }
618
518
  };
619
519
  }
620
520
  };
621
- return ref;
521
+ return f;
622
522
  }
623
523
  /**
624
524
  * Implementa SQL in-memory para testes — preferência: `@electric-sql/pglite`
@@ -639,80 +539,66 @@ var MockDb = class {
639
539
  *
640
540
  * Use `options.initSql` pra rodar DDL no setup (CREATE TABLE etc).
641
541
  */
642
- async sql(schema, options) {
643
- const ddls = options?.initSql ? Array.isArray(options.initSql) ? options.initSql : [options.initSql] : [];
542
+ async sql(e, r) {
543
+ let i = r?.initSql ? Array.isArray(r.initSql) ? r.initSql : [r.initSql] : [];
644
544
  try {
645
- const pglitePkg = await import(
545
+ let n = await import(
646
546
  /* webpackIgnore: true */
647
547
  '@electric-sql/pglite'
648
- );
649
- const drizzlePglitePkg = await import(
548
+ ), u = await import(
650
549
  /* webpackIgnore: true */
651
550
  'drizzle-orm/pglite'
652
- );
653
- const pglite = await pglitePkg.PGlite.create();
654
- for (const ddl of ddls) {
655
- await pglite.query(ddl);
656
- }
657
- const pgliteOrm = drizzlePglitePkg.drizzle(pglite, { schema });
658
- const ormAsNode = pgliteOrm;
551
+ ), g = await n.PGlite.create();
552
+ for (let h of i)
553
+ await g.query(h);
554
+ let p = u.drizzle(g, { schema: e });
659
555
  return {
660
- orm: ormAsNode,
661
- async transaction(fn, _opts) {
662
- return await pgliteOrm.transaction(fn);
556
+ orm: p,
557
+ async transaction(h, v) {
558
+ return await p.transaction(h);
663
559
  },
664
560
  async close() {
665
- if (!pglite.closed) await pglite.close();
561
+ g.closed || await g.close();
666
562
  }
667
563
  };
668
- } catch (_pgliteErr) {
564
+ } catch {
669
565
  }
670
- let pgMemMod;
671
- let drizzlePg;
566
+ let o, a;
672
567
  try {
673
- pgMemMod = await import(
568
+ o = await import(
674
569
  /* webpackIgnore: true */
675
570
  'pg-mem'
676
- );
677
- drizzlePg = await import(
571
+ ), a = await import(
678
572
  /* webpackIgnore: true */
679
573
  'drizzle-orm/node-postgres'
680
574
  );
681
575
  } catch {
682
- throw new NeetruDbError(
576
+ throw new _(
683
577
  "db_unavailable",
684
578
  "[MockDb] sql() requer @electric-sql/pglite OU pg-mem + drizzle-orm + pg como devDependencies. Preferido: npm install -D @electric-sql/pglite drizzle-orm. Alternativo: npm install -D pg-mem drizzle-orm pg."
685
579
  );
686
580
  }
687
- const memDb = pgMemMod.newDb({ noAstCoverageCheck: true });
688
- if (ddls.length > 0) {
689
- for (const ddl of ddls) {
690
- memDb.public.none(ddl);
581
+ let c = o.newDb({ noAstCoverageCheck: true });
582
+ if (i.length > 0)
583
+ for (let n of i)
584
+ c.public.none(n);
585
+ let d = c.adapters.createPg().Pool, f = new d(), s = f.query.bind(f);
586
+ f.query = (n, ...u) => {
587
+ if (n !== null && typeof n == "object") {
588
+ let p = n.types;
589
+ p !== null && typeof p == "object" && "getTypeParser" in p && delete p.getTypeParser;
691
590
  }
692
- }
693
- const adapters = memDb.adapters.createPg();
694
- const PoolCtor = adapters.Pool;
695
- const pool = new PoolCtor();
696
- const origQuery = pool.query.bind(pool);
697
- pool.query = (q, ...rest) => {
698
- if (q !== null && typeof q === "object") {
699
- const queryObj = q;
700
- const types = queryObj["types"];
701
- if (types !== null && typeof types === "object" && "getTypeParser" in types) {
702
- delete types["getTypeParser"];
703
- }
704
- }
705
- return origQuery(q, ...rest);
591
+ return s(n, ...u);
706
592
  };
707
- const orm = drizzlePg.drizzle(pool, { schema });
593
+ let t = a.drizzle(f, { schema: e });
708
594
  return {
709
- orm,
710
- async transaction(fn, _opts) {
711
- return await orm.transaction(fn);
595
+ orm: t,
596
+ async transaction(n, u) {
597
+ return await t.transaction(n);
712
598
  },
713
599
  async close() {
714
- const p = pool;
715
- if (p.end) await p.end();
600
+ let n = f;
601
+ n.end && await n.end();
716
602
  }
717
603
  };
718
604
  }
@@ -724,7 +610,7 @@ var MockDb = class {
724
610
  isLeaderTab: true
725
611
  };
726
612
  }
727
- onSyncStateChanged(_cb) {
613
+ onSyncStateChanged(e) {
728
614
  return () => {
729
615
  };
730
616
  }
@@ -737,65 +623,53 @@ var MockDb = class {
737
623
  return [];
738
624
  }
739
625
  /** Test helper — substitui fixture inteira de uma collection. */
740
- __setFixture(name, items) {
741
- this._store.set(name, new Map(Object.entries(items)));
626
+ __setFixture(e, r) {
627
+ this._store.set(e, new Map(Object.entries(r)));
742
628
  }
743
629
  /** Test helper — reset total. */
744
630
  __reset() {
745
631
  this._store.clear();
746
632
  }
747
- };
748
- var MockAi = class {
633
+ }, N = class {
749
634
  _calls = [];
750
635
  /** Extrai texto de um content string OU array multimodal (imagens ignoradas). */
751
- _contentToText(content) {
752
- if (typeof content === "string") return content;
753
- if (!Array.isArray(content)) return "";
754
- return content.filter((p) => !!p && p.type === "text").map((p) => p.text).join(" ");
755
- }
756
- _reply(opts) {
757
- const last = [...opts.messages].reverse().find((m) => m.role === "user") ?? opts.messages[opts.messages.length - 1];
758
- const content = this._contentToText(last?.content);
759
- return content ? `mock-reply: ${content}` : "mock-reply";
760
- }
761
- async chat(opts) {
762
- if (!opts || typeof opts.model !== "string" || opts.model.length === 0) {
763
- throw new NeetruError("validation_failed", "ai: model is required");
764
- }
765
- if (!Array.isArray(opts.messages) || opts.messages.length === 0) {
766
- throw new NeetruError("validation_failed", "ai: messages must be a non-empty array");
767
- }
768
- this._calls.push({ model: opts.model, messages: opts.messages, stream: false });
769
- const text = this._reply(opts);
770
- const promptTokens = opts.messages.reduce((n, m) => n + this._contentToText(m.content).length, 0);
771
- const completionTokens = text.length;
636
+ _contentToText(e) {
637
+ return typeof e == "string" ? e : Array.isArray(e) ? e.filter((r) => !!r && r.type === "text").map((r) => r.text).join(" ") : "";
638
+ }
639
+ _reply(e) {
640
+ let r = [...e.messages].reverse().find((o) => o.role === "user") ?? e.messages[e.messages.length - 1], i = this._contentToText(r?.content);
641
+ return i ? `mock-reply: ${i}` : "mock-reply";
642
+ }
643
+ async chat(e) {
644
+ if (!e || typeof e.model != "string" || e.model.length === 0)
645
+ throw new l("validation_failed", "ai: model is required");
646
+ if (!Array.isArray(e.messages) || e.messages.length === 0)
647
+ throw new l("validation_failed", "ai: messages must be a non-empty array");
648
+ this._calls.push({ model: e.model, messages: e.messages, stream: false });
649
+ let r = this._reply(e), i = e.messages.reduce((a, c) => a + this._contentToText(c.content).length, 0), o = r.length;
772
650
  return {
773
- choices: [{ message: { role: "assistant", content: text }, finish_reason: "stop" }],
651
+ choices: [{ message: { role: "assistant", content: r }, finish_reason: "stop" }],
774
652
  usage: {
775
- prompt_tokens: promptTokens,
776
- completion_tokens: completionTokens,
777
- total_tokens: promptTokens + completionTokens
653
+ prompt_tokens: i,
654
+ completion_tokens: o,
655
+ total_tokens: i + o
778
656
  },
779
- model: opts.model,
657
+ model: e.model,
780
658
  provider: "mock",
781
659
  usageWarning: false
782
660
  };
783
661
  }
784
- stream(opts) {
785
- if (!opts || typeof opts.model !== "string" || opts.model.length === 0) {
786
- throw new NeetruError("validation_failed", "ai: model is required");
787
- }
788
- if (!Array.isArray(opts.messages) || opts.messages.length === 0) {
789
- throw new NeetruError("validation_failed", "ai: messages must be a non-empty array");
790
- }
791
- this._calls.push({ model: opts.model, messages: opts.messages, stream: true });
792
- const text = this._reply(opts);
793
- const parts = text.match(/\S+\s*/g) ?? [text];
794
- const meta = Promise.resolve({ provider: "mock", usageWarning: false });
795
- async function* iterate() {
796
- for (const p of parts) yield p;
662
+ stream(e) {
663
+ if (!e || typeof e.model != "string" || e.model.length === 0)
664
+ throw new l("validation_failed", "ai: model is required");
665
+ if (!Array.isArray(e.messages) || e.messages.length === 0)
666
+ throw new l("validation_failed", "ai: messages must be a non-empty array");
667
+ this._calls.push({ model: e.model, messages: e.messages, stream: true });
668
+ let r = this._reply(e), i = r.match(/\S+\s*/g) ?? [r], o = Promise.resolve({ provider: "mock", usageWarning: false });
669
+ async function* a() {
670
+ for (let c of i) yield c;
797
671
  }
798
- return { meta, [Symbol.asyncIterator]: iterate };
672
+ return { meta: o, [Symbol.asyncIterator]: a };
799
673
  }
800
674
  /** Test helper — histórico de chamadas. */
801
675
  __getCalls() {
@@ -803,12 +677,10 @@ var MockAi = class {
803
677
  }
804
678
  };
805
679
 
806
- exports.DEV_FIXTURE_USER = DEV_FIXTURE_USER;
807
- exports.MockAi = MockAi;
808
- exports.MockAuth = MockAuth;
809
- exports.MockDb = MockDb;
810
- exports.MockEntitlements = MockEntitlements;
811
- exports.MockSupport = MockSupport;
812
- exports.MockUsage = MockUsage;
813
- //# sourceMappingURL=mocks.cjs.map
814
- //# sourceMappingURL=mocks.cjs.map
680
+ exports.DEV_FIXTURE_USER = x;
681
+ exports.MockAi = N;
682
+ exports.MockAuth = A;
683
+ exports.MockDb = C;
684
+ exports.MockEntitlements = D;
685
+ exports.MockSupport = P;
686
+ exports.MockUsage = T;