@neetru/sdk 3.1.2 → 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.
- package/README.md +56 -5
- package/dist/auth.cjs +255 -18
- 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 +255 -18
- 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 +267 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +267 -22
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs +25 -0
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +18 -1
- package/dist/mocks.d.ts +18 -1
- package/dist/mocks.mjs +25 -0
- 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-B3XFHD4A.d.ts → types-CRIIjqzC.d.ts} +105 -12
- package/dist/{types-DePdSU3P.d.cts → types-DvMdYbfV.d.cts} +105 -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/auth.d.cts
CHANGED
package/dist/auth.d.ts
CHANGED
package/dist/auth.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 {
|
|
@@ -4601,13 +4602,69 @@ function createRestSyncTransport(config) {
|
|
|
4601
4602
|
if (!config) {
|
|
4602
4603
|
return { docs: [], newWatermark: Date.now(), resyncRequired: false };
|
|
4603
4604
|
}
|
|
4604
|
-
return { docs: [], newWatermark: Date.now(), resyncRequired:
|
|
4605
|
+
return { docs: [], newWatermark: Date.now(), resyncRequired: true };
|
|
4605
4606
|
},
|
|
4606
|
-
async fullResync(
|
|
4607
|
+
async fullResync(collections) {
|
|
4607
4608
|
if (!config) {
|
|
4608
4609
|
return { docs: [], newWatermark: Date.now() };
|
|
4609
4610
|
}
|
|
4610
|
-
|
|
4611
|
+
const { httpRequest: httpRequest2 } = await Promise.resolve().then(() => (init_http(), http_exports));
|
|
4612
|
+
const tenantScopeId = config.tenantId ?? config.productId;
|
|
4613
|
+
const tenantHeaders = tenantScopeId ? { "x-neetru-tenant": tenantScopeId } : void 0;
|
|
4614
|
+
const now = Date.now();
|
|
4615
|
+
const docs = [];
|
|
4616
|
+
for (const collection of collections) {
|
|
4617
|
+
let raw;
|
|
4618
|
+
try {
|
|
4619
|
+
raw = await httpRequest2(config, {
|
|
4620
|
+
method: "GET",
|
|
4621
|
+
path: DATASTORE_COLLECTION_ENDPOINT(collection),
|
|
4622
|
+
requireAuth: true,
|
|
4623
|
+
retries: 2,
|
|
4624
|
+
headers: tenantHeaders,
|
|
4625
|
+
// Teto do Core é 200. Coleções > 200 docs truncam silenciosamente
|
|
4626
|
+
// aqui (paginação cursor é tarefa Core separada) — a detecção de
|
|
4627
|
+
// deleção-por-ausência do SyncEngine NÃO deve rodar sobre truncamento,
|
|
4628
|
+
// então mantemos o limite no máximo do servidor por ora.
|
|
4629
|
+
query: { limit: 200 }
|
|
4630
|
+
});
|
|
4631
|
+
} catch (err) {
|
|
4632
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4633
|
+
throw new NeetruDbError(
|
|
4634
|
+
"db_unavailable",
|
|
4635
|
+
`[RestSyncTransport] fullResync falhou na cole\xE7\xE3o "${collection}": ${msg}`
|
|
4636
|
+
);
|
|
4637
|
+
}
|
|
4638
|
+
const resp = raw;
|
|
4639
|
+
const items = Array.isArray(resp?.items) ? resp.items : [];
|
|
4640
|
+
for (const item of items) {
|
|
4641
|
+
if (!item || typeof item !== "object") continue;
|
|
4642
|
+
const record = item;
|
|
4643
|
+
const id = typeof record["id"] === "string" ? record["id"] : null;
|
|
4644
|
+
if (!id) continue;
|
|
4645
|
+
const { id: _inlinedId, ...data } = record;
|
|
4646
|
+
let serverTimestamp = now;
|
|
4647
|
+
const updatedAt = data["_updatedAt"];
|
|
4648
|
+
if (typeof updatedAt === "number") {
|
|
4649
|
+
serverTimestamp = updatedAt;
|
|
4650
|
+
} else if (updatedAt !== null && typeof updatedAt === "object" && typeof updatedAt["_seconds"] === "number") {
|
|
4651
|
+
serverTimestamp = updatedAt["_seconds"] * 1e3;
|
|
4652
|
+
} else if (typeof updatedAt === "string") {
|
|
4653
|
+
const parsed = Date.parse(updatedAt);
|
|
4654
|
+
if (!Number.isNaN(parsed)) serverTimestamp = parsed;
|
|
4655
|
+
}
|
|
4656
|
+
const serverVersion = `rest_${id}_${serverTimestamp}`;
|
|
4657
|
+
docs.push({
|
|
4658
|
+
collection,
|
|
4659
|
+
id,
|
|
4660
|
+
data,
|
|
4661
|
+
serverVersion,
|
|
4662
|
+
serverTimestamp,
|
|
4663
|
+
deleted: false
|
|
4664
|
+
});
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
return { docs, newWatermark: now };
|
|
4611
4668
|
}
|
|
4612
4669
|
};
|
|
4613
4670
|
}
|
|
@@ -4847,6 +4904,15 @@ function createLazyCollectionRef(name, getDocsPromise) {
|
|
|
4847
4904
|
// src/checkout.ts
|
|
4848
4905
|
init_errors();
|
|
4849
4906
|
init_http();
|
|
4907
|
+
function checkoutAuth(accessToken, method) {
|
|
4908
|
+
if (!accessToken || typeof accessToken !== "string") {
|
|
4909
|
+
throw new NeetruError(
|
|
4910
|
+
"validation_failed",
|
|
4911
|
+
`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).`
|
|
4912
|
+
);
|
|
4913
|
+
}
|
|
4914
|
+
return { requireAuth: false, headers: { authorization: `Bearer ${accessToken}` } };
|
|
4915
|
+
}
|
|
4850
4916
|
function parseStartResponse(raw) {
|
|
4851
4917
|
if (!raw || typeof raw !== "object") {
|
|
4852
4918
|
throw new NeetruError("invalid_response", "checkout.start response is not an object");
|
|
@@ -4924,11 +4990,13 @@ function createHttpCheckoutNamespace(config) {
|
|
|
4924
4990
|
};
|
|
4925
4991
|
if (input.tenantType) body.targetTenantType = input.tenantType;
|
|
4926
4992
|
if (input.tenantId) body.targetTenantId = input.tenantId;
|
|
4993
|
+
const { requireAuth, headers } = checkoutAuth(input.accessToken, "start");
|
|
4927
4994
|
const raw = await httpRequest(config, {
|
|
4928
4995
|
method: "POST",
|
|
4929
4996
|
path: "/api/v1/checkout/intents",
|
|
4930
4997
|
body,
|
|
4931
|
-
requireAuth
|
|
4998
|
+
requireAuth,
|
|
4999
|
+
headers,
|
|
4932
5000
|
idempotencyKey: true
|
|
4933
5001
|
});
|
|
4934
5002
|
const result = parseStartResponse(raw);
|
|
@@ -4938,25 +5006,29 @@ function createHttpCheckoutNamespace(config) {
|
|
|
4938
5006
|
}
|
|
4939
5007
|
return result;
|
|
4940
5008
|
},
|
|
4941
|
-
async get(intentId) {
|
|
5009
|
+
async get(intentId, opts) {
|
|
4942
5010
|
if (!intentId || typeof intentId !== "string") {
|
|
4943
5011
|
throw new NeetruError("validation_failed", "checkout.get: intentId is required");
|
|
4944
5012
|
}
|
|
5013
|
+
const { requireAuth, headers } = checkoutAuth(opts?.accessToken, "get");
|
|
4945
5014
|
const raw = await httpRequest(config, {
|
|
4946
5015
|
method: "GET",
|
|
4947
5016
|
path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
|
|
4948
|
-
requireAuth
|
|
5017
|
+
requireAuth,
|
|
5018
|
+
headers
|
|
4949
5019
|
});
|
|
4950
5020
|
return parseGetResponse(raw);
|
|
4951
5021
|
},
|
|
4952
|
-
async cancel(intentId) {
|
|
5022
|
+
async cancel(intentId, opts) {
|
|
4953
5023
|
if (!intentId || typeof intentId !== "string") {
|
|
4954
5024
|
throw new NeetruError("validation_failed", "checkout.cancel: intentId is required");
|
|
4955
5025
|
}
|
|
5026
|
+
const { requireAuth, headers } = checkoutAuth(opts?.accessToken, "cancel");
|
|
4956
5027
|
const raw = await httpRequest(config, {
|
|
4957
5028
|
method: "DELETE",
|
|
4958
5029
|
path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
|
|
4959
|
-
requireAuth
|
|
5030
|
+
requireAuth,
|
|
5031
|
+
headers
|
|
4960
5032
|
});
|
|
4961
5033
|
return {
|
|
4962
5034
|
ok: true,
|
|
@@ -5000,14 +5072,14 @@ var MockCheckout = class {
|
|
|
5000
5072
|
requiresKyc: false
|
|
5001
5073
|
};
|
|
5002
5074
|
}
|
|
5003
|
-
async get(intentId) {
|
|
5075
|
+
async get(intentId, _opts) {
|
|
5004
5076
|
const found = this.intents.get(intentId);
|
|
5005
5077
|
if (!found) {
|
|
5006
5078
|
throw new NeetruError("not_found", `Mock intent ${intentId} not found`);
|
|
5007
5079
|
}
|
|
5008
5080
|
return { ...found };
|
|
5009
5081
|
}
|
|
5010
|
-
async cancel(intentId) {
|
|
5082
|
+
async cancel(intentId, _opts) {
|
|
5011
5083
|
const found = this.intents.get(intentId);
|
|
5012
5084
|
if (!found) {
|
|
5013
5085
|
throw new NeetruError("not_found", `Mock intent ${intentId} not found`);
|
|
@@ -5462,6 +5534,31 @@ var MockAuth = class {
|
|
|
5462
5534
|
if (this._user) return this._user;
|
|
5463
5535
|
throw Object.assign(new Error("Nenhum user mock dispon\xEDvel"), { code: "token_invalid_signature" });
|
|
5464
5536
|
}
|
|
5537
|
+
/**
|
|
5538
|
+
* Mock de `handleRedirectCallback` (Bug 2 / 3.1.3) — não há redirect real no
|
|
5539
|
+
* mock, então retorna `null` por default. Use `__setPendingCallback(result)`
|
|
5540
|
+
* em testes pra simular um retorno do IdP.
|
|
5541
|
+
*/
|
|
5542
|
+
async handleRedirectCallback(_currentUrl) {
|
|
5543
|
+
return this._pendingCallback;
|
|
5544
|
+
}
|
|
5545
|
+
/**
|
|
5546
|
+
* Mock de `getIdToken` (Bug 2 / 3.1.3). Retorna `null` por default; use
|
|
5547
|
+
* `__setIdToken(token)` pra injetar um token cru em testes.
|
|
5548
|
+
*/
|
|
5549
|
+
getIdToken() {
|
|
5550
|
+
return this._idToken;
|
|
5551
|
+
}
|
|
5552
|
+
_pendingCallback = null;
|
|
5553
|
+
_idToken = null;
|
|
5554
|
+
/** Test helper — simula o material devolvido por um callback OIDC. */
|
|
5555
|
+
__setPendingCallback(result) {
|
|
5556
|
+
this._pendingCallback = result;
|
|
5557
|
+
}
|
|
5558
|
+
/** Test helper — injeta o id_token cru retornado por `getIdToken`. */
|
|
5559
|
+
__setIdToken(token) {
|
|
5560
|
+
this._idToken = token;
|
|
5561
|
+
}
|
|
5465
5562
|
_verifyTokenOverride = null;
|
|
5466
5563
|
/**
|
|
5467
5564
|
* Injeta override pra `verifyToken` em testes — permite simular expiração,
|
|
@@ -5680,6 +5777,49 @@ function _jwtPayloadToUser(payload) {
|
|
|
5680
5777
|
...payload
|
|
5681
5778
|
};
|
|
5682
5779
|
}
|
|
5780
|
+
var OIDC_TX_KEY = "neetru_oauth_tx";
|
|
5781
|
+
function resolveIdpOrigin(baseUrl) {
|
|
5782
|
+
const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
|
|
5783
|
+
return overrideAuthUrl ?? baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
|
|
5784
|
+
}
|
|
5785
|
+
function getWebCrypto() {
|
|
5786
|
+
const c = globalThis.crypto;
|
|
5787
|
+
if (!c || typeof c.getRandomValues !== "function" || !c.subtle) {
|
|
5788
|
+
throw new NeetruError(
|
|
5789
|
+
"runtime_unsupported",
|
|
5790
|
+
"auth.signIn requer WebCrypto (crypto.subtle) \u2014 indispon\xEDvel neste runtime. Use HTTPS (ou http://localhost) num browser moderno."
|
|
5791
|
+
);
|
|
5792
|
+
}
|
|
5793
|
+
return c;
|
|
5794
|
+
}
|
|
5795
|
+
function base64UrlFromBytes(bytes) {
|
|
5796
|
+
let str = "";
|
|
5797
|
+
for (const b of bytes) str += String.fromCharCode(b);
|
|
5798
|
+
const b64 = typeof btoa === "function" ? btoa(str) : Buffer.from(str, "binary").toString("base64");
|
|
5799
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
5800
|
+
}
|
|
5801
|
+
function randomUrlSafe(crypto2, byteLen) {
|
|
5802
|
+
const bytes = new Uint8Array(byteLen);
|
|
5803
|
+
crypto2.getRandomValues(bytes);
|
|
5804
|
+
return base64UrlFromBytes(bytes);
|
|
5805
|
+
}
|
|
5806
|
+
async function pkceChallengeS256(crypto2, verifier) {
|
|
5807
|
+
const data = new TextEncoder().encode(verifier);
|
|
5808
|
+
const digest = await crypto2.subtle.digest("SHA-256", data);
|
|
5809
|
+
return base64UrlFromBytes(new Uint8Array(digest));
|
|
5810
|
+
}
|
|
5811
|
+
function cleanCallbackUrl(parsed) {
|
|
5812
|
+
try {
|
|
5813
|
+
const history = globalThis.history;
|
|
5814
|
+
if (!history || typeof history.replaceState !== "function") return;
|
|
5815
|
+
const clean = new URL(parsed.toString());
|
|
5816
|
+
for (const p of ["code", "state", "error", "error_description", "iss", "session_state"]) {
|
|
5817
|
+
clean.searchParams.delete(p);
|
|
5818
|
+
}
|
|
5819
|
+
history.replaceState(history.state ?? null, "", clean.pathname + clean.search + clean.hash);
|
|
5820
|
+
} catch {
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5683
5823
|
function createOidcAuthNamespace(config) {
|
|
5684
5824
|
const STORAGE_KEY = "neetru_id_token";
|
|
5685
5825
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -5692,6 +5832,13 @@ function createOidcAuthNamespace(config) {
|
|
|
5692
5832
|
return null;
|
|
5693
5833
|
}
|
|
5694
5834
|
}
|
|
5835
|
+
function getSessionStorage() {
|
|
5836
|
+
try {
|
|
5837
|
+
return typeof globalThis.sessionStorage !== "undefined" ? globalThis.sessionStorage : null;
|
|
5838
|
+
} catch {
|
|
5839
|
+
return null;
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
5695
5842
|
function decodeJwtPayload(token) {
|
|
5696
5843
|
const parts = token.split(".");
|
|
5697
5844
|
if (parts.length !== 3) return null;
|
|
@@ -5775,20 +5922,48 @@ function createOidcAuthNamespace(config) {
|
|
|
5775
5922
|
return {
|
|
5776
5923
|
async signIn(options) {
|
|
5777
5924
|
if (typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function") {
|
|
5925
|
+
const crypto2 = getWebCrypto();
|
|
5778
5926
|
const redirectUri = options?.redirectUri ?? globalThis.location.origin;
|
|
5779
5927
|
const scope = options?.scope ?? "openid profile email";
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5928
|
+
let clientId = config.oidcClientId;
|
|
5929
|
+
if (!clientId && config.apiKey) {
|
|
5930
|
+
clientId = parseApiKey(config.apiKey).keyId;
|
|
5931
|
+
}
|
|
5932
|
+
if (!clientId) {
|
|
5933
|
+
throw new NeetruError(
|
|
5934
|
+
"invalid_config",
|
|
5935
|
+
"auth.signIn requer `oidcClientId` (ou `apiKey`) configurado para montar o client_id."
|
|
5936
|
+
);
|
|
5937
|
+
}
|
|
5938
|
+
const state = randomUrlSafe(crypto2, 16);
|
|
5939
|
+
const nonce = randomUrlSafe(crypto2, 16);
|
|
5940
|
+
const codeVerifier = randomUrlSafe(crypto2, 32);
|
|
5941
|
+
const codeChallenge = await pkceChallengeS256(crypto2, codeVerifier);
|
|
5942
|
+
const session = getSessionStorage();
|
|
5943
|
+
if (!session) {
|
|
5944
|
+
throw new NeetruError(
|
|
5945
|
+
"runtime_unsupported",
|
|
5946
|
+
"auth.signIn requer sessionStorage para guardar a transa\xE7\xE3o PKCE entre o redirect e o callback."
|
|
5947
|
+
);
|
|
5948
|
+
}
|
|
5949
|
+
const tx = {
|
|
5950
|
+
state,
|
|
5951
|
+
nonce,
|
|
5952
|
+
codeVerifier,
|
|
5953
|
+
redirectUri,
|
|
5954
|
+
postLoginRedirect: options?.postLoginRedirect
|
|
5955
|
+
};
|
|
5956
|
+
session.setItem(OIDC_TX_KEY, JSON.stringify(tx));
|
|
5957
|
+
const idpOrigin = resolveIdpOrigin(config.baseUrl);
|
|
5783
5958
|
const url = new URL("/api/v1/oauth/authorize", idpOrigin);
|
|
5784
5959
|
url.searchParams.set("response_type", "code");
|
|
5960
|
+
url.searchParams.set("client_id", clientId);
|
|
5785
5961
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
5786
5962
|
url.searchParams.set("scope", scope);
|
|
5787
5963
|
url.searchParams.set("state", state);
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
}
|
|
5964
|
+
url.searchParams.set("nonce", nonce);
|
|
5965
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
5966
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
5792
5967
|
globalThis.location.assign(url.toString());
|
|
5793
5968
|
return;
|
|
5794
5969
|
}
|
|
@@ -5797,6 +5972,67 @@ function createOidcAuthNamespace(config) {
|
|
|
5797
5972
|
"auth.signIn requires a browser context or mocks. Use NEETRU_ENV=dev or pass mocks.auth."
|
|
5798
5973
|
);
|
|
5799
5974
|
},
|
|
5975
|
+
async handleRedirectCallback(currentUrl) {
|
|
5976
|
+
const href = currentUrl ?? (typeof globalThis.location !== "undefined" ? globalThis.location.href : void 0);
|
|
5977
|
+
if (!href) return null;
|
|
5978
|
+
let parsed;
|
|
5979
|
+
try {
|
|
5980
|
+
parsed = new URL(href);
|
|
5981
|
+
} catch {
|
|
5982
|
+
return null;
|
|
5983
|
+
}
|
|
5984
|
+
const params = parsed.searchParams;
|
|
5985
|
+
const idpError = params.get("error");
|
|
5986
|
+
if (idpError) {
|
|
5987
|
+
const desc = params.get("error_description") ?? idpError;
|
|
5988
|
+
getSessionStorage()?.removeItem(OIDC_TX_KEY);
|
|
5989
|
+
cleanCallbackUrl(parsed);
|
|
5990
|
+
throw new NeetruError(idpError, `OIDC authorize falhou: ${desc}`);
|
|
5991
|
+
}
|
|
5992
|
+
const code = params.get("code");
|
|
5993
|
+
if (!code) return null;
|
|
5994
|
+
const returnedState = params.get("state");
|
|
5995
|
+
const session = getSessionStorage();
|
|
5996
|
+
const txRaw = session?.getItem(OIDC_TX_KEY) ?? null;
|
|
5997
|
+
let tx = null;
|
|
5998
|
+
if (txRaw) {
|
|
5999
|
+
try {
|
|
6000
|
+
tx = JSON.parse(txRaw);
|
|
6001
|
+
} catch {
|
|
6002
|
+
tx = null;
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
if (!tx) {
|
|
6006
|
+
throw new NeetruError(
|
|
6007
|
+
"oidc_state_mismatch",
|
|
6008
|
+
"Callback OIDC sem transa\xE7\xE3o pendente \u2014 `signIn` n\xE3o foi iniciado nesta sess\xE3o (ou j\xE1 consumido)."
|
|
6009
|
+
);
|
|
6010
|
+
}
|
|
6011
|
+
if (!returnedState || returnedState !== tx.state) {
|
|
6012
|
+
session?.removeItem(OIDC_TX_KEY);
|
|
6013
|
+
cleanCallbackUrl(parsed);
|
|
6014
|
+
throw new NeetruError(
|
|
6015
|
+
"oidc_state_mismatch",
|
|
6016
|
+
"state do callback OIDC n\xE3o confere com o da transa\xE7\xE3o (poss\xEDvel CSRF)."
|
|
6017
|
+
);
|
|
6018
|
+
}
|
|
6019
|
+
session?.removeItem(OIDC_TX_KEY);
|
|
6020
|
+
cleanCallbackUrl(parsed);
|
|
6021
|
+
return {
|
|
6022
|
+
code,
|
|
6023
|
+
codeVerifier: tx.codeVerifier,
|
|
6024
|
+
redirectUri: tx.redirectUri,
|
|
6025
|
+
nonce: tx.nonce,
|
|
6026
|
+
state: tx.state,
|
|
6027
|
+
postLoginRedirect: tx.postLoginRedirect
|
|
6028
|
+
};
|
|
6029
|
+
},
|
|
6030
|
+
getIdToken() {
|
|
6031
|
+
const storage = getStorage();
|
|
6032
|
+
const token = storage?.getItem(STORAGE_KEY) ?? null;
|
|
6033
|
+
if (!token) return null;
|
|
6034
|
+
return tokenToUser(token) ? token : null;
|
|
6035
|
+
},
|
|
5800
6036
|
async signOut() {
|
|
5801
6037
|
const storage = getStorage();
|
|
5802
6038
|
const storedToken = storage?.getItem(STORAGE_KEY) ?? null;
|
|
@@ -5903,6 +6139,7 @@ function createNeetruClient(config = {}) {
|
|
|
5903
6139
|
const env = resolveEnv(config.env);
|
|
5904
6140
|
const resolved = Object.freeze({
|
|
5905
6141
|
apiKey,
|
|
6142
|
+
oidcClientId: config.oidcClientId,
|
|
5906
6143
|
baseUrl,
|
|
5907
6144
|
fetch: fetchImpl.bind(globalThis),
|
|
5908
6145
|
env,
|