Make the web SPA behave correctly inside the Capacitor native shell, where the
bundle loads from a local origin:
- New lib/origin.ts gatewayOrigin(): absolute URLs resolve to VITE_GATEWAY_URL on
native (the finished-game export/share URL in Game.svelte and the Wallet
site-root link), falling back to the page origin on web. transport.ts already
resolved via VITE_GATEWAY_URL and is left as-is.
- Skip the PWA service worker on the native channel (the assets are already local;
a worker would risk serving stale content across store updates).
- Hide the money-purchase UI in the MVP: new distribution.purchasesHidden() folds
VITE_PAYMENTS_DISABLED and the Google Play flag. The Wallet "buy" tab shows a
neutral, pointer-free note (wallet.purchasesSoon) for the RuStore MVP and keeps
the RuStore stub Google-Play-only. A ?nopay mock force mirrors ?gp for the e2e.
- Native env types in vite-env.d.ts.
Client-only, contour-safe: no wire/proto/schema change; web/VK/Telegram unchanged.
Tests: origin + purchasesHidden unit tests, a ?nopay wallet e2e. svelte-check
clean, vitest green, web + native vite build clean.
Reworks the Wallet screen to be more compact and to separate the two flows, and fixes a
reported bug.
Bug: buying a value with too few chips showed the generic "Something went wrong" toast — the
backend's `insufficient_chips` (409) code was propagated correctly but had no i18n mapping, so
`errorKey` fell back to `error.generic`. Add `error.insufficient_chips` / `error.product_not_found`.
Also disable a value's Exchange button up front when the spendable balance cannot cover it (the
server stays authoritative).
Redesign:
- a compact **balance** row leads the screen — the context's own chips (🪙 N) then any linked
other-platform chips behind that platform's logo (monospaced digits); inside a VK/TG store only
that store's own segment shows;
- the benefits section is renamed **Active**, moved above the store, shows one inline line
(hints + ad-free) and hides when nothing is active;
- the **store** splits by a two-way toggle into **Buy chips** (money packs + the watch-an-ad row at
the top) and **Spend chips** (values, exchanged for chips);
- a value's action reads **Exchange** and opens a single confirmation dialog (chip spends are
instant, with no provider window to confirm them); the existing cross-platform store-compliance
warning folds into that same dialog when the spend would draw VK/TG chips.
No payments-model or wire change; the money→chips→values model is unchanged (verified: money buys
only chip packs, values are chips-only — "no-ads for money" is structurally impossible).
Tests: wallet e2e updated for the new layout (chromium + webkit green). Docs: FUNCTIONAL (+_ru)
wallet story rewritten. App bundle budget 126 → 127 KB (always-loaded settings hub).
Replace the disabled "Soon" pack action with a real purchase: the Wallet opens a
money order (wallet.order) and sends the player to the provider's hosted-payment
page (window.open via openExternalUrl); the chips are credited later by the
verified server callback. Add a public-offer link under the packs (paying
accepts the offer). Codec order round-trip unit test + a mock-e2e purchase test;
the Google Play stub and the chip-spend paths are unchanged.
Add the "Кошелёк" section to the settings hub: context-visible chip
balances, active benefits (no-ads term/forever, hints) and a storefront of
chip-priced values and money-priced chip packs. Guests have no wallet; the
Google Play build hides the money purchases behind a RuStore stub; a web
purchase that would draw VK/Telegram chips warns first.
Add the catalog read path the storefront needs — a context-projected
GET /api/v1/user/wallet/catalog (payments service + store, gateway op
wallet.catalog, FBS Catalog/CatalogProduct/CatalogAtom, client decode) —
plus the client leg for the existing wallet.get/buy ops. Value spends reuse
the existing spend path; the chip-pack purchase (money order flow) arrives
with payment intake, so its action is a disabled placeholder for now.
Covered by Go unit (catalog projection) + integration (/wallet/catalog over
Postgres), vitest (formatting, spendable selection, web-spend warning, GP
flag, codec + gateway encode round-trips) and Playwright mock e2e (render,
guest-hidden, GP stub, warning) on Chromium + WebKit.