@neetru/sdk 3.1.0 → 3.1.1

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 (95) hide show
  1. package/dist/auth.cjs +159 -15
  2. package/dist/auth.cjs.map +1 -1
  3. package/dist/auth.d.cts +1 -1
  4. package/dist/auth.d.ts +1 -1
  5. package/dist/auth.mjs +159 -15
  6. package/dist/auth.mjs.map +1 -1
  7. package/dist/catalog.cjs +50 -2
  8. package/dist/catalog.cjs.map +1 -1
  9. package/dist/catalog.d.cts +1 -1
  10. package/dist/catalog.d.ts +1 -1
  11. package/dist/catalog.mjs +50 -2
  12. package/dist/catalog.mjs.map +1 -1
  13. package/dist/checkout.cjs +52 -3
  14. package/dist/checkout.cjs.map +1 -1
  15. package/dist/checkout.d.cts +1 -1
  16. package/dist/checkout.d.ts +1 -1
  17. package/dist/checkout.mjs +52 -3
  18. package/dist/checkout.mjs.map +1 -1
  19. package/dist/db-react.cjs +3 -1
  20. package/dist/db-react.cjs.map +1 -1
  21. package/dist/db-react.d.cts +1 -1
  22. package/dist/db-react.d.ts +1 -1
  23. package/dist/db-react.mjs +3 -1
  24. package/dist/db-react.mjs.map +1 -1
  25. package/dist/db.cjs +93 -6
  26. package/dist/db.cjs.map +1 -1
  27. package/dist/db.d.cts +1 -1
  28. package/dist/db.d.ts +1 -1
  29. package/dist/db.mjs +93 -6
  30. package/dist/db.mjs.map +1 -1
  31. package/dist/entitlements.cjs +50 -2
  32. package/dist/entitlements.cjs.map +1 -1
  33. package/dist/entitlements.d.cts +1 -1
  34. package/dist/entitlements.d.ts +1 -1
  35. package/dist/entitlements.mjs +50 -2
  36. package/dist/entitlements.mjs.map +1 -1
  37. package/dist/errors.cjs.map +1 -1
  38. package/dist/errors.d.cts +3 -1
  39. package/dist/errors.d.ts +3 -1
  40. package/dist/errors.mjs.map +1 -1
  41. package/dist/firestore-compat.cjs +14 -2
  42. package/dist/firestore-compat.cjs.map +1 -1
  43. package/dist/firestore-compat.d.cts +28 -3
  44. package/dist/firestore-compat.d.ts +28 -3
  45. package/dist/firestore-compat.mjs +14 -2
  46. package/dist/firestore-compat.mjs.map +1 -1
  47. package/dist/index.cjs +195 -16
  48. package/dist/index.cjs.map +1 -1
  49. package/dist/index.d.cts +9 -3
  50. package/dist/index.d.ts +9 -3
  51. package/dist/index.mjs +194 -17
  52. package/dist/index.mjs.map +1 -1
  53. package/dist/mocks.cjs.map +1 -1
  54. package/dist/mocks.d.cts +1 -1
  55. package/dist/mocks.d.ts +1 -1
  56. package/dist/mocks.mjs.map +1 -1
  57. package/dist/notifications.cjs +50 -2
  58. package/dist/notifications.cjs.map +1 -1
  59. package/dist/notifications.d.cts +1 -1
  60. package/dist/notifications.d.ts +1 -1
  61. package/dist/notifications.mjs +50 -2
  62. package/dist/notifications.mjs.map +1 -1
  63. package/dist/react.cjs +2 -3
  64. package/dist/react.cjs.map +1 -1
  65. package/dist/react.d.cts +22 -4
  66. package/dist/react.d.ts +22 -4
  67. package/dist/react.mjs +2 -3
  68. package/dist/react.mjs.map +1 -1
  69. package/dist/support.cjs +50 -2
  70. package/dist/support.cjs.map +1 -1
  71. package/dist/support.d.cts +1 -1
  72. package/dist/support.d.ts +1 -1
  73. package/dist/support.mjs +50 -2
  74. package/dist/support.mjs.map +1 -1
  75. package/dist/telemetry.cjs +65 -4
  76. package/dist/telemetry.cjs.map +1 -1
  77. package/dist/telemetry.d.cts +1 -1
  78. package/dist/telemetry.d.ts +1 -1
  79. package/dist/telemetry.mjs +65 -4
  80. package/dist/telemetry.mjs.map +1 -1
  81. package/dist/{types-BRv8wBxX.d.ts → types-B3XFHD4A.d.ts} +60 -1
  82. package/dist/{types-nwErcRX8.d.cts → types-DePdSU3P.d.cts} +60 -1
  83. package/dist/usage.cjs +50 -2
  84. package/dist/usage.cjs.map +1 -1
  85. package/dist/usage.d.cts +1 -1
  86. package/dist/usage.d.ts +1 -1
  87. package/dist/usage.mjs +50 -2
  88. package/dist/usage.mjs.map +1 -1
  89. package/dist/webhooks.cjs +83 -2
  90. package/dist/webhooks.cjs.map +1 -1
  91. package/dist/webhooks.d.cts +1 -1
  92. package/dist/webhooks.d.ts +1 -1
  93. package/dist/webhooks.mjs +83 -3
  94. package/dist/webhooks.mjs.map +1 -1
  95. package/package.json +1 -1
