@neetru/sdk 3.1.2 → 3.1.6
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.
- package/CHANGELOG.md +9 -0
- package/README.md +64 -9
- package/dist/auth.cjs +290 -27
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +290 -27
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.mjs.map +1 -1
- package/dist/checkout.cjs +22 -7
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/checkout.mjs +22 -7
- package/dist/checkout.mjs.map +1 -1
- package/dist/db-react.d.cts +1 -1
- package/dist/db-react.d.ts +1 -1
- package/dist/db.cjs +59 -3
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +59 -3
- package/dist/db.mjs.map +1 -1
- package/dist/entitlements.cjs.map +1 -1
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/entitlements.mjs.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +11 -6
- package/dist/errors.d.ts +11 -6
- package/dist/errors.mjs.map +1 -1
- package/dist/firestore-compat.d.cts +1 -1
- package/dist/firestore-compat.d.ts +1 -1
- package/dist/index.cjs +302 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +302 -31
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs +51 -7
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +41 -7
- package/dist/mocks.d.ts +41 -7
- package/dist/mocks.mjs +51 -7
- package/dist/mocks.mjs.map +1 -1
- package/dist/notifications.cjs.map +1 -1
- package/dist/notifications.d.cts +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.mjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/support.cjs.map +1 -1
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- package/dist/support.mjs.map +1 -1
- package/dist/telemetry.cjs +2 -1
- package/dist/telemetry.cjs.map +1 -1
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.mjs +2 -1
- package/dist/telemetry.mjs.map +1 -1
- package/dist/{types-DePdSU3P.d.cts → types-BXvGHppn.d.cts} +113 -12
- package/dist/{types-B3XFHD4A.d.ts → types-CQVak2a3.d.ts} +113 -12
- package/dist/usage.cjs.map +1 -1
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/usage.mjs.map +1 -1
- package/dist/webhooks.cjs +11 -3
- package/dist/webhooks.cjs.map +1 -1
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/dist/webhooks.mjs +11 -3
- package/dist/webhooks.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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,
|
|
4
|
-
export { DEV_FIXTURE_USER, MockAuth, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.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-BXvGHppn.cjs';
|
|
4
|
+
export { DEV_FIXTURE_USER, MockAuth, MockAuthOptions, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.cjs';
|
|
5
5
|
import 'drizzle-orm/node-postgres';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -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.
|
|
45
|
+
declare const VERSION: "3.1.6";
|
|
46
46
|
|
|
47
47
|
export { VERSION, checkCoreVersionCompat };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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,
|
|
4
|
-
export { DEV_FIXTURE_USER, MockAuth, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.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-CQVak2a3.js';
|
|
4
|
+
export { DEV_FIXTURE_USER, MockAuth, MockAuthOptions, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.js';
|
|
5
5
|
import 'drizzle-orm/node-postgres';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -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.
|
|
45
|
+
declare const VERSION: "3.1.6";
|
|
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
|
-
|
|
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:
|
|
4616
|
+
return { docs: [], newWatermark: Date.now(), resyncRequired: true };
|
|
4616
4617
|
},
|
|
4617
|
-
async fullResync(
|
|
4618
|
+
async fullResync(collections) {
|
|
4618
4619
|
if (!config) {
|
|
4619
4620
|
return { docs: [], newWatermark: Date.now() };
|
|
4620
4621
|
}
|
|
4621
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|
|
@@ -5485,9 +5565,19 @@ var DEV_FIXTURE_USER = Object.freeze({
|
|
|
5485
5565
|
var MockAuth = class {
|
|
5486
5566
|
_user;
|
|
5487
5567
|
_listeners;
|
|
5488
|
-
|
|
5568
|
+
_allowUnsignedDecode;
|
|
5569
|
+
constructor(initialUser = null, options) {
|
|
5489
5570
|
this._user = initialUser;
|
|
5490
5571
|
this._listeners = /* @__PURE__ */ new Set();
|
|
5572
|
+
this._allowUnsignedDecode = options?.allowUnsignedDecode ?? false;
|
|
5573
|
+
if (this._allowUnsignedDecode) {
|
|
5574
|
+
const isTestEnv = typeof process !== "undefined" && (process.env?.NODE_ENV === "test" || process.env?.VITEST === "true" || process.env?.VITEST != null);
|
|
5575
|
+
if (!isTestEnv && typeof console !== "undefined") {
|
|
5576
|
+
console.warn(
|
|
5577
|
+
"[neetru-sdk] MockAuth.verifyToken est\xE1 em modo allowUnsignedDecode=true: tokens N\xC3O t\xEAm assinatura verificada. Este modo \xE9 exclusivo para testes \u2014 NUNCA use como security boundary em c\xF3digo deployado."
|
|
5578
|
+
);
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5491
5581
|
}
|
|
5492
5582
|
async signIn(_options) {
|
|
5493
5583
|
if (!this._user) this._user = { ...DEV_FIXTURE_USER };
|
|
@@ -5512,18 +5602,27 @@ var MockAuth = class {
|
|
|
5512
5602
|
};
|
|
5513
5603
|
}
|
|
5514
5604
|
/**
|
|
5515
|
-
* Mock de `verifyToken` —
|
|
5516
|
-
*
|
|
5517
|
-
* não-vazio sem chamar rede.
|
|
5605
|
+
* Mock de `verifyToken` — por default lança `unauthorized` pra prevenir uso
|
|
5606
|
+
* acidental como security boundary em código deployado.
|
|
5518
5607
|
*
|
|
5519
|
-
* Para
|
|
5608
|
+
* Para decodificar JWTs sem verificar assinatura em testes, crie a instância
|
|
5609
|
+
* com `new MockAuth(user, { allowUnsignedDecode: true })`. Isso é um opt-in
|
|
5610
|
+
* explícito — nunca acontece silenciosamente.
|
|
5611
|
+
*
|
|
5612
|
+
* Para simular falhas ou resultados customizados, use `__mockVerifyToken(fn)`.
|
|
5520
5613
|
*/
|
|
5521
5614
|
async verifyToken(token) {
|
|
5522
5615
|
if (this._verifyTokenOverride) {
|
|
5523
5616
|
return this._verifyTokenOverride(token);
|
|
5524
5617
|
}
|
|
5525
5618
|
if (!token) {
|
|
5526
|
-
throw
|
|
5619
|
+
throw new NeetruError("token_invalid_signature", "Token inv\xE1lido: string vazia");
|
|
5620
|
+
}
|
|
5621
|
+
if (!this._allowUnsignedDecode) {
|
|
5622
|
+
throw new NeetruError(
|
|
5623
|
+
"unauthorized",
|
|
5624
|
+
"MockAuth.verifyToken n\xE3o verifica assinaturas JWT e N\xC3O deve ser usado como security boundary em c\xF3digo deployado. Em testes, use new MockAuth(user, { allowUnsignedDecode: true }) para habilitar decodifica\xE7\xE3o sem assinatura, ou __mockVerifyToken(fn) para injetar resultado customizado."
|
|
5625
|
+
);
|
|
5527
5626
|
}
|
|
5528
5627
|
try {
|
|
5529
5628
|
const parts = token.split(".");
|
|
@@ -5550,7 +5649,32 @@ var MockAuth = class {
|
|
|
5550
5649
|
} catch {
|
|
5551
5650
|
}
|
|
5552
5651
|
if (this._user) return this._user;
|
|
5553
|
-
throw
|
|
5652
|
+
throw new NeetruError("token_invalid_signature", "Nenhum user mock dispon\xEDvel e JWT sem sub v\xE1lido");
|
|
5653
|
+
}
|
|
5654
|
+
/**
|
|
5655
|
+
* Mock de `handleRedirectCallback` (Bug 2 / 3.1.3) — não há redirect real no
|
|
5656
|
+
* mock, então retorna `null` por default. Use `__setPendingCallback(result)`
|
|
5657
|
+
* em testes pra simular um retorno do IdP.
|
|
5658
|
+
*/
|
|
5659
|
+
async handleRedirectCallback(_currentUrl) {
|
|
5660
|
+
return this._pendingCallback;
|
|
5661
|
+
}
|
|
5662
|
+
/**
|
|
5663
|
+
* Mock de `getIdToken` (Bug 2 / 3.1.3). Retorna `null` por default; use
|
|
5664
|
+
* `__setIdToken(token)` pra injetar um token cru em testes.
|
|
5665
|
+
*/
|
|
5666
|
+
getIdToken() {
|
|
5667
|
+
return this._idToken;
|
|
5668
|
+
}
|
|
5669
|
+
_pendingCallback = null;
|
|
5670
|
+
_idToken = null;
|
|
5671
|
+
/** Test helper — simula o material devolvido por um callback OIDC. */
|
|
5672
|
+
__setPendingCallback(result) {
|
|
5673
|
+
this._pendingCallback = result;
|
|
5674
|
+
}
|
|
5675
|
+
/** Test helper — injeta o id_token cru retornado por `getIdToken`. */
|
|
5676
|
+
__setIdToken(token) {
|
|
5677
|
+
this._idToken = token;
|
|
5554
5678
|
}
|
|
5555
5679
|
_verifyTokenOverride = null;
|
|
5556
5680
|
/**
|
|
@@ -6081,6 +6205,49 @@ function _jwtPayloadToUser(payload) {
|
|
|
6081
6205
|
...payload
|
|
6082
6206
|
};
|
|
6083
6207
|
}
|
|
6208
|
+
var OIDC_TX_KEY = "neetru_oauth_tx";
|
|
6209
|
+
function resolveIdpOrigin(baseUrl) {
|
|
6210
|
+
const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
|
|
6211
|
+
return overrideAuthUrl ?? baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
|
|
6212
|
+
}
|
|
6213
|
+
function getWebCrypto() {
|
|
6214
|
+
const c = globalThis.crypto;
|
|
6215
|
+
if (!c || typeof c.getRandomValues !== "function" || !c.subtle) {
|
|
6216
|
+
throw new NeetruError(
|
|
6217
|
+
"runtime_unsupported",
|
|
6218
|
+
"auth.signIn requer WebCrypto (crypto.subtle) \u2014 indispon\xEDvel neste runtime. Use HTTPS (ou http://localhost) num browser moderno."
|
|
6219
|
+
);
|
|
6220
|
+
}
|
|
6221
|
+
return c;
|
|
6222
|
+
}
|
|
6223
|
+
function base64UrlFromBytes(bytes) {
|
|
6224
|
+
let str = "";
|
|
6225
|
+
for (const b of bytes) str += String.fromCharCode(b);
|
|
6226
|
+
const b64 = typeof btoa === "function" ? btoa(str) : Buffer.from(str, "binary").toString("base64");
|
|
6227
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
6228
|
+
}
|
|
6229
|
+
function randomUrlSafe(crypto2, byteLen) {
|
|
6230
|
+
const bytes = new Uint8Array(byteLen);
|
|
6231
|
+
crypto2.getRandomValues(bytes);
|
|
6232
|
+
return base64UrlFromBytes(bytes);
|
|
6233
|
+
}
|
|
6234
|
+
async function pkceChallengeS256(crypto2, verifier) {
|
|
6235
|
+
const data = new TextEncoder().encode(verifier);
|
|
6236
|
+
const digest = await crypto2.subtle.digest("SHA-256", data);
|
|
6237
|
+
return base64UrlFromBytes(new Uint8Array(digest));
|
|
6238
|
+
}
|
|
6239
|
+
function cleanCallbackUrl(parsed) {
|
|
6240
|
+
try {
|
|
6241
|
+
const history = globalThis.history;
|
|
6242
|
+
if (!history || typeof history.replaceState !== "function") return;
|
|
6243
|
+
const clean = new URL(parsed.toString());
|
|
6244
|
+
for (const p of ["code", "state", "error", "error_description", "iss", "session_state"]) {
|
|
6245
|
+
clean.searchParams.delete(p);
|
|
6246
|
+
}
|
|
6247
|
+
history.replaceState(history.state ?? null, "", clean.pathname + clean.search + clean.hash);
|
|
6248
|
+
} catch {
|
|
6249
|
+
}
|
|
6250
|
+
}
|
|
6084
6251
|
function createOidcAuthNamespace(config) {
|
|
6085
6252
|
const STORAGE_KEY = "neetru_id_token";
|
|
6086
6253
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -6093,6 +6260,13 @@ function createOidcAuthNamespace(config) {
|
|
|
6093
6260
|
return null;
|
|
6094
6261
|
}
|
|
6095
6262
|
}
|
|
6263
|
+
function getSessionStorage() {
|
|
6264
|
+
try {
|
|
6265
|
+
return typeof globalThis.sessionStorage !== "undefined" ? globalThis.sessionStorage : null;
|
|
6266
|
+
} catch {
|
|
6267
|
+
return null;
|
|
6268
|
+
}
|
|
6269
|
+
}
|
|
6096
6270
|
function decodeJwtPayload(token) {
|
|
6097
6271
|
const parts = token.split(".");
|
|
6098
6272
|
if (parts.length !== 3) return null;
|
|
@@ -6176,20 +6350,48 @@ function createOidcAuthNamespace(config) {
|
|
|
6176
6350
|
return {
|
|
6177
6351
|
async signIn(options) {
|
|
6178
6352
|
if (typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function") {
|
|
6353
|
+
const crypto2 = getWebCrypto();
|
|
6179
6354
|
const redirectUri = options?.redirectUri ?? globalThis.location.origin;
|
|
6180
6355
|
const scope = options?.scope ?? "openid profile email";
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6356
|
+
let clientId = config.oidcClientId;
|
|
6357
|
+
if (!clientId && config.apiKey) {
|
|
6358
|
+
clientId = parseApiKey(config.apiKey).keyId;
|
|
6359
|
+
}
|
|
6360
|
+
if (!clientId) {
|
|
6361
|
+
throw new NeetruError(
|
|
6362
|
+
"invalid_config",
|
|
6363
|
+
"auth.signIn requer `oidcClientId` (ou `apiKey`) configurado para montar o client_id."
|
|
6364
|
+
);
|
|
6365
|
+
}
|
|
6366
|
+
const state = randomUrlSafe(crypto2, 16);
|
|
6367
|
+
const nonce = randomUrlSafe(crypto2, 16);
|
|
6368
|
+
const codeVerifier = randomUrlSafe(crypto2, 32);
|
|
6369
|
+
const codeChallenge = await pkceChallengeS256(crypto2, codeVerifier);
|
|
6370
|
+
const session = getSessionStorage();
|
|
6371
|
+
if (!session) {
|
|
6372
|
+
throw new NeetruError(
|
|
6373
|
+
"runtime_unsupported",
|
|
6374
|
+
"auth.signIn requer sessionStorage para guardar a transa\xE7\xE3o PKCE entre o redirect e o callback."
|
|
6375
|
+
);
|
|
6376
|
+
}
|
|
6377
|
+
const tx = {
|
|
6378
|
+
state,
|
|
6379
|
+
nonce,
|
|
6380
|
+
codeVerifier,
|
|
6381
|
+
redirectUri,
|
|
6382
|
+
postLoginRedirect: options?.postLoginRedirect
|
|
6383
|
+
};
|
|
6384
|
+
session.setItem(OIDC_TX_KEY, JSON.stringify(tx));
|
|
6385
|
+
const idpOrigin = resolveIdpOrigin(config.baseUrl);
|
|
6184
6386
|
const url = new URL("/api/v1/oauth/authorize", idpOrigin);
|
|
6185
6387
|
url.searchParams.set("response_type", "code");
|
|
6388
|
+
url.searchParams.set("client_id", clientId);
|
|
6186
6389
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
6187
6390
|
url.searchParams.set("scope", scope);
|
|
6188
6391
|
url.searchParams.set("state", state);
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
}
|
|
6392
|
+
url.searchParams.set("nonce", nonce);
|
|
6393
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
6394
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
6193
6395
|
globalThis.location.assign(url.toString());
|
|
6194
6396
|
return;
|
|
6195
6397
|
}
|
|
@@ -6198,6 +6400,67 @@ function createOidcAuthNamespace(config) {
|
|
|
6198
6400
|
"auth.signIn requires a browser context or mocks. Use NEETRU_ENV=dev or pass mocks.auth."
|
|
6199
6401
|
);
|
|
6200
6402
|
},
|
|
6403
|
+
async handleRedirectCallback(currentUrl) {
|
|
6404
|
+
const href = currentUrl ?? (typeof globalThis.location !== "undefined" ? globalThis.location.href : void 0);
|
|
6405
|
+
if (!href) return null;
|
|
6406
|
+
let parsed;
|
|
6407
|
+
try {
|
|
6408
|
+
parsed = new URL(href);
|
|
6409
|
+
} catch {
|
|
6410
|
+
return null;
|
|
6411
|
+
}
|
|
6412
|
+
const params = parsed.searchParams;
|
|
6413
|
+
const idpError = params.get("error");
|
|
6414
|
+
if (idpError) {
|
|
6415
|
+
const desc = params.get("error_description") ?? idpError;
|
|
6416
|
+
getSessionStorage()?.removeItem(OIDC_TX_KEY);
|
|
6417
|
+
cleanCallbackUrl(parsed);
|
|
6418
|
+
throw new NeetruError(idpError, `OIDC authorize falhou: ${desc}`);
|
|
6419
|
+
}
|
|
6420
|
+
const code = params.get("code");
|
|
6421
|
+
if (!code) return null;
|
|
6422
|
+
const returnedState = params.get("state");
|
|
6423
|
+
const session = getSessionStorage();
|
|
6424
|
+
const txRaw = session?.getItem(OIDC_TX_KEY) ?? null;
|
|
6425
|
+
let tx = null;
|
|
6426
|
+
if (txRaw) {
|
|
6427
|
+
try {
|
|
6428
|
+
tx = JSON.parse(txRaw);
|
|
6429
|
+
} catch {
|
|
6430
|
+
tx = null;
|
|
6431
|
+
}
|
|
6432
|
+
}
|
|
6433
|
+
if (!tx) {
|
|
6434
|
+
throw new NeetruError(
|
|
6435
|
+
"oidc_state_mismatch",
|
|
6436
|
+
"Callback OIDC sem transa\xE7\xE3o pendente \u2014 `signIn` n\xE3o foi iniciado nesta sess\xE3o (ou j\xE1 consumido)."
|
|
6437
|
+
);
|
|
6438
|
+
}
|
|
6439
|
+
if (!returnedState || returnedState !== tx.state) {
|
|
6440
|
+
session?.removeItem(OIDC_TX_KEY);
|
|
6441
|
+
cleanCallbackUrl(parsed);
|
|
6442
|
+
throw new NeetruError(
|
|
6443
|
+
"oidc_state_mismatch",
|
|
6444
|
+
"state do callback OIDC n\xE3o confere com o da transa\xE7\xE3o (poss\xEDvel CSRF)."
|
|
6445
|
+
);
|
|
6446
|
+
}
|
|
6447
|
+
session?.removeItem(OIDC_TX_KEY);
|
|
6448
|
+
cleanCallbackUrl(parsed);
|
|
6449
|
+
return {
|
|
6450
|
+
code,
|
|
6451
|
+
codeVerifier: tx.codeVerifier,
|
|
6452
|
+
redirectUri: tx.redirectUri,
|
|
6453
|
+
nonce: tx.nonce,
|
|
6454
|
+
state: tx.state,
|
|
6455
|
+
postLoginRedirect: tx.postLoginRedirect
|
|
6456
|
+
};
|
|
6457
|
+
},
|
|
6458
|
+
getIdToken() {
|
|
6459
|
+
const storage = getStorage();
|
|
6460
|
+
const token = storage?.getItem(STORAGE_KEY) ?? null;
|
|
6461
|
+
if (!token) return null;
|
|
6462
|
+
return tokenToUser(token) ? token : null;
|
|
6463
|
+
},
|
|
6201
6464
|
async signOut() {
|
|
6202
6465
|
const storage = getStorage();
|
|
6203
6466
|
const storedToken = storage?.getItem(STORAGE_KEY) ?? null;
|
|
@@ -6257,13 +6520,20 @@ function createOidcAuthNamespace(config) {
|
|
|
6257
6520
|
const issuer = idpOrigin;
|
|
6258
6521
|
const jwksUrl = `${idpOrigin}/api/v1/oauth/.well-known/jwks.json`;
|
|
6259
6522
|
const cacheTtlMs = options?.jwksCacheTtlMs ?? DEFAULT_JWKS_TTL_MS;
|
|
6523
|
+
const audienceFromOptions = options?.audience;
|
|
6260
6524
|
const parsedKey = tryParseApiKey(config.apiKey);
|
|
6261
|
-
const audience = parsedKey?.keyId;
|
|
6525
|
+
const audience = audienceFromOptions ?? parsedKey?.keyId;
|
|
6526
|
+
if (!audience) {
|
|
6527
|
+
throw new NeetruError(
|
|
6528
|
+
"invalid_config",
|
|
6529
|
+
"verifyToken requires an audience: provide apiKey on the client or pass options.audience. Calling jwtVerify without an audience allows tokens issued for other OIDC clients to pass."
|
|
6530
|
+
);
|
|
6531
|
+
}
|
|
6262
6532
|
const jwks = _getJwks(jwksUrl, cacheTtlMs);
|
|
6263
6533
|
try {
|
|
6264
6534
|
const { payload } = await jwtVerify(token, jwks, {
|
|
6265
6535
|
issuer,
|
|
6266
|
-
|
|
6536
|
+
audience,
|
|
6267
6537
|
algorithms: ["RS256"]
|
|
6268
6538
|
});
|
|
6269
6539
|
return _jwtPayloadToUser(payload);
|
|
@@ -6304,6 +6574,7 @@ function createNeetruClient(config = {}) {
|
|
|
6304
6574
|
const env = resolveEnv(config.env);
|
|
6305
6575
|
const resolved = Object.freeze({
|
|
6306
6576
|
apiKey,
|
|
6577
|
+
oidcClientId: config.oidcClientId,
|
|
6307
6578
|
baseUrl,
|
|
6308
6579
|
fetch: fetchImpl.bind(globalThis),
|
|
6309
6580
|
env,
|
|
@@ -6338,7 +6609,7 @@ function createNeetruClient(config = {}) {
|
|
|
6338
6609
|
init_errors();
|
|
6339
6610
|
init_db_errors();
|
|
6340
6611
|
init_http();
|
|
6341
|
-
var VERSION = "3.1.
|
|
6612
|
+
var VERSION = "3.1.6";
|
|
6342
6613
|
|
|
6343
6614
|
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
6615
|
//# sourceMappingURL=index.mjs.map
|