nostr-components 0.2.0
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/LICENSE +21 -0
- package/README.md +334 -0
- package/dist/assets/base-styles-CBypR3FR.js +145 -0
- package/dist/assets/base-styles-CBypR3FR.js.map +1 -0
- package/dist/assets/copy-delegation-C4uvRTVM.js +15 -0
- package/dist/assets/copy-delegation-C4uvRTVM.js.map +1 -0
- package/dist/assets/dialog-component-Dqg0QU9I.js +66 -0
- package/dist/assets/dialog-component-Dqg0QU9I.js.map +1 -0
- package/dist/assets/dialog-likers-BzTesCZa.js +238 -0
- package/dist/assets/dialog-likers-BzTesCZa.js.map +1 -0
- package/dist/assets/icons-Dr_d9MII.js +105 -0
- package/dist/assets/icons-Dr_d9MII.js.map +1 -0
- package/dist/assets/nip05-utils-BNBHUmkr.js +2 -0
- package/dist/assets/nip05-utils-BNBHUmkr.js.map +1 -0
- package/dist/assets/nostr-service-pr_crY62.js +78 -0
- package/dist/assets/nostr-service-pr_crY62.js.map +1 -0
- package/dist/assets/nostr-user-component-Q7GeeFyu.js +2 -0
- package/dist/assets/nostr-user-component-Q7GeeFyu.js.map +1 -0
- package/dist/assets/preload-helper-D7HrI6pR.js +2 -0
- package/dist/assets/preload-helper-D7HrI6pR.js.map +1 -0
- package/dist/assets/pure-jrVhRVpB.js +2 -0
- package/dist/assets/pure-jrVhRVpB.js.map +1 -0
- package/dist/assets/theme-C1r1Zw8r.js +2 -0
- package/dist/assets/theme-C1r1Zw8r.js.map +1 -0
- package/dist/assets/user-resolver-C-E6KdwY.js +2 -0
- package/dist/assets/user-resolver-C-E6KdwY.js.map +1 -0
- package/dist/assets/utils--bxLbhGF.js +2 -0
- package/dist/assets/utils--bxLbhGF.js.map +1 -0
- package/dist/assets/zap-utils-B1sz0Abx.js +2 -0
- package/dist/assets/zap-utils-B1sz0Abx.js.map +1 -0
- package/dist/components/nostr-comment.es.js +924 -0
- package/dist/components/nostr-comment.es.js.map +1 -0
- package/dist/components/nostr-dm.es.js +217 -0
- package/dist/components/nostr-dm.es.js.map +1 -0
- package/dist/components/nostr-follow-button.es.js +103 -0
- package/dist/components/nostr-follow-button.es.js.map +1 -0
- package/dist/components/nostr-like.es.js +296 -0
- package/dist/components/nostr-like.es.js.map +1 -0
- package/dist/components/nostr-live-chat.es.js +523 -0
- package/dist/components/nostr-live-chat.es.js.map +1 -0
- package/dist/components/nostr-post.es.js +441 -0
- package/dist/components/nostr-post.es.js.map +1 -0
- package/dist/components/nostr-profile-badge.es.js +100 -0
- package/dist/components/nostr-profile-badge.es.js.map +1 -0
- package/dist/components/nostr-profile.es.js +287 -0
- package/dist/components/nostr-profile.es.js.map +1 -0
- package/dist/components/nostr-zap.es.js +694 -0
- package/dist/components/nostr-zap.es.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/nostr-comment.d.ts +4 -0
- package/dist/nostr-components.es.js +2 -0
- package/dist/nostr-components.es.js.map +1 -0
- package/dist/nostr-components.umd.js +4200 -0
- package/dist/nostr-components.umd.js.map +1 -0
- 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-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 +10 -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 +52 -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 +53 -0
- package/dist/themes/dark.css +10 -0
- package/dist/themes/light.css +10 -0
- package/dist/themes.css +52 -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 +95 -0
|
@@ -0,0 +1,2 @@
|
|
|
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-CBypR3FR.js";import{U as c}from"./user-resolver-C-E6KdwY.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-Q7GeeFyu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nostr-user-component-Q7GeeFyu.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,CAAA,CAI5E,WAAW,oBAAqB,CACvB,MAAA,CACL,GAAG,MAAM,mBACT,OACA,SACA,OACF,CAAA,CAGF,mBAAoB,QAClBC,EAAA,MAAM,oBAAN,MAAAA,EAAA,WAEI,KAAK,kBACF,KAAA,sBAAA,EAAwB,MAAWC,GAAA,CAC9B,QAAA,MAAM,oCAAqCA,CAAC,CAAA,CACrD,CACH,CAGF,yBACEC,EACAC,EACAC,EACA,OACID,IAAaC,KACXJ,EAAA,MAAA,2BAAA,MAAAA,EAAA,UAA2BE,EAAMC,EAAUC,IAE7CF,IAAS,QAAUA,IAAS,SAAWA,IAAS,WAC9C,KAAK,kBAEF,KAAK,sBAAsB,EAEpC,CAIQ,gBAA0B,CAE9B,GAAA,CAAC,MAAM,iBACJ,YAAA,WAAW,IAAIH,EAAS,IAAI,EAC1B,GAGH,MAAAM,EAAU,KAAK,aAAa,MAAM,EAClCC,EAAU,KAAK,aAAa,QAAQ,EACpCC,EAAU,KAAK,aAAa,OAAO,EACnCC,EAAU,KAAK,QAAQ,YAAY,EAEnCC,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,GAAA,CAIT,MAAgB,uBAAuC,CAC/C,MAAAC,EAAM,EAAE,KAAK,QAGf,GAAA,CACF,MAAM,KAAK,qBAAqB,QACzBT,EAAG,CACN,GAAAS,IAAQ,KAAK,QAAS,OAElB,QAAA,MAAM,sEAAuET,CAAC,EACtF,MAAA,CAGG,KAAA,WAAW,IAAIF,EAAS,OAAO,EAEhC,GAAA,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,EAGG,GAAAF,IAAQ,KAAK,QAAS,OAE1B,GAAIE,GAAW,KAAM,CACnB,KAAK,WAAW,IAAIb,EAAS,MAAO,mBAAmB,EACvD,MAAA,CAGF,KAAK,KAAOY,EACZ,KAAK,QAAUC,EACV,KAAA,WAAW,IAAIb,EAAS,KAAK,EAE7B,KAAA,cAAc,IAAI,YAAYN,EAAU,CAC3C,OAAQ,CAAE,KAAM,KAAK,KAAM,QAAS,KAAK,OAAQ,EACjD,QAAS,GACT,SAAU,EAAA,CACX,CAAC,EACF,KAAK,YAAY,KAAK,KAAO,KAAK,OAAO,QAClCgB,EAAK,CACR,GAAAC,IAAQ,KAAK,QAAS,OAC1B,MAAMG,EAAMJ,aAAe,MAAQA,EAAI,QAAU,8BACzC,QAAA,MAAM,wBAA0BI,EAAKJ,CAAG,EAChD,KAAK,WAAW,IAAIV,EAAS,MAAOc,CAAG,CAAA,CACzC,CAGQ,eAAgB,CAAA,CAIhB,YAAYC,EAAgBC,EAAiC,CAAA,CACzE"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const h="modulepreload",E=function(i){return"/"+i},a={},y=function(u,s,v){let c=Promise.resolve();if(s&&s.length>0){document.getElementsByTagName("link");const e=document.querySelector("meta[property=csp-nonce]"),t=(e==null?void 0:e.nonce)||(e==null?void 0:e.getAttribute("nonce"));c=Promise.allSettled(s.map(r=>{if(r=E(r),r in a)return;a[r]=!0;const o=r.endsWith(".css"),d=o?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${r}"]${d}`))return;const n=document.createElement("link");if(n.rel=o?"stylesheet":h,o||(n.as="script"),n.crossOrigin="",n.href=r,t&&n.setAttribute("nonce",t),document.head.appendChild(n),o)return new Promise((f,m)=>{n.addEventListener("load",f),n.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${r}`)))})}))}function l(e){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return c.then(e=>{for(const t of e||[])t.status==="rejected"&&l(t.reason);return u().catch(l)})};export{y as _};
|
|
2
|
+
//# sourceMappingURL=preload-helper-D7HrI6pR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preload-helper-D7HrI6pR.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{s as a,b as n,a as o}from"./nostr-service-pr_crY62.js";var i=Symbol("verified"),l=e=>e instanceof Object;function c(e){if(!l(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!e.pubkey.match(/^[a-f0-9]{64}$/)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let r=e.tags[t];if(!Array.isArray(r))return!1;for(let s=0;s<r.length;s++)if(typeof r[s]=="object")return!1}return!0}new TextDecoder("utf-8");var y=new TextEncoder,g=class{generateSecretKey(){return a.utils.randomPrivateKey()}getPublicKey(e){return n(a.getPublicKey(e))}finalizeEvent(e,t){const r=e;return r.pubkey=n(a.getPublicKey(t)),r.id=u(r),r.sig=n(a.sign(u(r),t)),r[i]=!0,r}verifyEvent(e){if(typeof e[i]=="boolean")return e[i];const t=u(e);if(t!==e.id)return e[i]=!1,!1;try{const r=a.verify(e.sig,t,e.pubkey);return e[i]=r,r}catch{return e[i]=!1,!1}}};function b(e){if(!c(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function u(e){let t=o(y.encode(b(e)));return n(t)}var f=new g,p=f.generateSecretKey,h=f.getPublicKey,E=f.finalizeEvent;f.verifyEvent;export{E as finalizeEvent,p as generateSecretKey,u as getEventHash,h as getPublicKey,b as serializeEvent,c as validateEvent,i as verifiedSymbol};
|
|
2
|
+
//# sourceMappingURL=pure-jrVhRVpB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pure-jrVhRVpB.js","sources":["../../node_modules/nostr-tools/lib/esm/pure.js"],"sourcesContent":["// pure.ts\nimport { schnorr } from \"@noble/curves/secp256k1\";\nimport { bytesToHex } from \"@noble/hashes/utils\";\n\n// core.ts\nvar verifiedSymbol = Symbol(\"verified\");\nvar isRecord = (obj) => obj instanceof Object;\nfunction validateEvent(event) {\n if (!isRecord(event))\n return false;\n if (typeof event.kind !== \"number\")\n return false;\n if (typeof event.content !== \"string\")\n return false;\n if (typeof event.created_at !== \"number\")\n return false;\n if (typeof event.pubkey !== \"string\")\n return false;\n if (!event.pubkey.match(/^[a-f0-9]{64}$/))\n return false;\n if (!Array.isArray(event.tags))\n return false;\n for (let i2 = 0; i2 < event.tags.length; i2++) {\n let tag = event.tags[i2];\n if (!Array.isArray(tag))\n return false;\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] === \"object\")\n return false;\n }\n }\n return true;\n}\nfunction sortEvents(events) {\n return events.sort((a, b) => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at;\n }\n return a.id.localeCompare(b.id);\n });\n}\n\n// pure.ts\nimport { sha256 } from \"@noble/hashes/sha256\";\n\n// utils.ts\nvar utf8Decoder = new TextDecoder(\"utf-8\");\nvar utf8Encoder = new TextEncoder();\n\n// pure.ts\nvar JS = class {\n generateSecretKey() {\n return schnorr.utils.randomPrivateKey();\n }\n getPublicKey(secretKey) {\n return bytesToHex(schnorr.getPublicKey(secretKey));\n }\n finalizeEvent(t, secretKey) {\n const event = t;\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey));\n event.id = getEventHash(event);\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey));\n event[verifiedSymbol] = true;\n return event;\n }\n verifyEvent(event) {\n if (typeof event[verifiedSymbol] === \"boolean\")\n return event[verifiedSymbol];\n const hash = getEventHash(event);\n if (hash !== event.id) {\n event[verifiedSymbol] = false;\n return false;\n }\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey);\n event[verifiedSymbol] = valid;\n return valid;\n } catch (err) {\n event[verifiedSymbol] = false;\n return false;\n }\n }\n};\nfunction serializeEvent(evt) {\n if (!validateEvent(evt))\n throw new Error(\"can't serialize event with wrong or missing properties\");\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);\n}\nfunction getEventHash(event) {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)));\n return bytesToHex(eventHash);\n}\nvar i = new JS();\nvar generateSecretKey = i.generateSecretKey;\nvar getPublicKey = i.getPublicKey;\nvar finalizeEvent = i.finalizeEvent;\nvar verifyEvent = i.verifyEvent;\nexport {\n finalizeEvent,\n generateSecretKey,\n getEventHash,\n getPublicKey,\n serializeEvent,\n sortEvents,\n validateEvent,\n verifiedSymbol,\n verifyEvent\n};\n"],"names":["verifiedSymbol","isRecord","obj","validateEvent","event","i2","tag","j","utf8Encoder","JS","schnorr","secretKey","bytesToHex","t","getEventHash","hash","valid","serializeEvent","evt","eventHash","sha256","i","generateSecretKey","getPublicKey","finalizeEvent"],"mappings":"8DAKG,IAACA,EAAiB,OAAO,UAAU,EAClCC,EAAYC,GAAQA,aAAe,OACvC,SAASC,EAAcC,EAAO,CAa5B,GAZI,CAACH,EAASG,CAAK,GAEf,OAAOA,EAAM,MAAS,UAEtB,OAAOA,EAAM,SAAY,UAEzB,OAAOA,EAAM,YAAe,UAE5B,OAAOA,EAAM,QAAW,UAExB,CAACA,EAAM,OAAO,MAAM,gBAAgB,GAEpC,CAAC,MAAM,QAAQA,EAAM,IAAI,EAC3B,MAAO,GACT,QAASC,EAAK,EAAGA,EAAKD,EAAM,KAAK,OAAQC,IAAM,CAC7C,IAAIC,EAAMF,EAAM,KAAKC,CAAE,EACvB,GAAI,CAAC,MAAM,QAAQC,CAAG,EACpB,MAAO,GACT,QAASC,EAAI,EAAGA,EAAID,EAAI,OAAQC,IAC9B,GAAI,OAAOD,EAAIC,CAAC,GAAM,SACpB,MAAO,EAEf,CACE,MAAO,EACT,CAckB,IAAI,YAAY,OAAO,EACzC,IAAIC,EAAc,IAAI,YAGlBC,EAAK,KAAM,CACb,mBAAoB,CAClB,OAAOC,EAAQ,MAAM,iBAAkB,CAC3C,CACE,aAAaC,EAAW,CACtB,OAAOC,EAAWF,EAAQ,aAAaC,CAAS,CAAC,CACrD,CACE,cAAcE,EAAGF,EAAW,CAC1B,MAAMP,EAAQS,EACd,OAAAT,EAAM,OAASQ,EAAWF,EAAQ,aAAaC,CAAS,CAAC,EACzDP,EAAM,GAAKU,EAAaV,CAAK,EAC7BA,EAAM,IAAMQ,EAAWF,EAAQ,KAAKI,EAAaV,CAAK,EAAGO,CAAS,CAAC,EACnEP,EAAMJ,CAAc,EAAI,GACjBI,CACX,CACE,YAAYA,EAAO,CACjB,GAAI,OAAOA,EAAMJ,CAAc,GAAM,UACnC,OAAOI,EAAMJ,CAAc,EAC7B,MAAMe,EAAOD,EAAaV,CAAK,EAC/B,GAAIW,IAASX,EAAM,GACjB,OAAAA,EAAMJ,CAAc,EAAI,GACjB,GAET,GAAI,CACF,MAAMgB,EAAQN,EAAQ,OAAON,EAAM,IAAKW,EAAMX,EAAM,MAAM,EAC1D,OAAAA,EAAMJ,CAAc,EAAIgB,EACjBA,CACR,MAAa,CACZ,OAAAZ,EAAMJ,CAAc,EAAI,GACjB,EACb,CACA,CACA,EACA,SAASiB,EAAeC,EAAK,CAC3B,GAAI,CAACf,EAAce,CAAG,EACpB,MAAM,IAAI,MAAM,wDAAwD,EAC1E,OAAO,KAAK,UAAU,CAAC,EAAGA,EAAI,OAAQA,EAAI,WAAYA,EAAI,KAAMA,EAAI,KAAMA,EAAI,OAAO,CAAC,CACxF,CACA,SAASJ,EAAaV,EAAO,CAC3B,IAAIe,EAAYC,EAAOZ,EAAY,OAAOS,EAAeb,CAAK,CAAC,CAAC,EAChE,OAAOQ,EAAWO,CAAS,CAC7B,CACA,IAAIE,EAAI,IAAIZ,EACRa,EAAoBD,EAAE,kBACtBE,EAAeF,EAAE,aACjBG,EAAgBH,EAAE,cACJA,EAAE","x_google_ignoreList":[0]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-C1r1Zw8r.js","sources":["../../src/common/theme.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\nimport { Theme } from './types';\nimport { checkmarkIcon, nostrLogo } from './icons';\n\nexport function getNostrLogo(width: number = 21, height: number = 24) {\n return nostrLogo(width, height);\n}\n\nimport { loadingNostrich } from './icons';\n\nexport function getLoadingNostrich(){\n return loadingNostrich();\n}\n\nexport function getSuccessAnimation(theme: Theme = 'dark') {\n return checkmarkIcon(theme);\n}"],"names":["getNostrLogo","width","height","nostrLogo","getLoadingNostrich","loadingNostrich","getSuccessAnimation","theme","checkmarkIcon"],"mappings":"sDAKO,SAASA,EAAaC,EAAgB,GAAIC,EAAiB,GAAI,CAC7D,OAAAC,EAAUF,EAAOC,CAAM,CAChC,CAIO,SAASE,GAAoB,CAClC,OAAOC,EAAgB,CACzB,CAEgB,SAAAC,EAAoBC,EAAe,OAAQ,CACzD,OAAOC,EAAcD,CAAK,CAC5B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{i as o,v as a,b as l}from"./base-styles-CBypR3FR.js";class u{constructor(r){this.nostrService=r}validateInputs({npub:r,pubkey:e,nip05:i}){return!r&&!e&&!i?"Provide npub, nip05 or pubkey attribute":e&&!o(e)?`Invalid Pubkey: ${e}`:i&&!a(i)?`Invalid Nip05: ${i}`:r&&!l(r)?`Invalid Npub: ${r}`:null}async resolveUser({npub:r,pubkey:e,nip05:i}){const t=await this.nostrService.resolveNDKUser({npub:r,pubkey:e,nip05:i});if(!t)throw new Error("Unable to resolve user from provided identifier");const s=await this.nostrService.getProfile(t);return{user:t,profile:s??null}}}export{u as U};
|
|
2
|
+
//# sourceMappingURL=user-resolver-C-E6KdwY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-resolver-C-E6KdwY.js","sources":["../../src/base/resolvers/user-resolver.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\nimport { NDKUser, NDKUserProfile } from '@nostr-dev-kit/ndk';\nimport { NostrService } from '../../common/nostr-service';\nimport { isValidHex, validateNpub, validateNip05 } from '../../common/utils'\n\nexport class UserResolver {\n constructor(private nostrService: NostrService) { }\n\n validateInputs({ npub, pubkey, nip05 }: { npub?: string | null; pubkey?: string | null; nip05?: string | null }): string | null {\n if (!npub && !pubkey && !nip05) {\n return \"Provide npub, nip05 or pubkey attribute\";\n }\n if (pubkey && !isValidHex(pubkey)) return `Invalid Pubkey: ${pubkey}`;\n if (nip05 && !validateNip05(nip05)) return `Invalid Nip05: ${nip05}`;\n if (npub && !validateNpub(npub)) return `Invalid Npub: ${npub}`;\n return null;\n }\n\n async resolveUser({ npub, pubkey, nip05 }: { npub?: string | null; pubkey?: string | null; nip05?: string | null }): Promise<{ user: NDKUser, profile: NDKUserProfile | null }> {\n const user = await this.nostrService.resolveNDKUser({ npub, pubkey, nip05 });\n if (!user) throw new Error(\"Unable to resolve user from provided identifier\");\n\n const profile = await this.nostrService.getProfile(user);\n\n return { user, profile: profile ?? null };\n }\n}\n"],"names":["UserResolver","nostrService","npub","pubkey","nip05","isValidHex","validateNip05","validateNpub","user","profile"],"mappings":"4DAMO,MAAMA,CAAa,CACxB,YAAoBC,EAA4B,CAA5B,KAAA,aAAAA,CAAA,CAEpB,eAAe,CAAE,KAAAC,EAAM,OAAAC,EAAQ,MAAAC,GAAiG,CAC9H,MAAI,CAACF,GAAQ,CAACC,GAAU,CAACC,EAChB,0CAELD,GAAU,CAACE,EAAWF,CAAM,EAAU,mBAAmBA,CAAM,GAC/DC,GAAS,CAACE,EAAcF,CAAK,EAAU,kBAAkBA,CAAK,GAC9DF,GAAQ,CAACK,EAAaL,CAAI,EAAU,iBAAiBA,CAAI,GACtD,IAAA,CAGT,MAAM,YAAY,CAAE,KAAAA,EAAM,OAAAC,EAAQ,MAAAC,GAA8I,CACxK,MAAAI,EAAO,MAAM,KAAK,aAAa,eAAe,CAAE,KAAAN,EAAM,OAAAC,EAAQ,MAAAC,EAAO,EAC3E,GAAI,CAACI,EAAY,MAAA,IAAI,MAAM,iDAAiD,EAE5E,MAAMC,EAAU,MAAM,KAAK,aAAa,WAAWD,CAAI,EAEvD,MAAO,CAAE,KAAAA,EAAM,QAASC,GAAW,IAAK,CAAA,CAE5C"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function t(e){try{const r=new URL(e);return r.origin.replace("://m.","://").replace("://mobile.","://").replace("http://","https://").replace(/:\d+/,n=>n===":443"||n===":80"?"":n)+r.pathname.replace(/\/+/g,"/").replace(/\/*$/,"")}catch{return console.error("Invalid URL:",e),e}}function a(e){return/^[a-f0-9]{64}$/.test(e)}export{a as i,t as n};
|
|
2
|
+
//# sourceMappingURL=utils--bxLbhGF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils--bxLbhGF.js","sources":["../../src/nostr-comment/utils.ts"],"sourcesContent":["import { NDKEvent } from '@nostr-dev-kit/ndk';\n\nexport interface CommentEvent {\n id: string;\n pubkey: string;\n content: string;\n created_at: number;\n tags: string[][];\n sig: string;\n}\n\nexport interface ParsedComment {\n id: string;\n pubkey: string;\n content: string;\n created_at: number;\n replyTo?: string;\n rootUrl?: string;\n}\n\n/**\n * Normalize URL for consistent comment identification\n */\nexport function normalizeURL(raw: string): string {\n try {\n const url = new URL(raw);\n return (\n url.origin\n .replace('://m.', '://') // remove known 'mobile' subdomains\n .replace('://mobile.', '://')\n .replace('http://', 'https://') // default everything to https\n .replace(\n /:\\d+/,\n // remove 443 and 80 ports\n port => (port === ':443' || port === ':80' ? '' : port)\n ) +\n url.pathname\n .replace(/\\/+/g, '/') // remove duplicated slashes in the middle of the path\n .replace(/\\/*$/, '') // remove slashes from the end of path\n );\n } catch (error) {\n console.error('Invalid URL:', raw);\n return raw;\n }\n}\n\n/**\n * Parse Nostr event into comment structure\n */\nexport function parseCommentEvent(event: NDKEvent): ParsedComment | null {\n if (!event.id || !event.pubkey || !event.content || !event.created_at) {\n return null;\n }\n\n const comment: ParsedComment = {\n id: event.id,\n pubkey: event.pubkey,\n content: event.content,\n created_at: event.created_at\n };\n\n // Parse tags to find references\n for (const tag of event.tags || []) {\n if (tag[0] === 'I' && tag[1]) {\n comment.rootUrl = tag[1];\n } else if (tag[0] === 'e' && tag[1]) {\n comment.replyTo = tag[1];\n }\n }\n\n return comment;\n}\n\n/**\n * Create a comment event for publishing\n */\nexport function createCommentEvent(\n content: string,\n pubkey: string,\n url: string,\n replyTo?: string\n): Omit<CommentEvent, 'id' | 'sig'> {\n const tags: string[][] = [\n ['I', url], // URL reference\n ['client', 'nostr-components']\n ];\n\n if (replyTo) {\n tags.push(['e', replyTo, '', 'reply']);\n }\n\n return {\n pubkey,\n content: content.trim(),\n created_at: Math.floor(Date.now() / 1000),\n tags\n };\n}\n\n/**\n * Validate if a string is a valid Nostr public key\n */\nexport function isValidPublicKey(pubkey: string): boolean {\n return /^[a-f0-9]{64}$/.test(pubkey);\n}\n\n/**\n * Validate if a string is a valid Nostr event ID\n */\nexport function isValidEventId(eventId: string): boolean {\n return /^[a-f0-9]{64}$/.test(eventId);\n}\n\n/**\n * Truncate public key for display\n */\nexport function truncatePublicKey(pubkey: string, length: number = 8): string {\n if (pubkey.length <= length * 2) return pubkey;\n return `${pubkey.slice(0, length)}...${pubkey.slice(-length)}`;\n}\n\n/**\n * Format timestamp to relative time\n */\nexport function formatRelativeTime(timestamp: number): string {\n const now = Date.now() / 1000;\n const diff = now - timestamp;\n\n if (diff < 60) return 'just now';\n if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;\n if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;\n if (diff < 2592000) return `${Math.floor(diff / 86400)}d ago`;\n\n const date = new Date(timestamp * 1000);\n return date.toLocaleDateString();\n}\n\n/**\n * Sanitize HTML content to prevent XSS\n */\nexport function sanitizeContent(content: string): string {\n return content\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Parse URLs in content and make them clickable\n */\nexport function linkifyContent(content: string): string {\n const urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n return sanitizeContent(content).replace(urlRegex, '<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>');\n}\n\n/**\n * Generate a simple hash for content deduplication\n */\nexport function hashContent(content: string, pubkey: string): string {\n const combined = content + pubkey;\n let hash = 0;\n for (let i = 0; i < combined.length; i++) {\n const char = combined.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return Math.abs(hash).toString(36);\n}\n\n/**\n * Check if user has a Nostr extension (NIP-07)\n */\nexport function hasNostrExtension(): boolean {\n return typeof (window as any).nostr !== 'undefined';\n}\n\n/**\n * Get stored private key from localStorage\n */\nexport function getStoredPrivateKey(): string | null {\n try {\n const key = localStorage.getItem('nostr-comment-private-key');\n if (key && isValidPrivateKey(key)) {\n return key;\n }\n } catch (error) {\n console.warn('Failed to access localStorage:', error);\n }\n return null;\n}\n\n/**\n * Store private key in localStorage\n */\nexport function storePrivateKey(privateKey: string): boolean {\n try {\n if (isValidPrivateKey(privateKey)) {\n localStorage.setItem('nostr-comment-private-key', privateKey);\n return true;\n }\n } catch (error) {\n console.warn('Failed to store private key:', error);\n }\n return false;\n}\n\n/**\n * Validate if a string is a valid private key\n */\nexport function isValidPrivateKey(privateKey: string): boolean {\n return /^[a-f0-9]{64}$/.test(privateKey);\n}\n\n/**\n * Clear stored private key (for logout functionality)\n */\nexport function clearStoredPrivateKey(): void {\n try {\n localStorage.removeItem('nostr-comment-private-key');\n } catch (error) {\n console.warn('Failed to clear stored private key:', error);\n }\n}\n\n/**\n * Debounce function for rate limiting\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n return (...args: Parameters<T>) => {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => func(...args), wait);\n };\n}\n"],"names":["normalizeURL","raw","url","port","isValidPublicKey","pubkey"],"mappings":"AAuBO,SAASA,EAAaC,EAAqB,CAC1C,GAAA,CACM,MAAAC,EAAM,IAAI,IAAID,CAAG,EACvB,OACIC,EAAI,OACC,QAAQ,QAAS,KAAK,EACtB,QAAQ,aAAc,KAAK,EAC3B,QAAQ,UAAW,UAAU,EAC7B,QACG,OAESC,GAAAA,IAAS,QAAUA,IAAS,MAAQ,GAAKA,CAAA,EAE1DD,EAAI,SACC,QAAQ,OAAQ,GAAG,EACnB,QAAQ,OAAQ,EAAE,OAEf,CACJ,eAAA,MAAM,eAAgBD,CAAG,EAC1BA,CAAA,CAEf,CA0DO,SAASG,EAAiBC,EAAyB,CAC/C,MAAA,iBAAiB,KAAKA,CAAM,CACvC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{S as E,n as N,f as P}from"./nostr-service-pr_crY62.js";import{n as k}from"./utils--bxLbhGF.js";const m={},$=async t=>{if(m[t])return m[t];const n=new E,e=["wss://relay.nostr.band","wss://purplepag.es","wss://relay.damus.io","wss://nostr.wine"];try{const a=await n.get(e,{authors:[t],kinds:[0]});return m[t]=a,a}finally{n.close(e)}},O=async t=>{const n=t.filter(r=>!m[r]);if(n.length===0)return t.map(r=>({id:r,profile:m[r]}));const e=new E,a=["wss://relay.nostr.band","wss://purplepag.es","wss://relay.damus.io","wss://nostr.wine"];try{return(await e.querySync(a,{authors:n,kinds:[0]})).forEach(o=>{m[o.pubkey]=o}),t.map(o=>({id:o,profile:m[o]||null}))}finally{e.close(a)}},x=t=>{try{return JSON.parse((t==null?void 0:t.content)||"{}")}catch{return{}}},z=async t=>{const n=await N.getZapEndpoint(t);if(!n)throw new Error("Failed to retrieve zap LNURL");return n},S=async(t,n)=>{if(R())try{const e=window.nostr;if(e!=null&&e.signEvent)return await e.signEvent(t)}catch{}return P(t,C())},Z=async({profile:t,nip19Target:n,amount:e,relays:a,comment:r,anon:c,url:o})=>{const p={profile:t,amount:e,relays:a,comment:r||""},i=N.makeZapRequest(p);return o&&(i.tags.push(["k","web"]),i.tags.push(["i",k(o)])),(!R()||c)&&i.tags.push(["anon"]),S(i)},D=async({zapEndpoint:t,amount:n,comment:e,authorId:a,nip19Target:r,normalizedRelays:c,anon:o,url:p})=>{const i=await Z({profile:a,nip19Target:r,amount:n,relays:c,comment:e??"",anon:o,url:p});let d=`${t}?amount=${n}&nostr=${encodeURIComponent(JSON.stringify(i))}`;e&&(d+=`&comment=${encodeURIComponent(e??"")}`);const l=await fetch(d,{method:"GET"});if(!l.ok)throw new Error(`LNURL request failed: ${l.status} ${l.statusText}`);let u;try{u=await l.json()}catch{throw new Error("Invalid JSON from LNURL endpoint")}const{pr:h,reason:v,status:g}=u||{};if(h)return h;throw g==="ERROR"?new Error(v??"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 n=0;n<32;n++)t[n]=Math.floor(Math.random()*256)}return t},R=()=>typeof window<"u"&&!!window.nostr,J=async({pubkey:t,relays:n,url:e})=>{var p,i,d,l;const a=e?k(e):void 0,r=new E;let c=0;const o=[];try{const u={kinds:[9735],"#p":[t],limit:1e3},h=await r.querySync(n,u);for(const v of h){const g=(p=v.tags)==null?void 0:p.find(s=>s[0]==="description");if(g!=null&&g[1])try{const s=JSON.parse(g[1]),w=(i=s==null?void 0:s.tags)==null?void 0:i.find(f=>f[0]==="amount");if(a){const f=(d=s==null?void 0:s.tags)==null?void 0:d.find(y=>y[0]==="k"),b=(l=s==null?void 0:s.tags)==null?void 0:l.find(y=>y[0]==="i"),U=b!=null&&b[1]?k(b[1]):"";if((f==null?void 0:f[1])==="web"&&U===a&&(w!=null&&w[1])){const y=parseInt(w[1],10);y>0&&(c+=y,o.push({amount:y/1e3,date:new Date(v.created_at*1e3),authorPubkey:s.pubkey,comment:s.content}))}}else if(w!=null&&w[1]){const f=parseInt(w[1],10);f>0&&(c+=f,o.push({amount:f/1e3,date:new Date(v.created_at*1e3),authorPubkey:s.pubkey,comment:s.content}))}}catch(s){console.error("Nostr-Components: Zap button: Could not parse zap request from description tag",s)}}}catch(u){console.error("Nostr-Components: Zap button: Error fetching zap receipts",u)}finally{r.close(n)}return o.sort((u,h)=>h.date.getTime()-u.date.getTime()),{totalAmount:c/1e3,zapDetails:o}},M=({relays:t,receiversPubKey:n,invoice:e,onSuccess:a})=>{const r=new E,c=Array.from(new Set([...t,"wss://relay.nostr.band"])),o=Math.floor((Date.now()-24*60*60*1e3)/1e3);r.subscribe(c,{kinds:[9735],"#p":[n],since:o},{onevent(i){i.tags.some(l=>l[0]==="bolt11"&&l[1]===e)&&(a(),p())}});const p=()=>{r.close(c)};return p};export{x as extractProfileMetadataContent,D as fetchInvoice,J as fetchTotalZapAmount,O as getBatchedProfileMetadata,$ as getProfileMetadata,z as getZapEndpoint,R as isNip07ExtAvailable,M as listenForZapReceipt};
|
|
2
|
+
//# sourceMappingURL=zap-utils-B1sz0Abx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zap-utils-B1sz0Abx.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';\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 (isNip07ExtAvailable() && !anon) {\n try {\n const ext = (window as { nostr?: NostrExtension }).nostr;\n if (ext?.signEvent) return await ext.signEvent(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 if (!isNip07ExtAvailable() || 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\nexport const isNip07ExtAvailable = (): boolean => typeof window !== 'undefined' && !!(window as any).nostr;\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","isNip07ExtAvailable","ext","finalizeEvent","generateRandomPrivKey","makeZapEvent","profile","nip19Target","amount","comment","url","req","normalizeURL","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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"}
|