package/dist/auth.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as NeetruClientConfig, z as NeetruClient } from './types-nwErcRX8.cjs';
1
+ import { B as NeetruClientConfig, z as NeetruClient } from './types-DePdSU3P.cjs';
2
2
  import 'drizzle-orm/node-postgres';
3
3
  import './errors.cjs';
4
4
 
package/dist/auth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as NeetruClientConfig, z as NeetruClient } from './types-BRv8wBxX.js';
1
+ import { B as NeetruClientConfig, z as NeetruClient } from './types-B3XFHD4A.js';
2
2
  import 'drizzle-orm/node-postgres';
3
3
  import './errors.js';
4
4
 
package/dist/auth.mjs CHANGED
@@ -51,8 +51,47 @@ var init_idempotency = __esm({
51
51
  // src/http.ts
52
52
  var http_exports = {};
53
53
  __export(http_exports, {
54
+ checkCoreVersionCompat: () => checkCoreVersionCompat,
54
55
  httpRequest: () => httpRequest
55
56
  });
57
+ function stripRevision(v) {
58
+ return v.split("+")[0] ?? v;
59
+ }
60
+ function compareCalVer(a, b) {
61
+ const partsA = stripRevision(a).split(".").map(Number);
62
+ const partsB = stripRevision(b).split(".").map(Number);
63
+ const len = Math.max(partsA.length, partsB.length);
64
+ for (let i = 0; i < len; i++) {
65
+ const pa = partsA[i] ?? 0;
66
+ const pb = partsB[i] ?? 0;
67
+ if (pa !== pb) return pa - pb;
68
+ }
69
+ return 0;
70
+ }
71
+ function getSdkMajor() {
72
+ try {
73
+ const ver = globalThis.__NEETRU_SDK_VERSION__;
74
+ if (ver) return parseInt(ver.split(".")[0] ?? "3", 10);
75
+ } catch {
76
+ }
77
+ return 3;
78
+ }
79
+ function checkCoreVersionCompat(coreVersion) {
80
+ if (!coreVersion) return;
81
+ const sdkMajor = getSdkMajor();
82
+ const minCore = COMPAT_MATRIX[sdkMajor];
83
+ if (!minCore) return;
84
+ const stripped = stripRevision(coreVersion);
85
+ if (compareCalVer(stripped, minCore) < 0) {
86
+ const key = `${sdkMajor}:${stripped}`;
87
+ if (!_warnedCoreTooOld.has(key)) {
88
+ _warnedCoreTooOld.add(key);
89
+ console.warn(
90
+ `[Neetru SDK] Aten\xE7\xE3o: Core vers\xE3o "${coreVersion}" \xE9 anterior ao m\xEDnimo recomendado "${minCore}" para SDK major ${sdkMajor}. Alguns recursos podem n\xE3o funcionar corretamente. Atualize o Core para a vers\xE3o mais recente.`
91
+ );
92
+ }
93
+ }
94
+ }
56
95
  function backoffMs(attempt) {
57
96
  const base = 200 * Math.pow(4, attempt);
58
97
  const jitter = base * 0.2 * (Math.random() * 2 - 1);
@@ -61,11 +100,11 @@ function backoffMs(attempt) {
61
100
  function parseRetryAfter(value) {
62
101
  if (!value) return null;
63
102
  const secs = Number(value);
64
- if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1e3);
103
+ if (Number.isFinite(secs) && secs >= 0) return Math.min(Math.round(secs * 1e3), MAX_RETRY_AFTER_MS);
65
104
  const dateMs = Date.parse(value);
66
105
  if (Number.isFinite(dateMs)) {
67
106
  const delta = dateMs - Date.now();
68
- if (delta > 0) return delta;
107
+ if (delta > 0) return Math.min(delta, MAX_RETRY_AFTER_MS);
69
108
  }
70
109
  return null;
71
110
  }
@@ -76,6 +115,7 @@ function statusToCode(status) {
76
115
  if (status === 401) return "unauthorized";
77
116
  if (status === 403) return "forbidden";
78
117
  if (status === 404) return "not_found";
118
+ if (status === 409) return "conflict";
79
119
  if (status === 422 || status === 400) return "validation_failed";
80
120
  if (status === 429) return "rate_limited";
81
121
  if (status >= 500) return "server_error";
@@ -147,6 +187,8 @@ async function httpRequest(config, opts) {
147
187
  }
148
188
  const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
149
189
  if (res.ok) {
190
+ const coreVersion = res.headers.get("x-neetru-version");
191
+ if (coreVersion) checkCoreVersionCompat(coreVersion);
150
192
  const parsed = await safeJson(res);
151
193
  return parsed;
152
194
  }
@@ -175,11 +217,17 @@ async function httpRequest(config, opts) {
175
217
  }
176
218
  throw lastError ?? new NeetruError("unknown", "unexpected httpRequest exit");
177
219
  }
178
- var DEFAULT_RETRIES_READ, DEFAULT_RETRIES_WRITE, READ_METHODS, RETRYABLE_CODES;
220
+ var COMPAT_MATRIX, _warnedCoreTooOld, DEFAULT_RETRIES_READ, DEFAULT_RETRIES_WRITE, READ_METHODS, RETRYABLE_CODES, MAX_RETRY_AFTER_MS;
179
221
  var init_http = __esm({
180
222
  "src/http.ts"() {
181
223
  init_errors();
182
224
  init_idempotency();
225
+ COMPAT_MATRIX = {
226
+ // SDK major 3.x requer Core ≥ 2026.05.1 (suporte a X-Neetru-Version header,
227
+ // runTransaction write-after-read, verifyWebhookRequest, webhooks 3.0+)
228
+ 3: "2026.05.1"
229
+ };
230
+ _warnedCoreTooOld = /* @__PURE__ */ new Set();
183
231
  DEFAULT_RETRIES_READ = 2;
184
232
  DEFAULT_RETRIES_WRITE = 0;
185
233
  READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
@@ -188,6 +236,7 @@ var init_http = __esm({
188
236
  "server_error",
189
237
  "network_error"
190
238
  ]);
239
+ MAX_RETRY_AFTER_MS = 6e4;
191
240
  }
192
241
  });
193
242
 
@@ -889,11 +938,11 @@ var TRACK_MAX_QUEUE = 50;
889
938
  function createTelemetryNamespace(config) {
890
939
  const queue = [];
891
940
  let flushTimer = null;
941
+ let _inflightDrain = null;
892
942
  async function drainQueue() {
893
943
  if (queue.length === 0) return;
894
944
  const batch = queue.splice(0, queue.length);
895
- flushTimer = null;
896
- await Promise.allSettled(
945
+ const work = Promise.allSettled(
897
946
  batch.map(async (ev) => {
898
947
  try {
899
948
  const body = { name: ev.name };
@@ -915,6 +964,14 @@ function createTelemetryNamespace(config) {
915
964
  }
916
965
  })
917
966
  );
967
+ _inflightDrain = work.then(() => {
968
+ _inflightDrain = null;
969
+ });
970
+ await work;
971
+ flushTimer = null;
972
+ if (queue.length > 0) {
973
+ scheduleFlush();
974
+ }
918
975
  }
919
976
  function scheduleFlush() {
920
977
  if (flushTimer) return;
@@ -977,6 +1034,10 @@ function createTelemetryNamespace(config) {
977
1034
  if (input.name.length > 128) return;
978
1035
  queue.push(input);
979
1036
  if (queue.length >= TRACK_MAX_QUEUE) {
1037
+ if (flushTimer) {
1038
+ clearTimeout(flushTimer);
1039
+ flushTimer = null;
1040
+ }
980
1041
  void drainQueue();
981
1042
  } else {
982
1043
  scheduleFlush();
@@ -991,6 +1052,7 @@ function createTelemetryNamespace(config) {
991
1052
  clearTimeout(flushTimer);
992
1053
  flushTimer = null;
993
1054
  }
1055
+ if (_inflightDrain) await _inflightDrain;
994
1056
  await drainQueue();
995
1057
  },
996
1058
  /**
@@ -1479,6 +1541,31 @@ var LocalStore = class {
1479
1541
  this.db?.close();
1480
1542
  this.db = null;
1481
1543
  }
1544
+ /**
1545
+ * Apaga completamente o banco IndexedDB e o recria do zero.
1546
+ *
1547
+ * Ao contrário de `close()` + `open()` (que reabre o banco existente sem
1548
+ * apagar dados), `clearAll()` chama `indexedDB.deleteDatabase(dbName)` e
1549
+ * só então chama `open()` — garantindo que nenhum documento, mutação ou
1550
+ * metadado sobrevive.
1551
+ *
1552
+ * BUG fix: `clearCache()` em `NeetruDbDocumentsImpl` chamava close+open,
1553
+ * que reabre o mesmo banco. `clearAll()` é o método correto.
1554
+ */
1555
+ async clearAll() {
1556
+ if (this.db !== null) {
1557
+ this.db.close();
1558
+ this.db = null;
1559
+ }
1560
+ await new Promise((resolve, reject) => {
1561
+ const req = indexedDB.deleteDatabase(this.dbName);
1562
+ req.onsuccess = () => resolve();
1563
+ req.onerror = () => reject(req.error);
1564
+ req.onblocked = () => {
1565
+ };
1566
+ });
1567
+ await this.open();
1568
+ }
1482
1569
  assertOpen() {
1483
1570
  if (this.db === null) {
1484
1571
  throw new Error("LocalStore: banco n\xE3o est\xE1 aberto. Chame open() primeiro.");
@@ -1686,6 +1773,12 @@ var MemoryStore = class {
1686
1773
  async open() {
1687
1774
  }
1688
1775
  async close() {
1776
+ }
1777
+ /**
1778
+ * Apaga todos os dados em memória — equivalente ao `indexedDB.deleteDatabase`
1779
+ * que `LocalStore.clearAll()` executa em ambientes com IndexedDB.
1780
+ */
1781
+ async clearAll() {
1689
1782
  this._docs.clear();
1690
1783
  this._mutations.clear();
1691
1784
  this._meta.clear();
@@ -2200,6 +2293,8 @@ var SyncEngine = class {
2200
2293
  const phase1Ok = await this._phase1Push();
2201
2294
  if (!phase1Ok) {
2202
2295
  this._updateState({ status: "idle" });
2296
+ this._refreshPendingWrites().catch(() => {
2297
+ });
2203
2298
  this._syncing = false;
2204
2299
  return;
2205
2300
  }
@@ -2586,7 +2681,7 @@ var SyncEngine = class {
2586
2681
  ownerId: localDoc.meta.ownerId
2587
2682
  }
2588
2683
  };
2589
- const pendingMuts = await this._queue.drain();
2684
+ const pendingMuts = await this._queue.listAll();
2590
2685
  const docMut = pendingMuts.find(
2591
2686
  (m) => m.collection === serverDoc.collection && m.docId === serverDoc.id
2592
2687
  );
@@ -3940,8 +4035,13 @@ var NeetruDbDocumentsImpl = class {
3940
4035
  return this._engine.flush();
3941
4036
  }
3942
4037
  async clearCache() {
3943
- await this._store.close();
3944
- await this._store.open();
4038
+ const storeWithClear = this._store;
4039
+ if (typeof storeWithClear.clearAll === "function") {
4040
+ await storeWithClear.clearAll();
4041
+ } else {
4042
+ await this._store.close();
4043
+ await this._store.open();
4044
+ }
3945
4045
  }
3946
4046
  async getConflicts() {
3947
4047
  return this._store.listConflicts();
@@ -4828,7 +4928,8 @@ function createHttpCheckoutNamespace(config) {
4828
4928
  method: "POST",
4829
4929
  path: "/api/v1/checkout/intents",
4830
4930
  body,
4831
- requireAuth: true
4931
+ requireAuth: true,
4932
+ idempotencyKey: true
4832
4933
  });
4833
4934
  const result = parseStartResponse(raw);
4834
4935
  const shouldRedirect = input.autoRedirect !== false;
@@ -5583,6 +5684,7 @@ function createOidcAuthNamespace(config) {
5583
5684
  const STORAGE_KEY = "neetru_id_token";
5584
5685
  const listeners = /* @__PURE__ */ new Set();
5585
5686
  let cachedUser = null;
5687
+ let _expiryTimerId = null;
5586
5688
  function getStorage() {
5587
5689
  try {
5588
5690
  return typeof globalThis.localStorage !== "undefined" ? globalThis.localStorage : null;
@@ -5605,6 +5707,9 @@ function createOidcAuthNamespace(config) {
5605
5707
  function tokenToUser(token) {
5606
5708
  const payload = decodeJwtPayload(token);
5607
5709
  if (!payload || typeof payload.sub !== "string") return null;
5710
+ if (typeof payload.exp === "number" && payload.exp * 1e3 < Date.now()) {
5711
+ return null;
5712
+ }
5608
5713
  return {
5609
5714
  uid: payload.sub,
5610
5715
  email: typeof payload.email === "string" ? payload.email : "",
@@ -5618,12 +5723,28 @@ function createOidcAuthNamespace(config) {
5618
5723
  };
5619
5724
  }
5620
5725
  function loadCachedUser() {
5621
- if (cachedUser) return cachedUser;
5726
+ if (cachedUser) {
5727
+ const exp = cachedUser.exp;
5728
+ if (typeof exp === "number" && exp * 1e3 < Date.now()) {
5729
+ cachedUser = null;
5730
+ const storage2 = getStorage();
5731
+ storage2?.removeItem(STORAGE_KEY);
5732
+ notify();
5733
+ return null;
5734
+ }
5735
+ return cachedUser;
5736
+ }
5622
5737
  const storage = getStorage();
5623
5738
  if (!storage) return null;
5624
5739
  const token = storage.getItem(STORAGE_KEY);
5625
5740
  if (!token) return null;
5626
- cachedUser = tokenToUser(token);
5741
+ const user = tokenToUser(token);
5742
+ if (!user) {
5743
+ storage.removeItem(STORAGE_KEY);
5744
+ return null;
5745
+ }
5746
+ cachedUser = user;
5747
+ scheduleExpiryTimer(user);
5627
5748
  return cachedUser;
5628
5749
  }
5629
5750
  function notify() {
@@ -5634,6 +5755,23 @@ function createOidcAuthNamespace(config) {
5634
5755
  }
5635
5756
  }
5636
5757
  }
5758
+ function cancelExpiryTimer() {
5759
+ if (_expiryTimerId !== null) {
5760
+ clearTimeout(_expiryTimerId);
5761
+ _expiryTimerId = null;
5762
+ }
5763
+ }
5764
+ function scheduleExpiryTimer(user) {
5765
+ cancelExpiryTimer();
5766
+ const exp = user.exp;
5767
+ if (typeof exp !== "number") return;
5768
+ const msUntilExpiry = exp * 1e3 - Date.now();
5769
+ if (msUntilExpiry <= 0) return;
5770
+ _expiryTimerId = setTimeout(() => {
5771
+ _expiryTimerId = null;
5772
+ loadCachedUser();
5773
+ }, msUntilExpiry + 1);
5774
+ }
5637
5775
  return {
5638
5776
  async signIn(options) {
5639
5777
  if (typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function") {
@@ -5661,18 +5799,24 @@ function createOidcAuthNamespace(config) {
5661
5799
  },
5662
5800
  async signOut() {
5663
5801
  const storage = getStorage();
5802
+ const storedToken = storage?.getItem(STORAGE_KEY) ?? null;
5664
5803
  if (storage) storage.removeItem(STORAGE_KEY);
5804
+ cancelExpiryTimer();
5665
5805
  cachedUser = null;
5666
5806
  const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
5667
5807
  const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
5668
5808
  const revokeUrl = `${idpOrigin}/api/v1/oauth/revoke`;
5809
+ const revokeBody = storedToken ? JSON.stringify({ token: storedToken }) : null;
5669
5810
  let revokeError = null;
5670
5811
  for (let attempt = 0; attempt < 2; attempt++) {
5671
5812
  try {
5672
- await config.fetch(revokeUrl, {
5673
- method: "POST",
5674
- headers: { "content-type": "application/json" }
5675
- });
5813
+ if (revokeBody) {
5814
+ await config.fetch(revokeUrl, {
5815
+ method: "POST",
5816
+ headers: { "content-type": "application/json" },
5817
+ body: revokeBody
5818
+ });
5819
+ }
5676
5820
  revokeError = null;
5677
5821
  break;
5678
5822
  } catch (err) {