Skip to content

feat(calls): call analytics and call record export (Client.calls) - #281

Merged
purpshell merged 10 commits into
devfrom
t3code/calls-analytics
Sep 23, 2026
Merged

purpshell merged 10 commits into
devfrom
t3code/calls-analytics

Conversation

@purpshell

@purpshell purpshell commented Sep 19, 2026 •

Copy link
Copy Markdown
Member

Adds typed Client.calls analytics and call-record methods to @polymorfa/sdk for team and project server clients with sessions:read authority.

Method Route Result
calls.stats(params?) GET /platform/calls/stats Typed call statistics
calls.list(params?) GET /platform/calls Cursor page of call records
calls.export(params?) GET /platform/calls/export CSV or NDJSON body with next cursor
calls.exportAll(params?) Same route, all pages Async text chunks, with repeated CSV headers removed

The client validates filters, pagination, time strings, and project scope before sending. Export reads text only when the successful response has the expected content type; HTML or missing/wrong content type fails safely. Repeated export cursors are rejected before yielding a duplicate page. The methods retain SDK error classes and response metadata.

Contract and verification

Messaging and Platform snapshots are byte-identical to authoritative, merged monorepo dev commit 9c876c16c60b74370d934e1275f23ef6096bee12. contracts/source.json marks that source published. Current SDK dev at 8ce8f7b is normally merged, including retention, Campaigns, and Functions. The strict ledger reports 456 operations: 345 covered, 111 excluded, 0 missing or changed. Calls analytics route objects are unchanged from the earlier API analytics merge. If monorepo #228 merges before this SDK PR, the shared error catalog and exact source snapshot must be refreshed before merging.

Node 20 and 22 each pass all 1,142 tests across 107 files. Formatting, lint (no errors; two existing directive warnings), typecheck, coverage, Functions/name checks, workspace builds, and SDK package dry run pass. Live requests to a deployed API were not exercised. Fresh current-head CI and reviews are pending.

API, SDK, CLI, docs, feature, and Admin assessment

Part Status and evidence
API Unaffected in this repository. The three analytics routes and public shapes already exist on merged monorepo dev at the exact source commit above; no handler or scope change is proposed here.
SDKs Updated. The server SDK gains typed Calls analytics, validation, pagination, text export, and failure handling. Browser code does not gain a credentialless Calls analytics authority.
CLI Blocked on this package's publication. Existing CLI #26 has a local typed adapter; it needs the exact published SDK prerelease pin and full CI before review-ready publication.
Docs Updated. SDK README, contract notes, and package changelog describe the methods and source. Public Mintlify Calls analytics guides and API references live in the monorepo and already describe the API; customer availability is not inferred from this PR.
Feature releases Unchanged. The API enforces sessions:read; this SDK change adds no flag, enrollment, entitlement, rollout, or deployment action.
Admin Unaffected. These SDK methods do not change Admin's API-owned reads or capabilities.

Summary by CodeRabbit

  • New Features
    • Added call analytics with team- and project-scoped statistics and filters.
    • Added paginated call records and CSV or NDJSON exports, including an option to stream all export pages.
    • Added support for call records, filters, and analytics in the TypeScript client.
  • Documentation
    • Updated the API coverage and usage guides to include calls analytics and exports.

Add Client.calls (team and project clients) covering the Platform call
analytics routes at monorepo commit 4b755348 (branch t3code/calls-analytics):

- stats() -> GET /platform/calls/stats (CallStats with groups and heatmap)
- list() -> GET /platform/calls as CursorPage<CallRecord>
- export() -> GET /platform/calls/export, one CSV or NDJSON page with the
  Polymorfa-Next-Cursor header as nextCursor
- exportAll() walks export pages and drops repeated CSV header rows

HttpTransport gains requestText() and keeps polymorfa-next-cursor in
response metadata. Re-sync both contract snapshots to 4b755348, which also
fixes the event-stream frame discriminator (streamProjectEvents fingerprint)
and adds the bansafe.health_changed and bansafe.risk_changed webhook events,
now typed.
@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 43469fcb-be93-4be6-a976-95e9221b37b0

📥 Commits

Reviewing files that changed from the base of the PR and between 8ce8f7b and 34ff27b.

