Conversation
Wraps the apikey-to-host map that build tooling bakes into the app, and owns the partitioning of a flush batch by host. There is deliberately no default host: an apikey missing from the map does not resolve, so its events can be dropped rather than sent to a region that may be wrong. Grouping is by resolved host rather than by apikey so that several apikeys in the same region still share a single request, as they do today.
The collection endpoint is no longer hardcoded. buildRequest takes the host it should use, configure loads the baked map from the app bundle, and flush partitions the queue by resolved host and issues one request per host. Events whose site ID is not in the map are dropped and logged rather than requeued: the map cannot change while the app runs, so they would never resolve on a later flush. An offline host returns only its own events to the queue, so one failing region no longer strands another's events. Also removes RequestBuilder._baseURL, which was written and never read.
Resolves each declared site ID against Parse.ly at the publisher's build time and writes ParselyHosts.json, which the SDK reads at configure. The build fails on a missing or empty parsely-apikeys.json, on a site ID Parse.ly does not recognise, and on a write failure. A network failure is the one deliberate exception: if the generated file already covers every declared site ID the build warns and continues, so a Parse.ly outage does not break every customer's CI while still failing closed whenever data is actually missing. The podspec wires the phase automatically for CocoaPods users; everyone else adds a Run Script Phase, which the README now documents along with what is lost by skipping it.
The endpoint shipped at /api/<site id>/jess/sdk_config/, not the flat path this script was written against. Verified against production for a known site ID, an unknown one, a malformed declaration and an unreachable host. PARSELY_SDK_CONFIG_ENDPOINT becomes PARSELY_API_BASE, since the override is now the API root rather than a full endpoint path. Parse failures also stop dumping a Python traceback into the Xcode build log, where the one-line error is what the reader needs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parse.ly decides which collection endpoint a site's data goes to, and that decision can differ per site. The SDK hardcoded
https://p1.parsely.com/mobileproxy, so an app could only ever send to one endpoint regardless of which one its sites actually belong to.The endpoint is now resolved per site ID at the publisher's build time and baked into the app, the same way the web tracker resolves it when it builds a site's
p.js.How it works
parsely-apikeys.jsondeclaring every site ID the app can track — including any passed as asiteId:argument at runtime, not just the one given toconfigure(siteId:).Scripts/parsely-bake-hosts.sh) resolves each one against Parse.ly and writesParselyHosts.jsoninto the app bundle. CocoaPods users get the phase wired by the podspec; everyone else adds it manually.configureloads the map.flush()groups queued events by resolved endpoint and issues one request per endpoint.Grouping is by endpoint rather than by site ID deliberately: the payload already carries
idsiteper event, so several site IDs in one region still share a single request, exactly as they did before. A multi-site app in one region sends one request, not N.There is no default endpoint left in the binary. An event whose site ID is not in the baked map is dropped and logged, never sent somewhere that might be the wrong region. Nothing at runtime throws or crashes: a missing or malformed map logs at error level and sends nothing.
Breaking change
An app that upgrades without adding the build phase sends no analytics at all. That is intentional — the alternative is silently sending a site's data to an endpoint it does not belong to — but it means this cannot ship as a minor version. The README says so up front, and
CHANGES.rstmarks it breaking.Testing
make test→ 106 tests, 0 failures. New coverage: no baked map sends nothing and does not crash; malformed and wrong-version artifacts fail closed; one request per endpoint; two site IDs sharing an endpoint coalesce into one request; an unknown site ID is dropped while known ones still send; a partially-offline flush requeues only the failed endpoint's events.Scripts/parsely-bake-hosts.shverified against production for: a known site ID, an unknown one (build fails), a missing declaration, an empty declaration, malformed JSON, and an unreachable Parse.ly — which warns and proceeds when the committed artifact already covers every declared site ID, and fails when it does not.Two local details worth knowing for anyone running the suite:
make testpipes throughxcpretty, which is not in the Gemfile, and the project's deployment target (13.0) is below what Xcode 27 accepts, so a local run needsIPHONEOS_DEPLOYMENT_TARGET=15.0on the command line. Neither is changed here — the podspec's andPackage.swift's iOS 13 floor is the SDK's public compatibility promise.Companion changes
The equivalent Android change is Parsely/parsely-android#126. Both depend on the Parse.ly endpoint that serves the mapping, which is already live.
🤖 Generated with Claude Code