SDK TypeScript
Um pacote com seis pontos de entrada. Importe o que corresponde ao seu runtime, e a build com tree shaking deixa o restante fora do seu bundle.
Onde está publicado
@prodantix/sdk on npm.
Instalação
bun add @prodantix/sdkPontos de entrada
Cada subcaminho traz sua própria build ESM e CommonJS com seus próprios tipos. A raiz independe do runtime, e os demais acrescentam o que um runtime específico precisa.
| Subpath | What it exports |
|---|---|
| @prodantix/sdk | ProdantixClient, createClient, evaluateFlag, FlagsClient, MessagesClient |
| @prodantix/sdk/web | createWebClient, installAutocapture, installLinkCarry, installSessionReplay, WebTransport |
| @prodantix/sdk/node | createNodeClient, readSharedIdentity |
| @prodantix/sdk/csp | prodantixConnectSrc, prodantixImgSrc, prodantixScriptSrc |
| @prodantix/sdk/chat | mountChat, ChatClient, ChatPanel, resolveAppearance |
| @prodantix/sdk/messenger | fetchMessengerConfig, cachedMessengerConfig, MESSENGER_CACHE_KEY |
@prodantix/sdk
O cliente, o avaliador de flags e as interfaces de armazenamento e transporte. Nada aqui toca no DOM, então você pode fornecer seu próprio armazenamento, transporte, relógio ou fábrica de ids e executá-lo em qualquer lugar.
import { createClient, MemoryStorage } from '@prodantix/sdk';
const prodantix = createClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
storage: new MemoryStorage(),
});
prodantix.capture('order.completed', { properties: { amount: 4200, currency: 'XAF' } });
await prodantix.flush();@prodantix/sdk/web
A fiação de navegador sobre o mesmo cliente: persistência no armazenamento local, entrega por beacon quando a página se oculta, e autocaptura de pageviews e cliques. A repetição de sessão fica desligada até você informar um host de repetição.
import { createWebClient } from '@prodantix/sdk/web';
const prodantix = createWebClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
flagsHost: 'https://api.prodantix.com',
cookieDomain: 'example.com',
autocaptureOptions: { clicks: true, pageviews: true },
});
prodantix.identify('user-42', { set: { plan: 'pro' } });
if (await prodantix.isFeatureEnabled('new-checkout')) {
// ...
}
// Every per-flag read records one $feature_flag_called exposure.
const variant = await prodantix.getVariant('new-checkout');
if (variant?.key === 'treatment') {
// ...
}
// A flag targeting a cohort reads this user's memberships from the store;
// pass them yourself to skip the lookup.
if (await prodantix.isFeatureEnabledLocal('members', { cohorts: ['<cohort id>'] })) {
// ...
}Na web, o id anônimo e a sessão do visitante vivem em um único cookie de primeira parte no seu domínio registrável, de modo que xyz.com, app.xyz.com e console.xyz.com veem uma só pessoa: a visita de marketing, o cadastro e a primeira sessão no app caem na mesma linha do tempo assim que o app a identifica. O id identificado fica por origem no armazenamento local e nunca entra no cookie, porque todo host sob o domínio consegue lê-lo. O domínio é descoberto perguntando ao navegador, ou definido com cookieDomain; um site cujos subdomínios pertencem a inquilinos diferentes precisa defini-lo como o próprio host. Passe sharedStorage para não gravar cookie algum, por exemplo até que o consentimento seja dado, e o armazenamento local continua sendo a alternativa quando cookies são recusados. Um id de sessão é criado por visita, renovado após trinta minutos de inatividade ou vinte e quatro horas, carimbado em todo evento e compartilhado com a repetição de sessão.
Um cookie não consegue atravessar um domínio registrável, portanto um visitante que segue um link de um site para outro seria dois visitantes. Passe linkedDomains, vazio por padrão, e o cliente decora os links de saída para esses domínios, em click e auxclick, com um parâmetro _pdx que carrega três coisas: o id anônimo, o id da sessão e o instante em que a sessão começou, de modo que a janela de trinta minutos e o teto de vinte e quatro horas continuem depois do salto. Só o id anônimo viaja, nunca um id identificado, porque o destino identifica a pessoa por conta própria. Um link para o mesmo domínio registrável, um que já carrega _pdx, e os links mailto, tel, javascript e de âncora ficam todos intactos. Na chegada, createWebClient lê _pdx antes de a identidade ser construída, grava o id e a sessão trazidos no armazenamento compartilhado e retira o parâmetro com history.replaceState, de forma que ele não apareça em $current_url nem siga adiante; um parâmetro cujas três partes não se leem é ignorado e o endereço fica como estava. Se este host já tinha outro id anônimo, o cliente envia $create_alias, e o que havia registrado antes se dobra no id trazido; e um host que já identificou uma pessoa mantém essa pessoa: o id trazido vira o id anônimo dela, nunca o seu distinct id.
import { createWebClient } from '@prodantix/sdk/web';
const prodantix = createWebClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
linkedDomains: ['example.com', 'example-app.com'],
});
// A link to example-app.com now leaves as
// https://example-app.com/pricing?_pdx=<anonymousId>~<sessionId>~<startedAt>
// and the arriving page adopts it before it builds an identity of its own.
// The visitor's answer, from your own consent banner.
prodantix.setConsent({ identityLink: false });
prodantix.consent(); // { identityLink: false }A própria resposta do visitante sobre essa junção viaja no mesmo armazenamento compartilhado, sob pdx..consent, de modo que cada subdomínio e um servidor que leia o cookie vejam uma só resposta. Registre-a com setConsent({ identityLink: false }), leia-a de volta com consent(), e semeie-a com a opção consent quando sua aplicação já tiver a resposta: o banner de consentimento é seu para construir, e o prodantix honra o que ele recolhe. Enquanto identityLink for false, identify não envia id anônimo para juntar à pessoa, e um link para um domínio listado fica sem decoração, já que levar o id para lá é a mesma junção por outro caminho. Não definido ou true permite ambos, sujeito à configuração do próprio projeto no console, que o state worker aplica e não qualquer coisa que o navegador envie. Mudar a resposta vale a partir do próximo identify e do próximo clique; nada já juntado é desfeito.
@prodantix/sdk/node
O mesmo cliente com padrões de servidor. Os eventos ficam em buffer e são enviados em segundo plano, então chame shutdown antes de o processo terminar ou o último lote nunca sai.
import { createNodeClient } from '@prodantix/sdk/node';
// A node client streams flag changes over Socket.IO by default and refetches
// the snapshot on push; streamFlags: false leaves only the 30s poll.
const prodantix = createNodeClient({
apiKey: process.env.PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
streamFlags: true,
});
prodantix.capture('job.completed', { properties: { queue: 'emails' } });
await prodantix.shutdown();Um login que termina em um redirecionamento do servidor não desenha página alguma, então o identify do próprio navegador nunca roda ali. readSharedIdentity(cookieHeader, apiKey) lê o cookie que o cliente web escreve e responde o id anônimo, a sessão em que ele está e o consentimento do visitante, ou null quando o cookie está ausente ou não é deste SDK. Em seguida, link(distinctId, anonymousId, traits) envia o único $identify que o navegador teria enviado, para os ids dados, e deixa intacta a identidade do próprio cliente. O login da Bomdisoft chama os dois na conclusão do login, dentro da única função que todos os seus oito pontos de entrada já chamam: é ali que o subject da pessoa passa a ser conhecido no servidor enquanto o cookie ainda está na requisição. Seis desses pontos são server actions sem objeto de requisição, e por isso a função recebe uma string de cabeçalho de cookies em vez de uma requisição. Pule link quando a resposta lida de volta for identityLink false.
import { createNodeClient, readSharedIdentity } from '@prodantix/sdk/node';
const prodantix = createNodeClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
});
// At sign-in completion, where the person is known and the browser's
// cookie is still on the request.
export const completeSignIn = (sub: string, cookieHeader: string): void => {
const shared = readSharedIdentity(cookieHeader, PRODANTIX_PUBLIC_KEY);
if (shared !== null && shared.consent?.identityLink !== false) {
prodantix.link(sub, shared.anonymousId);
}
};@prodantix/sdk/csp
As fontes de política de segurança de conteúdo que um aplicativo precisa para alcançar o Prodantix. Não importa nada do React nem do navegador, então um arquivo de configuração de build pode lê-lo diretamente.
import { prodantixConnectSrc, prodantixImgSrc, prodantixScriptSrc } from '@prodantix/sdk/csp';
const hosts = {
ingest: 'https://eu.api.prodantix.com',
edge: 'https://eu.edge.prodantix.com',
replay: 'https://eu.replay.prodantix.com',
};
const policy = [
`connect-src ${prodantixConnectSrc(hosts)}`,
`script-src ${prodantixScriptSrc(hosts)}`,
`img-src ${prodantixImgSrc(hosts, ["'self'", 'data:'])}`,
].join('; ');O widget de suporte mostra as fotos da sua equipe a partir do edge e desenha os arquivos enviados pelos visitantes a partir de endereços blob:, então o img-src da política precisa dos dois. prodantixImgSrc os adiciona às fontes de imagem que você já permite. Sem eles, o navegador bloqueia essas imagens e só avisa no próprio console.
@prodantix/sdk/chat
O widget de suporte. Monte-o e você recebe um handle que abre, fecha, destrói e identifica o usuário. Ele é renderizado dentro de uma shadow root fechada, então os estilos da página hospedeira nunca o alcançam.
import { mountChat } from '@prodantix/sdk/chat';
const messenger = mountChat({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.edge.prodantix.com',
distinctId: prodantix.distinctId,
});
document.querySelector('#help')?.addEventListener('click', () => messenger.open());Cada mensagem do visitante carrega onde foi escrita. O painel lê location e document.title no momento do envio e envia host, path e title, sendo path apenas o caminho: nunca a consulta e nunca o fragmento, porque um link de redefinição, um link mágico ou um retorno do checkout carrega o seu token ali, e a caixa de entrada de um agente não é lugar para isso. O painel não desenha nada disso, então a conversa do visitante continua sendo apenas as palavras dele, e a resposta da borda de volta ao SDK também o omite, de modo que uma página que lê a própria conversa não vê o que o console vê. Onde ele aparece é na caixa de entrada, como uma linha discreta sob uma mensagem recebida.
@prodantix/sdk/messenger
O leitor de configurações por trás do widget: ele busca a configuração do mensageiro de um projeto, guarda em cache e informa se o projeto tem o mensageiro ligado. O trecho autoexecutável é construído à parte e não é alcançável por este subcaminho.
import { fetchMessengerConfig } from '@prodantix/sdk/messenger';
const config = await fetchMessengerConfig({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.edge.prodantix.com',
});
if (config?.enabled) {
// the project has the messenger switched on
}