# Nostr event schemas bitvid now centralizes every note that it publishes to Nostr in [`js/nostrEventSchemas.js`](../js/nostrEventSchemas.js). The module defines the kind, required tags, and content format for each note type so troubleshooting no longer requires hunting through the codebase. It also exposes helpers for building events and for overriding the schema at runtime when you need to experiment. ## Runtime helpers ```js import { NOTE_TYPES, getNostrEventSchema, setNostrEventSchemaOverrides, buildVideoPostEvent, buildRepostEvent, buildShareEvent, buildProfileMetadataEvent } from "./nostrEventSchemas.js"; // Inspect the current schema console.log(getNostrEventSchema(NOTE_TYPES.VIDEO_POST)); // Temporarily override the kind while debugging setNostrEventSchemaOverrides({ [NOTE_TYPES.VIDEO_POST]: { kind: 30000 } }); // Build an event with the active schema const event = buildVideoPostEvent({ pubkey, created_at: Math.floor(Date.now() / 1000), dTagValue: "debug-video", content: { version: 3, title: "Test", videoRootId: "debug", infoHash: "0123456789abcdef0123456789abcdef01234567" } }); ``` In the browser you can call the same helpers from DevTools via `window.bitvidNostrEvents` and `window.bitvidNostrEventOverrides`. When managing relay metadata, use `buildRelayListEvent` so the resulting replaceable event follows NIP-65 (`kind:10002`) with `"r"` tags describing the read/write split. ### Active signer registry Authentication providers should register their capabilities with the `nostrClient` after login so every publish helper can reuse them: ```js import { nostrClient } from "./nostrClientFacade.js"; import { setActiveSigner } from "./nostr/client.js"; setActiveSigner({ type: "extension", // optional label, used to request NIP-07 permissions pubkey, // hex or npub of the active account signEvent: (event) => extension.signEvent(event), nip04Encrypt: (targetHex, plaintext) => extension.nip04.encrypt(targetHex, plaintext), nip04Decrypt: (actorHex, ciphertext) => extension.nip04.decrypt(actorHex, ciphertext), nip44Encrypt: (targetHex, plaintext) => extension.nip44.encrypt(targetHex, plaintext), nip44Decrypt: (actorHex, ciphertext) => extension.nip44.decrypt(actorHex, ciphertext) }); await nostrClient.ensureExtensionPermissions(); ``` `setActiveSigner` accepts any object that implements the subset of capabilities you support. `nostrClient` (imported from the [NIP-07](https://github.com/nostr-protocol/nips/blob/master/07.md)-aligned `nostrClientFacade.js`) routes signing and encryption through the adapter registry in `js/nostr/client.js`, prefers the registered signer, and falls back to the strongest available capability (or session actors for telemetry) when a method is unavailable. Permission prompts are surfaced via `nostrClient.ensureExtensionPermissions()` or the `requestDefaultExtensionPermissions()` helper from `js/nostr/defaultClient.js`, so features can ask for access before issuing sign/encrypt calls. Call `clearActiveSigner()` on logout if your integration manages session state manually; the built-in logout handler already does this for the default extension flow. For adapter implementation details and test guidance, see [`docs/signing-adapter.md`](signing-adapter.md). ### Accessing raw events `NostrClient` now keeps a lightweight cache of parsed videos alongside a separate cache of the untouched event payloads. Call `nostrClient.fetchRawEventById(eventId)` when you need the original JSON that was received from the relay. For convenience, `nostrClient.getEventById(eventId, { includeRaw: true })` returns both shapes at once: ```js const { video, rawEvent } = await nostrClient.getEventById(eventId, { includeRaw: true }); // `video` is the normalized bitvid object and `rawEvent` is the original // Nostr event with `sig`, `id`, and relay metadata intact. ``` In DevTools the active client lives at `window.bitvidApp?.nostrClient`. Use the `rawEvent` blob when implementing “Rebroadcast” style flows so the client can republish exactly what was signed, including the original `sig`. Republishers should prefer `rawEvent.sig` over re-signing unless the payload actually changes; this avoids accidental drift in dedupe tags or timestamps. ### Default client bootstrap [`js/nostr/defaultClient.js`](../js/nostr/defaultClient.js) builds the shared `nostrClient` instance, registers it with the runtime via `registerNostrClient`, and exposes helpers like `requestDefaultExtensionPermissions`. Import the singleton or permission helper through the dedicated facade when you need to run a NIP-07 handshake: ```js import { nostrClient, requestDefaultExtensionPermissions } from "./nostrClientFacade.js"; ``` The compatibility shim has been removed; import from the facades above to avoid broken references.【F:js/nostr/defaultClient.js†L1-L25】 For analytics, route through the [NIP-71](https://github.com/nostr-protocol/nips/blob/master/71.md) helpers in `nostrViewEventsFacade.js`: ```js import { recordVideoView } from "./nostrViewEventsFacade.js"; ``` Watch-history list management layers a replaceable, [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md)-style list of monthly records. Import from `nostrWatchHistoryFacade.js` to stay aligned with the simplified month-by-month lifecycle: ```js import { updateWatchHistoryListWithDefaultClient } from "./nostrWatchHistoryFacade.js"; ``` ## Event catalogue | Note | Kind (default) | Tags | Content format | | ---------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Video post (`NOTE_TYPES.VIDEO_POST`) | `30078` | `['t','video']`, `['d', ]`, `['s', ]` plus optional schema append tags | JSON payload using Content Schema v3 (`version`, `title`, optional `url`, `magnet`, `thumbnail`, `description`, `mode`, `videoRootId`, `deleted`, `isPrivate`, `isNsfw`, `isForKids`, `enableComments`, `infoHash`, `fileSha256`, `originalFileSha256`, `ws`, `xs`) | | NIP-94 mirror (`NOTE_TYPES.VIDEO_MIRROR`) | `1063` | Tags forwarded from `publishVideo` (URL, mime type, thumbnail, alt text, magnet) | Plain text alt description | | Repost (`NOTE_TYPES.REPOST`) | `6` | `['e', , ]` with optional address pointer `['a', , ]`, and `['p', ]` when the origin author is known; inherits schema append tags | JSON-serialized event being reposted (or empty if unavailable) | | Generic Repost (`NOTE_TYPES.GENERIC_REPOST`) | `16` | Same as Repost; specific for non-text kinds (e.g. videos). | Same as Repost. | | Share note (`NOTE_TYPES.SHARE`) | `1` | `['e',