ReviewOS

also looking at this

craft-native/craft

feat(ios): signInWithApple, and scanQRCode's real reason — ratchet 25 → 23

#122
Merged glennmichael123 wants to merge feat/ios-sign-in-with-apple into main
6 files +591 -5
packages/zig/test/ios_conformance_test.zigmodified+18-5
Changes to packages/zig/test/ios_conformance_test.zig
@@ -58,6 +58,7 @@ const zig_sources = [_][]const u8{
5858 @embedFile("src/bridge_mobile_health.zig"),
5959 @embedFile("src/bridge_mobile_speech.zig"),
6060 @embedFile("src/bridge_mobile_nfc.zig"),
61 @embedFile("src/bridge_mobile_auth_apple.zig"),
6162};
6263
6364/// The action list lives in the `switch action` block, and nowhere else.
@@ -106,9 +107,13 @@ const dispatch_end = "func webView(";
106107/// audio tap, which is the first callback in this migration that runs on a
107108/// thread where a lock is a bug rather than a slowdown.
108109/// 24 with scanNFC, which had no recorded reason at all — not a deferral that
109/// expired, just an action nobody had reached. One framework, one guard, one
110/// small delegate; the four remaining like it are registerPush, scanQRCode and
111/// signInWithApple.
110/// expired, just an action nobody had reached.
111/// 23 with signInWithApple, which needed the first object-returning delegate
112/// method in the migration (`presentationAnchorForAuthorizationController:`).
113/// Of the four that had no recorded reason, scanQRCode turned out to have a
114/// real one and is in the table below; `registerPush` is the last, and its
115/// device token arrives through a notification the Swift app delegate posts,
116/// which is a coupling to weigh rather than a wall.
112117/// 25 with scheduleNotification. Its deferral was the first to expire on its
113118/// own: the blocker recorded in `bridge_mobile_notifications.zig` was that
114119/// `ios_async` could only resolve, so an action whose two failure paths are
@@ -116,7 +121,7 @@ const dispatch_end = "func webView(";
116121/// and `deliverErrorCode` landed the day after that was written. Worth
117122/// re-reading the other deferrals for the same reason before assuming they
118123/// still hold.
119const max_not_yet_migrated: usize = 24;
124const max_not_yet_migrated: usize = 23;
120125
121126fn dispatcherRegion() []const u8 {
122127 const begin = std.mem.indexOf(u8, swift_spec, dispatch_begin) orelse return "";
@@ -298,6 +303,14 @@ const deliberate_deferrals = [_]Deferral{
298303 .{ .action = "resumeLocationRecording", .reason = "Coordinator.init re-adopts recordings at launch; Zig cannot stop what Swift restored" },
299304 .{ .action = "getLocationRecordingState", .reason = "Coordinator.init re-adopts recordings at launch; Zig cannot stop what Swift restored" },
300305
306 // VisionKit's `DataScannerViewController` is Swift-only: the framework's
307 // Objective-C headers carry DocumentCamera and nothing else, and the
308 // delegate callback takes a `RecognizedItem`, a Swift enum with associated
309 // values that `objc_msgSend` cannot destructure. Same class of wall as
310 // ActivityKit, and checked against the iphonesimulator SDK rather than
311 // assumed.
312 .{ .action = "scanQRCode", .reason = "VisionKit's DataScanner is Swift-only; the delegate takes a Swift enum with associated values" },
313
301314 // Not a capability gap: the spec's own success path has never executed, so
302315 // there is no working contract to port. See the tracking issue.
303316 .{ .action = "startVideoRecording", .reason = "the spec reads info[.originalImage] for a movie pick, so its success path never runs" },
@@ -332,7 +345,7 @@ test "every recorded deferral is real, and still a deferral" {
332345 }
333346
334347 // Non-vacuity: the loop above is satisfied by an empty table.
335 try testing.expect(deliberate_deferrals.len >= 20);
348 try testing.expect(deliberate_deferrals.len >= 22);
336349
337350 // And the table cannot claim more than remain unmigrated.
338351 try testing.expect(deliberate_deferrals.len <= max_not_yet_migrated);