Skip to content

v1.0.1

@VistaApps-za VistaApps-za tagged this 25 May 08:02
audit flagged is closed in this release. Plus one critical
cross-SDK canonical rename so the Swift identity surface matches
the Web/Node/RN role-model contract exactly.

The v1.0.0 identify signature drifted from Web/Node/RN. v1.0.1
restores zero-drift parity. Migration is a one-line change:

```diff
- try? cd.identify(customerId: "user_847", traits: ["email": "wes@example.com", "plan": "pro"])
+ try? cd.identify(userId: "user_847", email: "wes@example.com", traits: ["plan": "pro"])
```

Specifically:

- `customerId:` → `userId:`. The previous name collided with
  `crossdeckCustomerId` (the cdcust_… canonical handle), confusing
  the mental model. The Web/Node/RN SDKs all use `userId`.
- `email` is now a first-class top-level argument. Previously it
  was buried inside `traits` and missed the bank-grade
  identity-merge that the Web SDK gets when email is shipped
  separately. Now hoisted to the wire as `$email` on the
  `$identify` event, matching Web/Node/RN.
- Internal `customerId` field on `Identity` renamed to
  `developerUserId` everywhere — the same name Web/Node/RN's
  `Diagnostics.developerUserId` uses.
- Wire event field renamed from `customer_id` to
  `developer_user_id` (also matches what the backend ingest
  expects).
- `EntitlementSnapshot.customerId` → `developerUserId`.
- `Identity.setCustomerIdSync(...)` → `setDeveloperUserIdSync(...)`.
- Error code `missing_customer_id` → `missing_user_id`.

The Swift SDK doc now ships native auth-provider code blocks for
Sign In with Apple, Firebase Auth iOS, and Auth0 iOS, matching
the Web SDK doc's coverage of Firebase / NextAuth / Clerk /
Supabase / Auth0 / custom backends.

- `Crossdeck.isEntitled(_:)` — synchronous bool check scoped to the
  currently identified customer. Safe to call from SwiftUI bodies
  and UIKit tap handlers. Never blocks on network.
- `Crossdeck.entitlementsForCurrentCustomer()` — synchronous set
  read. Returns nil if no customer is identified or the cache is
  cold for them.
- Internally backed by NSLock-protected mirror boxes on
  `EntitlementCache`, `Identity`, `SuperProperties`, and
  `ConsentManager`. Every actor mutation updates its sync mirror
  atomically; reads acquire the lock only.

- **NSException handler now chains into the prior handler.**
  Previous v1.0.0 overwrote the global handler, silently breaking
  Crashlytics / Sentry / Bugsnag for any consumer who turned on
  `captureUncaughtExceptions`. `ErrorCapture.install` now captures
  `NSGetUncaughtExceptionHandler()` before registering ours and
  invokes the prior handler after our snapshot.
- **PII scrubber runs on `$error` events.** Previously the error
  pipeline bypassed the scrubber — a `try?` that surfaced
  `"user jane@example.com not found"` shipped raw. Now every
  scrubbable field on the wire `$error` payload (message, stack
  symbols, breadcrumb messages + data) is run through the
  configured scrubber when `consent.scrubPII` is true.
- **Breadcrumbs attached to `$error` events.** Previously collected
  but dropped before enqueue. Now ship as
  `error.breadcrumbs: [{timestamp_ms, category, level, message, data}]`
  on the wire payload.
- **`identify(...)` unconditionally clears the entitlement cache.**
  Previous v1.0.0 only cleared on `didChange || priorId == nil`.
  Now identifies always clear, matching the documented contract
  that prevents stale entitlement leaks across customer switches.
- **Self-request skip wired into `captureError(_:)`.** Errors whose
  URL host matches the configured ingest endpoint are dropped
  before processing — closes the feedback loop where a custom-
  middleware-wrapped ingest failure would generate an `$error`
  event that itself fails, ad infinitum.
- **`track()` / `identify()` race fixed.** The pre-existing pattern
  read identity inside a Task, racing concurrent identify Tasks.
  Now reads identity synchronously on the caller's thread before
  spawning the enqueue task. Deterministic ordering between
  identify and a subsequent track.
- **Empty key validation on super-properties.** `register("", v)`
  and `registerOnce("", v)` previously wrote a null-key entry
  that landed on every wire event; now silently rejected at the
  boundary.

- **Errors-consent gate.** The error pipeline now honours
  `consent.errors` — previously only the analytics pipeline
  observed consent. Consumers can independently allow analytics
  while denying error capture (or vice versa).
- Removed dead code: stale `(anon, cust)` tuple in error capture
  + unused NSRange in `scrubPII`.

- **+19 new tests** (53 → 72 total). Coverage added for: sync
  paywall reads from any thread, identify cache clearing under
  same-id idempotent calls, identify cache clearing across
  customer switches, `stop()` rejecting subsequent calls
  (idempotent stop), URL-stub HTTP tests covering 2xx success,
  4xx permanent (400/401/422), 5xx retryable, 408 retryable,
  429 + Retry-After honoured, Idempotency-Key shipped verbatim
  in the request header, User-Agent header carries SDK name +
  version.

- Public API is additive — every v1.0.0 caller still compiles.
- The `Crossdeck` class remains `@unchecked Sendable` with a
  detailed safety comment explaining the lock pattern.
Assets 2
Loading