Skip to content

feat(audience): typed track() surface for v1 event catalogue (SDK-116)#2850

Merged
ImmutableJeffrey merged 2 commits intomainfrom
feat/audience-typed-events
Apr 14, 2026
Merged

feat(audience): typed track() surface for v1 event catalogue (SDK-116)#2850
ImmutableJeffrey merged 2 commits intomainfrom
feat/audience-typed-events

Conversation

@ImmutableJeffrey
Copy link
Copy Markdown
Contributor

@ImmutableJeffrey ImmutableJeffrey commented Apr 13, 2026

Summary

Adds pre-defined events per the Web SDK Event Reference (v1).

Linear: SDK-116.

Detail and impact of the change

Added

  • Rewrites sdk.track() as a generic track<E extends string> with a PropsFor<E> conditional type mapping each of 11 event names to its property interface
  • Exports AudienceEvents, 11 *Properties interfaces, ProgressionStatus, ResourceFlow
  • Adds sdk.test-d.ts with compile-time negative assertions
  • Adds runtime regression tests for 5 of the new events

Demo

2026-04-14.11-14-28.mov

Test plan

  • pnpm lint && pnpm typecheck && pnpm test && pnpm typegen — 54/54 passing

@ImmutableJeffrey ImmutableJeffrey requested a review from a team as a code owner April 13, 2026 10:19
@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Apr 13, 2026

View your CI Pipeline Execution ↗ for commit 3b16d38

Command Status Duration Result
nx run-many -p @imtbl/sdk,@imtbl/checkout-widge... ✅ Succeeded 5s View ↗
nx affected -t build,lint,test ✅ Succeeded 8s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-14 02:05:35 UTC

@ImmutableJeffrey ImmutableJeffrey marked this pull request as draft April 13, 2026 11:07
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/audience-typed-events branch 3 times, most recently from 3c09e6e to 90a8fec Compare April 13, 2026 12:55
@ImmutableJeffrey ImmutableJeffrey marked this pull request as ready for review April 13, 2026 23:22
@ImmutableJeffrey ImmutableJeffrey changed the title feat(audience): typed track() surface for v1 event catalogue feat(audience): typed track() surface for v1 event catalogue (SDK-116) Apr 13, 2026
Comment thread packages/audience/sdk/src/events.ts
Comment thread packages/audience/sdk/src/sdk.ts
bkbooth
bkbooth previously approved these changes Apr 13, 2026
Comment thread packages/audience/sdk/src/events.ts
Comment thread packages/audience/sdk/src/sdk.ts
Comment thread packages/audience/sdk/src/index.ts
Comment thread packages/audience/sdk/src/sdk.ts Outdated
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/audience-typed-events branch from 22182cd to 703e5b0 Compare April 14, 2026 00:20
ImmutableJeffrey added a commit that referenced this pull request Apr 14, 2026
- Widen track() generic constraint to `AudienceEventName | string & {}`.
  IntelliSense surfaces the 11 predefined event names at `sdk.track('|`.
- Export `AudienceEventName` and `PropsFor<E>` from the package root.
- Note predefined-event type enforcement in track()'s JSDoc.

Addresses PR #2850 review feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ImmutableJeffrey added a commit that referenced this pull request Apr 14, 2026
- Widen track() generic constraint to `AudienceEventName | string & {}`.
  IntelliSense surfaces the 11 predefined event names at `sdk.track('|`.
- Export `AudienceEventName` and `PropsFor<E>` from the package root.
- Note predefined-event type enforcement in track()'s JSDoc.

Addresses PR #2850 review feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/audience-typed-events branch from ace1525 to cbdab5d Compare April 14, 2026 01:21
ImmutableJeffrey and others added 2 commits April 14, 2026 11:51
Adds the v1 typed event surface to @imtbl/audience: 11 events
(sign_up, sign_in, wishlist_add, wishlist_remove, purchase,
game_launch, progression, resource, email_acquired, game_page_viewed,
link_clicked), each with a property interface and compile-time
enforcement on the track() call site.

Uses a single generic track<E extends string>(event, ...args) signature
backed by a PropsFor<E> conditional type. Traditional overloads fall
through to the string catch-all when the properties object is incomplete
(TypeScript picks the more-specific overload's first arg match, sees
the second arg is not assignable, then silently picks the less-specific
overload that accepts any object). The generic approach does not fall
through and produces a real error for missing, wrong-type, and extra
properties. A variadic-tuple conditional ({} extends PropsFor<E>) makes
the properties argument required for events that have required fields
and optional for events where every field is optional.

Extended events (email_acquired, game_page_viewed, link_clicked) carry
over from immutable/play#5151 with two normalisations:

- isLoggedIn is dropped from all three shapes. The SDK already knows
  logged-in state via identify() + consent level; pipeline consumers
  should derive is_logged_in from userId IS NOT NULL on the events
  table rather than accept a duplicated property from every call site.
- source is a free string. Play keeps its AudienceSource enum locally
  and passes its values into the SDK as strings.

Runtime is unchanged modulo one type cast in the enqueue call (widening
PropsFor<E> to Record<string, unknown>). Bundle size unchanged. The
track() method body's runtime logic is identical to baseline.

Type safety is asserted by a new sdk.test-d.ts file that uses
@ts-expect-error to prove negative cases fail typecheck — missing
required properties, extra properties, wrong value types, wrong enum
values, and zero-argument calls on required-props events. The file is
included in tsc but skipped by Jest (its .test-d.ts suffix does not
match the default test pattern).

Runtime coverage: five new it blocks in sdk.test.ts exercise sign_up,
game_launch, progression, resource, and wishlist_add end-to-end through
the queue flush path. 54 tests passing (up from 49).

Independent of the feat/audience-web-sdk-demo branch and the Phase 0
audience-foundations work. No shared files; merges in any order.

Spec: docs/superpowers/specs/2026-04-13-websdk-typed-events-design.md
Plan: docs/superpowers/plans/2026-04-13-websdk-typed-events.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Widen track() generic constraint to `AudienceEventName | string & {}`.
  IntelliSense surfaces the 11 predefined event names at `sdk.track('|`.
- Export `AudienceEventName` and `PropsFor<E>` from the package root.
- Note predefined-event type enforcement in track()'s JSDoc.

Addresses PR #2850 review feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/audience-typed-events branch from cbdab5d to 3b16d38 Compare April 14, 2026 01:52
@ImmutableJeffrey ImmutableJeffrey added this pull request to the merge queue Apr 14, 2026
ImmutableJeffrey added a commit that referenced this pull request Apr 14, 2026
TypeScript's `?` modifier already encodes property optionality at the
type level. The JSDoc labels duplicate what the syntax says without
adding information.

Follow-up to #2850.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merged via the queue into main with commit d781c61 Apr 14, 2026
7 checks passed
@ImmutableJeffrey ImmutableJeffrey deleted the feat/audience-typed-events branch April 14, 2026 02:19
ImmutableJeffrey added a commit that referenced this pull request Apr 14, 2026
TypeScript's `?` modifier already encodes property optionality at the
type level. The JSDoc labels duplicate what the syntax says without
adding information.

Follow-up to #2850.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants