| 1 | import WebKit |
| 2 | import os |
| 3 | |
| 4 | let catalogLog = Logger(subsystem: "com.elevenmessenger.messenger", category: "catalog") |
| 5 | |
| 6 | // 🤖 The live half of the registry's catalogue (docs/native-apps.md app-host |
| 7 | // protocol): any embed page that booted the web app framework can answer |
| 8 | // window.lchatNative.appCatalog() — the full registered-app set across all |
| 9 | // three tiers (built-in, admin custom, member). The platform web bridges call |
| 10 | // pull() when a page reports ready, and again (forced) on a {catalogChanged} |
| 11 | // post, so the registry learns this space's custom and member apps the first |
| 12 | // time any webview opens and stays current as the set changes. |
| 13 | public enum AppCatalogPull { |
| 14 | /// Pull the catalogue from a ready embed page into the origin's registry. |
| 15 | /// Cheap once a live report has landed (one pull per launch unless |
| 16 | /// forced). Tolerant of instances still serving a pre-bridge deploy — |
| 17 | /// the eval answers null there and nothing changes. |
| 18 | @MainActor |
| 19 | public static func pull(from web: WKWebView, origin: String, force: Bool = false) { |
| 20 | guard force || !AppRegistry.shared(origin: origin).hasLiveReport else { return } |
| 21 | let js = "window.lchatNative && window.lchatNative.appCatalog" |
| 22 | + " ? JSON.stringify(window.lchatNative.appCatalog()) : null" |
| 23 | web.evaluateJavaScript(js) { result, err in |
| 24 | guard let json = result as? String, !json.isEmpty else { |
| 25 | let why = err.map(String.init(describing:)) ?? "bridge absent or page booting" |
| 26 | catalogLog.notice("catalogue pull: no report (\(why, privacy: .public))") |
| 27 | return |
| 28 | } |
| 29 | Task { @MainActor in |
| 30 | AppRegistry.shared(origin: origin).update(reportJSON: Data(json.utf8)) |
| 31 | } |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | |