@neetru/sdk 3.1.1 → 3.1.4

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 (82) hide show
  1. package/README.md +56 -5
  2. package/dist/auth.cjs +255 -18
  3. package/dist/auth.cjs.map +1 -1
  4. package/dist/auth.d.cts +1 -1
  5. package/dist/auth.d.ts +1 -1
  6. package/dist/auth.mjs +255 -18
  7. package/dist/auth.mjs.map +1 -1
  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.map +1 -1
  12. package/dist/checkout.cjs +22 -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 +22 -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.cjs +59 -3
  21. package/dist/db.cjs.map +1 -1
  22. package/dist/db.d.cts +1 -1
  23. package/dist/db.d.ts +1 -1
  24. package/dist/db.mjs +59 -3
  25. package/dist/db.mjs.map +1 -1
  26. package/dist/entitlements.cjs.map +1 -1
  27. package/dist/entitlements.d.cts +1 -1
  28. package/dist/entitlements.d.ts +1 -1
  29. package/dist/entitlements.mjs.map +1 -1
  30. package/dist/errors.cjs.map +1 -1
  31. package/dist/errors.d.cts +11 -6
  32. package/dist/errors.d.ts +11 -6
  33. package/dist/errors.mjs.map +1 -1
  34. package/dist/firestore-compat.cjs +15 -2
  35. package/dist/firestore-compat.cjs.map +1 -1
  36. package/dist/firestore-compat.d.cts +1 -1
  37. package/dist/firestore-compat.d.ts +1 -1
  38. package/dist/firestore-compat.mjs +15 -2
  39. package/dist/firestore-compat.mjs.map +1 -1
  40. package/dist/index.cjs +267 -22
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +2 -2
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.mjs +267 -22
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/mocks.cjs +25 -0
  47. package/dist/mocks.cjs.map +1 -1
  48. package/dist/mocks.d.cts +18 -1
  49. package/dist/mocks.d.ts +18 -1
  50. package/dist/mocks.mjs +25 -0
  51. package/dist/mocks.mjs.map +1 -1
  52. package/dist/notifications.cjs.map +1 -1
  53. package/dist/notifications.d.cts +1 -1
  54. package/dist/notifications.d.ts +1 -1
  55. package/dist/notifications.mjs.map +1 -1
  56. package/dist/react.cjs.map +1 -1
  57. package/dist/react.d.cts +1 -1
  58. package/dist/react.d.ts +1 -1
  59. package/dist/react.mjs.map +1 -1
  60. package/dist/support.cjs.map +1 -1
  61. package/dist/support.d.cts +1 -1
  62. package/dist/support.d.ts +1 -1
  63. package/dist/support.mjs.map +1 -1
  64. package/dist/telemetry.cjs +2 -1
  65. package/dist/telemetry.cjs.map +1 -1
  66. package/dist/telemetry.d.cts +1 -1
  67. package/dist/telemetry.d.ts +1 -1
  68. package/dist/telemetry.mjs +2 -1
  69. package/dist/telemetry.mjs.map +1 -1
  70. package/dist/{types-B3XFHD4A.d.ts → types-CRIIjqzC.d.ts} +105 -12
  71. package/dist/{types-DePdSU3P.d.cts → types-DvMdYbfV.d.cts} +105 -12
  72. package/dist/usage.cjs.map +1 -1
  73. package/dist/usage.d.cts +1 -1
  74. package/dist/usage.d.ts +1 -1
  75. package/dist/usage.mjs.map +1 -1
  76. package/dist/webhooks.cjs +11 -3
  77. package/dist/webhooks.cjs.map +1 -1
  78. package/dist/webhooks.d.cts +1 -1
  79. package/dist/webhooks.d.ts +1 -1
  80. package/dist/webhooks.mjs +11 -3
  81. package/dist/webhooks.mjs.map +1 -1
  82. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
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, 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';
3
+ export { A as AuthNamespace, a as AuthStateListener, C as CatalogListOptions, b as CatalogListResponse, d as CheckoutIntentInfo, e as CheckoutIntentStatus, f as CheckoutNamespace, g as CheckoutStartInput, h as CheckoutStartResult, i as CheckoutTenantType, l as CreateTicketInput, D as DEFAULT_BASE_URL, m as DbBatchOp, n as DbChangeType, o as DbCollectionRef, p as DbDoc, q as DbDocRef, r as DbGetResult, s as DbListResult, t as DbNamespace, u as DbQuery, v as DbSqlLease, w as DbWhereFilter, E as EntitlementCheck, F as FieldSentinel, I as IncrementSentinel, L as ListNotificationsOptions, M as MockCheckout, y as MockNotifications, z as MockWebhooks, N as NEETRU_SENTINEL_KEY, B as NeetruClient, G as NeetruClientConfig, H as NeetruDb, K as NeetruDbEngine, O as NeetruDbError, P as NeetruDbErrorCode, Q as NeetruDbOptions, R as NeetruDbTransport, S as NeetruEnv, T as NeetruSqlClient, U as NeetruUser, V as NotificationScopeOptions, W as NotificationsNamespace, X as Product, Y as ProductNotification, Z as ProductNotificationSeverity, _ as ProductPlan, $ as ProductStatus, a1 as RedirectCallbackResult, a2 as RegisterWebhookInput, a3 as ResolvedConfig, a4 as SendNotificationInput, a5 as ServerTimestampSentinel, a6 as SignInOptions, a8 as SupportNamespace, a9 as SupportSeverity, aa as SupportStatus, ab as SupportTicket, ad as TelemetryEventAck, ae as TelemetryEventInput, ai as UsageEventInput, aj as UsageNamespace, ak as UsageQuota, al as VerifyTokenOptions, am as VerifyWebhookRequestOptions, an as VerifyWebhookRequestResult, ao as WebhookEndpoint, ap as WebhookEvent, aq as WebhookScopeOptions, ar as WebhookTestResult, as as WebhooksNamespace, at as WithFieldSentinels, au as createCheckoutNamespace, av as createNeetruDb, aw as createNotificationsNamespace, ay as createWebhooksNamespace, aA as increment, aB as isFieldSentinel, aC as isIncrementSentinel, aD as isServerTimestampSentinel, aE as serverTimestamp, aF as verifyWebhookRequest, aG as verifyWebhookSignature } from './types-DvMdYbfV.cjs';
4
4
  export { DEV_FIXTURE_USER, MockAuth, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.cjs';
5
5
  import 'drizzle-orm/node-postgres';
6
6
 
@@ -42,6 +42,6 @@ declare function checkCoreVersionCompat(coreVersion: string): void;
42
42
  */
43
43
 
44
44
  /** Versão do SDK — exportada explicitamente pra detecção em runtime. */
45
- declare const VERSION: "3.1.1";
45
+ declare const VERSION: "3.1.3";
46
46
 
47
47
  export { VERSION, checkCoreVersionCompat };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
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, 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';
3
+ export { A as AuthNamespace, a as AuthStateListener, C as CatalogListOptions, b as CatalogListResponse, d as CheckoutIntentInfo, e as CheckoutIntentStatus, f as CheckoutNamespace, g as CheckoutStartInput, h as CheckoutStartResult, i as CheckoutTenantType, l as CreateTicketInput, D as DEFAULT_BASE_URL, m as DbBatchOp, n as DbChangeType, o as DbCollectionRef, p as DbDoc, q as DbDocRef, r as DbGetResult, s as DbListResult, t as DbNamespace, u as DbQuery, v as DbSqlLease, w as DbWhereFilter, E as EntitlementCheck, F as FieldSentinel, I as IncrementSentinel, L as ListNotificationsOptions, M as MockCheckout, y as MockNotifications, z as MockWebhooks, N as NEETRU_SENTINEL_KEY, B as NeetruClient, G as NeetruClientConfig, H as NeetruDb, K as NeetruDbEngine, O as NeetruDbError, P as NeetruDbErrorCode, Q as NeetruDbOptions, R as NeetruDbTransport, S as NeetruEnv, T as NeetruSqlClient, U as NeetruUser, V as NotificationScopeOptions, W as NotificationsNamespace, X as Product, Y as ProductNotification, Z as ProductNotificationSeverity, _ as ProductPlan, $ as ProductStatus, a1 as RedirectCallbackResult, a2 as RegisterWebhookInput, a3 as ResolvedConfig, a4 as SendNotificationInput, a5 as ServerTimestampSentinel, a6 as SignInOptions, a8 as SupportNamespace, a9 as SupportSeverity, aa as SupportStatus, ab as SupportTicket, ad as TelemetryEventAck, ae as TelemetryEventInput, ai as UsageEventInput, aj as UsageNamespace, ak as UsageQuota, al as VerifyTokenOptions, am as VerifyWebhookRequestOptions, an as VerifyWebhookRequestResult, ao as WebhookEndpoint, ap as WebhookEvent, aq as WebhookScopeOptions, ar as WebhookTestResult, as as WebhooksNamespace, at as WithFieldSentinels, au as createCheckoutNamespace, av as createNeetruDb, aw as createNotificationsNamespace, ay as createWebhooksNamespace, aA as increment, aB as isFieldSentinel, aC as isIncrementSentinel, aD as isServerTimestampSentinel, aE as serverTimestamp, aF as verifyWebhookRequest, aG as verifyWebhookSignature } from './types-CRIIjqzC.js';
4
4
  export { DEV_FIXTURE_USER, MockAuth, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.js';
5
5
  import 'drizzle-orm/node-postgres';
6
6
 
@@ -42,6 +42,6 @@ declare function checkCoreVersionCompat(coreVersion: string): void;
42
42
  */
43
43
 
44
44
  /** Versão do SDK — exportada explicitamente pra detecção em runtime. */
45
- declare const VERSION: "3.1.1";
45
+ declare const VERSION: "3.1.3";
46
46
 
47
47
  export { VERSION, checkCoreVersionCompat };
package/dist/index.mjs CHANGED
@@ -1093,7 +1093,8 @@ function createTelemetryNamespace(config) {
1093
1093
  message: input.message
1094
1094
  };
1095
1095
  if (input.metadata) body.metadata = input.metadata;
1096
- if (input.productSlug) body.productSlug = input.productSlug;
1096
+ const productSlug = input.productSlug ?? config.productId;
1097
+ if (productSlug) body.productSlug = productSlug;
1097
1098
  let cid = input.correlationId;
1098
1099
  if (!cid) {
1099
1100
  try {
@@ -4612,13 +4613,69 @@ function createRestSyncTransport(config) {
4612
4613
  if (!config) {
4613
4614
  return { docs: [], newWatermark: Date.now(), resyncRequired: false };
4614
4615
  }
4615
- return { docs: [], newWatermark: Date.now(), resyncRequired: false };
4616
+ return { docs: [], newWatermark: Date.now(), resyncRequired: true };
4616
4617
  },
4617
- async fullResync(_collections) {
4618
+ async fullResync(collections) {
4618
4619
  if (!config) {
4619
4620
  return { docs: [], newWatermark: Date.now() };
4620
4621
  }
4621
- return { docs: [], newWatermark: Date.now() };
4622
+ const { httpRequest: httpRequest2 } = await Promise.resolve().then(() => (init_http(), http_exports));
4623
+ const tenantScopeId = config.tenantId ?? config.productId;
4624
+ const tenantHeaders = tenantScopeId ? { "x-neetru-tenant": tenantScopeId } : void 0;
4625
+ const now = Date.now();
4626
+ const docs = [];
4627
+ for (const collection of collections) {
4628
+ let raw;
4629
+ try {
4630
+ raw = await httpRequest2(config, {
4631
+ method: "GET",
4632
+ path: DATASTORE_COLLECTION_ENDPOINT(collection),
4633
+ requireAuth: true,
4634
+ retries: 2,
4635
+ headers: tenantHeaders,
4636
+ // Teto do Core é 200. Coleções > 200 docs truncam silenciosamente
4637
+ // aqui (paginação cursor é tarefa Core separada) — a detecção de
4638
+ // deleção-por-ausência do SyncEngine NÃO deve rodar sobre truncamento,
4639
+ // então mantemos o limite no máximo do servidor por ora.
4640
+ query: { limit: 200 }
4641
+ });
4642
+ } catch (err) {
4643
+ const msg = err instanceof Error ? err.message : String(err);
4644
+ throw new NeetruDbError(
4645
+ "db_unavailable",
4646
+ `[RestSyncTransport] fullResync falhou na cole\xE7\xE3o "${collection}": ${msg}`
4647
+ );
4648
+ }
4649
+ const resp = raw;
4650
+ const items = Array.isArray(resp?.items) ? resp.items : [];
4651
+ for (const item of items) {
4652
+ if (!item || typeof item !== "object") continue;
4653
+ const record = item;
4654
+ const id = typeof record["id"] === "string" ? record["id"] : null;
4655
+ if (!id) continue;
4656
+ const { id: _inlinedId, ...data } = record;
4657
+ let serverTimestamp2 = now;
4658
+ const updatedAt = data["_updatedAt"];
4659
+ if (typeof updatedAt === "number") {
4660
+ serverTimestamp2 = updatedAt;
4661
+ } else if (updatedAt !== null && typeof updatedAt === "object" && typeof updatedAt["_seconds"] === "number") {
4662
+ serverTimestamp2 = updatedAt["_seconds"] * 1e3;
4663
+ } else if (typeof updatedAt === "string") {
4664
+ const parsed = Date.parse(updatedAt);
4665
+ if (!Number.isNaN(parsed)) serverTimestamp2 = parsed;
4666
+ }
4667
+ const serverVersion = `rest_${id}_${serverTimestamp2}`;
4668
+ docs.push({
4669
+ collection,
4670
+ id,
4671
+ data,
4672
+ serverVersion,
4673
+ serverTimestamp: serverTimestamp2,
4674
+ deleted: false
4675
+ });
4676
+ }
4677
+ }
4678
+ return { docs, newWatermark: now };
4622
4679
  }
4623
4680
  };
4624
4681
  }
@@ -4858,6 +4915,15 @@ function createLazyCollectionRef(name, getDocsPromise) {
4858
4915
  // src/checkout.ts
4859
4916
  init_errors();
4860
4917
  init_http();
4918
+ function checkoutAuth(accessToken, method) {
4919
+ if (!accessToken || typeof accessToken !== "string") {
4920
+ throw new NeetruError(
4921
+ "validation_failed",
4922
+ `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).`
4923
+ );
4924
+ }
4925
+ return { requireAuth: false, headers: { authorization: `Bearer ${accessToken}` } };
4926
+ }
4861
4927
  function parseStartResponse(raw) {
4862
4928
  if (!raw || typeof raw !== "object") {
4863
4929
  throw new NeetruError("invalid_response", "checkout.start response is not an object");
@@ -4935,11 +5001,13 @@ function createHttpCheckoutNamespace(config) {
4935
5001
  };
4936
5002
  if (input.tenantType) body.targetTenantType = input.tenantType;
4937
5003
  if (input.tenantId) body.targetTenantId = input.tenantId;
5004
+ const { requireAuth, headers } = checkoutAuth(input.accessToken, "start");
4938
5005
  const raw = await httpRequest(config, {
4939
5006
  method: "POST",
4940
5007
  path: "/api/v1/checkout/intents",
4941
5008
  body,
4942
- requireAuth: true,
5009
+ requireAuth,
5010
+ headers,
4943
5011
  idempotencyKey: true
4944
5012
  });
4945
5013
  const result = parseStartResponse(raw);
@@ -4949,25 +5017,29 @@ function createHttpCheckoutNamespace(config) {
4949
5017
  }
4950
5018
  return result;
4951
5019
  },
4952
- async get(intentId) {
5020
+ async get(intentId, opts) {
4953
5021
  if (!intentId || typeof intentId !== "string") {
4954
5022
  throw new NeetruError("validation_failed", "checkout.get: intentId is required");
4955
5023
  }
5024
+ const { requireAuth, headers } = checkoutAuth(opts?.accessToken, "get");
4956
5025
  const raw = await httpRequest(config, {
4957
5026
  method: "GET",
4958
5027
  path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
4959
- requireAuth: true
5028
+ requireAuth,
5029
+ headers
4960
5030
  });
4961
5031
  return parseGetResponse(raw);
4962
5032
  },
4963
- async cancel(intentId) {
5033
+ async cancel(intentId, opts) {
4964
5034
  if (!intentId || typeof intentId !== "string") {
4965
5035
  throw new NeetruError("validation_failed", "checkout.cancel: intentId is required");
4966
5036
  }
5037
+ const { requireAuth, headers } = checkoutAuth(opts?.accessToken, "cancel");
4967
5038
  const raw = await httpRequest(config, {
4968
5039
  method: "DELETE",
4969
5040
  path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
4970
- requireAuth: true
5041
+ requireAuth,
5042
+ headers
4971
5043
  });
4972
5044
  return {
4973
5045
  ok: true,
@@ -5011,14 +5083,14 @@ var MockCheckout = class {
5011
5083
  requiresKyc: false
5012
5084
  };
5013
5085
  }
5014
- async get(intentId) {
5086
+ async get(intentId, _opts) {
5015
5087
  const found = this.intents.get(intentId);
5016
5088
  if (!found) {
5017
5089
  throw new NeetruError("not_found", `Mock intent ${intentId} not found`);
5018
5090
  }
5019
5091
  return { ...found };
5020
5092
  }
5021
- async cancel(intentId) {
5093
+ async cancel(intentId, _opts) {
5022
5094
  const found = this.intents.get(intentId);
5023
5095
  if (!found) {
5024
5096
  throw new NeetruError("not_found", `Mock intent ${intentId} not found`);
@@ -5036,7 +5108,7 @@ function createCheckoutNamespace(config) {
5036
5108
  // src/webhooks.ts
5037
5109
  init_errors();
5038
5110
  init_http();
5039
- async function verifyWebhookSignature(payload, signature, secret) {
5111
+ async function verifyWebhookSignature(payload, signature, secret, timestamp) {
5040
5112
  if (!signature || !secret) return false;
5041
5113
  const sigHex = signature.startsWith("sha256=") ? signature.slice(7) : signature;
5042
5114
  if (!/^[0-9a-f]+$/i.test(sigHex)) return false;
@@ -5049,7 +5121,15 @@ async function verifyWebhookSignature(payload, signature, secret) {
5049
5121
  }
5050
5122
  const encoder = new TextEncoder();
5051
5123
  const keyBytes = encoder.encode(secret);
5052
- const payloadBytes = typeof payload === "string" ? encoder.encode(payload) : payload;
5124
+ const rawBytes = typeof payload === "string" ? encoder.encode(payload) : payload;
5125
+ let payloadBytes = rawBytes;
5126
+ if (timestamp !== void 0) {
5127
+ const prefix = encoder.encode(`${timestamp}.`);
5128
+ const merged = new Uint8Array(prefix.length + rawBytes.length);
5129
+ merged.set(prefix, 0);
5130
+ merged.set(rawBytes, prefix.length);
5131
+ payloadBytes = merged;
5132
+ }
5053
5133
  const key = await subtle.importKey(
5054
5134
  "raw",
5055
5135
  keyBytes,
@@ -5097,7 +5177,7 @@ async function verifyWebhookRequest(payload, headers, secret, options = {}) {
5097
5177
  return { ok: false, reason: "timestamp_expired" };
5098
5178
  }
5099
5179
  const sig = getHeader("x-neetru-signature");
5100
- const valid = await verifyWebhookSignature(payload, sig, secret);
5180
+ const valid = await verifyWebhookSignature(payload, sig, secret, tsHeader);
5101
5181
  if (!valid) {
5102
5182
  return { ok: false, reason: "invalid_signature" };
5103
5183
  }
@@ -5552,6 +5632,31 @@ var MockAuth = class {
5552
5632
  if (this._user) return this._user;
5553
5633
  throw Object.assign(new Error("Nenhum user mock dispon\xEDvel"), { code: "token_invalid_signature" });
5554
5634
  }
5635
+ /**
5636
+ * Mock de `handleRedirectCallback` (Bug 2 / 3.1.3) — não há redirect real no
5637
+ * mock, então retorna `null` por default. Use `__setPendingCallback(result)`
5638
+ * em testes pra simular um retorno do IdP.
5639
+ */
5640
+ async handleRedirectCallback(_currentUrl) {
5641
+ return this._pendingCallback;
5642
+ }
5643
+ /**
5644
+ * Mock de `getIdToken` (Bug 2 / 3.1.3). Retorna `null` por default; use
5645
+ * `__setIdToken(token)` pra injetar um token cru em testes.
5646
+ */
5647
+ getIdToken() {
5648
+ return this._idToken;
5649
+ }
5650
+ _pendingCallback = null;
5651
+ _idToken = null;
5652
+ /** Test helper — simula o material devolvido por um callback OIDC. */
5653
+ __setPendingCallback(result) {
5654
+ this._pendingCallback = result;
5655
+ }
5656
+ /** Test helper — injeta o id_token cru retornado por `getIdToken`. */
5657
+ __setIdToken(token) {
5658
+ this._idToken = token;
5659
+ }
5555
5660
  _verifyTokenOverride = null;
5556
5661
  /**
5557
5662
  * Injeta override pra `verifyToken` em testes — permite simular expiração,
@@ -6081,6 +6186,49 @@ function _jwtPayloadToUser(payload) {
6081
6186
  ...payload
6082
6187
  };
6083
6188
  }
6189
+ var OIDC_TX_KEY = "neetru_oauth_tx";
6190
+ function resolveIdpOrigin(baseUrl) {
6191
+ const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
6192
+ return overrideAuthUrl ?? baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
6193
+ }
6194
+ function getWebCrypto() {
6195
+ const c = globalThis.crypto;
6196
+ if (!c || typeof c.getRandomValues !== "function" || !c.subtle) {
6197
+ throw new NeetruError(
6198
+ "runtime_unsupported",
6199
+ "auth.signIn requer WebCrypto (crypto.subtle) \u2014 indispon\xEDvel neste runtime. Use HTTPS (ou http://localhost) num browser moderno."
6200
+ );
6201
+ }
6202
+ return c;
6203
+ }
6204
+ function base64UrlFromBytes(bytes) {
6205
+ let str = "";
6206
+ for (const b of bytes) str += String.fromCharCode(b);
6207
+ const b64 = typeof btoa === "function" ? btoa(str) : Buffer.from(str, "binary").toString("base64");
6208
+ return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
6209
+ }
6210
+ function randomUrlSafe(crypto2, byteLen) {
6211
+ const bytes = new Uint8Array(byteLen);
6212
+ crypto2.getRandomValues(bytes);
6213
+ return base64UrlFromBytes(bytes);
6214
+ }
6215
+ async function pkceChallengeS256(crypto2, verifier) {
6216
+ const data = new TextEncoder().encode(verifier);
6217
+ const digest = await crypto2.subtle.digest("SHA-256", data);
6218
+ return base64UrlFromBytes(new Uint8Array(digest));
6219
+ }
6220
+ function cleanCallbackUrl(parsed) {
6221
+ try {
6222
+ const history = globalThis.history;
6223
+ if (!history || typeof history.replaceState !== "function") return;
6224
+ const clean = new URL(parsed.toString());
6225
+ for (const p of ["code", "state", "error", "error_description", "iss", "session_state"]) {
6226
+ clean.searchParams.delete(p);
6227
+ }
6228
+ history.replaceState(history.state ?? null, "", clean.pathname + clean.search + clean.hash);
6229
+ } catch {
6230
+ }
6231
+ }
6084
6232
  function createOidcAuthNamespace(config) {
6085
6233
  const STORAGE_KEY = "neetru_id_token";
6086
6234
  const listeners = /* @__PURE__ */ new Set();
@@ -6093,6 +6241,13 @@ function createOidcAuthNamespace(config) {
6093
6241
  return null;
6094
6242
  }
6095
6243
  }
6244
+ function getSessionStorage() {
6245
+ try {
6246
+ return typeof globalThis.sessionStorage !== "undefined" ? globalThis.sessionStorage : null;
6247
+ } catch {
6248
+ return null;
6249
+ }
6250
+ }
6096
6251
  function decodeJwtPayload(token) {
6097
6252
  const parts = token.split(".");
6098
6253
  if (parts.length !== 3) return null;
@@ -6176,20 +6331,48 @@ function createOidcAuthNamespace(config) {
6176
6331
  return {
6177
6332
  async signIn(options) {
6178
6333
  if (typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function") {
6334
+ const crypto2 = getWebCrypto();
6179
6335
  const redirectUri = options?.redirectUri ?? globalThis.location.origin;
6180
6336
  const scope = options?.scope ?? "openid profile email";
6181
- const state = options?.postLoginRedirect ?? globalThis.location.href;
6182
- const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
6183
- const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
6337
+ let clientId = config.oidcClientId;
6338
+ if (!clientId && config.apiKey) {
6339
+ clientId = parseApiKey(config.apiKey).keyId;
6340
+ }
6341
+ if (!clientId) {
6342
+ throw new NeetruError(
6343
+ "invalid_config",
6344
+ "auth.signIn requer `oidcClientId` (ou `apiKey`) configurado para montar o client_id."
6345
+ );
6346
+ }
6347
+ const state = randomUrlSafe(crypto2, 16);
6348
+ const nonce = randomUrlSafe(crypto2, 16);
6349
+ const codeVerifier = randomUrlSafe(crypto2, 32);
6350
+ const codeChallenge = await pkceChallengeS256(crypto2, codeVerifier);
6351
+ const session = getSessionStorage();
6352
+ if (!session) {
6353
+ throw new NeetruError(
6354
+ "runtime_unsupported",
6355
+ "auth.signIn requer sessionStorage para guardar a transa\xE7\xE3o PKCE entre o redirect e o callback."
6356
+ );
6357
+ }
6358
+ const tx = {
6359
+ state,
6360
+ nonce,
6361
+ codeVerifier,
6362
+ redirectUri,
6363
+ postLoginRedirect: options?.postLoginRedirect
6364
+ };
6365
+ session.setItem(OIDC_TX_KEY, JSON.stringify(tx));
6366
+ const idpOrigin = resolveIdpOrigin(config.baseUrl);
6184
6367
  const url = new URL("/api/v1/oauth/authorize", idpOrigin);
6185
6368
  url.searchParams.set("response_type", "code");
6369
+ url.searchParams.set("client_id", clientId);
6186
6370
  url.searchParams.set("redirect_uri", redirectUri);
6187
6371
  url.searchParams.set("scope", scope);
6188
6372
  url.searchParams.set("state", state);
6189
- if (config.apiKey) {
6190
- const { keyId } = parseApiKey(config.apiKey);
6191
- url.searchParams.set("client_id", keyId);
6192
- }
6373
+ url.searchParams.set("nonce", nonce);
6374
+ url.searchParams.set("code_challenge", codeChallenge);
6375
+ url.searchParams.set("code_challenge_method", "S256");
6193
6376
  globalThis.location.assign(url.toString());
6194
6377
  return;
6195
6378
  }
@@ -6198,6 +6381,67 @@ function createOidcAuthNamespace(config) {
6198
6381
  "auth.signIn requires a browser context or mocks. Use NEETRU_ENV=dev or pass mocks.auth."
6199
6382
  );
6200
6383
  },
6384
+ async handleRedirectCallback(currentUrl) {
6385
+ const href = currentUrl ?? (typeof globalThis.location !== "undefined" ? globalThis.location.href : void 0);
6386
+ if (!href) return null;
6387
+ let parsed;
6388
+ try {
6389
+ parsed = new URL(href);
6390
+ } catch {
6391
+ return null;
6392
+ }
6393
+ const params = parsed.searchParams;
6394
+ const idpError = params.get("error");
6395
+ if (idpError) {
6396
+ const desc = params.get("error_description") ?? idpError;
6397
+ getSessionStorage()?.removeItem(OIDC_TX_KEY);
6398
+ cleanCallbackUrl(parsed);
6399
+ throw new NeetruError(idpError, `OIDC authorize falhou: ${desc}`);
6400
+ }
6401
+ const code = params.get("code");
6402
+ if (!code) return null;
6403
+ const returnedState = params.get("state");
6404
+ const session = getSessionStorage();
6405
+ const txRaw = session?.getItem(OIDC_TX_KEY) ?? null;
6406
+ let tx = null;
6407
+ if (txRaw) {
6408
+ try {
6409
+ tx = JSON.parse(txRaw);
6410
+ } catch {
6411
+ tx = null;
6412
+ }
6413
+ }
6414
+ if (!tx) {
6415
+ throw new NeetruError(
6416
+ "oidc_state_mismatch",
6417
+ "Callback OIDC sem transa\xE7\xE3o pendente \u2014 `signIn` n\xE3o foi iniciado nesta sess\xE3o (ou j\xE1 consumido)."
6418
+ );
6419
+ }
6420
+ if (!returnedState || returnedState !== tx.state) {
6421
+ session?.removeItem(OIDC_TX_KEY);
6422
+ cleanCallbackUrl(parsed);
6423
+ throw new NeetruError(
6424
+ "oidc_state_mismatch",
6425
+ "state do callback OIDC n\xE3o confere com o da transa\xE7\xE3o (poss\xEDvel CSRF)."
6426
+ );
6427
+ }
6428
+ session?.removeItem(OIDC_TX_KEY);
6429
+ cleanCallbackUrl(parsed);
6430
+ return {
6431
+ code,
6432
+ codeVerifier: tx.codeVerifier,
6433
+ redirectUri: tx.redirectUri,
6434
+ nonce: tx.nonce,
6435
+ state: tx.state,
6436
+ postLoginRedirect: tx.postLoginRedirect
6437
+ };
6438
+ },
6439
+ getIdToken() {
6440
+ const storage = getStorage();
6441
+ const token = storage?.getItem(STORAGE_KEY) ?? null;
6442
+ if (!token) return null;
6443
+ return tokenToUser(token) ? token : null;
6444
+ },
6201
6445
  async signOut() {
6202
6446
  const storage = getStorage();
6203
6447
  const storedToken = storage?.getItem(STORAGE_KEY) ?? null;
@@ -6304,6 +6548,7 @@ function createNeetruClient(config = {}) {
6304
6548
  const env = resolveEnv(config.env);
6305
6549
  const resolved = Object.freeze({
6306
6550
  apiKey,
6551
+ oidcClientId: config.oidcClientId,
6307
6552
  baseUrl,
6308
6553
  fetch: fetchImpl.bind(globalThis),
6309
6554
  env,
@@ -6338,7 +6583,7 @@ function createNeetruClient(config = {}) {
6338
6583
  init_errors();
6339
6584
  init_db_errors();
6340
6585
  init_http();
6341
- var VERSION = "3.1.1";
6586
+ var VERSION = "3.1.3";
6342
6587
 
6343
6588
  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 };
6344
6589
  //# sourceMappingURL=index.mjs.map