@neetru/sdk 3.4.3 → 3.4.5

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 (56) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/ai.d.cts +1 -1
  3. package/dist/ai.d.ts +1 -1
  4. package/dist/auth.cjs +33 -11
  5. package/dist/auth.cjs.map +1 -1
  6. package/dist/auth.d.cts +1 -1
  7. package/dist/auth.d.ts +1 -1
  8. package/dist/auth.mjs +33 -11
  9. package/dist/auth.mjs.map +1 -1
  10. package/dist/catalog.d.cts +1 -1
  11. package/dist/catalog.d.ts +1 -1
  12. package/dist/checkout.cjs +17 -7
  13. package/dist/checkout.cjs.map +1 -1
  14. package/dist/checkout.d.cts +1 -1
  15. package/dist/checkout.d.ts +1 -1
  16. package/dist/checkout.mjs +17 -7
  17. package/dist/checkout.mjs.map +1 -1
  18. package/dist/db-react.d.cts +1 -1
  19. package/dist/db-react.d.ts +1 -1
  20. package/dist/db.d.cts +1 -1
  21. package/dist/db.d.ts +1 -1
  22. package/dist/entitlements.d.cts +1 -1
  23. package/dist/entitlements.d.ts +1 -1
  24. package/dist/firestore-compat.d.cts +1 -1
  25. package/dist/firestore-compat.d.ts +1 -1
  26. package/dist/index.cjs +34 -12
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +2 -2
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.mjs +34 -12
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/mocks.d.cts +1 -1
  33. package/dist/mocks.d.ts +1 -1
  34. package/dist/notifications.d.cts +1 -1
  35. package/dist/notifications.d.ts +1 -1
  36. package/dist/react.cjs +62 -3
  37. package/dist/react.cjs.map +1 -1
  38. package/dist/react.d.cts +38 -7
  39. package/dist/react.d.ts +38 -7
  40. package/dist/react.mjs +62 -3
  41. package/dist/react.mjs.map +1 -1
  42. package/dist/support.d.cts +1 -1
  43. package/dist/support.d.ts +1 -1
  44. package/dist/telemetry.cjs +16 -4
  45. package/dist/telemetry.cjs.map +1 -1
  46. package/dist/telemetry.d.cts +1 -1
  47. package/dist/telemetry.d.ts +1 -1
  48. package/dist/telemetry.mjs +16 -4
  49. package/dist/telemetry.mjs.map +1 -1
  50. package/dist/{types-D-QdG502.d.cts → types-DIVZl7nO.d.cts} +29 -8
  51. package/dist/{types-BlOLDMR0.d.ts → types-nnztVk7G.d.ts} +29 -8
  52. package/dist/usage.d.cts +1 -1
  53. package/dist/usage.d.ts +1 -1
  54. package/dist/webhooks.d.cts +1 -1
  55. package/dist/webhooks.d.ts +1 -1
  56. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,46 @@ All notable changes to `@neetru/sdk` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.4.5] - 2026-09-12 — **fix(telemetry): event()/track() usáveis no browser (401 silencioso em produção)**
9
+
10
+ Release **patch** (correção de bug — `client.telemetry.event()`/`.track()` documentados como uso client-side de alta frequência, mas nunca funcionaram de fato no browser).
11
+
12
+ ### Contexto
13
+
14
+ `event()`/`track()` só chamavam `POST /api/sdk/v1/telemetry/event`, que exige `Bearer` com `cli_api_keys` — credencial de operador que nunca deveria estar no browser. Resultado real em produção (achado 2026-09-09, `pdvagiliza.neetru.com`): 401 silencioso, telemetria de UI nunca persistida. Compondo o problema, `productSlug` nunca era enviado no body de nenhum dos dois métodos (só `log()` já mandava) — o Core exige `productSlug` fail-closed, então mesmo corrigindo a auth o evento seria rejeitado.
15
+
16
+ ### Corrigido
17
+
18
+ - **`event()`/`track()` agora enviam `productSlug`** no body (`input.productSlug ?? config.productId`, mesmo default de `log()`/`usage.report()`).
19
+ - **Roteamento browser vs server**: em contexto browser (`typeof window !== 'undefined'`), `event()`/`track()` chamam o novo `POST /api/sdk/v1/telemetry/event/public` do Core (sem Bearer — autoriza via `Origin`, não credencial). Server-side continua no endpoint autenticado original, sem mudança de comportamento.
20
+
21
+ ### Adicionado (aditivo, opcional)
22
+
23
+ - **`TelemetryEventInput.productSlug?: string`** — override explícito, mesmo padrão de `TelemetryLogInput.productSlug`.
24
+
25
+ Requer Core com a rota `/api/sdk/v1/telemetry/event/public` (PR companion `Neetru/neetru-core#448`) para o caminho browser funcionar; server-side não tem dependência nova.
26
+
27
+ ## [3.4.4] - 2026-09-07 — **fix(checkout): aceitar id_token no padrão BFF/cookie (desbloqueia checkout PAGO)**
28
+
29
+ Release **patch** (correção de bug que bloqueava 100% do checkout PAGO no padrão BFF/cookie; aditivos opcionais retrocompatíveis, nenhuma remoção de API, nenhuma mudança de wire além de um header aceito a mais). Bug `bug_72ccf42065304d3384aa3ed09accef8d` (HIGH).
30
+
31
+ ### Contexto
32
+
33
+ No padrão **BFF/cookie** (recomendado), o app troca `code`→tokens **no servidor**, guarda só o **id_token** num cookie **httpOnly** e **descarta o access_token** — então o browser NUNCA tem o access_token. Mas `checkout.start()` / `<CheckoutLink>` exigiam o access_token no browser, tornando impossível iniciar o checkout PAGO nesse padrão (só o `MockCheckout` de dev "funcionava"). O Core passou a aceitar o **id_token** no endpoint de checkout (via `verifyEndUserIdToken`, mesma validação forte de assinatura/kid/iss/exp da barra de conta), então o SDK agora expõe o caminho BFF.
34
+
35
+ ### Corrigido
36
+
37
+ - **`checkout.start()` / `get()` / `cancel()` aceitam `idToken`** além de `accessToken`. O helper de auth manda o token que houver no header `Bearer` (o Core resolve se é access_token ou id_token). Quando ambos vêm, `accessToken` tem prioridade (é revogável no servidor). Sem nenhum dos dois, continua lançando `validation_failed` sem tocar a rede.
38
+
39
+ ### Adicionado (aditivo, opcional)
40
+
41
+ - **`CheckoutStartInput.idToken?` / `CheckoutAuthOpts.idToken?`** — id_token OIDC do usuário final para o padrão BFF/cookie.
42
+ - **`<CheckoutLink startPath="/api/checkout/start">`** — novo modo BFF: o clique faz `POST` no route do PRÓPRIO app (same-origin, `credentials: 'include'` → manda o cookie httpOnly), que inicia o checkout server-side e devolve `{ redirectUrl }`. O `client` vira **opcional** neste modo (o browser não precisa de token nem de client). O modo legado `client.checkout.start()` (client-side, browser com token) segue intacto.
43
+
44
+ ### Padrão BFF suportado
45
+
46
+ Ver `docs/CHECKOUT_BFF.md` — passo a passo canônico do checkout num app BFF/cookie (o que o produto tem que fazer: route BFF que lê o id_token do cookie e chama `client.checkout.start({ ..., idToken })`, + `<CheckoutLink startPath=...>` no client).
47
+
8
48
  ## [3.4.3] - 2026-09-07 — **build-guard força pg + drizzle-orm no trace do standalone (causa-2 outage PDV 2026-09-07)**
9
49
 
10
50
  Release **patch** (só correção de build; nada de wire, nada removido da API). Fase 2 do conserto do outage do PDV.
package/dist/ai.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart, aJ as createAiNamespace } from './types-D-QdG502.cjs';
1
+ export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart, aJ as createAiNamespace } from './types-DIVZl7nO.cjs';
2
2
  import 'drizzle-orm/node-postgres';
3
3
  import './errors.cjs';
package/dist/ai.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart, aJ as createAiNamespace } from './types-BlOLDMR0.js';
1
+ export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart, aJ as createAiNamespace } from './types-nnztVk7G.js';
2
2
  import 'drizzle-orm/node-postgres';
3
3
  import './errors.js';
