snapback4-expo 0.4.9 → 0.4.10
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/README.md
CHANGED
|
@@ -59,8 +59,16 @@ runner, commands and artifact contract are in `snapback4 guide witness`
|
|
|
59
59
|
“Proving it on an iOS simulator”. No Expo Go or Metro process supplies a
|
|
60
60
|
Release witness.
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
At every milestone, run `npm run export:ios` for Hermes; on a Mac with Xcode,
|
|
63
|
+
`npm run native:smoke` (about 3 minutes warm). The Expo starters include both scripts.
|
|
64
|
+
The smoke builds and installs your Release app, chooses its own simulator and free
|
|
65
|
+
port, and keeps receipts in `artifacts/native-smoke/<timestamp>`. It proves local
|
|
66
|
+
store acquisition, cold offline reopen and reconnect. Pending write replay, media
|
|
67
|
+
and application assertions need the deeper scenario in `snapback4 guide witness`.
|
|
68
|
+
An empty starter proves lifecycle only; export alone proves no native execution.
|
|
69
|
+
|
|
70
|
+
Own-build preparation (`witness ios --build . --smoke`) uses the witness helper
|
|
71
|
+
in matching current `snapback4` and `snapback4-expo` packages. Its synchronous native observation hashes
|
|
64
72
|
the executable and the file selected by React Native SourceCode.scriptURL.
|
|
65
73
|
Selection must resolve to the verified installed main.jsbundle; unknown, remote
|
|
66
74
|
or alternate URLs fail, as do runtime __DEV__ true/unknown and launcher/updates
|
|
@@ -76,9 +84,9 @@ loading or E_OFFLINE is recorded as expected unavailability. Server-only reads
|
|
|
76
84
|
must answer online in prime and restart. Conditional native-module queries
|
|
77
85
|
require an application witness; generic smoke refuses that unsupported shape. Client semantics are unchanged.
|
|
78
86
|
|
|
79
|
-
After JS/assets edits, repeat `
|
|
80
|
-
|
|
87
|
+
After JS/assets edits, repeat `npm run native:smoke`; simulator selection and
|
|
88
|
+
fresh artifact directories are automatic. Warm Xcode intermediates
|
|
81
89
|
are reused; each run builds the current app and seals a new receipt. Repack
|
|
82
|
-
is withdrawn.
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
is withdrawn. NS round 0 cohort (2026-09-30), fresh starter: **221.7 s cold**, **83.5 s warm median (3 runs)**; social **186.2 s**.
|
|
91
|
+
Shared Apartment M5 Pro mini, 18 cores/64 GiB, Xcode/iOS 27; one-minute load: cold 3.61–61.41, warm 3.21–7.22, social 14.62–47.52.
|
|
92
|
+
Tools/dependencies installed first. Guidance, not a promise. See `guide witness` for scope.
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snapback4-expo",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Snapback 4's native module for Expo: the device in Rust (the partition in its own SQLite, the stream applied, the outbox kept, queries and predictions answered) behind one JSON call, and the opener `snapback4/native` takes.",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
".": { "types": "./src/index.ts", "default": "./src/index.ts" },
|
|
10
10
|
"./witness": { "types": "./src/witness.ts", "default": "./src/witness.ts" },
|
|
11
|
+
"./plugin": "./plugin.cjs",
|
|
11
12
|
"./package.json": "./package.json"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
15
|
+
"plugin.cjs",
|
|
14
16
|
"src",
|
|
15
17
|
"ios",
|
|
16
18
|
"expo-module.config.json",
|
package/plugin.cjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// @ref LLP 3000.030#13 — the pinned Expo starter must launch on iOS 27 without a manual migration.
|
|
2
|
+
const { withAppDelegate, withInfoPlist } = require('expo/config-plugins');
|
|
3
|
+
const marker = '// Snapback4 starter scene lifecycle';
|
|
4
|
+
const legacy = `#if os(iOS) || os(tvOS)
|
|
5
|
+
window = UIWindow(frame: UIScreen.main.bounds)
|
|
6
|
+
factory.startReactNative(
|
|
7
|
+
withModuleName: "main",
|
|
8
|
+
in: window,
|
|
9
|
+
launchOptions: launchOptions)
|
|
10
|
+
#endif`;
|
|
11
|
+
const scene = `
|
|
12
|
+
${marker}
|
|
13
|
+
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
14
|
+
var window: UIWindow?
|
|
15
|
+
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
|
16
|
+
guard let scene = scene as? UIWindowScene,
|
|
17
|
+
let app = UIApplication.shared.delegate as? AppDelegate,
|
|
18
|
+
let factory = app.reactNativeFactory else { return }
|
|
19
|
+
let window = UIWindow(windowScene: scene)
|
|
20
|
+
self.window = window
|
|
21
|
+
app.window = window
|
|
22
|
+
factory.startReactNative(withModuleName: "main", in: window, launchOptions: nil)
|
|
23
|
+
for context in connectionOptions.urlContexts {
|
|
24
|
+
_ = app.application(UIApplication.shared, open: context.url, options: [:])
|
|
25
|
+
}
|
|
26
|
+
for activity in connectionOptions.userActivities {
|
|
27
|
+
_ = app.application(UIApplication.shared, continue: activity, restorationHandler: { _ in })
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
func scene(_ scene: UIScene, openURLContexts contexts: Set<UIOpenURLContext>) {
|
|
31
|
+
guard let app = UIApplication.shared.delegate as? AppDelegate else { return }
|
|
32
|
+
for context in contexts { _ = app.application(UIApplication.shared, open: context.url, options: [:]) }
|
|
33
|
+
}
|
|
34
|
+
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
|
|
35
|
+
guard let app = UIApplication.shared.delegate as? AppDelegate else { return }
|
|
36
|
+
_ = app.application(UIApplication.shared, continue: userActivity, restorationHandler: { _ in })
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
module.exports = function withStarterScene(config) {
|
|
41
|
+
config = withAppDelegate(config, config => {
|
|
42
|
+
const mod = config.modResults;
|
|
43
|
+
if (mod.contents.includes(marker)) return config;
|
|
44
|
+
if (mod.language !== 'swift' || !mod.contents.includes(legacy) || mod.contents.includes('class SceneDelegate')) {
|
|
45
|
+
throw new Error('snapback4-expo/plugin requires the Expo 57 Swift starter; migrate custom UIScene lifecycle manually and remove this plugin');
|
|
46
|
+
}
|
|
47
|
+
mod.contents = mod.contents.replace(legacy, '') + scene;
|
|
48
|
+
return config;
|
|
49
|
+
});
|
|
50
|
+
return withInfoPlist(config, config => {
|
|
51
|
+
const manifest = { UIApplicationSupportsMultipleScenes: false, UISceneConfigurations: {
|
|
52
|
+
UIWindowSceneSessionRoleApplication: [{ UISceneConfigurationName: 'Default Configuration', UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate' }],
|
|
53
|
+
} };
|
|
54
|
+
const existing = config.modResults.UIApplicationSceneManifest;
|
|
55
|
+
if (existing && JSON.stringify(existing) !== JSON.stringify(manifest)) {
|
|
56
|
+
throw new Error('snapback4-expo/plugin refuses a custom UIApplicationSceneManifest; keep its own lifecycle and remove this plugin');
|
|
57
|
+
}
|
|
58
|
+
config.modResults.UIApplicationSceneManifest = manifest;
|
|
59
|
+
return config;
|
|
60
|
+
});
|
|
61
|
+
};
|
package/src/witness.ts
CHANGED
|
@@ -13,3 +13,11 @@ export function witness(): Witness | null {
|
|
|
13
13
|
}
|
|
14
14
|
return instance;
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
/** The starter may use normal guest sign-in during prime; never on ordinary launches. */
|
|
18
|
+
export function smokeSegment(): "prime" | "offline" | "restart" | null {
|
|
19
|
+
const container = requireOptionalNativeModule<WitnessContainer>("Snapback4");
|
|
20
|
+
if (!container?.witnessLaunch) return null;
|
|
21
|
+
const config = JSON.parse(container.witnessLaunch);
|
|
22
|
+
return config.smoke === true && ["prime", "offline", "restart"].includes(config.segment) ? config.segment : null;
|
|
23
|
+
}
|