Skip to content

feat: [SDK-5230] purge anonymous operations on start when Identity Verification is active - #1498

Merged
sherwinski merged 1 commit into
sherwin/sdk-5229from
sherwin/sdk-5230
Sep 22, 2026
Merged

sherwinski merged 1 commit into
sherwin/sdk-5229from
sherwin/sdk-5230

Conversation

@sherwinski

@sherwinski sherwinski commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

1 Line Summary

Purge queued anonymous operations after the saved operations load when IV behavior is active, and clear existingOnesignalId on the surviving login operations.

Details

Seventh and last M2 pull request for Identity Verification for Web SDK. Stacked on #1497 (SDK-5229). Targets sherwin/sdk-5229 now; retarget to feat/identity-verification after the earlier PRs merge.

Mirrors Android removeOperationsWithoutExternalId() and onJwtConfigHydrated() in OperationRepo.kt:293-332. Follows decision D4 on SDK-5215: the purge removes queued operations, never models.

Why a purge when SDK-5229 already suppresses at enqueue. Operations persisted while the requirement was off or unknown can carry no externalId. On the next start with the requirement on, they load into the queue past the enqueue check. An anonymous user has no JWT, so they can never pass the dispatch gate and would block the queue.

Where the hydrate point is on web. Android awaits initialized inside onJwtConfigHydrated so the purge runs after saved operations load. On the page, OneSignal.init fetches the config and persists the requirement before CoreModule exists, so the requirement is already known when OperationRepo._start runs. The purge goes right after _loadSavedOperations in _start, which gives the same order with no event.

src/core/operationRepo/OperationRepo.ts

  • _start calls _purgeAnonymousOperations() after _loadSavedOperations() when isIvBehaviorActive(), then starts the timer. isIvBehaviorActive implies isIvCodePathEnabled, so one check is enough.
  • _purgeAnonymousOperations filters the queue for items with no externalId, removes each one from the store through OperationModelStore._remove, and wakes any waiter with false and _Suppressed. Then every surviving LoginUserOperation with an existingOnesignalId has it cleared. Two short debug logs: OpRepo: purged N/M anonymous ops and OpRepo: purge cleared existingOnesignalId.

src/core/operations/LoginUserOperation.ts

  • New _clearExistingOnesignalId(). IV never transfers anonymous state, so the login must create. A stale local id would also keep _canStartExecute false forever, because the anonymous login that would have resolved it is gone. The change persists through the model store's change listener.

Multi-tab. ModelStore._persist rewrites the whole list. The purge uses the same _remove path as the existing drop path, so it adds no new race. Cross-tab work is SDK-5248 (M5).

Bundle size. Adds about 130 B gzipped to page.es6.js. The page limit moves to the measured 44.23 kB. Across the 7 M2 PRs the page bundle grows from 43.44 kB to 44.23 kB (about 790 B). SDK-5252 (M6) tracks the budget for the whole IV project.

Systems Affected

  • WebSDK
  • Backend
  • Dashboard

Validation

Tests

Info

src/core/operationRepo/OperationRepo.test.ts, new anonymous operation purge on start block. The store is seeded before _start so _loadSavedOperations picks the operations up, the same as rows persisted by an earlier session. Mirrors OperationRepoTests.kt:1045-1094.

  • IV active: an anonymous operation and an anonymous LoginUserOperation are removed from the queue and the store; an identified operation survives.
  • IV active: a surviving LoginUserOperation with a local existingOnesignalId has it cleared, _canStartExecute flips to true, and the key is gone from its JSON.
  • IV active: _loadSavedOperations runs before the first store removal, so the purge sees the loaded rows.
  • IV inactive: nothing is purged and existingOnesignalId is kept.

vp check, vp test (682 tests), and vp run build:prod pass on the stack tip.

Checklist

  • All the automated tests pass or I explained why that is not possible
  • I have personally tested this on my machine or explained why that is not possible
  • I have included test coverage for these changes or explained why they are not needed

Programming Checklist
Interfaces:

  • Don't use default export
  • New interfaces are in model files

Functions:

  • Don't use default export
  • All function signatures have return types
  • Helpers should not access any data but rather be given the data to operate on.

Typescript:

  • No Typescript warnings
  • Avoid silencing null/undefined warnings with the exclamation point

Other:

  • Iteration: refrain from using elem of array syntax. Prefer forEach or use map
  • Avoid using global OneSignal accessor for context if possible. Instead, we can pass it to function/constructor so that we don't call OneSignal.context

Screenshots

Info

Not needed. No UI change.

Checklist

  • I have included screenshots/recordings of the intended results or explained why they are not needed

Related Tickets

…is active

Operations persisted while the requirement was off or unknown may carry
no externalId. Once the requirement hydrates to on, an anonymous user has
no JWT, so these operations can never pass the dispatch gate. Remove them
from the queue and the store right after the saved operations load.

- OperationRepo._start runs _purgeAnonymousOperations after
  _loadSavedOperations when IV behavior is active
- Removed operations wake any waiter with the _Suppressed reason
- Surviving LoginUserOperations lose existingOnesignalId; IV never
  transfers anonymous state, and a stale local id would keep
  _canStartExecute false forever
- Models are untouched; the local push subscription folds into the
  create-user request at login
@sherwinski
sherwinski merged commit 7645e77 into feat/identity-verification Sep 22, 2026
2 checks passed
@sherwinski
sherwinski deleted the sherwin/sdk-5230 branch September 22, 2026 00:29
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.

2 participants