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