Repository navigation
feat(push): open a tap on the saved connection that sent it - #192
Open
objectstack-fleet[bot] wants to merge 3 commits into
Open
objectstack-fleet[bot] wants to merge 3 commits into
objectstack-fleet[bot] wants to merge 3 commits into
Conversation
Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
…start and the switch order Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
…n limit Claude-Session: https://claude.ai/code/session_01QSeKYnW1Xf6HDSWz1eGAqv Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
repo:mobile#1 · os-justin · session_01QSeKYnW1Xf6HDSWz1eGAqv Seat verdict: ACCEPT — Head-sha: 维护者速读
席位意见: 四条规则、MDM 锁定和应用锁都按派发令实现了。推送里的服务器地址只用来在已保存的服务器里挑选,app 不会去连推送点名的服务器。比对地址的方式和平台协议要求的标准格式一致,席位对照代码核过。全套 1092 个测试通过;故意改坏地址比对后有 15 个测试变红,证明测试真在把关。建议合并。 席位核对
|
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.
Fixes #174
Clause-②: no
Metadata-protocol: none
维护者速读
origin)找到对应的已保存连接;来自当前连接的照旧打开,来自另一个已保存连接的先切换过去,等它的 Console 加载好再打开页面。origin,保存了两个及以上连接时点开不再打开页面(只保存一个时照旧);回滚即还原本 PR,纯客户端改动,无数据迁移。hooks/usePushRouting.ts(openTap:先切换、确认已切换、再路由)、lib/push-notifications.ts(pushTapTarget:四条规则与 MDM 锁)、lib/connections/model.ts(connectionByOrigin:逐字节比较)。npx jest --ci __tests__/hooks/usePushRouting.test.ts __tests__/components/ConsoleScreen.test.tsx,预期 36 个测试全部通过。What changes
The platform's push data now names its sender:
origin, the origin the Console was loaded from when it registered the device (objectstackPushDeliveryDataSchema.origin, rule inpackages/spec/src/system/push-server-origin.ts). The shell uses it to pick the saved connection a tap opens on.lib/connections/model.ts:connectionByOrigin(list, origin)comparesoriginbyte for byte withoriginOf(connection.serverUrl). The stored server URL is normalized (lower-cased host, scheme default port dropped, scheme kept), so its origin is exactly what its Console reads aswindow.location.origin. No case folding, port guessing or host-only match; a non-string matches nothing.lib/push-notifications.ts:pushSenderFromResponsereadsoriginfrom the same dictionaries, in the same order, as the route.pushTapTargetapplies the rules:originis the current connection's: route there, as before.originis another saved connection's: that connection (the hook switches first).originpresent, no saved connection has it: drop.origin: the only saved connection; with two or more, drop.Under an MDM lock (
lockServer), only the managed connection is open to a tap; any other is dropped, never switched to (and while the managed address waits for its confirm step, every tap drops).routeFromPushDatais unchanged;routeFromResponseonly had its candidate list factored out.hooks/usePushRouting.ts: the hook takes onlyonRouteand reads the stores. Each tap (listener or cold-start response) is deduped by identifier at intake, as before, then held until the saved connections are loaded and the app lock is open. Then: pick the connection, compute the route against that connection's server URL, switch with the store'sselect(the switcher's path) when it is not current, check the switch stuck, and only then callonRoute. Only the latest held tap is opened.app/_layout.tsx: the call site drops theserverUrlargument. This file is outside the claim's file surface: measurement showed the hook is mounted here, not inapp/console.tsx, andapp/console.tsxneeded no change (see Acceptance notes).docs/PUSH-NOTIFICATIONS.mdgains "Which server a tap opens on" and theoriginkey in both payload samples;docs/HYBRID-SHELL.mdreplaces the "Push taps carry no connection" known limit with the one that remains (an older server, two or more saved connections) and notes the push switch under "Switching" and "Managed deployment"..changeset/174-push-per-connection.md(patch).Tests
__tests__/hooks/usePushRouting.test.ts(rewritten for the new signature, 14 hook cases): rules 1 to 4, aurlkey checked against the sender's Console, a tap with no route switches nothing, the MDM lock drop, the app-lock hold then switch on unlock, latest held tap wins, waiting for the saved connections to load, cold start through lock and switch routed once, cold start from a removed server opens nothing. Each routed case records the current connection at the moment the route arrives, which pins switch-before-route.__tests__/lib/push-notifications.test.ts:pushSenderFromResponse(FCM, APNs, absent, null, non-string) andpushTapTarget(each rule, byte-for-byte refusals such as an upper-cased host,:443, a trailing slash, the other scheme, a bare host, the lock and the pending-managed lock).__tests__/lib/connections/model.test.ts:connectionByOrigin, including the stored-document round trip (scheme kept, default port dropped, base path not part of the origin).__tests__/components/ConsoleScreen.test.tsx(existing harness; itsuseLocalSearchParamsmock became mutable): the route asked for after a switch reaches only the new connection's document, gated to its origin, after its Console says ready; and the same when the switch and the route land in one render.Acceptance notes
app/console.tsxto own the switch-then-route sequencing. Measured:usePushRoutingis mounted inapp/_layout.tsxand hands routes to the Console screen as search params; the switch is the store'sselect, which the WebView follows in a layout effect. Switching first and routing second already delivers the route to the new document (held until ready), so the sequencing lives in the hook andapp/console.tsxis untouched.app/_layout.tsxchanged by two lines (the call site).lockedHost) hides other connections in the switcher butselectitself does not refuse them, so the tap rule checks the lock before any switch.docs/PUSH-NOTIFICATIONS.md"Prerequisites" still says the server's device registry and push channel were never built; objectstack has since shipped them. Left as is: outside this card.Verification
All readings at head
f5f9a36.Gates
Ablation: the origin match
connectionByOriginmutated to answer the first saved connection (the current one in the hook fixtures) for any string origin, throughscripts/ablation-replace.mjs(anchor 1 to 0, blob changed; restore proven: blob equals HEAD,git diff HEADempty). Hook, push and model suites: 15 failed, 70 passed. Red:connectionByOrigin(3),pushTapTargetopens-on / byte-for-byte / unsaved-with-one / locked (4), and the hook's rule 2, rule 2 url, rule 3, MDM lock, app-lock hold, waits-for-load, both cold-start cases (8).Ablation: the app-lock hold, and a control for the switch-order pin
appLockeddropped from the hook's guard): 2 failed, 14 passed (the app-lock hold and the cold start through the lock). Restored, blob equals HEAD.https://erp.example.com, the document being left. Restored, blob equals HEAD.Generated by Claude Code