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