মূল কনটেন্টে যান

ক্লায়েন্ট লাইব্রেরি

ফ্রেমওয়ার্ক অ্যাডাপ্টার

TypeScript SDK

একটি প্যাকেজ, ছয়টি এন্ট্রি পয়েন্ট। আপনার রানটাইমের সাথে যেটি মেলে সেটি ইমপোর্ট করুন, ট্রি-শেকিং বিল্ড বাকিগুলি আপনার বান্ডল থেকে বাদ রাখে।

যেখানে প্রকাশিত

@prodantix/sdk on npm.

ইনস্টল

Bash
bun add @prodantix/sdk

এন্ট্রি পয়েন্ট

প্রতিটি সাবপাথ নিজস্ব ESM ও CommonJS বিল্ড এবং নিজস্ব টাইপ নিয়ে আসে। রুটটি রানটাইম-নিরপেক্ষ, আর বাকিগুলি একটি নির্দিষ্ট রানটাইমের যা দরকার তা যোগ করে।

SubpathWhat it exports
@prodantix/sdkProdantixClient, createClient, evaluateFlag, FlagsClient, MessagesClient
@prodantix/sdk/webcreateWebClient, installAutocapture, installLinkCarry, installSessionReplay, WebTransport
@prodantix/sdk/nodecreateNodeClient, readSharedIdentity
@prodantix/sdk/cspprodantixConnectSrc, prodantixImgSrc, prodantixScriptSrc
@prodantix/sdk/chatmountChat, ChatClient, ChatPanel, resolveAppearance
@prodantix/sdk/messengerfetchMessengerConfig, cachedMessengerConfig, MESSENGER_CACHE_KEY

@prodantix/sdk

ক্লায়েন্ট, ফ্ল্যাগ মূল্যায়নকারী, এবং স্টোরেজ ও ট্রান্সপোর্ট ইন্টারফেস। এখানে কিছুই DOM স্পর্শ করে না, তাই আপনি নিজের স্টোরেজ, ট্রান্সপোর্ট, ক্লক বা আইডি ফ্যাক্টরি দিয়ে যেকোনো জায়গায় চালাতে পারেন।

TypeScript
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

একই ক্লায়েন্টের উপরে ব্রাউজার ওয়্যারিং: লোকাল স্টোরেজে সংরক্ষণ, পেজ লুকালে বিকন দিয়ে পাঠানো, এবং পেজভিউ ও ক্লিকের অটোক্যাপচার। রিপ্লে হোস্ট না দেওয়া পর্যন্ত সেশন রিপ্লে বন্ধ থাকে।

TypeScript
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>'] })) {
  // ...
}

ওয়েবে দর্শকের বেনামী আইডি ও সেশন আপনার নিবন্ধনযোগ্য ডোমেইনে একটি ফার্স্ট-পার্টি কুকিতে থাকে, তাই xyz.com, app.xyz.com ও console.xyz.com একজন ব্যক্তিকেই দেখে: মার্কেটিং ভিজিট, সাইন-আপ এবং অ্যাপে প্রথম সেশন একই টাইমলাইনে পড়ে, যখনই অ্যাপ তাকে শনাক্ত করে। শনাক্ত আইডি প্রতিটি অরিজিনে লোকাল স্টোরেজে থাকে এবং কখনও কুকিতে ঢোকে না, কারণ ডোমেইনের অধীনে প্রতিটি হোস্ট সেটি পড়তে পারে। ডোমেইন ব্রাউজারকে জিজ্ঞেস করে পাওয়া যায়, অথবা cookieDomain দিয়ে সেট করা হয়; যে সাইটের সাবডোমেইনগুলো ভিন্ন ভিন্ন টেন্যান্টের, তাকে এটি নিজের হোস্টে সেট করতে হবে। কোনো কুকি না লিখতে sharedStorage পাঠান, যেমন সম্মতি পাওয়ার আগে পর্যন্ত, আর কুকি প্রত্যাখ্যাত হলে লোকাল স্টোরেজই ফলব্যাক থাকে। প্রতি ভিজিটে একটি সেশন আইডি তৈরি হয়, ত্রিশ মিনিট নিষ্ক্রিয় থাকলে বা চব্বিশ ঘণ্টা পর বদলায়, প্রতিটি ইভেন্টে বসানো হয় এবং সেশন রিপ্লের সাথে ভাগ করা হয়।

