把 opolyx 装到手机上——并且无需密码即可登录
opolyx 现在是一款真正可安装的应用,并且有四种登录方式:魔法链接、邮件验证码、Google 或 Apple。其中验证码是在任何环境下都能用的那一种。

通俗版
你可以把 opolyx 添加到主屏幕,像其他应用一样打开它:拥有自己的图标、没有浏览器工具栏、直接进入大厅。今天在 Android 和 iOS 上都可以通过浏览器菜单完成,而且这与我们正在为应用商店打包的是同一份构建。
- 全屏启动后直接进入大厅,而不是营销页面;
- 拥有自己的图标和启动画面,而不是一个浏览器快捷方式;
- 离线时显示一个正经的 opolyx 页面,而不是浏览器报错;
- 绝不缓存任何来自进行中对局的数据,因此已安装的应用与网站一样新。
现在登录有四条路径,你可以选择最适合当前设备的一种:
| 方式 | 工作原理 |
|---|---|
| 魔法链接 | 邮件里的一个链接——点一下即可,无需密码 |
| 邮件验证码 | 一个 8 位验证码,在登录页面输入 |
| 标准的账号选择界面 | |
| Apple | 包括 Hide My Email,其背后的地址我们从来看不到 |
通过邮件发送的验证码是在任何环境下都行得通的那条路——包括在应用外壳内部,因为在那里链接会在另一个浏览器中打开,无法把会话交回来。
技术细节
Service worker 的范围是刻意收窄的。它是一份白名单,而不是通吃:导航请求走"网络优先",失败时回退到离线页面;带哈希的静态资源采用 stale-while-revalidate;其余的一切——数据库、游戏服务器、实时通道、身份验证、服务端渲染的载荷——统统绕过,因此它绝不可能提供过期的棋盘,也不可能弄坏一局进行中的对战。
// public/sw.js — allow-list, not catch-all
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
if (url.origin !== self.location.origin) return; // Supabase, daemon: untouched
if (BYPASS.some((p) => url.pathname.startsWith(p))) return; // /auth, /api, RSC
if (event.request.mode === 'navigate') return event.respondWith(networkFirst(event));
if (HASHED.test(url.pathname)) return event.respondWith(staleWhileRevalidate(event));
});真正棘手的是被封装的 iOS 版本:在那里没有任何一种登录方式能够完成,而在所有浏览器里一切正常。原因是打包工具替你写入的一项 WebKit 设置:启用"应用绑定域名"后,WebKit 会静默取消任何指向未列入清单主机的顶层导航——而 OAuth 流程的第一跳恰恰就是这样的导航。另外,Google 出于政策拒绝嵌入式 webview,这一点任何配置都无法解决。
魔法链接在那里同样不可能奏效:它会在系统浏览器中打开,而应用的 webview 看不到系统浏览器的 Cookie 存储。正因如此,输入验证码才是唯一同源的邮件路径——它在提出请求的那个 webview 中完成。
对于 Google,官方认可的做法是在系统浏览器中跑完流程,再把会话交回来。这座桥梁在构造授权 URL 时刻意不使用 PKCE,于是流程会在回调片段中返回令牌,供外壳读取——若返回授权码,则只有持有校验值的那个浏览器才能兑换,而那恰恰不是我们需要的那一个。
