@duabalabs/connect-client
v0.4.0
Published
Typed client for DuabaConnect: social-media marketing (auto-generated, scheduled posts via connected platforms) and AI automations (parameterized n8n workflows) — the capabilities Sellub and other apps embed on behalf of their clients.
Readme
@duabalabs/connect-client
Typed client for DuabaConnect — the engine behind two client-facing capabilities other apps (e.g. Sellub) embed on behalf of their clients:
social— connect a client's social platforms, then run product campaigns that auto-generate image/video posts and publish them on a schedule (Postiz under the hood).automations— a catalog of parameterized AI/n8n workflows a client can deploy and run against their commerce journey.
npm install @duabalabs/connect-clientAuth & identity
apiKeyidentifies your app to Connect. Server-only — never ship it to the browser.clientRefis your stable identifier for the end client (e.g. the Sellub seller's account id or email). Connect maps it to its own account / Postiz customer. Pass the sameclientReffor the same client every time.
import { createConnectClient } from "@duabalabs/connect-client";
const connect = createConnectClient({
baseUrl: process.env.CONNECT_API_URL, // default https://api.duabaconnect.com
apiKey: process.env.CONNECT_API_KEY, // server-only
});Social: a product campaign
// 1. The client connects a platform (redirect them to the returned URL).
const { authorizationUrl } = await connect.social.connectPlatform({
clientRef, platform: "instagram", returnUrl: "https://app.sellub.com/marketing",
});
// 2. Launch an auto-posting campaign for a product.
const { campaign } = await connect.social.createCampaign({
clientRef,
product: { id: variant.id, name: variant.name, imageUrl, price, currency: "GHS", url },
platforms: ["instagram", "tiktok"],
mediaType: "video",
frequencyPerWeek: 3,
brief: "Energetic, Gen-Z tone; highlight the discount.",
});
// 3. Preview a single AI post. For video, content.status may be "generating"
// (the asset lands on the campaign post asynchronously).
const { content } = await connect.social.generateContent({
clientRef, product, mediaType: "image",
});Review & publish loop
Campaign posts are generated for review, not auto-posted. The scheduler
creates a post per platform as generating (async video) → ready (media in).
The client reviews ready posts and publishes them ("resend for posting"):
const { posts } = await connect.social.listPosts(campaign!.id);
const ready = posts!.filter((p) => p.status === "ready");
await connect.social.publishPost(ready[0].id); // → pushes to the platformMedia generation is an umbrella behind the server (CONNECT_MEDIA_GEN_PROVIDER):
an n8n workflow or Postiz generator returns the video to a callback that lands it
on the post; with no provider it's a caption-only draft.
Automations: subscribe → deploy → run
Billing flows through Sellub — each automation carries a sellubPlanCode.
Start the subscription on that plan with the Sellub SDK; Connect provisions on
the resulting entitlement.
const { automations } = await connect.automations.listCatalog();
// → each item has { workflowKey, name, priceGhs, sellubPlanCode, parameters }
// After the client is billed (Sellub) and entitled:
const { active } = await connect.automations.getEntitlement({ clientRef, workflowKey });
const { instance } = await connect.automations.deploy({
clientRef, workflowKey, config: { region: "GH", minMargin: 15 },
});
const { runId } = await connect.automations.run({ clientRef, instanceId: instance!.id });
const { result } = await connect.automations.getOutput({ clientRef, runId: runId! });Conventions
- Every method resolves to
{ success: boolean; …; error?: string }— never throws on HTTP/4xx/5xx (only on a missingfetch). Checksuccess. - Money amounts are in major units here for
priceGhs(display), but post durations/timestamps are ISO 8601. - The client is isomorphic (browser + Node 18+ global
fetch); passoptions.fetchfor other runtimes. Keep theapiKeyserver-side.
