feat(release): stage GitWorkshop and next node updates
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest'
|
||||
import { isCompanionApp } from '../openExternal'
|
||||
import { describe, it, expect, afterEach, vi } from 'vitest'
|
||||
import {
|
||||
installCertificateInCompanion,
|
||||
isCompanionApp,
|
||||
openInAppOrNewTab,
|
||||
} from '../openExternal'
|
||||
|
||||
// isCompanionApp() is the single companion-detection source used to skip the
|
||||
// demo intro (App.vue + RootRedirect.vue) and by appLauncher — it must be true
|
||||
@@ -26,4 +30,21 @@ describe('isCompanionApp', () => {
|
||||
w.ArchipelagoNative = { openExternal: () => {} }
|
||||
expect(isCompanionApp()).toBe(false)
|
||||
})
|
||||
|
||||
it('absolutizes same-origin paths before handing them to the native WebView', () => {
|
||||
const openInApp = vi.fn()
|
||||
w.ArchipelagoNative = { openInApp }
|
||||
|
||||
openInAppOrNewTab('/app/archipelago-source/')
|
||||
|
||||
expect(openInApp).toHaveBeenCalledWith(`${window.location.origin}/app/archipelago-source/`)
|
||||
})
|
||||
|
||||
it('hands a certificate to the native installer when available', () => {
|
||||
const installNodeCertificate = vi.fn()
|
||||
w.ArchipelagoNative = { openInApp: () => {}, installNodeCertificate }
|
||||
|
||||
expect(installCertificateInCompanion()).toBe(true)
|
||||
expect(installNodeCertificate).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,6 +15,8 @@ interface ArchipelagoNativeBridge {
|
||||
/** Richer launch (companion ≥0.5.26): catalog icon + display name drive the
|
||||
* native branded loader instead of the site favicon. */
|
||||
openInAppEx?: (url: string, iconUrl: string, name: string) => void
|
||||
/** Install only the connected node's CA through Android's system prompt. */
|
||||
installNodeCertificate?: () => void
|
||||
}
|
||||
|
||||
/** Optional app identity for the native loading screen. */
|
||||
@@ -58,15 +60,34 @@ export function openExternalUrl(url: string): void {
|
||||
export function openInAppOrNewTab(url: string, meta?: InAppLaunchMeta): void {
|
||||
if (!url) return
|
||||
const native = nativeBridge()
|
||||
// Native WebView.loadUrl requires a complete URL. Browser APIs accept
|
||||
// relative paths, so this only surfaced when a same-origin app was launched
|
||||
// by the companion bridge.
|
||||
let nativeUrl = url
|
||||
if (!/^[a-z][a-z\d+.-]*:/i.test(url)) {
|
||||
try {
|
||||
nativeUrl = new URL(url, window.location.origin).href
|
||||
} catch { /* keep as-is */ }
|
||||
}
|
||||
if (native && typeof native.openInAppEx === 'function' && (meta?.iconUrl || meta?.name)) {
|
||||
// Absolutize the icon path so the native shell can fetch it directly.
|
||||
const icon = meta.iconUrl ? new URL(meta.iconUrl, window.location.origin).href : ''
|
||||
native.openInAppEx(url, icon, meta.name ?? '')
|
||||
native.openInAppEx(nativeUrl, icon, meta.name ?? '')
|
||||
return
|
||||
}
|
||||
if (native && typeof native.openInApp === 'function') {
|
||||
native.openInApp(url)
|
||||
native.openInApp(nativeUrl)
|
||||
return
|
||||
}
|
||||
window.open(url, '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
|
||||
/** Use Android's credential installer when the dashboard runs in the
|
||||
* companion. Returns false in an ordinary browser so the caller can preserve
|
||||
* the normal file-download behavior. */
|
||||
export function installCertificateInCompanion(): boolean {
|
||||
const native = nativeBridge()
|
||||
if (!native || typeof native.installNodeCertificate !== 'function') return false
|
||||
native.installNodeCertificate()
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user