@idosgames/core 0.8.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 +112 -0
- package/dist/chunk-MEUEUF7D.js +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +455 -23
- package/dist/index.d.ts +455 -23
- package/dist/index.js +2 -2
- package/dist/platform/index.cjs +1 -1
- package/dist/platform/index.d.cts +9 -0
- package/dist/platform/index.d.ts +9 -0
- package/dist/platform/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-QJVWT32O.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,118 @@ 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
|
+
|
|
70
|
+
## [0.9.0] - 2026-08-24
|
|
71
|
+
|
|
72
|
+
Signing in by e-mail becomes a **two-step flow** with a confirmation code, and a password now
|
|
73
|
+
belongs to a **title**, not to the platform. Friend requests gain the outgoing direction, and the
|
|
74
|
+
usage history is rolled up into periods. Breaking — see below.
|
|
75
|
+
|
|
76
|
+
### Breaking
|
|
77
|
+
|
|
78
|
+
- **`registerWithEmail` no longer signs the player in.** It returns `EmailRegistrationOutcome`
|
|
79
|
+
(`codeTtlMinutes`, `resendCooldownSeconds`) instead of `ClientState`: the server only stores the
|
|
80
|
+
attempt and mails a code, and the player is created by `confirmEmailRegistration`. A screen that
|
|
81
|
+
waits for a session here waits forever. There is no flag to branch on — confirmation is platform
|
|
82
|
+
behaviour and no title can switch it off.
|
|
83
|
+
- **`EMAIL_ALREADY_EXISTS` is no longer returned by registration.** A free and a taken address
|
|
84
|
+
answer identically, so the form cannot be used to ask "does this person have an account here";
|
|
85
|
+
the owner of a taken address gets a "you already have an account" e-mail instead, without a code.
|
|
86
|
+
- **`loginWithPlatformToken` and `AuthenticationAction.LoginWithPlatformToken` removed.** The
|
|
87
|
+
backend stopped issuing the audience it accepted, so the endpoint was unreachable code. Use
|
|
88
|
+
`loginWithSsoCode` (see `beginSsoRedirect`).
|
|
89
|
+
- **`UserReferralState.FollowerIDs` removed.** It was an unbounded list in the hot player document
|
|
90
|
+
with no readers; the count that replaced it is server-sent, and the relationship itself lives on
|
|
91
|
+
the subscriber's side.
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- **`confirmEmailRegistration(email, code)`** — exchanges the mailed code for a session and creates
|
|
96
|
+
the player. Persists the credentials for `autoLogin()` exactly as `loginWithEmail` does; the
|
|
97
|
+
password comes from step one and is never sent again.
|
|
98
|
+
- **`resendVerificationCode(email)`** — mails a NEW code (only a hash is stored server-side, so the
|
|
99
|
+
previous one cannot be re-sent). Answers successfully whatever happened, with one exception worth
|
|
100
|
+
surfacing: `EMAIL_SENDER_NOT_CONFIGURED`, which is about the server's configuration and not about
|
|
101
|
+
the address.
|
|
102
|
+
- **`zEmailRegistrationResponse` / `EmailRegistrationResponse`** and
|
|
103
|
+
`AuthenticationRequest.VerificationCode`.
|
|
104
|
+
- **`client.social.getOutgoingRequests()`** + `SocialAction.GetOutgoingRequests` and the
|
|
105
|
+
`social:outgoingRequestsLoaded` event. Direction and status are separate axes, and the outgoing
|
|
106
|
+
list cannot be derived from a counter — without it the "Sent" mark on a card lived only until the
|
|
107
|
+
app restarted.
|
|
108
|
+
- **`UserSocialState.FriendsCount` / `IncomingCount` / `OutgoingCount`** — server-sent counters.
|
|
109
|
+
The friend lists themselves are now a local cache, filled by the matching `get*` call.
|
|
110
|
+
- **`UsagePeriodRecord`** — the rolled-up month/year record (`Seconds`, `Sessions`, `ActiveDays`,
|
|
111
|
+
`LongestSessionSeconds`, `ActiveHoursMask`, `FirstActiveDay`).
|
|
112
|
+
- **`BoardRollResponse.DiceValues`** — the individual dice behind the rolled total.
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- ⚠ **A password now belongs to the TITLE.** The same address in two games means two independent
|
|
117
|
+
passwords, and resetting in one game does not change the login for the other. The reset e-mail
|
|
118
|
+
goes out through the **publisher's** SMTP, so a shared password would let one publisher's mail
|
|
119
|
+
server control access to every other publisher's game. The identity stays shared — Google, Apple
|
|
120
|
+
and the idosgames.com sign-in still recognise the same person everywhere; identity answers "who
|
|
121
|
+
is this", not "what proves they may sign in". Don't tell the player "the same password as in your
|
|
122
|
+
other game", and don't reuse stored credentials across titles.
|
|
123
|
+
- **Every outcome of `resetPassword` answers the same** — `INVALID_RESET_CODE` for an unknown
|
|
124
|
+
address, a code never requested, an expired code and a wrong code alike; an exhausted code
|
|
125
|
+
answers `RESET_CODE_ATTEMPTS_EXCEEDED`. The remaining-attempt count is gone from the response: it
|
|
126
|
+
confirmed the account existed and told an attacker how much room was left. Don't parse a number
|
|
127
|
+
out of `error`.
|
|
128
|
+
|
|
17
129
|
## [0.7.0] - 2026-08-10
|
|
18
130
|
|
|
19
131
|
Real-money payment support. Every configured price becomes a **`PriceOptions` dictionary**, a
|
|
@@ -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};
|