feat(connectors/distribution): Postiz organic + Meta/TikTok DRAFT + Klaviyo Flows#22
Open
ninan-versioning wants to merge 1 commit into
Open
feat(connectors/distribution): Postiz organic + Meta/TikTok DRAFT + Klaviyo Flows#22ninan-versioning wants to merge 1 commit into
ninan-versioning wants to merge 1 commit into
Conversation
…laviyo Flows New @shoploop/connector-distribution package: four channel adapters behind a shared AdapterInterface, with MCP, Temporal, and CLI as thin shells over one dispatch core. - Postiz (organic): fan-out across meta_page/tiktok_business/ig_business/x - Meta (paid_draft): Marketing API v20.0, PAUSED campaign/adset/ad - TikTok (paid_draft): Marketing API v1.3, DISABLE campaign/adgroup/ad - Klaviyo (transactional): shoploop.creative_pack.ready Flow event; 409 = success DRAFT-only is enforced twice: payloads are built PAUSED/DISABLE, and a runtime assertNoLivePublish guard throws LivePublishForbidden on any ACTIVE/non-DISABLE status before the request leaves the process. No live-publish path exists in this PR. Idempotency keyed by (pack_id, channel, audience_id) via a LibSQL dispatch_log and the Temporal workflow id. FanoutPackWorkflow returns partial success. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New package
@shoploop/connector-distribution— the distribution layer that pushes Creative Packs (open-imaginecreative_pack.v1) to channels. Four adapters behind one sharedAdapterInterface; MCP, Temporal, and the CLI are thin shells over a single dispatch core. Mirrors the shape of the Shopify (PR #15) and Google Ads (PR #18) connectors.Adapters
organicpaid_draftstatus=PAUSEDstatus=ACTIVE⇒LivePublishForbiddenpaid_draftoperation_status=DISABLEoperation_status≠DISABLE⇒LivePublishForbiddentransactionalshoploop.creative_pack.readyServer Event (Flow owns send timing)DRAFT-only — enforced twice, no live path
Paid adapters are DRAFT-only in this PR. There is no live-publish code path, not even behind a flag. Two
LivePublishForbiddenguards scan every outbound payload before it leaves the process:meta.ts→assertNoLivePublish()throws if anystatus/effective_status/configured_status === "ACTIVE".tiktok.ts→assertNoLivePublish()throws if anyoperation_status !== "DISABLE".adapters.test.tsasserts both guards throw on a mutated (ACTIVE / ENABLE) payload, and that every real outbound Meta/TikTok body is PAUSED/DISABLE.Idempotency
Keyed by
(pack_id, channel, audience_id)at two layers: a LibSQLdispatch_logtable (non-failed row short-circuits, failed row retries) and the Temporal workflow iddispatch:<channel>:<packId>:<audienceHash>withREJECT_DUPLICATE.FanoutPackWorkflowfans out to all channels and returns partial success — one channel failing does not fail the workflow.Varitea acceptance
shoploop-distribution dispatch --pack test/fixtures/varitea_pack.json --channels allproduces 1 Klaviyo event + 1 Postiz organic schedule + 1 PAUSED Meta ad + 1 DISABLE TikTok ad, with channel URLs (verified locally against a mock standing in for all four APIs):Cost
Postiz $0–$20/mo (self-host or Cloud) · Meta/TikTok $0 (DRAFT-only ⇒ no ad spend) · Klaviyo events included · LibSQL $0 · co-located on the existing t4g.small. Total: $0–$20/mo.
Test plan
npm run typecheck— cleannpm run build— cleannpm test— 19/19 pass (adapters, workflows, mcp)adapters.test.ts— Meta/TikTok DRAFT invariants, bothLivePublishForbiddenguards, Klaviyo 409→success, Postiz multi-network aggregation, BrandVoiceViolationworkflows.test.ts— FanoutPack across 4 channels, idempotency on retry, partial success when one channel failsmcp.test.ts— in-process SSE; all 5 tools (dispatch_pack,get_dispatch,list_recent_dispatches,cancel_dispatch,list_channels)🤖 Generated with Claude Code