📒 Files selected for processing (19)
  • CHANGELOG.md
  • README.md
  • contracts/README.md
  • contracts/coverage.json
  • contracts/functions/coverage.json
  • contracts/functions/source.json
  • contracts/openapi.platform.json
  • contracts/source.json
  • contracts/testing-events.json
  • docs/internal/2026-09-22-test-event-fixtures.md
  • packages/typescript/README.md
  • packages/typescript/src/client.ts
  • packages/typescript/src/index.ts
  • packages/typescript/src/platform/calls.ts
  • packages/typescript/src/transport/http.ts
  • packages/typescript/test/coverage-reconciliation.test.ts
  • packages/typescript/test/coverage.test.ts
  • packages/typescript/test/platform-calls.test.ts
  • packages/typescript/test/testing-events.test.ts

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.


📝 Walkthrough

Walkthrough

The TypeScript SDK now exposes Client.calls for call statistics, paginated records, and CSV or NDJSON exports. The change adds request validation and export pagination handling. Contract coverage mappings and revision metadata are updated for Calls and Functions operations.

Changes

Calls analytics resource

Layer / File(s) Summary
Calls types, transport, and client wiring
packages/typescript/src/platform/calls.ts, packages/typescript/src/transport/http.ts, packages/typescript/src/client.ts, packages/typescript/src/index.ts
Adds call data types and text-response support. The client initializes and exports the calls resource.
Call queries and export traversal
packages/typescript/src/platform/calls.ts
Implements statistics, record listing, CSV or NDJSON exports, input validation, and cursor-based exportAll. Repeated cursors raise invalid_response before that page is yielded.
Calls tests, coverage, and usage documentation
packages/typescript/test/platform-calls.test.ts, packages/typescript/test/coverage.test.ts, contracts/coverage.json, packages/typescript/README.md, README.md, CHANGELOG.md
Tests cover filters, pagination, export responses, repeated cursors, and errors. Documentation and coverage records describe the calls operations.

API contract snapshot reconciliation

Layer / File(s) Summary
Functions route coverage mappings
contracts/coverage.json
Adds coverage mappings for Functions, deployments, invocations, and secrets operations.
Snapshot revisions and coverage records
contracts/README.md, contracts/*, README.md, docs/internal/2026-09-22-test-event-fixtures.md, packages/typescript/test/coverage-reconciliation.test.ts, packages/typescript/test/coverage.test.ts, packages/typescript/test/testing-events.test.ts
Updates API revision references, coverage counts, and related metadata. The Functions source manifest is marked published.

Priority: ⚪ Not assessed

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client.calls
  participant Resource as PlatformCallsResource
  participant Transport as HttpTransport
  participant API as Calls API
  Client->>Resource: exportAll(params)
  Resource->>Transport: requestText for export page
  Transport->>API: send export request
  API-->>Transport: export body and next-cursor header
  Transport-->>Resource: text response and metadata
  Resource-->>Client: yield page body
Loading

Merge Risk: ⚪ Minimal · up to 34ff2

This adds a new SDK surface for call statistics, call-record listing, and CSV/NDJSON exports. It does not change existing API behavior. No concrete defects were found in validation, pagination, or the contract metadata updates. The change looks ready to merge once normal CI passes.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 8 files. (10 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding call analytics and call record export through Client.calls.
Full details: Docstring Coverage

Explanation

Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 8 files. (10 skipped: 10 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR

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

…a1486

The stats 503 now has its own CallStatsTooSlow response instead of reusing
PropagationPending, whose description was about stored settings. Repin the
snapshots, source hashes, ledger and coverage gates to the branch head of
polymorfa/polymorfa#234. Coverage is unchanged: 427 operations, 311 covered,
0 missing, 0 changed fingerprints.
@purpshell

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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:37:14.062419Z 34ff27b 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: cdea6fa785

ℹ️ 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".

}
return value.toISOString();
}
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate timestamp strings as ISO date-times

Date.parse accepts many strings that are not ISO 8601 date-times—for example, Node accepts "1" and date-only values such as "2026-09-01"—and the function then sends the original string unchanged. Consequently, since or until values that should raise PolymorfaConfigurationError instead reach an endpoint whose contract requires date-time and fail as an API validation error; validate the string syntax and calendar value strictly before returning it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 240ca82. String since/until values must now be RFC 3339 date-times with Z or an offset and a real calendar date. "1" and date-only values raise PolymorfaConfigurationError. Date values are unchanged.

Date.parse accepted strings such as "1" and date-only values, which the API
then refused. since/until strings must now be full date-times with Z or an
offset and a real calendar date; Date values are unchanged.
@purpshell

Copy link
Copy Markdown
Member Author

Codex review follow-up (240ca82):

  • calls.ts:459: fixed. String since/until values must now be RFC 3339 date-times with Z or an offset, on a real calendar date. These are refused before any request is sent: "1", date-only values, missing offsets, Feb 30, hour 24 and RFC 1123 strings. Date values are unchanged.

@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: 240ca821c9

ℹ️ 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 on lines +330 to +332
if (body.length > 0) yield body;
if (data.nextCursor === null) return;
if (seen.has(data.nextCursor)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Check repeated cursors before yielding the page

When the export API repeats a cursor, this generator yields that repeated page before the seen check runs. A consumer that streams chunks directly to a file therefore writes duplicate records and only receives the error on its next iteration; move the repeated-cursor check ahead of the yield so the advertised protection prevents corrupt output.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in c9598aa. exportAll now checks the next cursor against every cursor it has requested (including the starting cursor) before yielding the page, so a replayed page is never yielded. Tests cover both cases.

exportAll yielded a page whose next cursor had already been requested and
only threw on the next iteration, so a consumer streaming to a file wrote the
replayed records. The check now runs before the yield, and the starting
cursor counts as already requested.
Preserve strict dates and repeated-cursor safeguards. BanSafe typed alignment remains dependent on SDK #282; its error-body and webhook catalog tests remain failing until integration.
# Conflicts:
#	CHANGELOG.md
#	contracts/README.md
#	packages/typescript/test/coverage.test.ts
# Conflicts:
#	CHANGELOG.md
#	README.md
#	contracts/README.md
#	packages/typescript/README.md
#	packages/typescript/src/client.ts
#	packages/typescript/test/coverage.test.ts
# Conflicts:
#	contracts/README.md
#	contracts/coverage.json
#	packages/typescript/test/coverage.test.ts
@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: 8ca84549e5

ℹ️ 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 on lines +488 to +489
const ISO_DATE_TIME =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,9})?(?:Z|[+-](\d{2}):(\d{2}))$/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept lowercase RFC 3339 separators

The Calls parameters are declared as OpenAPI date-time values, so valid RFC 3339 strings may use lowercase t and z; however, this case-sensitive regex rejects inputs such as 2026-09-01t00:00:00z with PolymorfaConfigurationError before sending the request. Make the separator and UTC designator matching case-insensitive while retaining the strict calendar validation.

Useful? React with 👍 / 👎.

@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: 34ff27b2c6

ℹ️ 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".

day <= daysInMonth &&
hour <= 23 &&
minute <= 59 &&
second <= 59 &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept valid RFC 3339 leap-second timestamps

When callers supply a timestamp at a declared leap second, such as 1990-12-31T23:59:60Z, this check rejects it before making the request even though RFC 3339 permits 60 for leap seconds and the Calls parameters are documented as RFC 3339/OpenAPI date-time values. Validate :60 against the RFC 3339 leap-second rules rather than rejecting it unconditionally.

Useful? React with 👍 / 👎.

@purpshell

Copy link
Copy Markdown
Member Author

The two current-head Codex suggestions about lowercase t/z and leap seconds were checked against the exact API source used by this SDK PR. The API's stats/list parser requires an uppercase T and a finite JavaScript Date; its export route uses Zod datetime({ offset: true }). In the API worktree, Zod rejects both 2026-09-01t00:00:00z and 1990-12-31T23:59:60Z; Date.parse also rejects the leap second. Passing either value through the SDK would turn an immediate configuration error into an API 400, not a successful request. The SDK intentionally follows the deployed route's accepted subset. Full RFC 3339 support would require an API contract/runtime change across stats, list, and export first; that is outside this SDK PR. No SDK code change is appropriate for these suggestions.

@purpshell

Copy link
Copy Markdown
Member Author

Merge gate on exact head 34ff27b2c6: Node 20/22 verification green; CodeRabbit completed with no actionable comments; local codex review --base origin/dev found no actionable defects. The two GitHub Codex timestamp suggestions are documented above as incompatible with the accepted API routes. Branch includes SDK dev 8ce8f7bae5 and targets dev; no Calls customer release or deployment is implied.

@purpshell
purpshell merged commit ad5e562 into dev Sep 23, 2026
4 checks passed
@purpshell
purpshell deleted the t3code/calls-analytics branch October 26, 2026 15:51
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