first
This commit is contained in:
318
NOSTR_LOGIN_LITE.md
Normal file
318
NOSTR_LOGIN_LITE.md
Normal file
@@ -0,0 +1,318 @@
|
||||
# NOSTR_LOGIN_LITE
|
||||
|
||||
Objective
|
||||
- Deliver a minimal, dependency-light replacement for the current auth/UI stack that:
|
||||
- Preserves all login methods: Nostr Connect (nip46), Extension, Local key, Read-only, OTP/DM.
|
||||
- Exposes the same window.nostr surface: [getPublicKey()](lite/nostr-login-lite.js:1), [signEvent(event)](lite/nostr-login-lite.js:1), [nip04.encrypt(pubkey, plaintext)](lite/nostr-login-lite.js:1), [nip04.decrypt(pubkey, ciphertext)](lite/nostr-login-lite.js:1), [nip44.encrypt(pubkey, plaintext)](lite/nostr-login-lite.js:1), [nip44.decrypt(pubkey, ciphertext)](lite/nostr-login-lite.js:1).
|
||||
- Dispatches identical nlAuth/nlLaunch/nlLogout/nlDarkMode events and accepts setAuth calls for compatibility.
|
||||
|
||||
Key differences vs current project
|
||||
- UI: replace Stencil/Tailwind component library with a single vanilla-JS modal and minimal CSS.
|
||||
- Transport: remove NDK; implement NIP-46 RPC using nostr-tools SimplePool.
|
||||
- Crypto: rely on nostr-tools (via CDN global window.NostrTools) for keygen/signing (finalizeEvent), nip04, nip19, and SimplePool; embed a small NIP-44 codec if window.NostrTools.nip44 is not available. The current project’s codec is in [packages/auth/src/utils/nip44.ts](packages/auth/src/utils/nip44.ts).
|
||||
|
||||
Nostr Tools via CDN (global window.NostrTools)
|
||||
- Include the bundle once in the page:
|
||||
<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
|
||||
- Access APIs via window.NostrTools inside the lite build:
|
||||
- [NostrTools.generateSecretKey()](lite/nostr-login-lite.js:1) or [NostrTools.generatePrivateKey()](lite/nostr-login-lite.js:1) (depending on CDN version)
|
||||
- [NostrTools.getPublicKey()](lite/nostr-login-lite.js:1)
|
||||
- [NostrTools.finalizeEvent()](lite/nostr-login-lite.js:1)
|
||||
- [NostrTools.nip04](lite/nostr-login-lite.js:1) encrypt/decrypt
|
||||
- [NostrTools.nip19](lite/nostr-login-lite.js:1) npub/nsec encode/decode
|
||||
- [NostrTools.SimplePool](lite/nostr-login-lite.js:1) relay connectivity
|
||||
|
||||
Supported login methods and crypto summary
|
||||
- Connect (nip46): secp256k1 Schnorr for event signing/hash; nip44 (ChaCha20/HKDF/HMAC) for RPC payloads, with nip04 fallback. Requires relay connectivity (via [NostrTools.SimplePool](lite/nostr-login-lite.js:1)).
|
||||
- Extension: crypto handled by the extension; we bridge calls.
|
||||
- Local key: secp256k1 Schnorr signing ([NostrTools.finalizeEvent()](lite/nostr-login-lite.js:1)) and nip04/nip44 encrypt/decrypt locally.
|
||||
- Read-only: no client crypto.
|
||||
- OTP/DM: no client crypto beyond state persistence; server sends DM and verifies via HTTP.
|
||||
|
||||
Minimal file layout
|
||||
- Single file drop-in (script tag friendly):
|
||||
- [lite/nostr-login-lite.js](lite/nostr-login-lite.js)
|
||||
- Optional split during development (bundled later):
|
||||
- [lite/core/nostr-lite.js](lite/core/nostr-lite.js)
|
||||
- [lite/core/nip46-client.js](lite/core/nip46-client.js)
|
||||
- [lite/core/extension-bridge.js](lite/core/extension-bridge.js)
|
||||
- [lite/core/store.js](lite/core/store.js)
|
||||
- [lite/ui/modal.js](lite/ui/modal.js)
|
||||
|
||||
External dependencies strategy
|
||||
- Use the CDN bundle to provide [window.NostrTools](lite/nostr-login-lite.js:1) at runtime. No npm installs required.
|
||||
- Prefer built-ins from window.NostrTools:
|
||||
- Keys/sign: [generateSecretKey()](lite/nostr-login-lite.js:1)/[generatePrivateKey()](lite/nostr-login-lite.js:1), [getPublicKey()](lite/nostr-login-lite.js:1), [finalizeEvent()](lite/nostr-login-lite.js:1).
|
||||
- Encoding: [nip19](lite/nostr-login-lite.js:1).
|
||||
- Encryption: [nip04](lite/nostr-login-lite.js:1).
|
||||
- Relays: [SimplePool](lite/nostr-login-lite.js:1).
|
||||
- Nip44 choice:
|
||||
- If window.NostrTools.nip44 is available, use it directly.
|
||||
- Otherwise embed the existing lightweight codec adapted from [packages/auth/src/utils/nip44.ts](packages/auth/src/utils/nip44.ts) as [Nip44](lite/nostr-login-lite.js:1).
|
||||
|
||||
Compatibility requirements
|
||||
- Provide the same exports: [init(opts)](lite/nostr-login-lite.js:1), [launch(startScreen)](lite/nostr-login-lite.js:1), [logout()](lite/nostr-login-lite.js:1), [setDarkMode(dark)](lite/nostr-login-lite.js:1), [setAuth(o)](lite/nostr-login-lite.js:1), [cancelNeedAuth()](lite/nostr-login-lite.js:1).
|
||||
- Dispatch identical events and payload shapes as in [onAuth()](packages/auth/src/modules/AuthNostrService.ts:347).
|
||||
|
||||
Architecture overview
|
||||
- NostrLite: window.nostr facade mirroring current behavior, invokes auth UI when needed.
|
||||
- Auth: manages methods (connect/extension/local/readOnly/otp), state, storage, event dispatch.
|
||||
- NIP46Client: minimal RPC over [NostrTools.SimplePool](lite/nostr-login-lite.js:1) (subscribe, send request, parse/decrypt, dedupe auth_url).
|
||||
- ExtensionBridge: safely handle window.nostr detection, guard against overwrites, switch to extension mode when requested.
|
||||
- Store: localStorage helpers for accounts/current/recents and misc values.
|
||||
- UI: single vanilla modal that lists options and drives flow, with optional inline iframe starter for providers that publish iframe_url.
|
||||
|
||||
Function-level TODO checklist (execution order)
|
||||
|
||||
Bootstrap and API surface
|
||||
- [ ] [Deps.ensureNostrToolsLoaded()](lite/nostr-login-lite.js:1)
|
||||
- Verify window.NostrTools presence; throw with actionable message if missing.
|
||||
|
||||
- [ ] [NostrLite.init(options: NostrLoginOptions)](lite/nostr-login-lite.js:1)
|
||||
- Call [Deps.ensureNostrToolsLoaded()](lite/nostr-login-lite.js:1).
|
||||
- Bind window.nostr to the facade.
|
||||
- Initialize ExtensionBridge checking loop.
|
||||
- Mount modal UI, persist options (theme, perms, bunkers, methods, otp URLs, default relays).
|
||||
- Wire nlLaunch/nlLogout/nlDarkMode/nlSetAuth listeners.
|
||||
|
||||
- [ ] [NostrLite.launch(startScreen?: string)](lite/nostr-login-lite.js:1)
|
||||
- Open modal with selected start screen or switch-account if accounts exist.
|
||||
|
||||
- [ ] [NostrLite.logout()](lite/nostr-login-lite.js:1)
|
||||
- Clear current account; dispatch nlAuth logout; reset signer/client state.
|
||||
|
||||
- [ ] [NostrLite.setDarkMode(dark: boolean)](lite/nostr-login-lite.js:1)
|
||||
- Persist and apply theme to modal.
|
||||
|
||||
- [ ] [NostrLite.setAuth(o: NostrLoginAuthOptions)](lite/nostr-login-lite.js:1)
|
||||
- Validate o.type in {login, signup, logout}; o.method in {connect, extension, local, otp, readOnly}.
|
||||
- Delegate to [Auth.switchAccount()](lite/nostr-login-lite.js:1); dispatch consistent nlAuth.
|
||||
|
||||
- [ ] [NostrLite.cancelNeedAuth()](lite/nostr-login-lite.js:1)
|
||||
- Cancel current connect/listen flow and close modal section if waiting.
|
||||
|
||||
window.nostr facade
|
||||
- [ ] [NostrLite.ensureAuth()](lite/nostr-login-lite.js:1)
|
||||
- If no user, open modal; await until authenticated or rejected.
|
||||
|
||||
- [ ] [NostrLite.getPublicKey()](lite/nostr-login-lite.js:1)
|
||||
- Ensure auth, return current pubkey or throw.
|
||||
|
||||
- [ ] [NostrLite.signEvent(event: NostrEvent)](lite/nostr-login-lite.js:1)
|
||||
- Ensure auth; if local key then sign locally via [NostrTools.finalizeEvent()](lite/nostr-login-lite.js:1); else sign via [NIP46Client.sendRequest()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [NostrLite.nip04.encrypt(pubkey, plaintext)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [NostrLite.nip04.decrypt(pubkey, ciphertext)](lite/nostr-login-lite.js:1)
|
||||
- Ensure auth; route to local ([NostrTools.nip04](lite/nostr-login-lite.js:1)) or remote signer via NIP-46 nip04_{encrypt|decrypt}.
|
||||
|
||||
- [ ] [NostrLite.nip44.encrypt(pubkey, plaintext)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [NostrLite.nip44.decrypt(pubkey, ciphertext)](lite/nostr-login-lite.js:1)
|
||||
- Ensure auth; use window.NostrTools.nip44 if present or local [Nip44](lite/nostr-login-lite.js:1); remote via nip44_{encrypt|decrypt}.
|
||||
|
||||
Auth module
|
||||
- [ ] [Auth.startAuthSession()](lite/nostr-login-lite.js:1)
|
||||
- Create a promise used by ensureAuth/waitReady; allows Connect flow to resolve or be cancelled.
|
||||
|
||||
- [ ] [Auth.endAuthSession()](lite/nostr-login-lite.js:1)
|
||||
- Resolve session; if iframeUrl present, bind iframe port to NIP46Client before resolving.
|
||||
|
||||
- [ ] [Auth.resetAuthSession()](lite/nostr-login-lite.js:1)
|
||||
- Cancel current session safely.
|
||||
|
||||
- [ ] [Auth.onAuth(type: "login" | "signup" | "logout", info?: Info)](lite/nostr-login-lite.js:1)
|
||||
- Update state, persist, dispatch nlAuth; fetch profile asynchronously and update name/picture when fetched; preserve nip05 semantics.
|
||||
|
||||
- [ ] [Auth.switchAccount(info: Info, signup = false)](lite/nostr-login-lite.js:1)
|
||||
- Branch to [Auth.setReadOnly()](lite/nostr-login-lite.js:1)/[Auth.setOTP()](lite/nostr-login-lite.js:1)/[Auth.setLocal()](lite/nostr-login-lite.js:1)/[Auth.trySetExtensionForPubkey()](lite/nostr-login-lite.js:1)/[Auth.setConnect()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [Auth.setReadOnly(pubkey: string)](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [Auth.setOTP(pubkey: string, data: string)](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [Auth.localSignup(name: string, sk?: string)](lite/nostr-login-lite.js:1)
|
||||
- Generate sk via [NostrTools.generateSecretKey()](lite/nostr-login-lite.js:1)/[generatePrivateKey()](lite/nostr-login-lite.js:1) if missing; [Auth.setLocal(signup=true)](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [Auth.setLocal(info: Info, signup?: boolean)](lite/nostr-login-lite.js:1)
|
||||
- Instantiate [LocalSigner](lite/nostr-login-lite.js:1); call [Auth.onAuth()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [Auth.trySetExtensionForPubkey(pubkey: string)](lite/nostr-login-lite.js:1)
|
||||
- Use [ExtensionBridge.setExtensionReadPubkey()](lite/nostr-login-lite.js:1) and reconcile.
|
||||
|
||||
- [ ] [Auth.setConnect(info: Info)](lite/nostr-login-lite.js:1)
|
||||
- Initialize NIP46Client with existing token/relays via [NIP46Client.init()](lite/nostr-login-lite.js:1) and [NIP46Client.connect()](lite/nostr-login-lite.js:1); call [Auth.onAuth()](lite/nostr-login-lite.js:1); [Auth.endAuthSession()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [Auth.authNip46(type, { name, bunkerUrl, sk, domain, iframeUrl })](lite/nostr-login-lite.js:1)
|
||||
- Parse bunkerUrl/nip05; [NIP46Client.init()](lite/nostr-login-lite.js:1) + [NIP46Client.connect()](lite/nostr-login-lite.js:1); [Auth.onAuth()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [Auth.nostrConnect(relay?: string, opts?: { domain?: string; link?: string; importConnect?: boolean; iframeUrl?: string })](lite/nostr-login-lite.js:1)
|
||||
- Create local keypair and secret; open provider link or show iframe starter; [NIP46Client.listen()](lite/nostr-login-lite.js:1) to learn signerPubkey, then [NIP46Client.initUserPubkey()](lite/nostr-login-lite.js:1); set bunkerUrl; [Auth.onAuth()](lite/nostr-login-lite.js:1) unless importConnect.
|
||||
|
||||
- [ ] [Auth.createNostrConnect(relay?: string)](lite/nostr-login-lite.js:1)
|
||||
- Build nostrconnect:// URL with meta (icon/url/name/perms).
|
||||
|
||||
- [ ] [Auth.getNostrConnectServices(): Promise<[string, ConnectionString[]]>](lite/nostr-login-lite.js:1)
|
||||
- Return nostrconnect URL and preconfigured providers; query .well-known/nostr.json for relays and iframe_url.
|
||||
|
||||
- [ ] [Auth.importAndConnect(cs: ConnectionString)](lite/nostr-login-lite.js:1)
|
||||
- nostrConnect(..., importConnect=true) → logout keep signer → onAuth(login, connect info).
|
||||
|
||||
- [ ] [Auth.createAccount(nip05: string)](lite/nostr-login-lite.js:1) (optional parity)
|
||||
- Use bunker provider to create account; return bunkerUrl and sk.
|
||||
|
||||
NIP46Client (transport over NostrTools.SimplePool)
|
||||
- [ ] [NIP46Client.init(localSk: string, remotePubkey?: string, relays: string[], iframeOrigin?: string)](lite/nostr-login-lite.js:1)
|
||||
- Create [this.pool = new NostrTools.SimplePool()](lite/nostr-login-lite.js:1).
|
||||
- Cache relays; initialize local signer state (seckey, pubkey via [NostrTools.getPublicKey()](lite/nostr-login-lite.js:1)).
|
||||
- If remotePubkey provided, set it; cache iframeOrigin.
|
||||
|
||||
- [ ] [NIP46Client.setUseNip44(use: boolean)](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [NIP46Client.subscribeReplies()](lite/nostr-login-lite.js:1)
|
||||
- sub = pool.sub(relays, [{ kinds:[24133], '#p':[localPubkey] }])
|
||||
- sub.on('event', (ev) => [NIP46Client.onEvent(ev)](lite/nostr-login-lite.js:1)); sub.on('eose', () => {/* keep alive */})
|
||||
|
||||
- [ ] [NIP46Client.onEvent(ev: NostrEvent)](lite/nostr-login-lite.js:1)
|
||||
- Parse/decrypt via [NIP46Client.parseEvent()](lite/nostr-login-lite.js:1); route to response handlers.
|
||||
|
||||
- [ ] [NIP46Client.listen(nostrConnectSecret: string): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- Await unsolicited reply to local pubkey; accept "ack" or exact secret; return signer’s pubkey; unsubscribe this one-shot subscription.
|
||||
|
||||
- [ ] [NIP46Client.connect(token?: string, perms?: string)](lite/nostr-login-lite.js:1)
|
||||
- [NIP46Client.sendRequest()](lite/nostr-login-lite.js:1) with method "connect" and params [userPubkey, token||'', perms||'']; resolve on ack.
|
||||
|
||||
- [ ] [NIP46Client.initUserPubkey(hint?: string): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- If hint present, set and return; else call "get_public_key" RPC and store result.
|
||||
|
||||
- [ ] [NIP46Client.sendRequest(remotePubkey: string, method: string, params: string[], kind = 24133, cb?: (res) => void)](lite/nostr-login-lite.js:1)
|
||||
- id = random string
|
||||
- ev = [NIP46Client.createRequestEvent(id, remotePubkey, method, params, kind)](lite/nostr-login-lite.js:1)
|
||||
- pool.publish(relays, ev)
|
||||
- [NIP46Client.setResponseHandler(id, cb)](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [NIP46Client.createRequestEvent(id, remotePubkey, method, params, kind)](lite/nostr-login-lite.js:1)
|
||||
- content = JSON.stringify({ id, method, params })
|
||||
- encrypt content using nip44 unless method==='create_account', otherwise nip04 fallback
|
||||
- tags: [ ['p', remotePubkey] ]
|
||||
- sign via [NostrTools.finalizeEvent()](lite/nostr-login-lite.js:1)
|
||||
- return event object
|
||||
|
||||
- [ ] [NIP46Client.parseEvent(event)](lite/nostr-login-lite.js:1)
|
||||
- Detect nip04 vs nip44 by ciphertext shape; decrypt using local seckey and remote pubkey (nip04 or [Nip44](lite/nostr-login-lite.js:1)/window.NostrTools.nip44).
|
||||
- Return { id, method, params, event } or { id, result, error, event }.
|
||||
|
||||
- [ ] [NIP46Client.setResponseHandler(id, cb)](lite/nostr-login-lite.js:1)
|
||||
- Deduplicate 'auth_url' emissions; ensure only one resolution per id; log elapsed; cleanup map entries.
|
||||
|
||||
- [ ] [NIP46Client.setWorkerIframePort(port: MessagePort)](lite/nostr-login-lite.js:1)
|
||||
- When iframe is present, forward signed events via postMessage and map request id↔event.id; send keepalive pings.
|
||||
|
||||
- [ ] [NIP46Client.teardown()](lite/nostr-login-lite.js:1)
|
||||
- Unsubscribe; clear timers/ports; pool.close(relays).
|
||||
|
||||
Iframe handshake
|
||||
- [ ] [IframeReadyListener.start(messages: string[], origin: string)](lite/nostr-login-lite.js:1)
|
||||
- Listen for ["workerReady","workerError"] and ["starterDone","starterError"]; origin-check by host or subdomain.
|
||||
|
||||
- [ ] [IframeReadyListener.wait(): Promise<any>](lite/nostr-login-lite.js:1)
|
||||
|
||||
ExtensionBridge
|
||||
- [ ] [ExtensionBridge.startChecking(nostrLite: NostrLite)](lite/nostr-login-lite.js:1)
|
||||
- Poll window.nostr until found; then call [ExtensionBridge.initExtension()](lite/nostr-login-lite.js:1) once; retry after a delay to capture last extension.
|
||||
|
||||
- [ ] [ExtensionBridge.initExtension(nostrLite: NostrLite, lastTry?: boolean)](lite/nostr-login-lite.js:1)
|
||||
- Cache extension, reassign window.nostr to nostrLite; if currently authed as extension, reconcile; schedule a final late check.
|
||||
|
||||
- [ ] [ExtensionBridge.setExtensionReadPubkey(expectedPubkey?: string)](lite/nostr-login-lite.js:1)
|
||||
- Temporarily set window.nostr = extension; read pubkey; compare to expected; emit extensionLogin/extensionLogout.
|
||||
|
||||
- [ ] [ExtensionBridge.trySetForPubkey(expectedPubkey: string)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [ExtensionBridge.setExtension()](lite/nostr-login-lite.js:1)
|
||||
- [ ] [ExtensionBridge.unset(nostrLite: NostrLite)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [ExtensionBridge.hasExtension(): boolean](lite/nostr-login-lite.js:1)
|
||||
|
||||
Local signer (wrapping window.NostrTools)
|
||||
- [ ] [LocalSigner.constructor(sk: string)](lite/nostr-login-lite.js:1)
|
||||
- Cache public key on construct via [NostrTools.getPublicKey()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [LocalSigner.pubkey(): string](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [LocalSigner.sign(event: NostrEvent): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- Use [NostrTools.finalizeEvent()](lite/nostr-login-lite.js:1), set id/sig/pubkey.
|
||||
|
||||
- [ ] [LocalSigner.encrypt04(pubkey: string, plaintext: string): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- Use [NostrTools.nip04.encrypt()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [LocalSigner.decrypt04(pubkey: string, ciphertext: string): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- Use [NostrTools.nip04.decrypt()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [LocalSigner.encrypt44(pubkey: string, plaintext: string): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- Use window.NostrTools.nip44 if available, else [Nip44.encrypt()](lite/nostr-login-lite.js:1).
|
||||
|
||||
- [ ] [LocalSigner.decrypt44(pubkey: string, ciphertext: string): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
- Use window.NostrTools.nip44 if available, else [Nip44.decrypt()](lite/nostr-login-lite.js:1).
|
||||
|
||||
Store (localStorage helpers)
|
||||
- [ ] [Store.addAccount(info: Info)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Store.removeCurrentAccount()](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Store.getCurrent(): Info | null](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Store.getAccounts(): Info[]](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Store.getRecents(): Info[]](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Store.setItem(key: string, value: string)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Store.getIcon(): Promise<string>](lite/nostr-login-lite.js:1)
|
||||
|
||||
UI (single modal)
|
||||
- [ ] [Modal.init(options)](lite/nostr-login-lite.js:1)
|
||||
- Create modal container; inject minimal CSS; set theme and RTL if required.
|
||||
|
||||
- [ ] [Modal.open(opts: { startScreen?: string })](lite/nostr-login-lite.js:1)
|
||||
- Render options: Connect (with provider list/QR), Extension, Local (Create/Import), Read-only, OTP (if server URLs configured), Switch Account if prior accounts.
|
||||
|
||||
- [ ] [Modal.close()](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [Modal.showAuthUrl(url: string)](lite/nostr-login-lite.js:1)
|
||||
- For connect OAuth-like prompt; present link/QR; if iframeUrl is used, show embedded iframe.
|
||||
|
||||
- [ ] [Modal.showIframeUrl(url: string)](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [Modal.onSwitchAccount(info: Info)](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [Modal.onLogoutConfirm()](lite/nostr-login-lite.js:1)
|
||||
|
||||
- [ ] [Modal.onImportConnectionString(cs: ConnectionString)](lite/nostr-login-lite.js:1)
|
||||
- Import-and-connect flow: calls [Auth.importAndConnect()](lite/nostr-login-lite.js:1).
|
||||
|
||||
Event bus
|
||||
- [ ] [Bus.on(event: string, handler: Function)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Bus.off(event: string, handler: Function)](lite/nostr-login-lite.js:1)
|
||||
- [ ] [Bus.emit(event: string, payload?: any)](lite/nostr-login-lite.js:1)
|
||||
|
||||
Relay configuration helpers
|
||||
- [ ] [Relays.getDefaultRelays(options): string[]](lite/nostr-login-lite.js:1)
|
||||
- From options or sensible defaults.
|
||||
|
||||
- [ ] [Relays.normalize(relays: string[]): string[]](lite/nostr-login-lite.js:1)
|
||||
- Ensure proper wss:// and deduping.
|
||||
|
||||
Parity acceptance criteria
|
||||
- Same external API names and events exported as current initializer: [init](packages/auth/src/index.ts:333), [launch](packages/auth/src/index.ts:333), [logout](packages/auth/src/index.ts:333), [setDarkMode](packages/auth/src/index.ts:333), [setAuth](packages/auth/src/index.ts:333), [cancelNeedAuth](packages/auth/src/index.ts:333).
|
||||
- Same nlAuth payload shape as [onAuth()](packages/auth/src/modules/AuthNostrService.ts:347-418).
|
||||
- window.nostr behavior matches [class Nostr](packages/auth/src/modules/Nostr.ts:23).
|
||||
|
||||
Notes and implementation tips
|
||||
- Load order: [Deps.ensureNostrToolsLoaded()](lite/nostr-login-lite.js:1) must guard all usages of window.NostrTools.
|
||||
- Request de-duplication: mirror [setResponseHandler()](packages/auth/src/modules/Nip46.ts:150-173) behavior to avoid auth_url flooding.
|
||||
- NIP-44 selection: use nip44 for all methods except "create_account".
|
||||
- Iframe origin checks: follow [ReadyListener](packages/auth/src/modules/Nip46.ts:291-338) host/subdomain verification.
|
||||
- Secret handling in nostrconnect: accept 'ack' or exact secret; see [listen](packages/auth/src/modules/Nip46.ts:71-107).
|
||||
- Profile fetch is optional; keep it async and non-blocking, update UI/state when complete.
|
||||
|
||||
Out of scope for initial lite version
|
||||
- Complex banners/popups and multi-window flows.
|
||||
- Full NDK feature parity beyond the minimum for NIP-46 RPC.
|
||||
- Advanced error telemetry; keep console logs minimal.
|
||||
|
||||
Deliverables
|
||||
- Single distributable [lite/nostr-login-lite.js](lite/nostr-login-lite.js) usable via:
|
||||
- <script src="..."></script> with window.nostr present after [init()](lite/nostr-login-lite.js:1).
|
||||
- Optional ESM import with same API.
|
||||
- Minimal HTML example showing each auth method path is functional.
|
||||
Reference in New Issue
Block a user