@neetru/sdk 3.5.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 (114) hide show
  1. package/CHANGELOG.md +71 -1
  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 +3560 -4993
  7. package/dist/auth.d.cts +1 -1
  8. package/dist/auth.d.ts +1 -1
  9. package/dist/auth.mjs +3557 -4990
  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 +3627 -5135
  41. package/dist/index.d.cts +6 -4
  42. package/dist/index.d.ts +6 -4
  43. package/dist/index.mjs +3731 -5239
  44. package/dist/mobile.cjs +411 -0
  45. package/dist/mobile.d.cts +89 -0
  46. package/dist/mobile.d.ts +89 -0
  47. package/dist/mobile.mjs +409 -0
  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 +9 -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/mocks.cjs.map +0 -1
  102. package/dist/mocks.mjs.map +0 -1
  103. package/dist/notifications.cjs.map +0 -1
  104. package/dist/notifications.mjs.map +0 -1
  105. package/dist/react.cjs.map +0 -1
  106. package/dist/react.mjs.map +0 -1
  107. package/dist/support.cjs.map +0 -1
  108. package/dist/support.mjs.map +0 -1
  109. package/dist/telemetry.cjs.map +0 -1
  110. package/dist/telemetry.mjs.map +0 -1
  111. package/dist/usage.cjs.map +0 -1
  112. package/dist/usage.mjs.map +0 -1
  113. package/dist/webhooks.cjs.map +0 -1
  114. package/dist/webhooks.mjs.map +0 -1
@@ -0,0 +1,409 @@
1
+ // src/errors.ts
2
+ var r = class t extends Error {
3
+ code;
4
+ status;
5
+ requestId;
6
+ /**
7
+ * Motivo semântico opcional propagado pelo Core no corpo do erro (campo
8
+ * `reason` no TOPO do body, fora de `error`). Usado principalmente pelo 503
9
+ * de lease de DB, onde `reason` discrimina o estado do ambiente
10
+ * (`suspended` | `archived` | `revoked` | `provisioning` | `degraded` |
11
+ * `no_route` | `expired`). Camadas superiores (ex.: `db/sql`) mapeiam isso
12
+ * para um `NeetruDbErrorCode` mais específico (recuperável vs não).
13
+ */
14
+ reason;
15
+ constructor(e, i, s, o, l) {
16
+ super(i), this.name = "NeetruError", this.code = e, this.status = s, this.requestId = o, this.reason = l, Object.setPrototypeOf(this, t.prototype);
17
+ }
18
+ };
19
+
20
+ // src/types.ts
21
+ var L = "https://api.neetru.com";
22
+
23
+ // src/base-url-allowlist.ts
24
+ var O = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]), F = ".neetru.com", J = "neetru.com", Y = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?\.(test|localhost)$/;
25
+ function D(t) {
26
+ return Y.test(t);
27
+ }
28
+ function X(t) {
29
+ return t.toLowerCase().replace(/\.+$/, "");
30
+ }
31
+ function M(t, e = []) {
32
+ if (typeof t != "string" || t.length === 0)
33
+ throw new r("invalid_config", "baseUrl is required");
34
+ let i;
35
+ try {
36
+ i = new URL(t);
37
+ } catch {
38
+ throw new r("invalid_config", `baseUrl is not a valid URL: ${t}`);
39
+ }
40
+ let s = i.protocol, o = X(i.hostname);
41
+ if (Z())
42
+ return typeof console < "u" && console.warn(
43
+ `[neetru-sdk] NEETRU_ALLOW_INSECURE_BASEURL=1 ativo. baseUrl=${t} aceito sem valida\xE7\xE3o.`
44
+ ), t.replace(/\/+$/, "");
45
+ if (s !== "https:" && s !== "http:")
46
+ throw new r(
47
+ "invalid_config",
48
+ `baseUrl protocol must be http: or https:, got ${s}`
49
+ );
50
+ if (s === "http:") {
51
+ if (!(O.has(o) || D(o)))
52
+ throw new r(
53
+ "invalid_config",
54
+ `baseUrl with http: only allowed for localhost/127.0.0.1/*.test/*.localhost. Got: ${o}. Use https: or set NEETRU_ALLOW_INSECURE_BASEURL=1 to bypass.`
55
+ );
56
+ return t.replace(/\/+$/, "");
57
+ }
58
+ let l = o === J || o.endsWith(F), A = e.some((m) => {
59
+ let k = m.toLowerCase();
60
+ return o === k || o.endsWith(`.${k}`);
61
+ }), R = O.has(o) || D(o);
62
+ if (!l && !A && !R)
63
+ throw new r(
64
+ "invalid_config",
65
+ `baseUrl ${o} is not in the allowlist. Allowed: *.neetru.com, localhost, or configure { allowedHosts: ['...'] }. Bypass: NEETRU_ALLOW_INSECURE_BASEURL=1.`
66
+ );
67
+ return t.replace(/\/+$/, "");
68
+ }
69
+ function Z() {
70
+ try {
71
+ let e = globalThis.process?.env?.NEETRU_ALLOW_INSECURE_BASEURL;
72
+ if (e === "1" || e === "true") return !0;
73
+ } catch {
74
+ }
75
+ try {
76
+ let t = globalThis.NEETRU_ALLOW_INSECURE_BASEURL;
77
+ if (t === "1" || t === "true" || t === !0) return !0;
78
+ } catch {
79
+ }
80
+ return false;
81
+ }
82
+
83
+ // src/api-key.ts
84
+ var G = /^nrt_([A-Za-z0-9]+)_([A-Za-z0-9]+)$/;
85
+ function K(t) {
86
+ if (typeof t != "string" || t.length === 0)
87
+ throw new r(
88
+ "invalid_config",
89
+ "apiKey is required (formato nrt_<keyId>_<secret>)"
90
+ );
91
+ let e = G.exec(t);
92
+ if (!e)
93
+ throw new r(
94
+ "invalid_config",
95
+ "apiKey malformado - esperado formato nrt_<keyId>_<secret>"
96
+ );
97
+ return { keyId: e[1], secret: e[2] };
98
+ }
99
+
100
+ // src/auth-pkce-shared.ts
101
+ function H() {
102
+ let t = globalThis.crypto;
103
+ if (!t || typeof t.getRandomValues != "function" || !t.subtle)
104
+ throw new r(
105
+ "runtime_unsupported",
106
+ "auth.signIn requer WebCrypto (crypto.subtle) \u2014 indispon\xEDvel neste runtime. Use HTTPS (ou http://localhost) num browser moderno, ou instale um polyfill WebCrypto (ex: react-native-quick-crypto) em React Native."
107
+ );
108
+ return t;
109
+ }
110
+ function $(t) {
111
+ let e = "";
112
+ for (let s of t) e += String.fromCharCode(s);
113
+ return (typeof btoa == "function" ? btoa(e) : Buffer.from(e, "binary").toString("base64")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
114
+ }
115
+ function v(t, e) {
116
+ let i = new Uint8Array(e);
117
+ return t.getRandomValues(i), $(i);
118
+ }
119
+ async function B(t, e) {
120
+ let i = new TextEncoder().encode(e), s = await t.subtle.digest("SHA-256", i);
121
+ return $(new Uint8Array(s));
122
+ }
123
+ function U(t) {
124
+ return (typeof globalThis.NEETRU_AUTH_URL == "string" ? globalThis.NEETRU_AUTH_URL : null) ?? t.replace(/^https?:\/\/api\./, "https://auth.");
125
+ }
126
+ function I(t) {
127
+ let e = t.oidcClientId;
128
+ if (!e && t.apiKey && (e = K(t.apiKey).keyId), !e)
129
+ throw new r(
130
+ "invalid_config",
131
+ "auth OIDC requer `oidcClientId` (ou `apiKey`) configurado para montar o client_id."
132
+ );
133
+ return e;
134
+ }
135
+ function q(t) {
136
+ let e = new URL("/api/v1/oauth/authorize", t.idpOrigin);
137
+ return e.searchParams.set("response_type", "code"), e.searchParams.set("client_id", t.clientId), e.searchParams.set("redirect_uri", t.redirectUri), e.searchParams.set("scope", t.scope), e.searchParams.set("state", t.state), e.searchParams.set("nonce", t.nonce), e.searchParams.set("code_challenge", t.codeChallenge), e.searchParams.set("code_challenge_method", "S256"), e;
138
+ }
139
+ var W = "/api/v1/oauth/token";
140
+ function N(t) {
141
+ let e = t.split(".");
142
+ if (e.length !== 3) return null;
143
+ try {
144
+ let i = e[1].replace(/-/g, "+").replace(/_/g, "/"), s = "=".repeat((4 - i.length % 4) % 4), o = typeof atob == "function" ? atob(i + s) : Buffer.from(i + s, "base64").toString("utf-8");
145
+ return JSON.parse(o);
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+ function _(t) {
151
+ let e = N(t);
152
+ return !e || typeof e.sub != "string" || typeof e.exp == "number" && e.exp * 1e3 < Date.now() ? null : {
153
+ uid: e.sub,
154
+ email: typeof e.email == "string" ? e.email : "",
155
+ emailVerified: typeof e.email_verified == "boolean" ? e.email_verified : void 0,
156
+ displayName: typeof e.name == "string" ? e.name : void 0,
157
+ photoURL: typeof e.picture == "string" ? e.picture : void 0,
158
+ isStaff: e.is_staff === true,
159
+ isCustomer: e.is_customer === true,
160
+ tenantId: typeof e.tenant_id == "string" ? e.tenant_id : void 0,
161
+ ...e
162
+ };
163
+ }
164
+
165
+ // src/mobile.ts
166
+ var h = "neetru_oauth_tx", y = "neetru_id_token", S = "neetru_refresh_token";
167
+ function Q(t) {
168
+ if (!t.storage)
169
+ throw new r(
170
+ "invalid_config",
171
+ "createMobileAuthNamespace requer `storage` (MobileAuthStorage) \u2014 ver JSDoc de src/mobile.ts requisito 4."
172
+ );
173
+ if (typeof t.openAuthUrl != "function")
174
+ throw new r(
175
+ "invalid_config",
176
+ "createMobileAuthNamespace requer `openAuthUrl` (browser externo, NUNCA WebView embutida) \u2014 ver JSDoc de src/mobile.ts requisito 3."
177
+ );
178
+ let e = t.fetch ?? globalThis.fetch;
179
+ if (typeof e != "function")
180
+ throw new r(
181
+ "invalid_config",
182
+ "fetch is not available in this runtime. Pass `fetch` explicitly to createMobileAuthNamespace."
183
+ );
184
+ let i = M(t.baseUrl ?? L, t.allowedHosts ?? []);
185
+ return {
186
+ fetchImpl: e.bind(globalThis),
187
+ baseUrl: i,
188
+ oidcClientId: t.oidcClientId,
189
+ apiKey: t.apiKey,
190
+ storage: t.storage,
191
+ openAuthUrl: t.openAuthUrl
192
+ };
193
+ }
194
+ async function z(t, e, i) {
195
+ let s;
196
+ try {
197
+ s = await t(e, {
198
+ method: "POST",
199
+ headers: { "content-type": "application/x-www-form-urlencoded" },
200
+ body: i.toString()
201
+ });
202
+ } catch (l) {
203
+ throw new r(
204
+ "network_error",
205
+ `POST ${e} falhou (network): ${l?.message ?? String(l)}`
206
+ );
207
+ }
208
+ let o = null;
209
+ try {
210
+ o = await s.json();
211
+ } catch {
212
+ o = null;
213
+ }
214
+ if (!s.ok || typeof o?.error == "string") {
215
+ let l = typeof o?.error_description == "string" && o.error_description || typeof o?.error == "string" && o.error || `HTTP ${s.status}`;
216
+ throw new r(
217
+ "token_exchange_failed",
218
+ `Troca de tokens falhou no /token: ${l}`,
219
+ s.status
220
+ );
221
+ }
222
+ return o ?? {};
223
+ }
224
+ function ge(t) {
225
+ let e = Q(t), i = /* @__PURE__ */ new Set();
226
+ function s() {
227
+ return `${U(e.baseUrl)}${W}`;
228
+ }
229
+ async function o() {
230
+ let n = await m();
231
+ for (let a of i)
232
+ try {
233
+ a(n);
234
+ } catch {
235
+ }
236
+ }
237
+ async function l(n) {
238
+ if (!n?.redirectUri)
239
+ throw new r(
240
+ "invalid_config",
241
+ "mobile auth.signIn requer `redirectUri` (Universal Link/App Link https://... registrado no Core) \u2014 n\xE3o h\xE1 location.origin impl\xEDcito em React Native."
242
+ );
243
+ let a = H(), u = n.scope ?? "openid profile email", c = I(e), d = v(a, 16), f = v(a, 16), g = v(a, 32), p = await B(a, g), T = {
244
+ state: d,
245
+ nonce: f,
246
+ codeVerifier: g,
247
+ redirectUri: n.redirectUri,
248
+ postLoginRedirect: n.postLoginRedirect
249
+ };
250
+ await e.storage.setItem(h, JSON.stringify(T));
251
+ let C = U(e.baseUrl), w = q({
252
+ idpOrigin: C,
253
+ clientId: c,
254
+ redirectUri: n.redirectUri,
255
+ scope: u,
256
+ state: d,
257
+ nonce: f,
258
+ codeChallenge: p
259
+ });
260
+ await e.openAuthUrl(w.toString());
261
+ }
262
+ async function A(n) {
263
+ if (!n || typeof n != "string")
264
+ throw new r(
265
+ "invalid_config",
266
+ "mobile auth.completeSignIn requer `callbackUrl` (a URL completa do deep link de retorno) \u2014 mobile n\xE3o tem location.href impl\xEDcito."
267
+ );
268
+ let a;
269
+ try {
270
+ a = new URL(n);
271
+ } catch {
272
+ throw new r("invalid_config", `callbackUrl n\xE3o \xE9 uma URL v\xE1lida: ${n}`);
273
+ }
274
+ let u = a.searchParams, c = u.get("error");
275
+ if (c) {
276
+ let j = u.get("error_description") ?? c;
277
+ throw await e.storage.removeItem(h), new r(c, `OIDC authorize falhou: ${j}`);
278
+ }
279
+ let d = u.get("code");
280
+ if (!d)
281
+ throw await e.storage.removeItem(h), new r(
282
+ "invalid_config",
283
+ "callbackUrl n\xE3o cont\xE9m `?code=` nem `?error=` \u2014 n\xE3o \xE9 um callback OIDC v\xE1lido."
284
+ );
285
+ let f = u.get("state"), g = await e.storage.getItem(h), p = null;
286
+ if (g)
287
+ try {
288
+ p = JSON.parse(g);
289
+ } catch {
290
+ p = null;
291
+ }
292
+ if (!p)
293
+ throw new r(
294
+ "oidc_state_mismatch",
295
+ "Callback OIDC sem transa\xE7\xE3o pendente \u2014 `signIn` n\xE3o foi iniciado (ou j\xE1 consumido)."
296
+ );
297
+ if (!f || f !== p.state)
298
+ throw await e.storage.removeItem(h), new r(
299
+ "oidc_state_mismatch",
300
+ "state do callback OIDC n\xE3o confere com o da transa\xE7\xE3o (poss\xEDvel CSRF)."
301
+ );
302
+ await e.storage.removeItem(h);
303
+ let T = I(e), C = new URLSearchParams({
304
+ grant_type: "authorization_code",
305
+ code: d,
306
+ redirect_uri: p.redirectUri,
307
+ client_id: T,
308
+ code_verifier: p.codeVerifier
309
+ }), w = await z(e.fetchImpl, s(), C), b = w.id_token;
310
+ if (typeof b != "string" || b.length === 0)
311
+ throw new r(
312
+ "token_exchange_failed",
313
+ "Resposta do /token sem `id_token` \u2014 o login n\xE3o pode ser completado."
314
+ );
315
+ let x = N(b);
316
+ if (!x)
317
+ throw new r(
318
+ "token_exchange_failed",
319
+ "id_token retornado pelo /token \xE9 malformado (payload indecodific\xE1vel)."
320
+ );
321
+ if (x.nonce !== p.nonce)
322
+ throw new r(
323
+ "oidc_nonce_mismatch",
324
+ "nonce do id_token n\xE3o confere com o da transa\xE7\xE3o OIDC (poss\xEDvel replay). Token descartado."
325
+ );
326
+ let E = _(b);
327
+ if (!E)
328
+ throw new r(
329
+ "token_exchange_failed",
330
+ "id_token retornado pelo /token n\xE3o tem `sub` ou j\xE1 est\xE1 expirado."
331
+ );
332
+ await e.storage.setItem(y, b);
333
+ let P = w.refresh_token;
334
+ return typeof P == "string" && P.length > 0 && await e.storage.setItem(S, P), await o(), { user: E, postLoginRedirect: p.postLoginRedirect };
335
+ }
336
+ async function R() {
337
+ let n = await e.storage.getItem(y);
338
+ return n && _(n) ? n : null;
339
+ }
340
+ async function m() {
341
+ let n = await e.storage.getItem(y);
342
+ return n ? _(n) : null;
343
+ }
344
+ async function k() {
345
+ let n = await e.storage.getItem(S);
346
+ if (!n) return false;
347
+ let a;
348
+ try {
349
+ a = I(e);
350
+ } catch {
351
+ return false;
352
+ }
353
+ let u = new URLSearchParams({
354
+ grant_type: "refresh_token",
355
+ refresh_token: n,
356
+ client_id: a
357
+ }), c;
358
+ try {
359
+ c = await z(e.fetchImpl, s(), u);
360
+ } catch {
361
+ return false;
362
+ }
363
+ let d = c.id_token;
364
+ if (typeof d != "string" || d.length === 0 || !_(d)) return false;
365
+ await e.storage.setItem(y, d);
366
+ let g = c.refresh_token;
367
+ return typeof g == "string" && g.length > 0 && await e.storage.setItem(S, g), await o(), true;
368
+ }
369
+ async function V() {
370
+ let n = await e.storage.getItem(y);
371
+ if (await e.storage.removeItem(y), await e.storage.removeItem(S), n) {
372
+ let u = `${U(e.baseUrl)}/api/v1/oauth/revoke`;
373
+ try {
374
+ await e.fetchImpl(u, {
375
+ method: "POST",
376
+ headers: { "content-type": "application/json" },
377
+ body: JSON.stringify({ token: n })
378
+ });
379
+ } catch (c) {
380
+ typeof console < "u" && console.warn(
381
+ "[neetru-sdk] mobile signOut: server-side revoke falhou. Refresh token pode estar stale.",
382
+ c
383
+ );
384
+ }
385
+ }
386
+ await o();
387
+ }
388
+ return {
389
+ signIn: l,
390
+ completeSignIn: A,
391
+ getIdToken: R,
392
+ getUser: m,
393
+ onAuthStateChanged(n) {
394
+ return i.add(n), m().then((a) => {
395
+ if (i.has(n))
396
+ try {
397
+ n(a);
398
+ } catch {
399
+ }
400
+ }), () => {
401
+ i.delete(n);
402
+ };
403
+ },
404
+ refreshTokens: k,
405
+ signOut: V
406
+ };
407
+ }
408
+
409
+ export { ge as createMobileAuthNamespace };