Skip to content

feat(campaigns): campaign recipients, audiences and opt-out settings - #30

Merged
purpshell merged 22 commits into
devfrom
t3code/campaigns-p0-cli
Sep 23, 2026
Merged

purpshell merged 22 commits into
devfrom
t3code/campaigns-p0-cli

Conversation

@purpshell

@purpshell purpshell commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

Campaigns can manage audiences, append and list recipients, and read or replace keyword opt-out settings through the CLI. Recipient output preserves pagination and partial-import results. Stop reports immediate cancellation when the API returns a null operation ID.

Campaign commands use the Messaging API with a project slug. Audience and opt-out commands use organization-scoped Platform methods. CSV input is parsed locally and sent inline; server-side import accepts an existing file ID and mapping. Empty batches, malformed variables and unsafe names fail before transport. Appends are sent once by default.

Create and lifecycle help describes the API's 24-hour idempotency receipt: a repeated successful request returns 409 idempotency_completed. Requeue has no replay guarantee. Existing operation commands inspect asynchronous work.

The CLI pins the published @polymorfa/sdk@0.1.0-dev.20260923115544 exactly in its manifest and lockfile. That SDK dev build comes from 8ce8f7bae55fbc03da5a68e5609864d5742dc201, a descendant of merged sdks#285 at 7b8b44e9cd15356724e5ba825db320d90d896b06. The Campaigns contract comes from merged API dev at f4a340da3b74248232ebea73f3e72b42f667beef.

Part Assessment
API Unaffected here: no handlers or specs changed. Commands use the merged Campaigns P0 contract in polymorfa#232, including cursor pages, nullable stop operation IDs and append limits.
SDKs Updated in sdks#285, merged and included in the exact dev version pinned here. The installed package exposes the Campaigns and Functions types and methods used by this CLI head.
CLI Commands, flags, input validation, output, errors and help updated. The exact registry SDK dependency is pinned. Existing event, trigger and SIP commands remain.
Docs README and command research describe the commands, source revisions and availability limits. Public API/SDK guides were updated with the API change; no unpublished CLI command is announced as generally available.
Feature releases This code is not deployed or generally available. API entitlement and release checks still govern access; this PR changes no production flag or rollout control.
Admin Unaffected: public CLI commands do not alter staff capabilities or Temporal authority.

Validation: after merging CLI dev at a76c1161c1c6bca890e23f5fa4adc1490d458d69, Node 22 npm ci and npm run verify passed: 695 tests, format, lint, typecheck, build, package dry run and production audit. The installed SDK package and SDK_VERSION both report 0.1.0-dev.20260923115544. Regression tests cover semicolon CSV headers and data with more commas than separators. Hosted CI and Codex review are running on the latest head. No deployment or real message send was performed.

…ttings

Add campaign recipients list/add, audience create with CSV or file import,
audience member add/list/remove, and opt-out settings view/update.

Fix campaign stop, which the contract now answers with a nullable operationId:
a campaign with no active delivery run is cancelled immediately, and the CLI
says so instead of reporting 'operation null'.
Move the SDK dependency to the published `dev` dist-tag. The previous
github:polymorfa/sdks#<sha> pin can no longer work: the SDK repository made its
root a private workspace, so a git install exposes no package entry points. The
lockfile still records the old pin and must be regenerated once the SDK
prerelease that carries these methods is published.

Update the calls socket expectation for the newer SDK, which emits `claim` on a
placed call (sdks d4d6c81).
@coderabbitai

coderabbitai Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

  • Ask an admin to enable usage-based reviews

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Next included review available in 9 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 74 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

The included review limit has been reached and this organization has disabled usage-based review continuation. Wait for reviews to reset or ask a billing admin to change After included review limits.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 8408234a-abe3-431a-a671-60e65593cf46

📥 Commits

Reviewing files that changed from the base of the PR and between a76c116 and 2905559.

📒 Files selected for processing (23)
  • README.md
  • docs/command-research/campaigns.md
  • package.json
  • src/commands/audience/create.ts
  • src/commands/audience/members/add.ts
  • src/commands/audience/members/list.ts
  • src/commands/audience/members/remove.ts
  • src/commands/campaign/pause.ts
  • src/commands/campaign/recipients/add.ts
  • src/commands/campaign/recipients/list.ts
  • src/commands/campaign/requeue.ts
  • src/commands/campaign/resume.ts
  • src/commands/campaign/stop.ts
  • src/commands/optout/settings/update.ts
  • src/commands/optout/settings/view.ts
  • src/input/recipients.ts
  • src/services/audiences.ts
  • src/services/campaigns.ts
  • src/services/opt-outs.ts
  • test/commands/audiences-optouts.test.ts
  • test/commands/calls-sockets.test.ts
  • test/commands/campaign-recipients.test.ts
  • test/commands/campaigns.test.ts

Comment @coderabbitai help to get the list of available commands.

Re-sync to polymorfa/polymorfa d48b43c6e24a52175eba3880c1eefda1e07a3bf0.

No command changed. The revision declares projectId on the single-campaign
Platform operations, which no CLI command calls, and adds recipientListId to
the Platform campaign update body, which the CLI does not expose: the Messaging
surface behind the campaign topic has no update route.
Re-sync to polymorfa/polymorfa ef1653e3c4fc7a98b9da56fffae5f2184b7e4574.

No command changed. The revision declares the 409 that campaign update answers
after launch and documents projectId on the single-campaign Platform
operations; the CLI calls neither.
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-23T12:29:29.600431Z 2905559 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1954024965

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread package.json Resolved
The --idempotency-key help on campaign recipients add, audience members add,
audience create and optout settings update said a key is generated when
omitted. The SDK generates none for these, and from sdks b663914 it sends
recipient and member appends once because the API declares no replay for
them. The help, README and command research now say so, and the research
baseline moves to that SDK commit.

Verified with npm run verify against a tarball packed from sdks b663914.
package.json and package-lock.json are unchanged: no published prerelease
contains the campaign methods yet.
@purpshell
purpshell marked this pull request as draft September 22, 2026 11:35
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48a2fed35e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/commands/audience/create.ts Resolved
Comment thread src/input/recipients.ts Resolved
Brings in the npm SDK prerelease pin (#16), operation commands (#24), doctor,
link/project, api fields and the Blacksmith CI runners.

package.json takes dev's exact pin, @polymorfa/sdk 0.1.0-dev.20260922102711,
plus jq-wasm, so it now matches dev's package-lock.json and npm ci resolves.
That prerelease lacks the campaign recipient, audience member and opt-out
settings methods, so typecheck still fails against it until sdks#285 is
published and this pin is bumped to the resulting exact version.

README keeps this branch's stop and recipients/audiences/opt-outs sections
and takes dev's pointer to the operation commands in place of the old
"operation inspection is console-only" line. oclif topics are the union.
… rows

audience create --file-id now requires --mapping. The API refuses a file
import without one (400), so the command stops before transport with oclif's
dependency error instead of sending an unusable request.

A CSV row with other values but an empty phone cell was silently dropped, so
it never reached the API's invalid counts. readCsvRecipients now refuses the
file and names up to 20 such rows (header is row 1); wholly blank rows are
still ignored. This covers campaign recipients add, audience members add and
audience create --csv.

The research baseline moves to sdks 1abacf9.
CreateAudienceRequest is now a members-or-mapped-file union; audience create
already sends one of those shapes, and npm run verify passes unchanged against
a tarball packed from that commit.
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea3719caa3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/recipients.ts Resolved
Comment thread src/input/recipients.ts Resolved
… delimiter

The append request schema requires phone to be 1 to 64 characters, so an
--input entry with "" (or a CSV/JSON phone over 64 characters) made the API
refuse the whole batch with 400 instead of reporting an invalid row. Those
entries are now refused locally, naming the entry, before anything is sent.
Whitespace-only JSON phones are refused too, matching the CSV path.

CSV delimiter detection counted separators inside quoted header fields, so
"Phone, Intl";Name was read as comma-separated and failed the column check.
It now counts only separators outside quotes in the header record.
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5fad0baaa3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/recipients.ts Resolved
Comment thread src/input/recipients.ts Resolved
…name

Both append request schemas require at least one entry (minItems 1), so an
--input of [] or {recipients: []} was rejected wholesale by the API. It is now
refused locally before transport.

--variable __proto__=Column passed the name pattern, but assigning it to a
plain object invoked the prototype setter, so the mapping was silently
dropped. The name is now refused with an explicit error.
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: c72acac339

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 574717db58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/recipients.ts Resolved
Comment thread src/input/recipients.ts Resolved
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 422abdca34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/recipients.ts Resolved
Comment thread src/services/audiences.ts Resolved
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 4402031d8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9341066118

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/recipients.ts Resolved
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 0ac1a3e091

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b7342bcd03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/recipients.ts Resolved
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2922a921e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread package.json Resolved
@purpshell

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 2905559bb7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@purpshell
purpshell marked this pull request as ready for review September 23, 2026 12:30
@purpshell
purpshell merged commit b782436 into dev Sep 23, 2026
3 checks passed
@purpshell
purpshell deleted the t3code/campaigns-p0-cli branch October 26, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant