Skip to content

feat(audience): SDK-142 foundations — typed events, Identity, ConsentStore, SSOT#693

Merged
ImmutableJeffrey merged 7 commits into
mainfrom
feat/sdk-147-singleton-2
Apr 22, 2026
Merged

feat(audience): SDK-142 foundations — typed events, Identity, ConsentStore, SSOT#693
ImmutableJeffrey merged 7 commits into
mainfrom
feat/sdk-147-singleton-2

Conversation

@ImmutableJeffrey
Copy link
Copy Markdown
Collaborator

@ImmutableJeffrey ImmutableJeffrey commented Apr 21, 2026

Summary

  • Adds typed event schemas and the IdentityType enum.
  • Extends Identity with Get (no-create) and ClearCache; relocates the test fixture to Tests/Runtime/Core/.
  • Extracts named constants for the HTTP publishable-key header, URL helper, and 256-char field-length limit.
  • Mirrors the Runtime/ folder layout onto Tests/Runtime/.
  • Adds SSOT MessageTypes / MessageFields constants and Unity-ready build scaffolding in the core asmdef and Audience.Runtime.csproj.
  • Adds ConsentStore for atomic consent persistence.

Linear:

  • SDK-142 — primary
  • SDK-144 — contributes the IdentityType enum consumed by Identify / Alias
  • SDK-143 — contributes ConsentStore (disk persistence at imtbl_audience/consent)

Base automatically changed from feat/sdk-147-singleton-1 to main April 21, 2026 23:00
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-2 branch 2 times, most recently from 1720e85 to 2cbe87f Compare April 21, 2026 23:08
Public schema surface for the Audience SDK:

- IEvent interface: EventName + ToProperties contract that the
  singleton's Track(IEvent) overload consumes. Usable by custom
  IEvent implementations as well as the built-in typed events.
- Progression / Resource / Purchase / MilestoneReached: the four
  typed gameplay events with Required / Optional field hints and
  enum-to-wire mappers that throw on unknown casts.
- Purchase validates ISO 4217 three-letter uppercase currency codes
  via a hand-rolled IsIso4217 helper (no System.Text.RegularExpressions,
  keeps IL2CPP build small).
- MilestoneReached rejects null or empty Name.
- ProgressionStatus (Start/Complete/Fail) and ResourceFlow
  (Source/Sink) enums with matching ToWireString extensions.
- IdentityType enum for the eight backend-accepted provider names
  (Passport, Steam, Epic, Google, Apple, Discord, Email, Custom)
  plus its ToWireString mapper.

The event classes throw ArgumentException from ToProperties on
invalid payloads; the singleton's Track(IEvent) catches and drops
with a warning so a buggy call site cannot crash the game.
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-2 branch from 2cbe87f to 6fecbed Compare April 21, 2026 23:20
@nattb8 nattb8 marked this pull request as ready for review April 21, 2026 23:31
@nattb8 nattb8 requested review from a team as code owners April 21, 2026 23:31
Comment thread src/Packages/Audience/Runtime/Core/Identity.cs Outdated
Comment thread src/Packages/Audience/Runtime/Events/TypedEvents.cs
Comment thread src/Packages/Audience/Runtime/Core/Identity.cs Outdated
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-2 branch from fe69470 to fd34007 Compare April 22, 2026 00:57
…ests to Core/

Adds two methods to Identity that support the SDK's GDPR and
lifecycle needs: Get returns the existing anonymousId without
minting a new one (so GDPR DeleteData doesn't register an id
just to delete it), and ClearCache drops the in-memory cache
without touching disk (so re-Init with a different
persistentDataPath reads the new file instead of returning the
previous session's id).

Relocates the test fixture from Tests/Runtime/IdentityTests.cs to
Tests/Runtime/Core/IdentityTests.cs to mirror Runtime/Core/Identity.cs.
The relocation expands coverage with two new tests for Get
(Get_NoExistingFile_ReturnsNull_AndDoesNotCreate,
Get_ExistingFile_ReturnsPersistedId) and swaps hardcoded
Path.Combine(_testDir, "imtbl_audience", "identity") calls for the
AudiencePaths.IdentityFile helper. The original five tests
(NewDirectory_*, ExistingFile_*, SecondCall_*, Reset_*,
ConsentNone_*) are preserved byte-equivalent modulo the path
helper swap.
…er, and field length

Replaces the x-immutable-publishable-key literal, the inline
BaseUrl(...) + MessagesPath URL construction, and the repeated 256
MaxFieldLength literal in MessageBuilder with named Constants
helpers. Pure refactor of code already on main - no behaviour
change.
Runtime is already organised into Core/, Events/, Transport/,
Utility/. Tests has had matching subfolders since the Identity,
typed-event, JsonReader, and Log peels landed, but six fixtures
were still sitting flat at the root. Moves them under the matching
subfolder so Tests mirrors Runtime one-to-one.

Pure rename, no content change. csproj uses glob includes so no
build file update is needed.

- MessageBuilderTests.cs -> Events/
- DiskStoreTests.cs (+.meta) -> Transport/
- EventQueueTests.cs (+.meta) -> Transport/
- HttpTransportTests.cs -> Transport/
- GzipTests.cs -> Utility/
- JsonTests.cs -> Utility/
…dd Unity build scaffolding

Groundwork for the ImmutableAudience singleton and the forthcoming
Unity integration layer. Pure refactor - no runtime behaviour change.

Constants:
- Core/Constants.cs: adds LibraryVersion ("0.1.0") so the message
  builder and tests share one source of truth; ConsentUrl and
  DataUrl helpers matching the existing MessagesUrl shape;
  MessageTypes ("track"/"identify"/"alias") and MessageFields
  ("type"/"userId") - values that cross module boundaries inside
  the SDK and were previously stringly-coded in multiple places.
- Events/MessageBuilder.cs: swap the six string literals for the
  new MessageTypes / MessageFields constants.
- Tests/Runtime/ConstantsTests.cs: covers the BaseUrl/MessagesUrl/
  ConsentUrl/DataUrl sandbox-vs-prod selection.

Scaffolding (forward-pointing for the Unity layer that follows):
- .gitignore: ignore bin/.
- AssemblyInfo: grant internals to Immutable.Audience.Unity.
- Audience.Runtime.csproj: exclude Unity/ from the headless
  dotnet-SDK build so Audience.Tests compiles once the Unity
  integration lands. No-op until Unity/ files exist.
Introduces Core/ConsentStore, a tiny static wrapper that reads and
writes the user's ConsentLevel to disk under
{persistentDataPath}/imtbl_audience/consent. Save uses the same
write-temp-then-move pattern as DiskStore and Identity so a crash
mid-write cannot leave a half-written consent level on disk; Load
returns null on missing, malformed, or unreadable files so callers
can fall back to the configured default.

No production callers yet. ImmutableAudience will consume this in
the next commit to persist SetConsent decisions across launches.

Tests/Runtime/Core/ConsentStoreTests covers the round-trip, the
null return for missing/corrupt/out-of-range files, and the
behaviour when the backing directory does not yet exist.
Applies #nullable enable + targeted `?` annotations per the
HttpTransport precedent (PR 691). Scope: the six files introduced
or substantially modified in Slice 2.

- IEvent.cs: no annotations needed; impl returns non-null.
- IdentityType.cs: ToLowercaseString return → string? (existing
  comment documents null-on-unknown-cast contract).
- TypedEvents.cs: optional properties → string?; also tightens
  IsIso4217 to non-null param (Currency gets an explicit
  null-or-invalid check before dict assignment). Adds a
  Resource.Currency null/empty validation that was missing.
- Core/ConsentStore.cs: no annotations needed.
- Core/Constants.cs: BaseUrl/MessagesUrl/ConsentUrl/DataUrl params
  → string? (code already guards with `publishableKey != null`).
- Events/MessageBuilder.cs: Track/Identify guarded params
  (anonymousId, userId, identityType) → string?; properties/traits
  → Dictionary<string, object>?. Truncate tightened to non-null
  input (callers guard before the call).

Compile-time annotations only. Zero runtime behaviour change
except Resource.Currency now throws on null/empty, matching the
"Required" comment on the field.
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-2 branch from fd34007 to 2268fba Compare April 22, 2026 01:04
@ImmutableJeffrey ImmutableJeffrey merged commit 443f590 into main Apr 22, 2026
18 checks passed
@ImmutableJeffrey ImmutableJeffrey deleted the feat/sdk-147-singleton-2 branch April 22, 2026 01:27
@nattb8 nattb8 changed the title feat(audience): SDK-147 foundations — typed events, Identity, ConsentStore, SSOT feat(audience): SDK-142 foundations — typed events, Identity, ConsentStore, SSOT Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants