Files
archy/docker/kithmoot/integrate.py
T

61 lines
4.1 KiB
Python

"""Small, fail-closed downstream changes for the pinned upstream source.
Run only inside the disposable build context, from the upstream checkout root.
Upstream changes must be re-reviewed rather than silently patched by regex.
"""
from pathlib import Path
def replace(path, old, new):
file = Path(path)
text = file.read_text()
if text.count(old) != 1:
raise SystemExit(f"Upstream contract changed: {path}: {old[:70]!r}")
file.write_text(text.replace(old, new))
replace('app/index.html', ' <meta charset="utf-8" />',
' <meta charset="utf-8" />\n <script src="/nostr-provider.js?v=tab-signer-v4" data-app-id="kithmoot" data-no-nip98></script>')
replace('app/index.html', '</body>', '<script type="module" src="/video-entry.mjs"></script>\n </body>')
# Build-time insertion, not response substitution: offline HTML retains the
# provider reference. The provider itself lives outside /j/ and its SW scope.
replace('app/src/main.ts', 'async function signInWithNostr(): Promise<void> {', '''async function signInWithNostr(reuseSelected = false, useHost = true): Promise<void> {''')
replace('app/src/main.ts', " account = await login({ appName: 'KithMoot', relayUrls: signinRelays(RELAYS),", ''' const host = useHost ? (window as Window & { archipelagoNostr?: {
selectIdentity?: () => Promise<unknown>
getSelectedIdentity?: () => unknown
} }).archipelagoNostr : undefined
if (host?.selectIdentity && (!reuseSelected || !host.getSelectedIdentity?.())) {
await host.selectIdentity()
}
account = await login({ appName: 'KithMoot', relayUrls: signinRelays(RELAYS),
preferredMethod: host?.selectIdentity ? 'nip07' : undefined,''')
replace('app/src/main.ts', " methods: ['nip07', 'amber', 'remote-signet', 'local-signet', 'bunker', 'nostrconnect', 'nsec'] })",
" methods: ['nip07', 'amber', 'remote-signet', 'local-signet', 'bunker', 'nostrconnect'] })")
# Use the existing account-adoption/generation checks. Never auto-join a room.
replace('app/src/main.ts', '// Only an explicit switch or safe update in this tab skips the door.', '''// Ask once after restoration and UI setup; cancellation leaves normal login.
// An existing remote signer or remembered account is never silently replaced.
void identityReady.then(() => {
const host = (window as Window & { archipelagoNostr?: unknown }).archipelagoNostr
if (host && !nostrSession && !expectedAccount && !loginBusy && !session && !joining) {
return signInWithNostr(true).catch(error => setStatus(describeError(error)))
}
})
const otherSigner = document.createElement('button')
otherSigner.type = 'button'
otherSigner.textContent = 'Use another signer'
otherSigner.className = 'quiet'
otherSigner.addEventListener('click', () => {
void signInWithNostr(false, false).catch(error => setStatus(describeError(error)))
})
$('headerSignIn').insertAdjacentElement('afterend', otherSigner)
// Only an explicit switch or safe update in this tab skips the door.''')
# A static UI package must not promise a TURN credential service it lacks.
replace('app/src/main.ts', "const TURN_CREDENTIAL_ENDPOINT: string | undefined = '/turn'",
'const TURN_CREDENTIAL_ENDPOINT: string | undefined = undefined')
replace('app/index.html', '<button id="getMeetingCode" type="button">Get a meeting code</button>',
'<button id="getMeetingCode" type="button" disabled title="Meeting-code service is not included in this package; share an invitation link instead.">Meeting codes unavailable</button>')
# Explain the package boundary before users try unavailable infrastructure.
replace('app/index.html', '<div id="ordinaryStartupNotice" role="status" aria-live="polite">',
'<aside id="archipelagoPackageNotice" role="note" style="padding:0.75rem">Archipelago preview: calls require HTTPS and browser permissions. No TURN or meeting-code service is bundled; share full invitation links. Configure shared file storage explicitly in Settings. Room keys and history are stored in this browser, not backed up by the node.</aside>\n <div id="ordinaryStartupNotice" role="status" aria-live="polite">')