mirror of
https://github.com/PR0M3TH3AN/bitlogin.git
synced 2026-10-27 08:31:21 +00:00
widget: ship generated type declarations + typed element/events
Integrators had to read the demo to learn the API: the package built via vite with no .d.ts and no types field, so @bitlogin/widget and @bitlogin/widget/session resolved to `any`. Emit declarations from source (tsconfig.types.json -> dist-types, build:types wired into build) and point the package types/exports conditions at them, for both the root and the /session entry. Generated, so they can't drift from the implementation. Add the type surface integrators actually want: - HTMLElementTagNameMap["bitlogin-auth"], so querySelector/createElement return the typed element. - Typed addEventListener/removeEventListener overloads (declaration-merged interface) for the bitlogin-* events. - Exported event-detail types and BitLoginEventMap (src/events.ts), matching element.ts's dispatchEvent shapes. Verified with a consumer conformance typecheck (typed detail with no cast, typed element methods, readCachedSession return type). README gains a "TypeScript" section. Addresses the ".d.ts / documented API surface" item of the Tessera integration feedback (docs/TODO.md). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01BXQCvJPA6sVSQ5j8uBd9bB
This commit is contained in:
1 parent
1b39e0f60c
commit
5ae41ed9db
7 files changed
+154
-6
No files matched your search
@@ -242,6 +242,33 @@ Nostr signer (browser extension) is active in this browser and couldn't be
|
||||
replaced...") using the same warning banner already shown for rollback and
|
||||
relay-disagreement conditions.
|
||||
|
||||
### TypeScript
|
||||
|
||||
The package ships type declarations (`@bitlogin/widget` and
|
||||
`@bitlogin/widget/session`), generated from source so they can't drift.
|
||||
Registering the widget augments the DOM types, so integrators get real
|
||||
autocomplete instead of reading the demo:
|
||||
|
||||
```ts
|
||||
import "@bitlogin/widget"; // registers <bitlogin-auth> and its types
|
||||
|
||||
const el = document.querySelector("bitlogin-auth"); // typed as BitLoginAuthElement
|
||||
el?.addEventListener("bitlogin-login", (e) => {
|
||||
// e.detail is typed: { publicKey?: string; method; capabilities }
|
||||
console.log(e.detail.method, e.detail.capabilities.nip44);
|
||||
});
|
||||
await el?.getPublicKey(); // typed element methods
|
||||
|
||||
import { readCachedSession } from "@bitlogin/widget/session";
|
||||
const who = await readCachedSession(); // { pubkey, npub, name? } | null
|
||||
```
|
||||
|
||||
Exported types include `BitLoginAuthElement`, the `bitlogin-*`
|
||||
`...EventDetail` shapes and `BitLoginEventMap`, `PublicSessionInfo`,
|
||||
`SignerMethod`/`SignerCapabilities`, `BitLoginConfig`, and the
|
||||
`window.bitlogin` (`BitLoginGlobal`) interface. Run `npm run build` (or
|
||||
`build:types`) to emit them into `dist-types/`.
|
||||
|
||||
### Theming
|
||||
|
||||
`<bitlogin-auth>` renders in a shadow root, but its colors, radius, font, and
|
||||
|
||||
+12
-3
@@ -416,6 +416,15 @@ how much they cost.
|
||||
|
||||
### Small
|
||||
|
||||
- Ship a `.d.ts` (or documented event/method surface) for the element:
|
||||
`getPublicKey`, `signEvent`, `nip44Encrypt/Decrypt`, and the event
|
||||
`detail` shapes. Integrators currently read the demo to learn the API.
|
||||
- **[DONE 2026-08-11]** Ship a `.d.ts` (or documented event/method surface) for
|
||||
the element. **Shipped:** the widget now emits type declarations from source
|
||||
(`tsconfig.types.json` → `dist-types/`, wired via `build:types` and the
|
||||
package `types`/`exports` conditions for both `@bitlogin/widget` and
|
||||
`@bitlogin/widget/session`) — zero-drift because they're generated, not
|
||||
hand-written. Added the type surface integrators actually want: a
|
||||
`HTMLElementTagNameMap["bitlogin-auth"]` augmentation (typed
|
||||
`querySelector`/`createElement`), typed `addEventListener` overloads via a
|
||||
declaration-merged interface, and exported event-detail types
|
||||
(`BitLoginLoginEventDetail` etc. + `BitLoginEventMap`) in `src/events.ts`.
|
||||
Verified with a consumer conformance typecheck; README "TypeScript" section
|
||||
added.
|
||||
@@ -6,12 +6,20 @@
|
||||
"type": "module",
|
||||
"description": "BitLogin embeddable login widget: a <bitlogin-auth> custom element plus a window.nostr NIP-07-compatible provider, backed by a dedicated crypto Web Worker.",
|
||||
"main": "./dist/bitlogin.js",
|
||||
"types": "./dist-types/index.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/bitlogin.js",
|
||||
"./session": "./dist/bitlogin-session.js"
|
||||
".": {
|
||||
"types": "./dist-types/index.d.ts",
|
||||
"default": "./dist/bitlogin.js"
|
||||
},
|
||||
"./session": {
|
||||
"types": "./dist-types/session.d.ts",
|
||||
"default": "./dist/bitlogin-session.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"build": "vite build && npm run build:types",
|
||||
"build:types": "tsc -p tsconfig.types.json",
|
||||
"dev": "vite build --watch",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
|
||||
@@ -20,6 +20,7 @@ import { Nip46Signer } from "./signers/nip46.js";
|
||||
import type { Signer, SignerCapabilities, SignerMethod } from "./signers/types.js";
|
||||
import { renderQrSvg } from "./qr.js";
|
||||
import { setActiveSession, clearActiveSession } from "./globalSession.js";
|
||||
import type { BitLoginEventMap } from "./events.js";
|
||||
import {
|
||||
buildPasskeyCreateOptions,
|
||||
buildPasskeyGetOptions,
|
||||
@@ -2217,3 +2218,39 @@ function pickRandomIndices(max: number, count: number): number[] {
|
||||
function escapeHtml(input: string): string {
|
||||
return input.replace(/[&<>"']/gu, (ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ch]!);
|
||||
}
|
||||
|
||||
// Declaration merge: give BitLoginAuthElement typed addEventListener/
|
||||
// removeEventListener overloads for its own bitlogin-* events, so a host gets
|
||||
// `e.detail` typed without a cast. The string overload preserves the base
|
||||
// signature for every other event. Merging an interface of the same name adds
|
||||
// these to the class type; the runtime implementation stays HTMLElement's.
|
||||
export interface BitLoginAuthElement {
|
||||
addEventListener<K extends keyof BitLoginEventMap>(
|
||||
type: K,
|
||||
listener: (this: BitLoginAuthElement, ev: BitLoginEventMap[K]) => void,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void;
|
||||
removeEventListener<K extends keyof BitLoginEventMap>(
|
||||
type: K,
|
||||
listener: (this: BitLoginAuthElement, ev: BitLoginEventMap[K]) => void,
|
||||
options?: boolean | EventListenerOptions
|
||||
): void;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean | EventListenerOptions
|
||||
): void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
// So document.querySelector("bitlogin-auth") and
|
||||
// document.createElement("bitlogin-auth") are typed as the element.
|
||||
"bitlogin-auth": BitLoginAuthElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Public event contract for `<bitlogin-auth>`. These are the CustomEvents the
|
||||
* element dispatches on itself; the detail shapes here match element.ts's
|
||||
* `dispatchEvent` calls exactly. Integrators previously had to read the demo to
|
||||
* learn them — the typed `addEventListener` overloads on BitLoginAuthElement
|
||||
* (see element.ts) now surface them in editors.
|
||||
*/
|
||||
import type { SignerMethod, SignerCapabilities } from "./signers/types.js";
|
||||
|
||||
/** `bitlogin-login` — a session was established OR silently restored on page
|
||||
* load (the two are intentionally indistinguishable to a listener). */
|
||||
export interface BitLoginLoginEventDetail {
|
||||
/** The signed-in account's public key (hex), when known. */
|
||||
publicKey?: string;
|
||||
/** How the session was established. */
|
||||
method: SignerMethod;
|
||||
/** What the active signer supports (NIP-07 extensions vary). */
|
||||
capabilities: SignerCapabilities;
|
||||
}
|
||||
|
||||
/** `bitlogin-connection-granted` — the user shared an NWC wallet connection with
|
||||
* an origin (Connection Vault, reveal mode). */
|
||||
export interface BitLoginConnectionGrantedEventDetail {
|
||||
origin: string;
|
||||
}
|
||||
|
||||
/** `bitlogin-signer-claimed` — the element tried to install itself as
|
||||
* `window.nostr`; `windowNostrClaimed` says whether it won the slot. */
|
||||
export interface BitLoginSignerClaimedEventDetail {
|
||||
windowNostrClaimed: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/** Maps each `bitlogin-*` event name to its concrete event type. Events without
|
||||
* a detail payload are plain `CustomEvent<undefined>`. */
|
||||
export interface BitLoginEventMap {
|
||||
"bitlogin-login": CustomEvent<BitLoginLoginEventDetail>;
|
||||
"bitlogin-logout": CustomEvent<undefined>;
|
||||
"bitlogin-connection-granted": CustomEvent<BitLoginConnectionGrantedEventDetail>;
|
||||
"bitlogin-signer-claimed": CustomEvent<BitLoginSignerClaimedEventDetail>;
|
||||
"bitlogin-signer-released": CustomEvent<undefined>;
|
||||
"bitlogin-request-pending": CustomEvent<undefined>;
|
||||
"bitlogin-offer-pending": CustomEvent<undefined>;
|
||||
}
|
||||
@@ -96,6 +96,13 @@ window.bitlogin = {
|
||||
export { readCachedSession } from "./session.js";
|
||||
export type { PublicSessionInfo } from "./publicSession.js";
|
||||
export { BitLoginAuthElement } from "./element.js";
|
||||
export type {
|
||||
BitLoginEventMap,
|
||||
BitLoginLoginEventDetail,
|
||||
BitLoginConnectionGrantedEventDetail,
|
||||
BitLoginSignerClaimedEventDetail
|
||||
} from "./events.js";
|
||||
export type { SignerMethod, SignerCapabilities } from "./signers/types.js";
|
||||
export { WorkerClient } from "./worker/workerClient.js";
|
||||
export { createNip07Provider } from "./provider.js";
|
||||
export type { BitLoginConfig } from "./config.js";
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"//": "Emits public .d.ts for @bitlogin/widget (and /session) into dist-types. Kept separate from tsconfig.json (which is noEmit typecheck-only). Tests and the e2e tree are excluded so they don't ship as declarations.",
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist-types",
|
||||
"rootDir": "src",
|
||||
"noEmit": false,
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"declarationMap": false,
|
||||
"sourceMap": false,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["src/e2e", "**/*.test.ts"]
|
||||
}
|
||||
Reference in new issue
Block a user