nostr-components 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -46
- package/dist/assets/{base-styles-DC0ilu4S.js → base-styles-Dmuzg8I4.js} +3 -3
- package/dist/assets/{base-styles-DC0ilu4S.js.map → base-styles-Dmuzg8I4.js.map} +1 -1
- package/dist/assets/{copy-delegation-CcagQMIW.js → copy-delegation-xzt-t_do.js} +5 -5
- package/dist/assets/{copy-delegation-CcagQMIW.js.map → copy-delegation-xzt-t_do.js.map} +1 -1
- package/dist/assets/dark-nostrich-running.gif +0 -0
- package/dist/assets/default_dp-NQ3TGrtT.png +0 -0
- package/dist/assets/default_dp.png +0 -0
- package/dist/assets/default_dp_32.png +0 -0
- package/dist/assets/{dialog-component-Dqg0QU9I.js → dialog-component-Da1ZIYh9.js} +7 -2
- package/dist/assets/dialog-component-Da1ZIYh9.js.map +1 -0
- package/dist/assets/{dialog-likers-D3c7WIMp.js → dialog-likers-Bq6kUbS0.js} +4 -4
- package/dist/assets/{dialog-likers-D3c7WIMp.js.map → dialog-likers-Bq6kUbS0.js.map} +1 -1
- package/dist/assets/light-nostrich-running.gif +0 -0
- package/dist/assets/{nostr-service-m3Hgc5Xx.js → nostr-service-CA0Qx4nJ.js} +3 -3
- package/dist/assets/{nostr-service-m3Hgc5Xx.js.map → nostr-service-CA0Qx4nJ.js.map} +1 -1
- package/dist/assets/nostr-user-component-r-MUbTL6.js +2 -0
- package/dist/assets/nostr-user-component-r-MUbTL6.js.map +1 -0
- package/dist/assets/{pure-laCRX9eG.js → pure-DOoUcNQv.js} +2 -2
- package/dist/assets/{pure-laCRX9eG.js.map → pure-DOoUcNQv.js.map} +1 -1
- package/dist/assets/{theme-C1r1Zw8r.js → theme-BN1Bvweb.js} +2 -2
- package/dist/assets/{theme-C1r1Zw8r.js.map → theme-BN1Bvweb.js.map} +1 -1
- package/dist/assets/{user-resolver-DqI5KGh6.js → user-resolver-ArI0680e.js} +2 -2
- package/dist/assets/{user-resolver-DqI5KGh6.js.map → user-resolver-ArI0680e.js.map} +1 -1
- package/dist/assets/zap-utils-BiKkJPt6.js +2 -0
- package/dist/assets/zap-utils-BiKkJPt6.js.map +1 -0
- package/dist/components/nostr-comment.es.js +6 -6
- package/dist/components/nostr-comment.es.js.map +1 -1
- package/dist/components/nostr-dm.es.js +2 -2
- package/dist/components/nostr-dm.es.js.map +1 -1
- package/dist/components/nostr-follow-button.es.js +3 -3
- package/dist/components/nostr-follow-button.es.js.map +1 -1
- package/dist/components/nostr-like.es.js +6 -6
- package/dist/components/nostr-like.es.js.map +1 -1
- package/dist/components/nostr-live-chat.es.js +3 -3
- package/dist/components/nostr-live-chat.es.js.map +1 -1
- package/dist/components/nostr-post.es.js +2 -2
- package/dist/components/nostr-post.es.js.map +1 -1
- package/dist/components/nostr-profile-badge.es.js +3 -3
- package/dist/components/nostr-profile-badge.es.js.map +1 -1
- package/dist/components/nostr-profile.es.js +5 -5
- package/dist/components/nostr-profile.es.js.map +1 -1
- package/dist/components/nostr-zap.es.js +5 -5
- package/dist/components/nostr-zap.es.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/nostr-comment.d.ts +4 -0
- package/dist/nostr-components.es.js +1 -1
- package/dist/nostr-components.es.js.map +1 -1
- package/dist/nostr-components.umd.js +69 -40
- package/dist/nostr-components.umd.js.map +1 -1
- package/dist/nostr-dm.d.ts +4 -0
- package/dist/nostr-follow-button.d.ts +4 -0
- package/dist/nostr-like.d.ts +4 -0
- package/dist/nostr-live-chat.d.ts +4 -0
- package/dist/nostr-post.d.ts +4 -0
- package/dist/nostr-profile-badge.d.ts +4 -0
- package/dist/nostr-profile.d.ts +4 -0
- package/dist/nostr-zap.d.ts +4 -0
- package/dist/src/base/base-component/nostr-base-component.d.ts +116 -0
- package/dist/src/base/copy-delegation.d.ts +5 -0
- package/dist/src/base/dialog-component/dialog-component.d.ts +67 -0
- package/dist/src/base/dialog-component/style.d.ts +5 -0
- package/dist/src/base/event-component/nostr-event-component.d.ts +53 -0
- package/dist/src/base/render-options.d.ts +5 -0
- package/dist/src/base/resolvers/event-resolver.d.ts +20 -0
- package/dist/src/base/resolvers/user-resolver.d.ts +19 -0
- package/dist/src/base/text-row/render-name.d.ts +7 -0
- package/dist/src/base/text-row/render-nip05.d.ts +1 -0
- package/dist/src/base/text-row/render-npub.d.ts +1 -0
- package/dist/src/base/text-row/render-text-row.d.ts +9 -0
- package/dist/src/base/user-component/nostr-user-component.d.ts +43 -0
- package/dist/src/common/base-styles.d.ts +44 -0
- package/dist/src/common/constants.d.ts +4 -0
- package/dist/src/common/date-utils.d.ts +9 -0
- package/dist/src/common/icons.d.ts +7 -0
- package/dist/src/common/nip05-utils.d.ts +13 -0
- package/dist/src/common/nostr-login-service.d.ts +26 -0
- package/dist/src/common/nostr-service.d.ts +40 -0
- package/dist/src/common/theme.d.ts +4 -0
- package/dist/src/common/types.d.ts +1 -0
- package/dist/src/common/utils.d.ts +34 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/nostr-comment/nostr-comment.d.ts +60 -0
- package/dist/src/nostr-comment/render.d.ts +15 -0
- package/dist/src/nostr-comment/utils.d.ts +81 -0
- package/dist/src/nostr-dm/nostr-dm.d.ts +34 -0
- package/dist/src/nostr-dm/render.d.ts +15 -0
- package/dist/src/nostr-follow-button/nostr-follow-button.d.ts +24 -0
- package/dist/src/nostr-follow-button/render.d.ts +11 -0
- package/dist/src/nostr-follow-button/style.d.ts +1 -0
- package/dist/src/nostr-like/dialog-help-style.d.ts +1 -0
- package/dist/src/nostr-like/dialog-help.d.ts +2 -0
- package/dist/src/nostr-like/dialog-likers-style.d.ts +1 -0
- package/dist/src/nostr-like/dialog-likers.d.ts +24 -0
- package/dist/src/nostr-like/like-utils.d.ts +48 -0
- package/dist/src/nostr-like/nostr-like.d.ts +49 -0
- package/dist/src/nostr-like/render.d.ts +10 -0
- package/dist/src/nostr-like/style.d.ts +1 -0
- package/dist/src/nostr-live-chat/nostr-live-chat.d.ts +65 -0
- package/dist/src/nostr-live-chat/render.d.ts +31 -0
- package/dist/src/nostr-post/nostr-post.d.ts +25 -0
- package/dist/src/nostr-post/parse-text.d.ts +8 -0
- package/dist/src/nostr-post/render-content.d.ts +5 -0
- package/dist/src/nostr-post/render.d.ts +19 -0
- package/dist/src/nostr-post/style.d.ts +1 -0
- package/dist/src/nostr-profile/nostr-profile.d.ts +24 -0
- package/dist/src/nostr-profile/render-stats.d.ts +1 -0
- package/dist/src/nostr-profile/render.d.ts +22 -0
- package/dist/src/nostr-profile/style.d.ts +1 -0
- package/dist/src/nostr-profile-badge/nostr-profile-badge.d.ts +34 -0
- package/dist/src/nostr-profile-badge/render.d.ts +11 -0
- package/dist/src/nostr-profile-badge/style.d.ts +1 -0
- package/dist/src/nostr-zap/dialog-help-style.d.ts +5 -0
- package/dist/src/nostr-zap/dialog-help.d.ts +2 -0
- package/dist/src/nostr-zap/dialog-zap-style.d.ts +6 -0
- package/dist/src/nostr-zap/dialog-zap.d.ts +31 -0
- package/dist/src/nostr-zap/dialog-zappers-style.d.ts +1 -0
- package/dist/src/nostr-zap/dialog-zappers.d.ts +25 -0
- package/dist/src/nostr-zap/nostr-zap.d.ts +45 -0
- package/dist/src/nostr-zap/render.d.ts +9 -0
- package/dist/src/nostr-zap/style.d.ts +1 -0
- package/dist/src/nostr-zap/zap-utils.d.ts +57 -0
- package/dist/vite.config.d.ts +2 -0
- package/dist/vite.config.esm.d.ts +2 -0
- package/dist/vite.config.umd.d.ts +2 -0
- package/package.json +1 -1
- package/dist/assets/dialog-component-Dqg0QU9I.js.map +0 -1
- package/dist/assets/nostr-user-component-XEnanH-d.js +0 -2
- package/dist/assets/nostr-user-component-XEnanH-d.js.map +0 -1
- package/dist/assets/zap-utils-BZcaCsT_.js +0 -2
- package/dist/assets/zap-utils-BZcaCsT_.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NDKUser, NDKUserProfile } from '@nostr-dev-kit/ndk';
|
|
2
|
+
export interface RenderProfileBadgeOptions {
|
|
3
|
+
isLoading: boolean;
|
|
4
|
+
isError: boolean;
|
|
5
|
+
errorMessage?: string;
|
|
6
|
+
userProfile: NDKUserProfile | null;
|
|
7
|
+
ndkUser: NDKUser | null;
|
|
8
|
+
showNpub: boolean;
|
|
9
|
+
showFollow: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function renderProfileBadge({ isLoading, isError, errorMessage, userProfile, ndkUser, showNpub, showFollow }: RenderProfileBadgeOptions): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getProfileBadgeStyles(): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DialogComponent } from '../base/dialog-component/dialog-component';
|
|
2
|
+
interface WebLN {
|
|
3
|
+
enable: () => Promise<void>;
|
|
4
|
+
sendPayment: (invoice: string) => Promise<{
|
|
5
|
+
preimage: string;
|
|
6
|
+
}>;
|
|
7
|
+
}
|
|
8
|
+
declare global {
|
|
9
|
+
interface Window {
|
|
10
|
+
webln?: WebLN;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export interface OpenZapModalParams {
|
|
14
|
+
npub: string;
|
|
15
|
+
relays: string;
|
|
16
|
+
cachedDialogComponent?: DialogComponent | null;
|
|
17
|
+
buttonColor?: string;
|
|
18
|
+
theme?: 'light' | 'dark';
|
|
19
|
+
fixedAmount?: number;
|
|
20
|
+
defaultAmount?: number;
|
|
21
|
+
initialAmount?: number;
|
|
22
|
+
anon?: boolean;
|
|
23
|
+
url?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare const injectCSS: (theme?: "light" | "dark") => void;
|
|
26
|
+
/**
|
|
27
|
+
* Opens (or re-opens) the zap modal. Returns the DialogComponent so the caller
|
|
28
|
+
* can cache it between clicks.
|
|
29
|
+
*/
|
|
30
|
+
export declare function init(params: OpenZapModalParams): Promise<DialogComponent>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getZappersDialogStyles(theme?: 'light' | 'dark'): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DialogComponent } from '../base/dialog-component/dialog-component';
|
|
2
|
+
import { ZapDetails } from './zap-utils';
|
|
3
|
+
/**
|
|
4
|
+
* Modal dialog for displaying individual zap details (zappers).
|
|
5
|
+
*
|
|
6
|
+
* Shows a list of all zaps received by a user with:
|
|
7
|
+
* - Zap amount
|
|
8
|
+
* - Zap date (relative time)
|
|
9
|
+
* - Zap author's name
|
|
10
|
+
* - Zap author's profile picture
|
|
11
|
+
* - Clickable links to author profiles via njump.me
|
|
12
|
+
*/
|
|
13
|
+
export interface OpenZappersModalParams {
|
|
14
|
+
zapDetails: ZapDetails[];
|
|
15
|
+
theme?: 'light' | 'dark';
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Inject zappers dialog content styles into document head
|
|
19
|
+
* Prevents duplicate injection by checking for existing styles
|
|
20
|
+
*/
|
|
21
|
+
export declare const injectZappersDialogStyles: (theme?: "light" | "dark") => void;
|
|
22
|
+
/**
|
|
23
|
+
* Opens the zappers dialog showing individual zap details
|
|
24
|
+
*/
|
|
25
|
+
export declare function openZappersDialog(params: OpenZappersModalParams): Promise<DialogComponent>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { NostrUserComponent } from '../base/user-component/nostr-user-component';
|
|
2
|
+
import { NCStatus } from '../base/base-component/nostr-base-component';
|
|
3
|
+
/**
|
|
4
|
+
* <nostr-zap>
|
|
5
|
+
* Attributes:
|
|
6
|
+
* - npub | pubkey | nip05 (required) : Nostr user to zap
|
|
7
|
+
* - relays (optional) : comma-separated relay URLs
|
|
8
|
+
* - theme (optional) : "light" | "dark" (default light)
|
|
9
|
+
* - text (optional) : custom text (default "Zap")
|
|
10
|
+
* - amount (optional) : pre-defined zap amount in sats
|
|
11
|
+
* - default-amount (optional) : default zap amount in sats (default 21)
|
|
12
|
+
* - url (optional) : URL to send zap to (enables URL-based zaps)
|
|
13
|
+
*
|
|
14
|
+
* TODO: Doesn't yet support dynamic updates of attributes.
|
|
15
|
+
*/
|
|
16
|
+
export default class NostrZap extends NostrUserComponent {
|
|
17
|
+
protected zapActionStatus: {
|
|
18
|
+
set: (s: NCStatus, e?: string) => void;
|
|
19
|
+
get: () => NCStatus;
|
|
20
|
+
};
|
|
21
|
+
protected zapListStatus: {
|
|
22
|
+
set: (s: NCStatus, e?: string) => void;
|
|
23
|
+
get: () => NCStatus;
|
|
24
|
+
};
|
|
25
|
+
private totalZapAmount;
|
|
26
|
+
private cachedZapDetails;
|
|
27
|
+
private cachedAmountDialog;
|
|
28
|
+
constructor();
|
|
29
|
+
connectedCallback(): void;
|
|
30
|
+
static get observedAttributes(): string[];
|
|
31
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
32
|
+
disconnectedCallback(): void;
|
|
33
|
+
/** Base class functions */
|
|
34
|
+
protected onStatusChange(_status: NCStatus): void;
|
|
35
|
+
protected onUserReady(_user: any, _profile: any): void;
|
|
36
|
+
/** Protected methods */
|
|
37
|
+
protected validateInputs(): boolean;
|
|
38
|
+
/** Private functions */
|
|
39
|
+
private handleZapClick;
|
|
40
|
+
private handleHelpClick;
|
|
41
|
+
private handleZappersClick;
|
|
42
|
+
private attachDelegatedListeners;
|
|
43
|
+
private updateZapCount;
|
|
44
|
+
protected renderContent(): void;
|
|
45
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IRenderOptions } from '../base/render-options';
|
|
2
|
+
export interface RenderZapButtonOptions extends IRenderOptions {
|
|
3
|
+
isAmountLoading: boolean;
|
|
4
|
+
isSuccess: boolean;
|
|
5
|
+
buttonText: string;
|
|
6
|
+
totalZapAmount: number | null;
|
|
7
|
+
hasZaps?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function renderZapButton({ isLoading, isError, isSuccess, errorMessage, buttonText, totalZapAmount, isAmountLoading, hasZaps, }: RenderZapButtonOptions): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getZapButtonStyles(): string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Filter, Event } from 'nostr-tools';
|
|
2
|
+
export declare const getProfileMetadata: (authorId: string) => Promise<any>;
|
|
3
|
+
export declare const getBatchedProfileMetadata: (authorIds: string[]) => Promise<{
|
|
4
|
+
id: string;
|
|
5
|
+
profile: any;
|
|
6
|
+
}[]>;
|
|
7
|
+
export declare const extractProfileMetadataContent: (profileMetadata: any) => any;
|
|
8
|
+
export declare const getZapEndpoint: (profileMetadata: any) => Promise<string>;
|
|
9
|
+
export declare const fetchInvoice: ({ zapEndpoint, amount, comment, authorId, nip19Target, normalizedRelays, anon, url, }: {
|
|
10
|
+
zapEndpoint: string;
|
|
11
|
+
amount: number;
|
|
12
|
+
comment?: string;
|
|
13
|
+
authorId: string;
|
|
14
|
+
nip19Target?: string;
|
|
15
|
+
normalizedRelays: string[];
|
|
16
|
+
anon?: boolean;
|
|
17
|
+
url?: string;
|
|
18
|
+
}) => Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Check if NostrLogin is available
|
|
21
|
+
* @deprecated Use ensureInitialized() instead - it will initialize NostrLogin if needed
|
|
22
|
+
*/
|
|
23
|
+
export declare const isNip07ExtAvailable: () => boolean;
|
|
24
|
+
export declare function resolveNip05(nip05Identifier: string): Promise<string | null>;
|
|
25
|
+
declare module 'nostr-tools' {
|
|
26
|
+
interface SimplePool {
|
|
27
|
+
subscribe(relays: string[], filter: Filter, params: {
|
|
28
|
+
onevent: (event: Event) => void;
|
|
29
|
+
onclose?: () => void;
|
|
30
|
+
id?: string;
|
|
31
|
+
maxWait?: number;
|
|
32
|
+
}): {
|
|
33
|
+
close: () => void;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export interface ZapDetails {
|
|
38
|
+
amount: number;
|
|
39
|
+
date: Date;
|
|
40
|
+
authorPubkey: string;
|
|
41
|
+
comment?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ZapAmountResult {
|
|
44
|
+
totalAmount: number;
|
|
45
|
+
zapDetails: ZapDetails[];
|
|
46
|
+
}
|
|
47
|
+
export declare const fetchTotalZapAmount: ({ pubkey, relays, url, }: {
|
|
48
|
+
pubkey: string;
|
|
49
|
+
relays: string[];
|
|
50
|
+
url?: string;
|
|
51
|
+
}) => Promise<ZapAmountResult>;
|
|
52
|
+
export declare const listenForZapReceipt: ({ relays, receiversPubKey, invoice, onSuccess, }: {
|
|
53
|
+
relays: string[];
|
|
54
|
+
receiversPubKey: string;
|
|
55
|
+
invoice: string;
|
|
56
|
+
onSuccess: () => void;
|
|
57
|
+
}) => () => void;
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-component-Dqg0QU9I.js","sources":["../../src/base/dialog-component/style.ts","../../src/base/dialog-component/dialog-component.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\n/**\n * Base dialog component styles\n * Provides common styling for all dialog components\n */\nexport const getDialogComponentStyles = (): string => {\n return `\n /* Base Dialog Styles */\n .nostr-base-dialog {\n width: 400px;\n max-width: 90vw;\n border: none;\n border-radius: var(--nostrc-border-radius-lg, 10px);\n padding: var(--nostrc-spacing-xl, 20px);\n background: var(--nostrc-theme-bg, #ffffff);\n color: var(--nostrc-theme-text-primary, #000000);\n position: relative;\n font-family: var(--nostrc-font-family-primary, ui-sans-serif, system-ui, sans-serif);\n }\n\n .nostr-base-dialog[open] {\n display: block;\n }\n\n .nostr-base-dialog::backdrop {\n background: rgba(0, 0, 0, 0.5);\n }\n\n .dialog-header {\n position: relative;\n margin-bottom: var(--nostrc-spacing-lg, 16px);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .dialog-header h2 {\n font-size: var(--nostrc-font-size-large, 1.25rem);\n font-weight: var(--nostrc-font-weight-bold, 700);\n margin: 0;\n flex: 1;\n text-align: left;\n padding-top: 2px;\n color: var(--nostrc-theme-text-primary, #000000);\n }\n\n .dialog-close-btn {\n border: none;\n background: var(--nostrc-theme-hover-bg, #f7fafc);\n border-radius: var(--nostrc-border-radius-full, 50%);\n width: 32px;\n height: 32px;\n min-width: 32px;\n font-size: var(--nostrc-font-size-base, 16px);\n cursor: pointer;\n color: var(--nostrc-theme-text-secondary, #666666);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .dialog-close-btn:hover {\n background: var(--nostrc-theme-border, rgba(0, 0, 0, 0.05));\n color: var(--nostrc-theme-text-primary, #000000);\n }\n\n .dialog-content {\n line-height: 1.6;\n color: var(--nostrc-theme-text-primary, #000000);\n }\n `;\n};\n\n","// SPDX-License-Identifier: MIT\n\nimport { getDialogComponentStyles } from './style';\n\n/**\n * Base dialog component that extends HTMLElement\n * Provides common dialog functionality with header, close button, and content area\n * \n * Usage:\n * ```typescript\n * const dialog = document.createElement('dialog-component');\n * dialog.setAttribute('header', 'Dialog Title');\n * dialog.innerHTML = '<p>Your content goes here</p>';\n * dialog.showModal(); // Don't append to body, just call showModal()\n * ```\n * \n * Features:\n * - Header with customizable text\n * - Close button\n * - Click outside to close\n * - ESC key to close\n * - Automatic cleanup on close\n * \n * Important: Only one instance of this component should be added to the DOM at any time.\n * Multiple instances may cause conflicts with event listeners and cleanup behavior.\n */\nexport class DialogComponent extends HTMLElement {\n private dialog: HTMLDialogElement | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Observed attributes for the component\n */\n static get observedAttributes() {\n return ['header', 'data-theme'];\n }\n\n /**\n * Inject dialog styles into document head\n * Prevents duplicate injection by checking for existing styles\n */\n private injectStyles(): void {\n if (document.querySelector('style[data-dialog-component-styles]')) return;\n \n const style = document.createElement('style');\n style.setAttribute('data-dialog-component-styles', 'true');\n style.textContent = getDialogComponentStyles();\n document.head.appendChild(style);\n }\n\n /**\n * Render the dialog\n */\n private render(): void {\n this.injectStyles();\n\n const headerText = this.getAttribute('header') || 'Dialog';\n const theme = this.getAttribute('data-theme');\n\n this.dialog = document.createElement('dialog');\n this.dialog.className = 'nostr-base-dialog';\n if (theme) {\n this.dialog.setAttribute('data-theme', theme);\n }\n\n const headerDiv = document.createElement('div');\n headerDiv.className = 'dialog-header';\n \n const headerH2 = document.createElement('h2');\n headerH2.textContent = headerText;\n \n const closeBtn = document.createElement('button');\n closeBtn.className = 'dialog-close-btn';\n closeBtn.setAttribute('aria-label', 'Close dialog');\n closeBtn.textContent = '✕';\n \n headerDiv.appendChild(headerH2);\n headerDiv.appendChild(closeBtn);\n\n const contentDiv = document.createElement('div');\n contentDiv.className = 'dialog-content';\n \n // Safely move child nodes from component to dialog content\n // This preserves any existing DOM nodes without using innerHTML\n while (this.firstChild) {\n contentDiv.appendChild(this.firstChild);\n }\n\n this.dialog.appendChild(headerDiv);\n this.dialog.appendChild(contentDiv);\n\n document.body.appendChild(this.dialog);\n\n this.setupEventListeners();\n }\n\n /**\n * Setup event listeners for closing the dialog\n */\n private setupEventListeners(): void {\n if (!this.dialog) return;\n\n // Close button click\n const closeBtn = this.dialog.querySelector('.dialog-close-btn');\n closeBtn?.addEventListener('click', () => {\n this.close();\n });\n\n // Click outside dialog (on backdrop)\n this.dialog.addEventListener('click', (e) => {\n if (e.target === this.dialog) {\n this.close();\n }\n });\n\n // ESC key handler\n this.dialog.addEventListener('cancel', (e) => {\n e.preventDefault();\n this.close();\n });\n\n // Cleanup on close\n this.dialog.addEventListener('close', () => {\n this.cleanup();\n });\n }\n\n /**\n * Show the dialog (alias for showModal)\n */\n public show(): void {\n this.showModal();\n }\n\n /**\n * Show the dialog as modal\n */\n public showModal(): void {\n if (!this.dialog) {\n this.render();\n }\n this.dialog?.showModal();\n }\n\n /**\n * Close the dialog\n */\n public close(): void {\n this.dialog?.close();\n }\n\n /**\n * Cleanup when dialog is closed\n */\n private cleanup(): void {\n if (this.dialog && this.dialog.isConnected) {\n this.dialog.remove();\n }\n if (this.isConnected) {\n this.remove();\n }\n this.dialog = null;\n }\n\n /**\n * Called when component is removed from DOM\n */\n disconnectedCallback(): void {\n this.cleanup();\n }\n\n /**\n * Called when observed attributes change\n */\n attributeChangedCallback(name: string, _oldValue: string, newValue: string): void {\n if (name === 'header' && this.dialog) {\n const heading = this.dialog.querySelector('.dialog-header h2');\n if (heading) {\n heading.textContent = newValue || 'Dialog';\n }\n } else if (name === 'data-theme' && this.dialog) {\n if (newValue) {\n this.dialog.setAttribute('data-theme', newValue);\n } else {\n this.dialog.removeAttribute('data-theme');\n }\n }\n }\n}\n\n// Define custom element\nif (!customElements.get('dialog-component')) {\n customElements.define('dialog-component', DialogComponent);\n}\n\n"],"names":["getDialogComponentStyles","DialogComponent","__publicField","style","headerText","theme","headerDiv","headerH2","closeBtn","contentDiv","e","_a","name","_oldValue","newValue","heading"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var l=Object.defineProperty;var p=(i,r,e)=>r in i?l(i,r,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[r]=e;var n=(i,r,e)=>p(i,typeof r!="symbol"?r+"":r,e);import{N as h,a as o}from"./base-styles-DC0ilu4S.js";import{U as c}from"./user-resolver-DqI5KGh6.js";const d="nc:user";class C extends h{constructor(e=!0){super(e);n(this,"user",null);n(this,"profile",null);n(this,"userStatus",this.channel("user"));n(this,"loadSeq",0);n(this,"resolver",new c(this.nostrService));this.initChannelStatus("user",o.Loading,{reflectOverall:!1})}static get observedAttributes(){return[...super.observedAttributes,"npub","pubkey","nip05"]}connectedCallback(){var e;(e=super.connectedCallback)==null||e.call(this),this.validateInputs()&&this.resolveUserAndProfile().catch(t=>{console.error("[NostrUserComponent] init failed:",t)})}attributeChangedCallback(e,t,s){var u;t!==s&&((u=super.attributeChangedCallback)==null||u.call(this,e,t,s),(e==="npub"||e==="nip05"||e==="pubkey")&&this.validateInputs()&&this.resolveUserAndProfile())}validateInputs(){if(!super.validateInputs())return this.userStatus.set(o.Idle),!1;const e=this.getAttribute("npub"),t=this.getAttribute("pubkey"),s=this.getAttribute("nip05"),u=this.tagName.toLowerCase(),a=this.resolver.validateInputs({npub:e,pubkey:t,nip05:s});return a?(this.userStatus.set(o.Error,a),console.error(`Nostr-Components: ${u}: ${a}`),!1):(this.errorMessage="",!0)}async resolveUserAndProfile(){const e=++this.loadSeq;try{await this.ensureNostrConnected()}catch(t){if(e!==this.loadSeq)return;console.error("[NostrUserComponent] Relay connect failed before user/profile load:",t);return}this.userStatus.set(o.Loading);try{const{user:t,profile:s}=await this.resolver.resolveUser({npub:this.getAttribute("npub"),pubkey:this.getAttribute("pubkey"),nip05:this.getAttribute("nip05")});if(e!==this.loadSeq)return;if(s==null){this.userStatus.set(o.Error,"Profile not found");return}this.user=t,this.profile=s,this.userStatus.set(o.Ready),this.dispatchEvent(new CustomEvent(d,{detail:{user:this.user,profile:this.profile},bubbles:!0,composed:!0})),this.onUserReady(this.user,this.profile)}catch(t){if(e!==this.loadSeq)return;const s=t instanceof Error?t.message:"Failed to load user/profile";console.error("[NostrUserComponent] "+s,t),this.userStatus.set(o.Error,s)}}renderContent(){}onUserReady(e,t){}}export{C as N};
|
|
2
|
-
//# sourceMappingURL=nostr-user-component-XEnanH-d.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nostr-user-component-XEnanH-d.js","sources":["../../src/base/user-component/nostr-user-component.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\nimport { NDKUser, NDKUserProfile } from '@nostr-dev-kit/ndk';\nimport { NostrBaseComponent, NCStatus } from '../base-component/nostr-base-component';\nimport { UserResolver } from '../resolvers/user-resolver';\n\nconst EVT_USER = 'nc:user';\n\n/**\n * NostrUserComponent\n * ==================\n * Extension of `NostrBaseComponent` that resolves and manages a Nostr user.\n *\n * Overview\n * - Accepts identity attributes (`npub`, `nip05`, or `pubkey`) and validates them.\n * - Resolves an `NDKUser` via the shared `nostrService` and fetches its profile.\n * - Exposes resolved `user` and `profile` to subclasses for rendering or logic.\n * - Emits lifecycle events for status and user readiness.\n *\n * Observed attributes\n * - `npub` — user's Nostr public key (bech32 npub)\n * - `nip05` — NIP-05 identifier (e.g. `alice@example.com`)\n * - `pubkey` — raw hex-encoded public key\n *\n * Events\n * - `nc:status` — from base, reflects connection and user/profile loading status\n * - `nc:user` — fired when a user and profile are successfully resolved\n */\n\nexport class NostrUserComponent extends NostrBaseComponent {\n\n protected user: NDKUser | null = null;\n protected profile: NDKUserProfile | null = null;\n\n protected userStatus = this.channel('user');\n\n // guard to ignore stale user fetches\n private loadSeq = 0;\n\n private resolver = new UserResolver(this.nostrService);\n\n constructor(shadow: boolean = true) {\n super(shadow);\n this.initChannelStatus('user', NCStatus.Loading, { reflectOverall: false });\n }\n\n /** Lifecycle methods */\n static get observedAttributes() {\n return [\n ...super.observedAttributes,\n 'npub',\n 'pubkey',\n 'nip05',\n ];\n }\n\n connectedCallback() {\n super.connectedCallback?.();\n\n if (this.validateInputs()) {\n this.resolveUserAndProfile().catch(e => {\n console.error('[NostrUserComponent] init failed:', e);\n });\n }\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string | null,\n newValue: string | null\n ) {\n if (oldValue === newValue) return;\n super.attributeChangedCallback?.(name, oldValue, newValue);\n\n if (name === 'npub' || name === 'nip05' || name === 'pubkey') {\n if (this.validateInputs()) {\n // Re-resolve user + profile on identity changes\n void this.resolveUserAndProfile();\n }\n }\n }\n\n /** Protected methods */\n protected validateInputs(): boolean {\n\n if (!super.validateInputs()) {\n this.userStatus.set(NCStatus.Idle);\n return false;\n }\n\n const npub = this.getAttribute(\"npub\");\n const pubkey = this.getAttribute(\"pubkey\");\n const nip05 = this.getAttribute(\"nip05\");\n const tagName = this.tagName.toLowerCase();\n\n const err = this.resolver.validateInputs({\n npub: npub,\n pubkey: pubkey,\n nip05: nip05,\n });\n\n if (err) {\n this.userStatus.set(NCStatus.Error, err);\n console.error(`Nostr-Components: ${tagName}: ${err}`);\n return false;\n }\n\n this.errorMessage = \"\";\n return true;\n\n }\n\n protected async resolveUserAndProfile(): Promise<void> {\n const seq = ++this.loadSeq; // token to prevent stale writes\n\n // Ensure relays are connected; handle failure inside to avoid unhandled rejection\n try {\n await this.ensureNostrConnected();\n } catch (e) {\n if (seq !== this.loadSeq) return; // stale\n // Base already set status=Error, but make the failure explicit here too\n console.error('[NostrUserComponent] Relay connect failed before user/profile load:', e);\n return;\n }\n\n this.userStatus.set(NCStatus.Loading);\n\n try {\n const { user, profile } = await this.resolver.resolveUser({\n npub: this.getAttribute('npub'),\n pubkey: this.getAttribute('pubkey'),\n nip05: this.getAttribute('nip05'),\n });\n\n // stale call check\n if (seq !== this.loadSeq) return;\n\n if (profile == null) {\n this.userStatus.set(NCStatus.Error, \"Profile not found\");\n return;\n }\n\n this.user = user;\n this.profile = profile;\n this.userStatus.set(NCStatus.Ready);\n // Notify listeners that user + profile are available\n this.dispatchEvent(new CustomEvent(EVT_USER, {\n detail: { user: this.user, profile: this.profile },\n bubbles: true,\n composed: true,\n }));\n this.onUserReady(this.user!, this.profile);\n } catch (err) {\n if (seq !== this.loadSeq) return; // stale\n const msg = err instanceof Error ? err.message : 'Failed to load user/profile';\n console.error('[NostrUserComponent] ' + msg, err);\n this.userStatus.set(NCStatus.Error, msg);\n }\n }\n\n protected renderContent() { }\n\n /** Hook for subclasses to react when user/profile are ready (e.g., render). */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected onUserReady(_user: NDKUser, _profile: NDKUserProfile | null) { }\n}\n"],"names":["EVT_USER","NostrUserComponent","NostrBaseComponent","shadow","__publicField","UserResolver","NCStatus","_a","e","name","oldValue","newValue","npub","pubkey","nip05","tagName","err","seq","user","profile","msg","_user","_profile"],"mappings":"yQAMA,MAAMA,EAAW,UAuBV,MAAMC,UAA2BC,CAAmB,CAYzD,YAAYC,EAAkB,GAAM,CAClC,MAAMA,CAAM,EAXJC,EAAA,YAAuB,MACvBA,EAAA,eAAiC,MAEjCA,EAAA,kBAAa,KAAK,QAAQ,MAAM,GAGlCA,EAAA,eAAU,GAEVA,EAAA,gBAAW,IAAIC,EAAa,KAAK,YAAY,GAInD,KAAK,kBAAkB,OAAQC,EAAS,QAAS,CAAE,eAAgB,GAAO,CAC5E,CAGA,WAAW,oBAAqB,CAC9B,MAAO,CACL,GAAG,MAAM,mBACT,OACA,SACA,OAAA,CAEJ,CAEA,mBAAoB,QAClBC,EAAA,MAAM,oBAAN,MAAAA,EAAA,WAEI,KAAK,kBACP,KAAK,sBAAA,EAAwB,MAAMC,GAAK,CACtC,QAAQ,MAAM,oCAAqCA,CAAC,CACtD,CAAC,CAEL,CAEA,yBACEC,EACAC,EACAC,EACA,OACID,IAAaC,KACjBJ,EAAA,MAAM,2BAAN,MAAAA,EAAA,UAAiCE,EAAMC,EAAUC,IAE7CF,IAAS,QAAUA,IAAS,SAAWA,IAAS,WAC9C,KAAK,kBAEF,KAAK,sBAAA,EAGhB,CAGU,gBAA0B,CAElC,GAAI,CAAC,MAAM,iBACT,YAAK,WAAW,IAAIH,EAAS,IAAI,EAC1B,GAGT,MAAMM,EAAU,KAAK,aAAa,MAAM,EAClCC,EAAU,KAAK,aAAa,QAAQ,EACpCC,EAAU,KAAK,aAAa,OAAO,EACnCC,EAAU,KAAK,QAAQ,YAAA,EAEvBC,EAAM,KAAK,SAAS,eAAe,CACvC,KAAAJ,EACA,OAAAC,EACA,MAAAC,CAAA,CACD,EAED,OAAIE,GACF,KAAK,WAAW,IAAIV,EAAS,MAAOU,CAAG,EACvC,QAAQ,MAAM,qBAAqBD,CAAO,KAAKC,CAAG,EAAE,EAC7C,KAGT,KAAK,aAAe,GACb,GAET,CAEA,MAAgB,uBAAuC,CACrD,MAAMC,EAAM,EAAE,KAAK,QAGnB,GAAI,CACF,MAAM,KAAK,qBAAA,CACb,OAAST,EAAG,CACV,GAAIS,IAAQ,KAAK,QAAS,OAE1B,QAAQ,MAAM,sEAAuET,CAAC,EACtF,MACF,CAEA,KAAK,WAAW,IAAIF,EAAS,OAAO,EAEpC,GAAI,CACF,KAAM,CAAE,KAAAY,EAAM,QAAAC,CAAA,EAAY,MAAM,KAAK,SAAS,YAAY,CACxD,KAAM,KAAK,aAAa,MAAM,EAC9B,OAAQ,KAAK,aAAa,QAAQ,EAClC,MAAO,KAAK,aAAa,OAAO,CAAA,CACjC,EAGD,GAAIF,IAAQ,KAAK,QAAS,OAE1B,GAAIE,GAAW,KAAM,CACnB,KAAK,WAAW,IAAIb,EAAS,MAAO,mBAAmB,EACvD,MACF,CAEA,KAAK,KAAOY,EACZ,KAAK,QAAUC,EACf,KAAK,WAAW,IAAIb,EAAS,KAAK,EAElC,KAAK,cAAc,IAAI,YAAYN,EAAU,CAC3C,OAAQ,CAAE,KAAM,KAAK,KAAM,QAAS,KAAK,OAAA,EACzC,QAAS,GACT,SAAU,EAAA,CACX,CAAC,EACF,KAAK,YAAY,KAAK,KAAO,KAAK,OAAO,CAC3C,OAASgB,EAAK,CACZ,GAAIC,IAAQ,KAAK,QAAS,OAC1B,MAAMG,EAAMJ,aAAe,MAAQA,EAAI,QAAU,8BACjD,QAAQ,MAAM,wBAA0BI,EAAKJ,CAAG,EAChD,KAAK,WAAW,IAAIV,EAAS,MAAOc,CAAG,CACzC,CACF,CAEU,eAAgB,CAAE,CAIlB,YAAYC,EAAgBC,EAAiC,CAAE,CAC3E"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{S as E,n as N,f as P}from"./nostr-service-m3Hgc5Xx.js";import{e as R,s as S}from"./nostr-login-service-D2FmscPI.js";import{n as k}from"./utils--bxLbhGF.js";import"./preload-helper-D7HrI6pR.js";const d={},x=async t=>{if(d[t])return d[t];const e=new E,s=["wss://relay.nostr.band","wss://purplepag.es","wss://relay.damus.io","wss://nostr.wine"];try{const a=await e.get(s,{authors:[t],kinds:[0]});return d[t]=a,a}finally{e.close(s)}},D=async t=>{const e=t.filter(r=>!d[r]);if(e.length===0)return t.map(r=>({id:r,profile:d[r]}));const s=new E,a=["wss://relay.nostr.band","wss://purplepag.es","wss://relay.damus.io","wss://nostr.wine"];try{return(await s.querySync(a,{authors:e,kinds:[0]})).forEach(n=>{d[n.pubkey]=n}),t.map(n=>({id:n,profile:d[n]||null}))}finally{s.close(a)}},J=t=>{try{return JSON.parse((t==null?void 0:t.content)||"{}")}catch{return{}}},I=async t=>{const e=await N.getZapEndpoint(t);if(!e)throw new Error("Failed to retrieve zap LNURL");return e},L=async(t,e)=>{try{return await R(),await S(t)}catch{}return P(t,C())},Z=async({profile:t,nip19Target:e,amount:s,relays:a,comment:r,anon:i,url:n})=>{const f={profile:t,amount:s,relays:a,comment:r||""},c=N.makeZapRequest(f);n&&(c.tags.push(["k","web"]),c.tags.push(["i",k(n)]));let l=!1;try{await R(),l=typeof window<"u"&&!!window.nostr}catch{l=!1}return(!l||i)&&c.tags.push(["anon"]),L(c)},M=async({zapEndpoint:t,amount:e,comment:s,authorId:a,nip19Target:r,normalizedRelays:i,anon:n,url:f})=>{const c=await Z({profile:a,nip19Target:r,amount:e,relays:i,comment:s??"",anon:n,url:f});let l=`${t}?amount=${e}&nostr=${encodeURIComponent(JSON.stringify(c))}`;s&&(l+=`&comment=${encodeURIComponent(s??"")}`);const p=await fetch(l,{method:"GET"});if(!p.ok)throw new Error(`LNURL request failed: ${p.status} ${p.statusText}`);let m;try{m=await p.json()}catch{throw new Error("Invalid JSON from LNURL endpoint")}const{pr:h,reason:b,status:g}=m||{};if(h)return h;throw g==="ERROR"?new Error(b??"Unable to fetch invoice"):new Error("Unable to fetch invoice")},C=()=>{const t=new Uint8Array(32);if(typeof crypto<"u"&&typeof crypto.getRandomValues=="function")crypto.getRandomValues(t);else{console.warn("crypto.getRandomValues not available, using Math.random as fallback");for(let e=0;e<32;e++)t[e]=Math.floor(Math.random()*256)}return t},V=async({pubkey:t,relays:e,url:s})=>{var f,c,l,p;const a=s?k(s):void 0,r=new E;let i=0;const n=[];try{const m={kinds:[9735],"#p":[t],limit:1e3},h=await r.querySync(e,m);for(const b of h){const g=(f=b.tags)==null?void 0:f.find(o=>o[0]==="description");if(g!=null&&g[1])try{const o=JSON.parse(g[1]),w=(c=o==null?void 0:o.tags)==null?void 0:c.find(u=>u[0]==="amount");if(a){const u=(l=o==null?void 0:o.tags)==null?void 0:l.find(y=>y[0]==="k"),v=(p=o==null?void 0:o.tags)==null?void 0:p.find(y=>y[0]==="i"),U=v!=null&&v[1]?k(v[1]):"";if((u==null?void 0:u[1])==="web"&&U===a&&(w!=null&&w[1])){const y=parseInt(w[1],10);y>0&&(i+=y,n.push({amount:y/1e3,date:new Date(b.created_at*1e3),authorPubkey:o.pubkey,comment:o.content}))}}else if(w!=null&&w[1]){const u=parseInt(w[1],10);u>0&&(i+=u,n.push({amount:u/1e3,date:new Date(b.created_at*1e3),authorPubkey:o.pubkey,comment:o.content}))}}catch(o){console.error("Nostr-Components: Zap button: Could not parse zap request from description tag",o)}}}catch(m){console.error("Nostr-Components: Zap button: Error fetching zap receipts",m)}finally{r.close(e)}return n.sort((m,h)=>h.date.getTime()-m.date.getTime()),{totalAmount:i/1e3,zapDetails:n}},_=({relays:t,receiversPubKey:e,invoice:s,onSuccess:a})=>{const r=new E,i=Array.from(new Set([...t,"wss://relay.nostr.band"])),n=Math.floor((Date.now()-24*60*60*1e3)/1e3);r.subscribe(i,{kinds:[9735],"#p":[e],since:n},{onevent(c){c.tags.some(p=>p[0]==="bolt11"&&p[1]===s)&&(a(),f())}});const f=()=>{r.close(i)};return f};export{J as extractProfileMetadataContent,M as fetchInvoice,V as fetchTotalZapAmount,D as getBatchedProfileMetadata,x as getProfileMetadata,I as getZapEndpoint,_ as listenForZapReceipt};
|
|
2
|
-
//# sourceMappingURL=zap-utils-BZcaCsT_.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"zap-utils-BZcaCsT_.js","sources":["../../src/nostr-zap/zap-utils.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\nimport {\n nip57,\n nip05,\n finalizeEvent,\n SimplePool,\n} from 'nostr-tools';\nimport { decodeNip19Entity } from '../common/utils';\nimport { ensureInitialized, signEvent as signEventWithNostrLogin } from '../common/nostr-login-service';\n\n/**\n * Helper utilities for Nostr zap operations (adapted from the original `nostr-zap` repo).\n * These are deliberately kept self-contained so `nostr-zap` Web Component can import\n * everything from a single module without polluting the rest of the codebase.\n */\n\n// Basic in-memory cache – sufficient for component lifetime.\nconst profileCache: Record<string, any> = {};\n\nexport const getProfileMetadata = async (authorId: string) => {\n if (profileCache[authorId]) return profileCache[authorId];\n\n const pool = new SimplePool();\n const relays = [\n 'wss://relay.nostr.band',\n 'wss://purplepag.es',\n 'wss://relay.damus.io',\n 'wss://nostr.wine',\n ];\n\n try {\n const event = await pool.get(relays, {\n authors: [authorId],\n kinds: [0],\n });\n profileCache[authorId] = event;\n return event;\n } finally {\n pool.close(relays);\n }\n};\n\nexport const getBatchedProfileMetadata = async (authorIds: string[]) => {\n // Filter out already cached profiles\n const uncachedIds = authorIds.filter(id => !profileCache[id]);\n\n // If all profiles are cached, return them\n if (uncachedIds.length === 0) {\n return authorIds.map(id => ({ id, profile: profileCache[id] }));\n }\n\n const pool = new SimplePool();\n const relays = [\n 'wss://relay.nostr.band',\n 'wss://purplepag.es',\n 'wss://relay.damus.io',\n 'wss://nostr.wine',\n ];\n\n try {\n // Fetch all uncached profiles in a single query\n const events = await pool.querySync(relays, {\n authors: uncachedIds,\n kinds: [0],\n });\n\n // Cache the fetched profiles\n events.forEach(event => {\n profileCache[event.pubkey] = event;\n });\n\n // Combine cached and newly fetched profiles\n const allProfiles = authorIds.map(id => ({\n id,\n profile: profileCache[id] || null\n }));\n\n return allProfiles;\n } finally {\n pool.close(relays);\n }\n};\n\nexport const extractProfileMetadataContent = (profileMetadata: any) => {\n try {\n return JSON.parse(profileMetadata?.content || '{}');\n } catch {\n return {};\n }\n};\n\nexport const getZapEndpoint = async (profileMetadata: any) => {\n const endpoint = await nip57.getZapEndpoint(profileMetadata);\n if (!endpoint) throw new Error('Failed to retrieve zap LNURL');\n return endpoint;\n};\n\ninterface NostrExtension {\n signEvent(event: any): Promise<{\n id: string;\n sig: string;\n kind: number;\n tags: string[][];\n pubkey: string;\n content: string;\n created_at: number;\n }>;\n}\n\nconst signEvent = async (zapEvent: any, anon?: boolean) => {\n if (!anon) {\n try {\n await ensureInitialized();\n return await signEventWithNostrLogin(zapEvent);\n } catch {\n /* fall-through -> anonymous */\n }\n }\n return finalizeEvent(zapEvent, generateRandomPrivKey());\n};\n\nconst makeZapEvent = async ({\n profile,\n nip19Target,\n amount,\n relays,\n comment,\n anon,\n url,\n}: {\n profile: string;\n nip19Target?: string;\n amount: number;\n relays: string[];\n comment?: string;\n anon?: boolean;\n url?: string;\n}) => {\n const req: any = {\n profile,\n amount,\n relays,\n comment: comment || '',\n };\n if (nip19Target?.startsWith('note')) {\n req.event = decodeNip19Entity(nip19Target);\n }\n const event = nip57.makeZapRequest(req);\n\n if (nip19Target?.startsWith('naddr')) {\n const naddrData: any = decodeNip19Entity(nip19Target);\n const relayTag = naddrData?.relays?.join(',') ?? '';\n event.tags.push(['a', `${naddrData.kind}:${naddrData.pubkey}:${naddrData.identifier}`, relayTag]);\n }\n\n // Add URL-based zap tags if URL is provided\n if (url) {\n event.tags.push(['k', 'web']);\n event.tags.push(['i', normalizeURL(url)]);\n }\n\n // Check if NostrLogin is available (will initialize if needed)\n // Note: We check availability here to decide if we should add 'anon' tag\n // The actual signing happens in signEvent() which will ensure initialization\n let isNostrLoginAvailable = false;\n if (!anon) {\n try {\n await ensureInitialized();\n isNostrLoginAvailable = typeof window !== 'undefined' && !!(window as any).nostr;\n } catch {\n // If initialization fails, fall back to anonymous\n isNostrLoginAvailable = false;\n }\n }\n \n if (!isNostrLoginAvailable || anon) {\n event.tags.push(['anon']);\n }\n\n return signEvent(event, anon);\n};\n\nexport const fetchInvoice = async ({\n zapEndpoint,\n amount,\n comment,\n authorId,\n nip19Target,\n normalizedRelays,\n anon,\n url,\n}: {\n zapEndpoint: string;\n amount: number;\n comment?: string;\n authorId: string;\n nip19Target?: string;\n normalizedRelays: string[];\n anon?: boolean;\n url?: string;\n}): Promise<string> => {\n const zapEvent = await makeZapEvent({\n profile: authorId,\n nip19Target,\n amount,\n relays: normalizedRelays,\n comment: comment ?? '',\n anon,\n url,\n });\n\n\n let invoiceUrl = `${zapEndpoint}?amount=${amount}&nostr=${encodeURIComponent(\n JSON.stringify(zapEvent)\n )}`;\n if (comment) invoiceUrl += `&comment=${encodeURIComponent(comment ?? '')}`;\n\n const res = await fetch(invoiceUrl, { method: 'GET' });\n if (!res.ok) {\n throw new Error(`LNURL request failed: ${res.status} ${res.statusText}`);\n }\n let json: any;\n try {\n json = await res.json();\n } catch {\n throw new Error('Invalid JSON from LNURL endpoint');\n }\n const { pr: invoice, reason, status } = json || {};\n if (invoice) return invoice;\n if (status === 'ERROR') throw new Error(reason ?? 'Unable to fetch invoice');\n throw new Error('Unable to fetch invoice');\n};\n\nconst generateRandomPrivKey = (): Uint8Array => {\n const bytes = new Uint8Array(32);\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(bytes);\n } else {\n // Node.js fallback during build – use Math.random (not cryptographically strong but acceptable for anon zaps)\n console.warn('crypto.getRandomValues not available, using Math.random as fallback');\n for (let i = 0; i < 32; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return bytes;\n};\n\n/**\n * Check if NostrLogin is available\n * @deprecated Use ensureInitialized() instead - it will initialize NostrLogin if needed\n */\nexport const isNip07ExtAvailable = (): boolean => {\n // This function is kept for backward compatibility but will always return false\n // until ensureInitialized() is called. Components should use ensureInitialized() instead.\n return typeof window !== 'undefined' && !!(window as any).nostr;\n};\n\n// ---------------------------------------------------------------------------\n// nip05 resolution helper – very lightweight fetch to /.well-known/nostr.json\n// ---------------------------------------------------------------------------\n\n\n\nexport async function resolveNip05(nip05Identifier: string): Promise<string | null> {\n try {\n const profile = await nip05.queryProfile(nip05Identifier);\n return profile?.pubkey || null;\n } catch (error) {\n console.error(`Failed to resolve NIP-05 ${nip05Identifier}:`, error);\n return null;\n }\n}\n\n// Import necessary types from nostr-tools\nimport type { Filter, Event } from 'nostr-tools';\nimport { normalizeURL } from '../nostr-comment/utils';\n\n// Augment the SimplePool type to include our usage\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ndeclare module 'nostr-tools' {\n interface SimplePool {\n subscribe(\n relays: string[],\n filter: Filter,\n params: {\n onevent: (event: Event) => void;\n onclose?: () => void;\n id?: string;\n maxWait?: number;\n }\n ): {\n close: () => void;\n };\n }\n}\n\nexport interface ZapDetails {\n amount: number;\n date: Date;\n authorPubkey: string;\n comment?: string;\n}\n\nexport interface ZapAmountResult {\n totalAmount: number;\n zapDetails: ZapDetails[];\n}\n\nexport const fetchTotalZapAmount = async ({\n pubkey,\n relays,\n url,\n}: {\n pubkey: string;\n relays: string[];\n url?: string;\n}): Promise<ZapAmountResult> => {\n // Normalize URL at the beginning for consistent comparison with tags\n const normalizedUrl = url ? normalizeURL(url) : undefined;\n \n const pool = new SimplePool();\n let totalAmount = 0;\n const zapDetails: ZapDetails[] = [];\n\n try {\n // Build filter for zap receipt events\n const filter: any = {\n kinds: [9735], // Zap receipt\n '#p': [pubkey],\n limit: 1000,\n };\n\n // Add URL-based filtering if URL is provided\n // TODO: These tags doesn't appear in zap receipt event.\n // They goes into the description tag, which has the zap request JSON.\n /*\n if (normalizedUrl) {\n filter['#k'] = ['web'];\n filter['#i'] = [normalizedUrl];\n }\n */\n\n // Use pool.querySync to fetch multiple zap receipt events\n const events = await pool.querySync(relays, filter);\n\n for (const event of events) {\n const descriptionTag = event.tags?.find((tag: string[]) => tag[0] === 'description');\n if (descriptionTag?.[1]) {\n try {\n const zapRequest = JSON.parse(descriptionTag[1]);\n const amountTag = zapRequest?.tags?.find((tag: string[]) => tag[0] === 'amount');\n \n // If URL is provided, check for URL-based zap tags\n // TODO: Too much work, since #k and #i tags doesn't appear in zap receipt event.\n // This is not a practical solution, but it's working for now!\n if (normalizedUrl) {\n const kTag = zapRequest?.tags?.find((tag: string[]) => tag[0] === 'k');\n const iTag = zapRequest?.tags?.find((tag: string[]) => tag[0] === 'i');\n \n const iTagNormalized = iTag?.[1] ? normalizeURL(iTag[1]) : '';\n if (kTag?.[1] === 'web' && iTagNormalized === normalizedUrl && amountTag?.[1]) {\n const amount = parseInt(amountTag[1], 10);\n if (amount > 0) {\n totalAmount += amount;\n zapDetails.push({\n amount: amount / 1000, // convert from msats to sats\n date: new Date(event.created_at * 1000),\n authorPubkey: zapRequest.pubkey,\n comment: zapRequest.content,\n });\n }\n }\n } else {\n // No URL filtering - count all zaps\n if (amountTag?.[1]) {\n const amount = parseInt(amountTag[1], 10);\n if (amount > 0) {\n totalAmount += amount;\n zapDetails.push({\n amount: amount / 1000, // convert from msats to sats\n date: new Date(event.created_at * 1000),\n authorPubkey: zapRequest.pubkey,\n comment: zapRequest.content,\n });\n }\n }\n }\n } catch (e) {\n console.error(\"Nostr-Components: Zap button: Could not parse zap request from description tag\", e);\n }\n }\n }\n } catch (error) {\n console.error(\"Nostr-Components: Zap button: Error fetching zap receipts\", error);\n } finally {\n pool.close(relays);\n }\n\n // Sort zap details by date (newest first)\n zapDetails.sort((a, b) => b.date.getTime() - a.date.getTime());\n\n return {\n totalAmount: totalAmount / 1000, // convert from msats to sats\n zapDetails,\n };\n};\n\nexport const listenForZapReceipt = ({\n relays,\n receiversPubKey,\n invoice,\n onSuccess,\n}: {\n relays: string[];\n receiversPubKey: string,\n invoice: string;\n onSuccess: () => void;\n}) => {\n const pool = new SimplePool();\n const normalizedRelays = Array.from(new Set([...relays, 'wss://relay.nostr.band']));\n const since = Math.floor((Date.now() - 24 * 60 * 60 * 1000) / 1000); // current time - 24 hours\n\n pool.subscribe(\n normalizedRelays,\n {\n kinds: [9735],\n '#p': [receiversPubKey],\n since,\n },\n {\n onevent(event: Event) {\n const tags = event.tags as [string, string][];\n if (tags.some(t => t[0] === 'bolt11' && t[1] === invoice)) {\n onSuccess();\n cleanup();\n }\n }\n }\n );\n\n const cleanup = () => {\n pool.close(normalizedRelays);\n };\n\n return cleanup;\n};\n"],"names":["profileCache","getProfileMetadata","authorId","pool","SimplePool","relays","event","getBatchedProfileMetadata","authorIds","uncachedIds","id","extractProfileMetadataContent","profileMetadata","getZapEndpoint","endpoint","nip57","signEvent","zapEvent","anon","ensureInitialized","signEventWithNostrLogin","finalizeEvent","generateRandomPrivKey","makeZapEvent","profile","nip19Target","amount","comment","url","req","normalizeURL","isNostrLoginAvailable","fetchInvoice","zapEndpoint","normalizedRelays","invoiceUrl","res","json","invoice","reason","status","bytes","i","fetchTotalZapAmount","pubkey","normalizedUrl","totalAmount","zapDetails","filter","events","descriptionTag","_a","tag","zapRequest","amountTag","_b","kTag","_c","iTag","_d","iTagNormalized","e","error","a","b","listenForZapReceipt","receiversPubKey","onSuccess","since","t","cleanup"],"mappings":"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"}
|