@idosgames/core 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,59 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
14
14
 
15
15
  ## [Unreleased]
16
16
 
17
+ ## [0.10.0] - 2026-08-31
18
+
19
+ Where a player came from is now captured and delivered automatically, and playtime finally reaches
20
+ the publisher's analytics. Referral codes become short human codes with a server-built invite link.
21
+ Breaking — see below.
22
+
23
+ ### Breaking
24
+
25
+ - **`SpendRewardDefinition.Percent` is now `Rate`, and it is a FRACTION.** `0.05` means 5%, not
26
+ `5`. The old field never reached the server: it was dropped at deserialisation, so every kickback
27
+ rule written through it silently paid nobody. Render a percentage if you like, but keep the wire
28
+ value a fraction.
29
+ - **`UserData.patchReferralSubscription` takes the referrer's ID, not the code.** While a code and
30
+ a `UserID` were the same string, echoing the code back happened to be right; with a short code it
31
+ writes a code into an ID field. The activation response now carries `ReferrerUserID` separately
32
+ from `ReferralCode`.
33
+ - **A referral code is no longer a `UserID`.** `activateReferralCode` accepts only the short code
34
+ (or the invite link containing it); an internal identifier is rejected before any lookup. Nothing
35
+ had shipped on the old form, so there is no migration path and none is needed.
36
+
37
+ ### Added
38
+
39
+ - **`AcquisitionCapture`** — reads the launch URL and Telegram launch parameters when the client is
40
+ created (`utm_*`, `gclid`/`fbclid`/`ttclid`/`msclkid`/`yclid`, `?ref=`, `idos_click`,
41
+ `document.referrer`), keeps them across the login screen with a 30-day TTL, and attaches them to
42
+ whichever sign-in the player uses. Nothing to wire; nothing to call.
43
+ - **`PlaytimeTracker`** — counts playtime and reports it from login. Without it `addUsageTime` had
44
+ no caller at all, so a web title reported **zero** active users no matter how many people played:
45
+ DAU, WAU, MAU, stickiness and every retention cohort are derived from what it sends. Flush
46
+ interval and idle threshold match the Unity SDK so the two platforms count the same thing.
47
+ - **`IDosGamesSettings.appVersion`** — the build number that rides along with the acquisition
48
+ signal. The web has no `Application.version`, so the host has to pass it; without it no player is
49
+ attributed to a release and cohort-by-version is unanswerable.
50
+ - **`UserReferralState.Code`** — the player's own short invite code, minted lazily by the server on
51
+ the first `getUserState()`.
52
+ - **`UserReferralState.PendingActivationReward`** — set when the binding happened at login rather
53
+ than by typing a code; the debt is settled by the next `getUserState()`.
54
+ - **`UserReferralStateResponse.InviteUrl`** — a ready-made invite link built by the server. Do not
55
+ assemble one from a template: a client-built link is an open redirect.
56
+ - **`SpendRewardDefinition`** gains `Basis`, `MinSourceAmount`, `MaxRewardPerOperation` and
57
+ `Limits` — the anti-farm controls that existed on the server and could not be expressed here.
58
+ - **`PlatformAdapter.getReferrer?()`** — optional, so existing custom adapters keep compiling.
59
+
60
+ ### Fixed
61
+
62
+ - **Playtime was lost on every tab switch.** `visibilitychange` fires _after_ the state flips, so
63
+ the tracker asked the document, was told "hidden", and discarded the visible stretch that led up
64
+ to the switch — up to a full flush interval, every time.
65
+ - **Response schemas no longer strip unknown fields.** `zUserReferralStateResponse`,
66
+ `zActivateReferralCodeResponse`, `zClaimInviteRewardResponse` and
67
+ `zReferralDefinitionsResponse` were missing `.passthrough()`, so `InviteUrl` never reached the
68
+ client at all.
69
+
17
70
  ## [0.9.0] - 2026-08-24
18
71
 
19
72
  Signing in by e-mail becomes a **two-step flow** with a confirmation code, and a password now
@@ -0,0 +1 @@
1
+ var n=class{getString(e){if(typeof localStorage>"u")return null;try{return localStorage.getItem(e)}catch{return null}}setString(e,t){if(!(typeof localStorage>"u"))try{localStorage.setItem(e,t);}catch{}}remove(e){if(!(typeof localStorage>"u"))try{localStorage.removeItem(e);}catch{}}},o=class{map=new Map;getString(e){return this.map.get(e)??null}setString(e,t){this.map.set(e,t);}remove(e){this.map.delete(e);}};function r(){return globalThis.Telegram?.WebApp??null}function l(){return crypto.randomUUID()}var s="idos_device_id",i=class{storage;constructor(e=new n){this.storage=e;}getPlatform(){return r()?.platform??"Web"}getFullURL(){return typeof location<"u"?location.href:""}getStartParameter(){let e=r()?.initDataUnsafe?.start_param;return typeof e=="string"?e:null}getReferrer(){if(typeof document>"u")return null;let e=document.referrer;return e&&e.length>0?e:null}getTelegramInitDataRaw(){let e=r()?.initData;return e&&e.length>0?e:null}getDeviceID(){let e=this.storage.getString(s);return e||(e=l(),this.storage.setString(s,e)),e}getDeviceModel(){return typeof navigator<"u"&&navigator.userAgent?navigator.userAgent:"Web"}shareLink(e){let t=r();if(t?.openTelegramLink){t.openTelegramLink(e);return}typeof window<"u"&&window.open(e,"_blank");}openInvoice(e){let t=r();if(t?.openInvoice){t.openInvoice(e);return}typeof window<"u"&&window.open(e,"_blank");}async showAd(e){let t=globalThis;typeof t.showAd=="function"&&await t.showAd(e);}async copyToClipboard(e){typeof navigator<"u"&&navigator.clipboard&&await navigator.clipboard.writeText(e);}};var p="idos_device_id",g=class{storage;constructor(e=new o){this.storage=e;}getPlatform(){return "Web"}getFullURL(){return ""}getStartParameter(){return null}getTelegramInitDataRaw(){return null}getDeviceID(){let e=this.storage.getString(p);return e||(e="noop-device",this.storage.setString(p,e)),e}getDeviceModel(){return "Noop"}shareLink(){}openInvoice(){}async showAd(){}async copyToClipboard(){}};export{n as a,o as b,r as c,l as d,i as e,g as f};