একটি কুকি নিবন্ধনযোগ্য ডোমেইন পার হতে পারে না, তাই এক সাইট থেকে অন্য সাইটে লিঙ্ক অনুসরণ করা দর্শক দুজন দর্শক হয়ে যেত। linkedDomains পাঠান, যা ডিফল্টে খালি, তখন ক্লায়েন্ট সেই ডোমেইনগুলোর দিকে যাওয়া লিঙ্কগুলোকে click ও auxclick-এ একটি _pdx প্যারামিটার দিয়ে সাজায়; প্যারামিটারটি তিনটি জিনিস বহন করে: বেনামী আইডি, সেশন আইডি এবং সেশন শুরুর মুহূর্ত, যাতে ত্রিশ মিনিটের জানালা ও চব্বিশ ঘণ্টার সীমা লাফের পরেও চলতে থাকে। কেবল বেনামী আইডিই যায়, শনাক্ত আইডি কখনও নয়, কারণ গন্তব্য নিজেই ব্যক্তিকে শনাক্ত করে। একই নিবন্ধনযোগ্য ডোমেইনের লিঙ্ক, যেটিতে আগে থেকেই _pdx আছে, এবং mailto, tel, javascript ও হ্যাশ লিঙ্ক সবই অস্পর্শ থাকে। পৌঁছানোর পর createWebClient পরিচয় গড়ার আগেই _pdx পড়ে, বহন করা আইডি ও সেশন শেয়ার্ড স্টোরে লেখে, এবং history.replaceState দিয়ে প্যারামিটারটি সরায়, ফলে সেটি $current_url-এ দেখা যায় না এবং সামনেও যায় না; যে প্যারামিটারের তিনটি অংশ পড়া যায় না তা উপেক্ষা করা হয় এবং ঠিকানা যেমন ছিল তেমনই থাকে। এই হোস্টে যদি আগে থেকেই অন্য একটি বেনামী আইডি থাকে, ক্লায়েন্ট $create_alias পাঠায়, তাই আগে যা রেকর্ড হয়েছিল তা বাহিত আইডিতে মিশে যায়; আর যে হোস্ট আগেই কোনো ব্যক্তিকে শনাক্ত করেছে সে সেই ব্যক্তিকেই রাখে: বাহিত আইডি তার বেনামী আইডি হয়, কখনও তার শনাক্ত আইডি নয়।

TypeScript
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 }

সেই সংযুক্তি নিয়ে দর্শকের নিজের উত্তরও একই শেয়ার্ড স্টোরে থাকে, pdx..consent-এর নিচে, তাই প্রতিটি সাবডোমেইন এবং কুকি পড়া সার্ভার একটিই উত্তর দেখে। setConsent({ identityLink: false }) দিয়ে সেটি রেকর্ড করুন, consent() দিয়ে পড়ুন, আর আপনার অ্যাপে উত্তরটি আগেই থাকলে consent বিকল্প দিয়ে বসিয়ে দিন: সম্মতির ব্যানার আপনার বানানোর জিনিস, আর prodantix তা সংগ্রহ করা উত্তরকে সম্মান করে। identityLink যখন false, তখন identify ব্যক্তির সঙ্গে জোড়া লাগানোর জন্য কোনো বেনামী আইডি পাঠায় না, আর কোনো লিঙ্কড ডোমেইনের লিঙ্ক সাজানো হয় না, কারণ আইডি বয়ে নেওয়া মানেই অন্য পথে একই সংযুক্তি। অসেট বা true দুটোই অনুমোদন করে, তবে কনসোলে প্রকল্পের নিজস্ব সেটিং অনুযায়ী, যা ব্রাউজারের পাঠানো কিছু নয় বরং স্টেট ওয়ার্কার প্রয়োগ করে। উত্তর বদলালে তা পরের identify ও পরের ক্লিক থেকে কার্যকর হয়; আগে যা জোড়া লেগেছে তা খোলে না।

@prodantix/sdk/node

একই ক্লায়েন্ট, সার্ভারের ডিফল্ট নিয়ে। ইভেন্টগুলি বাফারে জমা হয়ে পটভূমিতে পাঠানো হয়, তাই প্রসেস শেষ হওয়ার আগে shutdown কল করুন, নইলে শেষ ব্যাচটি কখনও বের হবে না।

TypeScript
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();

সার্ভার রিডাইরেক্টে শেষ হওয়া সাইন-ইন কোনো পাতা আঁকে না, তাই ব্রাউজারের নিজস্ব identify সেখানে কখনও চলে না। readSharedIdentity(cookieHeader, apiKey) ওয়েব ক্লায়েন্টের লেখা কুকি পড়ে এবং বেনামী আইডি, যে সেশনে সে আছে এবং দর্শকের সম্মতি ফিরিয়ে দেয়, অথবা কুকি না থাকলে বা সেটি এই SDK-র না হলে null দেয়। এরপর link(distinctId, anonymousId, traits) ব্রাউজার যে একটিমাত্র $identify পাঠাত সেটিই দেওয়া আইডি দুটির জন্য পাঠায়, এই ক্লায়েন্টের নিজের পরিচয়ে হাত না দিয়ে। Bomdisoft-এর লগইন সাইন-ইন সম্পূর্ণ হওয়ার মুহূর্তে দুটোই ডাকে, সেই একটিমাত্র ফাংশনের ভেতরে যেটি তার আটটি সাইন-ইন জায়গাই আগে থেকে ডাকে: সেখানেই ব্যক্তির subject প্রথমবার সার্ভারে জানা যায় আর কুকিটি তখনও অনুরোধের সঙ্গে থাকে। ওই জায়গাগুলোর ছয়টি সার্ভার অ্যাকশন, যাদের কোনো রিকোয়েস্ট অবজেক্ট নেই, তাই ফাংশনটি রিকোয়েস্ট নয়, কুকি হেডার স্ট্রিং নেয়। পড়ে পাওয়া উত্তর identityLink false হলে link এড়িয়ে যান।

TypeScript
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

একটি অ্যাপকে Prodantix-এ পৌঁছাতে যে কনটেন্ট সিকিউরিটি পলিসি সোর্সগুলি লাগে। এটি React বা ব্রাউজার থেকে কিছুই ইমপোর্ট করে না, তাই একটি বিল্ড কনফিগ ফাইল সরাসরি এটি পড়তে পারে।

TypeScript
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('; ');

সাপোর্ট উইজেট আপনার টিমের ছবি edge থেকে দেখায় এবং ভিজিটরদের পাঠানো ফাইল blob: ঠিকানা থেকে আঁকে, তাই পলিসির img-src-এ দুটোই লাগে। prodantixImgSrc এগুলো আপনার আগে থেকে অনুমোদিত ছবির সোর্সের সঙ্গে যোগ করে। এগুলো ছাড়া ব্রাউজার সেই ছবিগুলো আটকে দেয় এবং শুধু নিজের কনসোলেই তা জানায়।

@prodantix/sdk/chat

সাপোর্ট উইজেট। এটি মাউন্ট করলে এমন একটি হ্যান্ডেল পাবেন যা খোলে, বন্ধ করে, ধ্বংস করে এবং পরিচয় দেয়। এটি একটি বন্ধ শ্যাডো রুটের ভিতরে আঁকা হয়, তাই হোস্ট পেজের স্টাইল কখনও এতে পৌঁছায় না।

TypeScript
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());

দর্শকের প্রতিটি বার্তা বহন করে সেটি কোথায় লেখা হয়েছিল। প্যানেল পাঠানোর মুহূর্তে location ও document.title পড়ে এবং host, path ও title পাঠায়, যেখানে path কেবল পাথনেম: কখনও কোয়েরি নয়, কখনও ফ্র্যাগমেন্ট নয়, কারণ রিসেট লিঙ্ক, ম্যাজিক লিঙ্ক বা চেকআউট রিটার্ন সেখানেই তার টোকেন বহন করে, আর এজেন্টের ইনবক্স তার জায়গা নয়। প্যানেল এর কিছুই আঁকে না, তাই দর্শকের থ্রেড তার নিজের কথাই থাকে; এজ থেকে SDK-তে ফেরা উত্তরও এটি বাদ দেয়, তাই নিজের থ্রেড পড়া কোনো পাতা কনসোল যা দেখে তা দেখতে পায় না। এটি দেখা যায় ইনবক্সে, একটি ইনবাউন্ড টার্নের নিচে একটি মৃদু লাইন হিসেবে।

@prodantix/sdk/messenger

উইজেটের পেছনের সেটিংস রিডার: এটি একটি প্রকল্পের মেসেঞ্জার কনফিগারেশন আনে, ক্যাশ করে, এবং প্রকল্পটি মেসেঞ্জার চালু রেখেছে কি না তা জানায়। স্বয়ংচালিত স্নিপেট বিল্ডটি আলাদাভাবে তৈরি হয় এবং এই সাবপাথ দিয়ে পাওয়া যায় না।

TypeScript
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
}