@neetru/sdk 3.0.2 → 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 (98) hide show
  1. package/CHANGELOG.md +554 -530
  2. package/dist/auth.cjs +219 -54
  3. package/dist/auth.cjs.map +1 -1
  4. package/dist/auth.d.cts +1 -2
  5. package/dist/auth.d.ts +1 -2
  6. package/dist/auth.mjs +219 -54
  7. package/dist/auth.mjs.map +1 -1
  8. package/dist/catalog.cjs +50 -2
  9. package/dist/catalog.cjs.map +1 -1
  10. package/dist/catalog.d.cts +1 -2
  11. package/dist/catalog.d.ts +1 -2
  12. package/dist/catalog.mjs +50 -2
  13. package/dist/catalog.mjs.map +1 -1
  14. package/dist/checkout.cjs +52 -3
  15. package/dist/checkout.cjs.map +1 -1
  16. package/dist/checkout.d.cts +1 -2
  17. package/dist/checkout.d.ts +1 -2
  18. package/dist/checkout.mjs +52 -3
  19. package/dist/checkout.mjs.map +1 -1
  20. package/dist/db-react.cjs +18 -6
  21. package/dist/db-react.cjs.map +1 -1
  22. package/dist/db-react.d.cts +35 -13
  23. package/dist/db-react.d.ts +35 -13
  24. package/dist/db-react.mjs +18 -6
  25. package/dist/db-react.mjs.map +1 -1
  26. package/dist/db.cjs +164 -56
  27. package/dist/db.cjs.map +1 -1
  28. package/dist/db.d.cts +1 -2
  29. package/dist/db.d.ts +1 -2
  30. package/dist/db.mjs +164 -56
  31. package/dist/db.mjs.map +1 -1
  32. package/dist/entitlements.cjs +50 -2
  33. package/dist/entitlements.cjs.map +1 -1
  34. package/dist/entitlements.d.cts +1 -2
  35. package/dist/entitlements.d.ts +1 -2
  36. package/dist/entitlements.mjs +50 -2
  37. package/dist/entitlements.mjs.map +1 -1
  38. package/dist/errors.cjs.map +1 -1
  39. package/dist/errors.d.cts +3 -1
  40. package/dist/errors.d.ts +3 -1
  41. package/dist/errors.mjs.map +1 -1
  42. package/dist/firestore-compat.cjs +411 -0
  43. package/dist/firestore-compat.cjs.map +1 -0
  44. package/dist/firestore-compat.d.cts +319 -0
  45. package/dist/firestore-compat.d.ts +319 -0
  46. package/dist/firestore-compat.mjs +383 -0
  47. package/dist/firestore-compat.mjs.map +1 -0
  48. package/dist/index.cjs +266 -66
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +9 -4
  51. package/dist/index.d.ts +9 -4
  52. package/dist/index.mjs +265 -67
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/mocks.cjs.map +1 -1
  55. package/dist/mocks.d.cts +1 -2
  56. package/dist/mocks.d.ts +1 -2
  57. package/dist/mocks.mjs.map +1 -1
  58. package/dist/notifications.cjs +50 -2
  59. package/dist/notifications.cjs.map +1 -1
  60. package/dist/notifications.d.cts +1 -2
  61. package/dist/notifications.d.ts +1 -2
  62. package/dist/notifications.mjs +50 -2
  63. package/dist/notifications.mjs.map +1 -1
  64. package/dist/react.cjs +268 -2
  65. package/dist/react.cjs.map +1 -1
  66. package/dist/react.d.cts +135 -3
  67. package/dist/react.d.ts +135 -3
  68. package/dist/react.mjs +266 -3
  69. package/dist/react.mjs.map +1 -1
  70. package/dist/support.cjs +50 -2
  71. package/dist/support.cjs.map +1 -1
  72. package/dist/support.d.cts +1 -2
  73. package/dist/support.d.ts +1 -2
  74. package/dist/support.mjs +50 -2
  75. package/dist/support.mjs.map +1 -1
  76. package/dist/telemetry.cjs +65 -4
  77. package/dist/telemetry.cjs.map +1 -1
  78. package/dist/telemetry.d.cts +1 -2
  79. package/dist/telemetry.d.ts +1 -2
  80. package/dist/telemetry.mjs +65 -4
  81. package/dist/telemetry.mjs.map +1 -1
  82. package/dist/{types-D7zVkO3n.d.ts → types-B3XFHD4A.d.ts} +640 -2
  83. package/dist/{types-Dc4bjrrt.d.cts → types-DePdSU3P.d.cts} +640 -2
  84. package/dist/usage.cjs +50 -2
  85. package/dist/usage.cjs.map +1 -1
  86. package/dist/usage.d.cts +1 -2
  87. package/dist/usage.d.ts +1 -2
  88. package/dist/usage.mjs +50 -2
  89. package/dist/usage.mjs.map +1 -1
  90. package/dist/webhooks.cjs +83 -2
  91. package/dist/webhooks.cjs.map +1 -1
  92. package/dist/webhooks.d.cts +1 -2
  93. package/dist/webhooks.d.ts +1 -2
  94. package/dist/webhooks.mjs +83 -3
  95. package/dist/webhooks.mjs.map +1 -1
  96. package/package.json +156 -151
  97. package/dist/collection-ref-BDdfD87k.d.cts +0 -581
  98. package/dist/collection-ref-BDdfD87k.d.ts +0 -581