package/dist/auth.cjs CHANGED
@@ -1273,6 +1273,12 @@ function createEntitlementsNamespace(config) {
1273
1273
  init_errors();
1274
1274
  init_http();
1275
1275
  var VALID_LOG_LEVELS = ["debug", "info", "warn", "error", "fatal"];
1276
+ function isBrowserContext() {
1277
+ return typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
1278
+ }
1279
+ function resolveEventTransport() {
1280
+ return isBrowserContext() ? { path: "/api/sdk/v1/telemetry/event/public", requireAuth: false } : { path: "/api/sdk/v1/telemetry/event", requireAuth: true };
1281
+ }
1276
1282
  function consoleFor(level) {
1277
1283
  switch (level) {
1278
1284
  case "debug":
@@ -1302,15 +1308,18 @@ function createTelemetryNamespace(config) {
1302
1308
  batch.map(async (ev) => {
1303
1309
  try {
1304
1310
  const body = { name: ev.name };
1311
+ const productSlug = ev.productSlug ?? config.productId;
1312
+ if (productSlug) body.productSlug = productSlug;
1305
1313
  if (ev.properties && typeof ev.properties === "object") {
1306
1314
  body.properties = ev.properties;
1307
1315
  }
1308
1316
  if (ev.timestamp) body.timestamp = ev.timestamp;
1317
+ const transport = resolveEventTransport();
1309
1318
  await httpRequest(config, {
1310
1319
  method: "POST",
1311
- path: "/api/sdk/v1/telemetry/event",
1320
+ path: transport.path,
1312
1321
  body,
1313
- requireAuth: true,
1322
+ requireAuth: transport.requireAuth,
1314
1323
  retries: 1,
1315
1324
  // caça-bruxas: retry sem Idempotency-Key duplicava o evento se o
1316
1325
  // servidor já tinha persistido antes da falha transiente. Mesmo
@@ -1363,15 +1372,18 @@ function createTelemetryNamespace(config) {
1363
1372
  throw new NeetruError("validation_failed", "event.name max 128 chars");
1364
1373
  }
1365
1374
  const body = { name: input.name };
1375
+ const productSlug = input.productSlug ?? config.productId;
1376
+ if (productSlug) body.productSlug = productSlug;
1366
1377
  if (input.properties && typeof input.properties === "object") {
1367
1378
  body.properties = input.properties;
1368
1379
  }
1369
1380
  if (input.timestamp) body.timestamp = input.timestamp;
1381
+ const transport = resolveEventTransport();
1370
1382
  const raw = await httpRequest(config, {
1371
1383
  method: "POST",
1372
- path: "/api/sdk/v1/telemetry/event",
1384
+ path: transport.path,
1373
1385
  body,
1374
- requireAuth: true
1386
+ requireAuth: transport.requireAuth
1375
1387
  });
1376
1388
  if (!raw || raw.ok !== true || typeof raw.eventId !== "string") {
1377
1389
  throw new NeetruError("invalid_response", "Telemetry response missing eventId");
@@ -5576,14 +5588,15 @@ function createLazyCollectionRef(name, getDocsPromise) {
5576
5588
  // src/checkout.ts
5577
5589
  init_errors();
5578
5590
  init_http();
5579
- function checkoutAuth(accessToken, method) {
5580
- if (!accessToken || typeof accessToken !== "string") {
5591
+ function checkoutAuth(auth, method) {
5592
+ const token = auth?.accessToken || auth?.idToken;
5593
+ if (!token || typeof token !== "string") {
5581
5594
  throw new NeetruError(
5582
5595
  "validation_failed",
5583
- `checkout.${method} requer o access_token OIDC do usu\xE1rio final (passe \`accessToken\`). A chave de API do SDK (nrt_*) N\xC3O \xE9 aceita pelo endpoint de checkout \u2014 ele autentica a identidade do cliente que est\xE1 assinando (Bearer access_token OIDC ou cookie de sess\xE3o).`
5596
+ `checkout.${method} requer o access_token OU o id_token OIDC do usu\xE1rio final (passe \`accessToken\` ou \`idToken\`). A chave de API do SDK (nrt_*) N\xC3O \xE9 aceita pelo endpoint de checkout \u2014 ele autentica a identidade do cliente que est\xE1 assinando (Bearer access_token/id_token OIDC ou cookie de sess\xE3o). No padr\xE3o BFF/cookie, passe o \`idToken\` que seu servidor guardou no cookie httpOnly.`
5584
5597
  );
5585
5598
  }
5586
- return { requireAuth: false, headers: { authorization: `Bearer ${accessToken}` } };
5599
+ return { requireAuth: false, headers: { authorization: `Bearer ${token}` } };
5587
5600
  }
5588
5601
  function parseStartResponse(raw) {
5589
5602
  if (!raw || typeof raw !== "object") {
@@ -5662,7 +5675,10 @@ function createHttpCheckoutNamespace(config) {
5662
5675
  };
5663
5676
  if (input.tenantType) body.targetTenantType = input.tenantType;
5664
5677
  if (input.tenantId) body.targetTenantId = input.tenantId;
5665
- const { requireAuth, headers } = checkoutAuth(input.accessToken, "start");
5678
+ const { requireAuth, headers } = checkoutAuth(
5679
+ { accessToken: input.accessToken, idToken: input.idToken },
5680
+ "start"
5681
+ );
5666
5682
  const raw = await httpRequest(config, {
5667
5683
  method: "POST",
5668
5684
  path: "/api/v1/checkout/intents",
@@ -5682,7 +5698,10 @@ function createHttpCheckoutNamespace(config) {
5682
5698
  if (!intentId || typeof intentId !== "string") {
5683
5699
  throw new NeetruError("validation_failed", "checkout.get: intentId is required");
5684
5700
  }
5685
- const { requireAuth, headers } = checkoutAuth(opts?.accessToken, "get");
5701
+ const { requireAuth, headers } = checkoutAuth(
5702
+ { accessToken: opts?.accessToken, idToken: opts?.idToken },
5703
+ "get"
5704
+ );
5686
5705
  const raw = await httpRequest(config, {
5687
5706
  method: "GET",
5688
5707
  path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
@@ -5695,7 +5714,10 @@ function createHttpCheckoutNamespace(config) {
5695
5714
  if (!intentId || typeof intentId !== "string") {
5696
5715
  throw new NeetruError("validation_failed", "checkout.cancel: intentId is required");
5697
5716
  }
5698
- const { requireAuth, headers } = checkoutAuth(opts?.accessToken, "cancel");
5717
+ const { requireAuth, headers } = checkoutAuth(
5718
+ { accessToken: opts?.accessToken, idToken: opts?.idToken },
5719
+ "cancel"
5720
+ );
5699
5721
  const raw = await httpRequest(config, {
5700
5722
  method: "DELETE",
5701
5723
  path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,