package/dist/index.d.cts CHANGED
@@ -1,10 +1,15 @@
1
1
  export { createNeetruClient } from './auth.cjs';
2
2
  export { NeetruError, NeetruErrorCode } from './errors.cjs';
3
- export { A as AuthNamespace, a as AuthStateListener, C as CatalogListOptions, b as CatalogListResponse, c as CheckoutIntentInfo, d as CheckoutIntentStatus, e as CheckoutNamespace, f as CheckoutStartInput, g as CheckoutStartResult, h as CheckoutTenantType, i as CreateTicketInput, D as DEFAULT_BASE_URL, j as DbNamespace, k as DbSqlLease, l as DbWhereFilter, E as EntitlementCheck, L as ListNotificationsOptions, M as MockCheckout, m as MockNotifications, n as MockWebhooks, N as NeetruClient, o as NeetruClientConfig, p as NeetruDb, q as NeetruDbEngine, r as NeetruDbError, s as NeetruDbErrorCode, t as NeetruDbOptions, u as NeetruDbTransport, v as NeetruEnv, w as NeetruSqlClient, x as NeetruUser, y as NotificationScopeOptions, z as NotificationsNamespace, P as Product, B as ProductNotification, F as ProductNotificationSeverity, G as ProductPlan, H as ProductStatus, R as RegisterWebhookInput, I as ResolvedConfig, S as SendNotificationInput, J as SignInOptions, O as SupportNamespace, Q as SupportSeverity, T as SupportStatus, U as SupportTicket, V as TelemetryEventAck, W as TelemetryEventInput, Z as UsageEventInput, _ as UsageNamespace, $ as UsageQuota, a0 as VerifyTokenOptions, a1 as WebhookEndpoint, a2 as WebhookEvent, a3 as WebhookScopeOptions, a4 as WebhookTestResult, a5 as WebhooksNamespace, a6 as createCheckoutNamespace, a7 as createNeetruDb, a8 as createNotificationsNamespace, aa as createWebhooksNamespace, ac as verifyWebhookSignature } from './types-Dc4bjrrt.cjs';
4
- export { D as DbBatchOp, b as DbChangeType, c as DbCollectionRef, d as DbDoc, e as DbDocRef, f as DbGetResult, g as DbListResult, h as DbQuery, F as FieldSentinel, I as IncrementSentinel, N as NEETRU_SENTINEL_KEY, S as ServerTimestampSentinel, W as WithFieldSentinels, l as increment, m as isFieldSentinel, n as isIncrementSentinel, o as isServerTimestampSentinel, s as serverTimestamp } from './collection-ref-BDdfD87k.cjs';
3
+ export { A as AuthNamespace, a as AuthStateListener, C as CatalogListOptions, b as CatalogListResponse, c as CheckoutIntentInfo, d as CheckoutIntentStatus, e as CheckoutNamespace, f as CheckoutStartInput, g as CheckoutStartResult, h as CheckoutTenantType, k as CreateTicketInput, D as DEFAULT_BASE_URL, l as DbBatchOp, m as DbChangeType, n as DbCollectionRef, o as DbDoc, p as DbDocRef, q as DbGetResult, r as DbListResult, s as DbNamespace, t as DbQuery, u as DbSqlLease, v as DbWhereFilter, E as EntitlementCheck, F as FieldSentinel, I as IncrementSentinel, L as ListNotificationsOptions, M as MockCheckout, x as MockNotifications, y as MockWebhooks, N as NEETRU_SENTINEL_KEY, z as NeetruClient, B as NeetruClientConfig, G as NeetruDb, J as NeetruDbEngine, K as NeetruDbError, O as NeetruDbErrorCode, P as NeetruDbOptions, Q as NeetruDbTransport, R as NeetruEnv, S as NeetruSqlClient, T as NeetruUser, U as NotificationScopeOptions, V as NotificationsNamespace, W as Product, X as ProductNotification, Y as ProductNotificationSeverity, Z as ProductPlan, _ as ProductStatus, a0 as RegisterWebhookInput, a1 as ResolvedConfig, a2 as SendNotificationInput, a3 as ServerTimestampSentinel, a4 as SignInOptions, a6 as SupportNamespace, a7 as SupportSeverity, a8 as SupportStatus, a9 as SupportTicket, ab as TelemetryEventAck, ac as TelemetryEventInput, ag as UsageEventInput, ah as UsageNamespace, ai as UsageQuota, aj as VerifyTokenOptions, ak as VerifyWebhookRequestOptions, al as VerifyWebhookRequestResult, am as WebhookEndpoint, an as WebhookEvent, ao as WebhookScopeOptions, ap as WebhookTestResult, aq as WebhooksNamespace, ar as WithFieldSentinels, as as createCheckoutNamespace, at as createNeetruDb, au as createNotificationsNamespace, aw as createWebhooksNamespace, ay as increment, az as isFieldSentinel, aA as isIncrementSentinel, aB as isServerTimestampSentinel, aC as serverTimestamp, aD as verifyWebhookRequest, aE as verifyWebhookSignature } from './types-DePdSU3P.cjs';
5
4
  export { DEV_FIXTURE_USER, MockAuth, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.cjs';
6
5
  import 'drizzle-orm/node-postgres';
7
6
 
7
+ /**
8
+ * Verifica se a versão do Core (`X-Neetru-Version`) é compatível com a SDK major.
9
+ * Emite `console.warn` quando incompatível (uma vez por processo por versão detectada).
10
+ */
11
+ declare function checkCoreVersionCompat(coreVersion: string): void;
12
+
8
13
  /**
9
14
  * @neetru/sdk — biblioteca runtime para consumir o ecossistema Neetru.
10
15
  *
@@ -37,6 +42,6 @@ import 'drizzle-orm/node-postgres';
37
42
  */
38
43
 
39
44
  /** Versão do SDK — exportada explicitamente pra detecção em runtime. */
40
- declare const VERSION: "3.0.1";
45
+ declare const VERSION: "3.1.1";
41
46
 
42
- export { VERSION };
47
+ export { VERSION, checkCoreVersionCompat };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  export { createNeetruClient } from './auth.js';
2
2
  export { NeetruError, NeetruErrorCode } from './errors.js';
3
- export { A as AuthNamespace, a as AuthStateListener, C as CatalogListOptions, b as CatalogListResponse, c as CheckoutIntentInfo, d as CheckoutIntentStatus, e as CheckoutNamespace, f as CheckoutStartInput, g as CheckoutStartResult, h as CheckoutTenantType, i as CreateTicketInput, D as DEFAULT_BASE_URL, j as DbNamespace, k as DbSqlLease, l as DbWhereFilter, E as EntitlementCheck, L as ListNotificationsOptions, M as MockCheckout, m as MockNotifications, n as MockWebhooks, N as NeetruClient, o as NeetruClientConfig, p as NeetruDb, q as NeetruDbEngine, r as NeetruDbError, s as NeetruDbErrorCode, t as NeetruDbOptions, u as NeetruDbTransport, v as NeetruEnv, w as NeetruSqlClient, x as NeetruUser, y as NotificationScopeOptions, z as NotificationsNamespace, P as Product, B as ProductNotification, F as ProductNotificationSeverity, G as ProductPlan, H as ProductStatus, R as RegisterWebhookInput, I as ResolvedConfig, S as SendNotificationInput, J as SignInOptions, O as SupportNamespace, Q as SupportSeverity, T as SupportStatus, U as SupportTicket, V as TelemetryEventAck, W as TelemetryEventInput, Z as UsageEventInput, _ as UsageNamespace, $ as UsageQuota, a0 as VerifyTokenOptions, a1 as WebhookEndpoint, a2 as WebhookEvent, a3 as WebhookScopeOptions, a4 as WebhookTestResult, a5 as WebhooksNamespace, a6 as createCheckoutNamespace, a7 as createNeetruDb, a8 as createNotificationsNamespace, aa as createWebhooksNamespace, ac as verifyWebhookSignature } from './types-D7zVkO3n.js';
4
- export { D as DbBatchOp, b as DbChangeType, c as DbCollectionRef, d as DbDoc, e as DbDocRef, f as DbGetResult, g as DbListResult, h as DbQuery, F as FieldSentinel, I as IncrementSentinel, N as NEETRU_SENTINEL_KEY, S as ServerTimestampSentinel, W as WithFieldSentinels, l as increment, m as isFieldSentinel, n as isIncrementSentinel, o as isServerTimestampSentinel, s as serverTimestamp } from './collection-ref-BDdfD87k.js';
3
+ export { A as AuthNamespace, a as AuthStateListener, C as CatalogListOptions, b as CatalogListResponse, c as CheckoutIntentInfo, d as CheckoutIntentStatus, e as CheckoutNamespace, f as CheckoutStartInput, g as CheckoutStartResult, h as CheckoutTenantType, k as CreateTicketInput, D as DEFAULT_BASE_URL, l as DbBatchOp, m as DbChangeType, n as DbCollectionRef, o as DbDoc, p as DbDocRef, q as DbGetResult, r as DbListResult, s as DbNamespace, t as DbQuery, u as DbSqlLease, v as DbWhereFilter, E as EntitlementCheck, F as FieldSentinel, I as IncrementSentinel, L as ListNotificationsOptions, M as MockCheckout, x as MockNotifications, y as MockWebhooks, N as NEETRU_SENTINEL_KEY, z as NeetruClient, B as NeetruClientConfig, G as NeetruDb, J as NeetruDbEngine, K as NeetruDbError, O as NeetruDbErrorCode, P as NeetruDbOptions, Q as NeetruDbTransport, R as NeetruEnv, S as NeetruSqlClient, T as NeetruUser, U as NotificationScopeOptions, V as NotificationsNamespace, W as Product, X as ProductNotification, Y as ProductNotificationSeverity, Z as ProductPlan, _ as ProductStatus, a0 as RegisterWebhookInput, a1 as ResolvedConfig, a2 as SendNotificationInput, a3 as ServerTimestampSentinel, a4 as SignInOptions, a6 as SupportNamespace, a7 as SupportSeverity, a8 as SupportStatus, a9 as SupportTicket, ab as TelemetryEventAck, ac as TelemetryEventInput, ag as UsageEventInput, ah as UsageNamespace, ai as UsageQuota, aj as VerifyTokenOptions, ak as VerifyWebhookRequestOptions, al as VerifyWebhookRequestResult, am as WebhookEndpoint, an as WebhookEvent, ao as WebhookScopeOptions, ap as WebhookTestResult, aq as WebhooksNamespace, ar as WithFieldSentinels, as as createCheckoutNamespace, at as createNeetruDb, au as createNotificationsNamespace, aw as createWebhooksNamespace, ay as increment, az as isFieldSentinel, aA as isIncrementSentinel, aB as isServerTimestampSentinel, aC as serverTimestamp, aD as verifyWebhookRequest, aE as verifyWebhookSignature } from './types-B3XFHD4A.js';
5
4
  export { DEV_FIXTURE_USER, MockAuth, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.js';
6
5
  import 'drizzle-orm/node-postgres';
7
6
 
7
+ /**
8
+ * Verifica se a versão do Core (`X-Neetru-Version`) é compatível com a SDK major.
9
+ * Emite `console.warn` quando incompatível (uma vez por processo por versão detectada).
10
+ */
11
+ declare function checkCoreVersionCompat(coreVersion: string): void;
12
+
8
13
  /**
9
14
  * @neetru/sdk — biblioteca runtime para consumir o ecossistema Neetru.
10
15
  *
@@ -37,6 +42,6 @@ import 'drizzle-orm/node-postgres';
37
42
  */
38
43
 
39
44
  /** Versão do SDK — exportada explicitamente pra detecção em runtime. */
40
- declare const VERSION: "3.0.1";
45
+ declare const VERSION: "3.1.1";
41
46
 
42
- export { VERSION };
47
+ export { VERSION, checkCoreVersionCompat };
package/dist/index.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();
@@ -2041,7 +2134,71 @@ var MutationQueue = class {
2041
2134
  }
2042
2135
  };
2043
2136
 
2137
+ // src/db/field-value.ts
2138
+ var NEETRU_SENTINEL_KEY = "__neetru__";
2139
+ function serverTimestamp() {
2140
+ return { __neetru__: "serverTimestamp" };
2141
+ }
2142
+ function increment(n) {
2143
+ if (typeof n !== "number" || !Number.isFinite(n)) {
2144
+ throw new TypeError(
2145
+ `increment(n): n deve ser um n\xFAmero finito (recebido: ${String(n)}).`
2146
+ );
2147
+ }
2148
+ return { __neetru__: "increment", operand: n };
2149
+ }
2150
+ function isFieldSentinel(v) {
2151
+ return typeof v === "object" && v !== null && NEETRU_SENTINEL_KEY in v && typeof v[NEETRU_SENTINEL_KEY] === "string";
2152
+ }
2153
+ function isServerTimestampSentinel(v) {
2154
+ return isFieldSentinel(v) && v.__neetru__ === "serverTimestamp";
2155
+ }
2156
+ function isIncrementSentinel(v) {
2157
+ return isFieldSentinel(v) && v.__neetru__ === "increment" && typeof v.operand === "number" && Number.isFinite(v.operand);
2158
+ }
2159
+ function resolveSentinelLocally(value, baseValue) {
2160
+ if (isServerTimestampSentinel(value)) {
2161
+ return Date.now();
2162
+ }
2163
+ if (isIncrementSentinel(value)) {
2164
+ const base = typeof baseValue === "number" && Number.isFinite(baseValue) ? baseValue : 0;
2165
+ return base + value.operand;
2166
+ }
2167
+ return value;
2168
+ }
2169
+ function resolveSentinelsLocally(data, existing) {
2170
+ let touched = false;
2171
+ const out = {};
2172
+ for (const [k, v] of Object.entries(data)) {
2173
+ if (isFieldSentinel(v)) {
2174
+ touched = true;
2175
+ out[k] = resolveSentinelLocally(v, existing?.[k]);
2176
+ } else {
2177
+ out[k] = v;
2178
+ }
2179
+ }
2180
+ return touched ? out : data;
2181
+ }
2182
+ function hasFieldSentinel(data) {
2183
+ for (const v of Object.values(data)) {
2184
+ if (isFieldSentinel(v)) return true;
2185
+ }
2186
+ return false;
2187
+ }
2188
+
2044
2189
  // src/db/offline/sync-engine.ts
2190
+ function hasSentinels(payload) {
2191
+ return payload !== null && hasFieldSentinel(payload);
2192
+ }
2193
+ function sanitizeSentinelPayload(payload) {
2194
+ if (payload === null) return null;
2195
+ if (!hasFieldSentinel(payload)) return payload;
2196
+ const out = {};
2197
+ for (const [k, v] of Object.entries(payload)) {
2198
+ if (!isFieldSentinel(v)) out[k] = v;
2199
+ }
2200
+ return out;
2201
+ }
2045
2202
  var SyncEngine = class {
2046
2203
  _store;
2047
2204
  _queue;
@@ -2147,6 +2304,8 @@ var SyncEngine = class {
2147
2304
  const phase1Ok = await this._phase1Push();
2148
2305
  if (!phase1Ok) {
2149
2306
  this._updateState({ status: "idle" });
2307
+ this._refreshPendingWrites().catch(() => {
2308
+ });
2150
2309
  this._syncing = false;
2151
2310
  return;
2152
2311
  }
@@ -2249,11 +2408,16 @@ var SyncEngine = class {
2249
2408
  }
2250
2409
  return;
2251
2410
  }
2252
- const newData = mut.payload ?? (existing?.data ?? {});
2411
+ const literalPayload = sanitizeSentinelPayload(mut.payload);
2412
+ const newData = literalPayload ?? (existing?.data ?? {});
2253
2413
  const updatedDoc = {
2254
2414
  collection,
2255
2415
  id: docId,
2256
- data: mut.op === "update" ? { ...existing?.data ?? {}, ...newData } : newData,
2416
+ data: mut.op === "update" ? { ...existing?.data ?? {}, ...newData } : (
2417
+ // add/set: se o payload tinha sentinels, o cache otimista (existing.data)
2418
+ // é a fonte de verdade até o pull; senão usa o payload literal.
2419
+ hasSentinels(mut.payload) ? { ...existing?.data ?? {}, ...newData } : newData
2420
+ ),
2257
2421
  meta: {
2258
2422
  serverVersion,
2259
2423
  updatedAtServer: serverTimestamp2,
@@ -2528,7 +2692,7 @@ var SyncEngine = class {
2528
2692
  ownerId: localDoc.meta.ownerId
2529
2693
  }
2530
2694
  };
2531
- const pendingMuts = await this._queue.drain();
2695
+ const pendingMuts = await this._queue.listAll();
2532
2696
  const docMut = pendingMuts.find(
2533
2697
  (m) => m.collection === serverDoc.collection && m.docId === serverDoc.id
2534
2698
  );
@@ -3335,54 +3499,6 @@ var TabCoordinator = class {
3335
3499
 
3336
3500
  // src/db/collection-ref.ts
3337
3501
  init_db_errors();
3338
-
3339
- // src/db/field-value.ts
3340
- var NEETRU_SENTINEL_KEY = "__neetru__";
3341
- function serverTimestamp() {
3342
- return { __neetru__: "serverTimestamp" };
3343
- }
3344
- function increment(n) {
3345
- if (typeof n !== "number" || !Number.isFinite(n)) {
3346
- throw new TypeError(
3347
- `increment(n): n deve ser um n\xFAmero finito (recebido: ${String(n)}).`
3348
- );
3349
- }
3350
- return { __neetru__: "increment", operand: n };
3351
- }
3352
- function isFieldSentinel(v) {
3353
- return typeof v === "object" && v !== null && NEETRU_SENTINEL_KEY in v && typeof v[NEETRU_SENTINEL_KEY] === "string";
3354
- }
3355
- function isServerTimestampSentinel(v) {
3356
- return isFieldSentinel(v) && v.__neetru__ === "serverTimestamp";
3357
- }
3358
- function isIncrementSentinel(v) {
3359
- return isFieldSentinel(v) && v.__neetru__ === "increment" && typeof v.operand === "number" && Number.isFinite(v.operand);
3360
- }
3361
- function resolveSentinelLocally(value, baseValue) {
3362
- if (isServerTimestampSentinel(value)) {
3363
- return Date.now();
3364
- }
3365
- if (isIncrementSentinel(value)) {
3366
- const base = typeof baseValue === "number" && Number.isFinite(baseValue) ? baseValue : 0;
3367
- return base + value.operand;
3368
- }
3369
- return value;
3370
- }
3371
- function resolveSentinelsLocally(data, existing) {
3372
- let touched = false;
3373
- const out = {};
3374
- for (const [k, v] of Object.entries(data)) {
3375
- if (isFieldSentinel(v)) {
3376
- touched = true;
3377
- out[k] = resolveSentinelLocally(v, existing?.[k]);
3378
- } else {
3379
- out[k] = v;
3380
- }
3381
- }
3382
- return touched ? out : data;
3383
- }
3384
-
3385
- // src/db/collection-ref.ts
3386
3502
  function isIndexedDBUnavailable() {
3387
3503
  return typeof indexedDB === "undefined" || typeof window === "undefined";
3388
3504
  }
@@ -3930,8 +4046,13 @@ var NeetruDbDocumentsImpl = class {
3930
4046
  return this._engine.flush();
3931
4047
  }
3932
4048
  async clearCache() {
3933
- await this._store.close();
3934
- await this._store.open();
4049
+ const storeWithClear = this._store;
4050
+ if (typeof storeWithClear.clearAll === "function") {
4051
+ await storeWithClear.clearAll();
4052
+ } else {
4053
+ await this._store.close();
4054
+ await this._store.open();
4055
+ }
3935
4056
  }
3936
4057
  async getConflicts() {
3937
4058
  return this._store.listConflicts();
@@ -4818,7 +4939,8 @@ function createHttpCheckoutNamespace(config) {
4818
4939
  method: "POST",
4819
4940
  path: "/api/v1/checkout/intents",
4820
4941
  body,
4821
- requireAuth: true
4942
+ requireAuth: true,
4943
+ idempotencyKey: true
4822
4944
  });
4823
4945
  const result = parseStartResponse(raw);
4824
4946
  const shouldRedirect = input.autoRedirect !== false;
@@ -4949,6 +5071,38 @@ async function verifyWebhookSignature(payload, signature, secret) {
4949
5071
  }
4950
5072
  return diff === 0;
4951
5073
  }
5074
+ async function verifyWebhookRequest(payload, headers, secret, options = {}) {
5075
+ const toleranceMs = options.toleranceMs ?? 3e5;
5076
+ const getHeader = (name) => {
5077
+ if (typeof headers.get === "function") {
5078
+ return headers.get(name);
5079
+ }
5080
+ const rec = headers;
5081
+ const lower = name.toLowerCase();
5082
+ for (const key of Object.keys(rec)) {
5083
+ if (key.toLowerCase() === lower) return rec[key] ?? null;
5084
+ }
5085
+ return null;
5086
+ };
5087
+ const tsHeader = getHeader("x-neetru-timestamp");
5088
+ if (!tsHeader) {
5089
+ return { ok: false, reason: "timestamp_missing" };
5090
+ }
5091
+ const tsMs = Number(tsHeader);
5092
+ if (!Number.isFinite(tsMs)) {
5093
+ return { ok: false, reason: "timestamp_missing" };
5094
+ }
5095
+ const skewMs = Math.abs(Date.now() - tsMs);
5096
+ if (skewMs > toleranceMs) {
5097
+ return { ok: false, reason: "timestamp_expired" };
5098
+ }
5099
+ const sig = getHeader("x-neetru-signature");
5100
+ const valid = await verifyWebhookSignature(payload, sig, secret);
5101
+ if (!valid) {
5102
+ return { ok: false, reason: "invalid_signature" };
5103
+ }
5104
+ return { ok: true };
5105
+ }
4952
5106
  function hexToBytes(hex) {
4953
5107
  if (hex.length % 2 !== 0) return null;
4954
5108
  const bytes = new Uint8Array(hex.length / 2);
@@ -5931,6 +6085,7 @@ function createOidcAuthNamespace(config) {
5931
6085
  const STORAGE_KEY = "neetru_id_token";
5932
6086
  const listeners = /* @__PURE__ */ new Set();
5933
6087
  let cachedUser = null;
6088
+ let _expiryTimerId = null;
5934
6089
  function getStorage() {
5935
6090
  try {
5936
6091
  return typeof globalThis.localStorage !== "undefined" ? globalThis.localStorage : null;
@@ -5953,6 +6108,9 @@ function createOidcAuthNamespace(config) {
5953
6108
  function tokenToUser(token) {
5954
6109
  const payload = decodeJwtPayload(token);
5955
6110
  if (!payload || typeof payload.sub !== "string") return null;
6111
+ if (typeof payload.exp === "number" && payload.exp * 1e3 < Date.now()) {
6112
+ return null;
6113
+ }
5956
6114
  return {
5957
6115
  uid: payload.sub,
5958
6116
  email: typeof payload.email === "string" ? payload.email : "",
@@ -5966,12 +6124,28 @@ function createOidcAuthNamespace(config) {
5966
6124
  };
5967
6125
  }
5968
6126
  function loadCachedUser() {
5969
- if (cachedUser) return cachedUser;
6127
+ if (cachedUser) {
6128
+ const exp = cachedUser.exp;
6129
+ if (typeof exp === "number" && exp * 1e3 < Date.now()) {
6130
+ cachedUser = null;
6131
+ const storage2 = getStorage();
6132
+ storage2?.removeItem(STORAGE_KEY);
6133
+ notify();
6134
+ return null;
6135
+ }
6136
+ return cachedUser;
6137
+ }
5970
6138
  const storage = getStorage();
5971
6139
  if (!storage) return null;
5972
6140
  const token = storage.getItem(STORAGE_KEY);
5973
6141
  if (!token) return null;
5974
- cachedUser = tokenToUser(token);
6142
+ const user = tokenToUser(token);
6143
+ if (!user) {
6144
+ storage.removeItem(STORAGE_KEY);
6145
+ return null;
6146
+ }
6147
+ cachedUser = user;
6148
+ scheduleExpiryTimer(user);
5975
6149
  return cachedUser;
5976
6150
  }
5977
6151
  function notify() {
@@ -5982,6 +6156,23 @@ function createOidcAuthNamespace(config) {
5982
6156
  }
5983
6157
  }
5984
6158
  }
6159
+ function cancelExpiryTimer() {
6160
+ if (_expiryTimerId !== null) {
6161
+ clearTimeout(_expiryTimerId);
6162
+ _expiryTimerId = null;
6163
+ }
6164
+ }
6165
+ function scheduleExpiryTimer(user) {
6166
+ cancelExpiryTimer();
6167
+ const exp = user.exp;
6168
+ if (typeof exp !== "number") return;
6169
+ const msUntilExpiry = exp * 1e3 - Date.now();
6170
+ if (msUntilExpiry <= 0) return;
6171
+ _expiryTimerId = setTimeout(() => {
6172
+ _expiryTimerId = null;
6173
+ loadCachedUser();
6174
+ }, msUntilExpiry + 1);
6175
+ }
5985
6176
  return {
5986
6177
  async signIn(options) {
5987
6178
  if (typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function") {
@@ -6009,18 +6200,24 @@ function createOidcAuthNamespace(config) {
6009
6200
  },
6010
6201
  async signOut() {
6011
6202
  const storage = getStorage();
6203
+ const storedToken = storage?.getItem(STORAGE_KEY) ?? null;
6012
6204
  if (storage) storage.removeItem(STORAGE_KEY);
6205
+ cancelExpiryTimer();
6013
6206
  cachedUser = null;
6014
6207
  const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
6015
6208
  const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
6016
6209
  const revokeUrl = `${idpOrigin}/api/v1/oauth/revoke`;
6210
+ const revokeBody = storedToken ? JSON.stringify({ token: storedToken }) : null;
6017
6211
  let revokeError = null;
6018
6212
  for (let attempt = 0; attempt < 2; attempt++) {
6019
6213
  try {
6020
- await config.fetch(revokeUrl, {
6021
- method: "POST",
6022
- headers: { "content-type": "application/json" }
6023
- });
6214
+ if (revokeBody) {
6215
+ await config.fetch(revokeUrl, {
6216
+ method: "POST",
6217
+ headers: { "content-type": "application/json" },
6218
+ body: revokeBody
6219
+ });
6220
+ }
6024
6221
  revokeError = null;
6025
6222
  break;
6026
6223
  } catch (err) {
@@ -6140,8 +6337,9 @@ function createNeetruClient(config = {}) {
6140
6337
  // src/index.ts
6141
6338
  init_errors();
6142
6339
  init_db_errors();
6143
- var VERSION = "3.0.1";
6340
+ init_http();
6341
+ var VERSION = "3.1.1";
6144
6342
 
6145
- export { DEFAULT_BASE_URL, DEV_FIXTURE_USER, MockAuth, MockCheckout, MockDb, MockEntitlements, MockNotifications, MockSupport, MockUsage, MockWebhooks, NEETRU_SENTINEL_KEY, NeetruDbError, NeetruError, VERSION, createCheckoutNamespace, createNeetruClient, createNeetruDb, createNotificationsNamespace, createWebhooksNamespace, increment, isFieldSentinel, isIncrementSentinel, isServerTimestampSentinel, serverTimestamp, verifyWebhookSignature };
6343
+ export { DEFAULT_BASE_URL, DEV_FIXTURE_USER, MockAuth, MockCheckout, MockDb, MockEntitlements, MockNotifications, MockSupport, MockUsage, MockWebhooks, NEETRU_SENTINEL_KEY, NeetruDbError, NeetruError, VERSION, checkCoreVersionCompat, createCheckoutNamespace, createNeetruClient, createNeetruDb, createNotificationsNamespace, createWebhooksNamespace, increment, isFieldSentinel, isIncrementSentinel, isServerTimestampSentinel, serverTimestamp, verifyWebhookRequest, verifyWebhookSignature };
6146
6344
  //# sourceMappingURL=index.mjs.map
6147
6345
  //# sourceMappingURL=index.mjs.map