lint fix wip

This commit is contained in:
Nicolas Cantu 2026-01-09 01:01:04 +01:00
parent 899c20631a
commit f471fa3d31
9 changed files with 103 additions and 74 deletions

View File

@ -36,7 +36,7 @@ export function ArticleEditor({ onPublishSuccess, onCancel, seriesOptions, onSel
const submit = buildSubmitHandler({
publishArticle,
draft,
onPublishSuccess,
...(onPublishSuccess ? { onPublishSuccess } : {}),
connect,
connected,
})

View File

@ -123,7 +123,7 @@ export function ConnectButton(): React.ReactElement {
})
if (mode === 'connected') {
return <ConnectedState pubkey={pubkey} profile={profile} loading={loading} disconnect={disconnect} />
return <ConnectedState pubkey={requirePubkey(pubkey)} profile={profile} loading={loading} disconnect={disconnect} />
}
if (mode === 'unlock_required') {
@ -146,3 +146,12 @@ export function ConnectButton(): React.ReactElement {
</>
)
}
function requirePubkey(pubkey: string | null): string {
if (!pubkey) {
const error = new Error('Invariant violation: pubkey is required when ConnectButton mode is "connected"')
console.error(error.message, { pubkey })
throw error
}
return pubkey
}

View File

@ -7,7 +7,7 @@ import type { ReviewFormProps } from './reviewForms/reviewFormTypes'
export function ReviewForm({ article, onSuccess, onCancel }: ReviewFormProps): React.ReactElement {
const { pubkey, connect } = useNostrAuth()
const ctrl = useReviewFormController({ article, pubkey, onSuccess })
const ctrl = useReviewFormController({ article, pubkey, ...(onSuccess ? { onSuccess } : {}) })
if (!pubkey) {
return (
@ -20,5 +20,5 @@ export function ReviewForm({ article, onSuccess, onCancel }: ReviewFormProps): R
)
}
return <ReviewFormView ctrl={ctrl} onCancel={onCancel} />
return <ReviewFormView ctrl={ctrl} {...(onCancel ? { onCancel } : {})} />
}

View File

@ -7,7 +7,7 @@ import type { ReviewTipFormProps } from './reviewForms/reviewFormTypes'
export function ReviewTipForm({ review, article, onSuccess, onCancel }: ReviewTipFormProps): React.ReactElement {
const { pubkey, connect } = useNostrAuth()
const ctrl = useReviewTipFormController({ review, article, pubkey, onSuccess })
const ctrl = useReviewTipFormController({ review, article, pubkey, ...(onSuccess ? { onSuccess } : {}) })
if (!pubkey) {
return (
@ -19,5 +19,5 @@ export function ReviewTipForm({ review, article, onSuccess, onCancel }: ReviewTi
/>
)
}
return <ReviewTipFormView ctrl={ctrl} onCancel={onCancel} />
return <ReviewTipFormView ctrl={ctrl} {...(onCancel ? { onCancel } : {})} />
}

View File

@ -37,7 +37,7 @@ export function useReviewFormController(params: {
setLoading,
setError,
reset: () => resetFields({ setContent, setTitle, setText }),
onSuccess: params.onSuccess,
...(params.onSuccess ? { onSuccess: params.onSuccess } : {}),
})
return {
@ -67,7 +67,8 @@ function buildReviewSubmitHandler(params: {
}): (e: React.FormEvent) => Promise<void> {
return async (e: React.FormEvent): Promise<void> => {
e.preventDefault()
if (!params.pubkey) {
const pubkey = params.pubkey
if (!pubkey) {
return
}
const contentError = validateRequiredContent(params.content)
@ -75,7 +76,7 @@ function buildReviewSubmitHandler(params: {
params.setError(contentError)
return
}
await submitReview(params)
await submitReview({ ...params, pubkey })
}
}

View File

@ -3,6 +3,7 @@ import { articlePublisher } from '@/lib/articlePublisher'
import { nostrService } from '@/lib/nostr'
import type { ArticleDraft } from '@/lib/articlePublisher'
import type { RelayPublishStatus } from '@/lib/publishResult'
import type { PublishedArticle } from '@/lib/articlePublisherTypes'
interface UseArticlePublishingState {
loading: boolean
@ -83,7 +84,7 @@ function buildPublishArticleHandler(params: {
}
function handlePublishResult(params: {
result: { success: boolean; relayStatuses?: RelayPublishStatus[]; articleId: string | null; error?: string | undefined }
result: PublishedArticle
setSuccess: (success: boolean) => void
setRelayStatuses: (statuses: RelayPublishStatus[]) => void
setError: (error: string | null) => void
@ -91,7 +92,7 @@ function handlePublishResult(params: {
if (params.result.success) {
params.setSuccess(true)
params.setRelayStatuses(params.result.relayStatuses ?? [])
return params.result.articleId
return params.result.articleId ? params.result.articleId : null
}
params.setError(params.result.error ?? 'Failed to publish article')

View File

@ -77,7 +77,13 @@ export class ArticlePublisher {
return buildFailure('Presentation not found')
}
return encryptAndPublish(draft, authorPubkey, validation.authorPrivateKeyForEncryption, validation.category, presentation.id)
return encryptAndPublish({
draft,
authorPubkey,
authorPrivateKeyForEncryption: validation.authorPrivateKeyForEncryption,
category: validation.category,
presentationId: presentation.id,
})
} catch (error) {
console.error('Error publishing article:', error)
return buildFailure(error instanceof Error ? error.message : 'Unknown error')

View File

@ -23,77 +23,78 @@ export function createMessageVerificationFilters(messageEventId: string, authorP
]
}
interface MessageVerificationContext {
messageEventId: string
articleId: string
recipientPubkey: string
authorPubkey: string
}
export function handleMessageVerificationEvent(
event: import('nostr-tools').Event,
articleId: string,
recipientPubkey: string,
authorPubkey: string,
ctx: MessageVerificationContext,
finalize: (value: boolean) => void
): void {
console.warn('Private message verified on relay', {
messageEventId: event.id,
articleId,
recipientPubkey,
authorPubkey,
articleId: ctx.articleId,
recipientPubkey: ctx.recipientPubkey,
authorPubkey: ctx.authorPubkey,
timestamp: new Date().toISOString(),
})
finalize(true)
}
export function setupMessageVerificationHandlers(
sub: import('@/types/nostr-tools-extended').Subscription,
messageEventId: string,
articleId: string,
recipientPubkey: string,
authorPubkey: string,
finalize: (value: boolean) => void,
params: {
sub: import('@/types/nostr-tools-extended').Subscription
ctx: MessageVerificationContext
finalize: (value: boolean) => void
isResolved: () => boolean
}
): void {
sub.on('event', (event: Event): void => {
handleMessageVerificationEvent(event, articleId, recipientPubkey, authorPubkey, finalize)
params.sub.on('event', (event: Event): void => {
handleMessageVerificationEvent(event, params.ctx, params.finalize)
})
sub.on('eose', (): void => {
params.sub.on('eose', (): void => {
console.warn('Private message not found on relay after EOSE', {
messageEventId,
articleId,
recipientPubkey,
messageEventId: params.ctx.messageEventId,
articleId: params.ctx.articleId,
recipientPubkey: params.ctx.recipientPubkey,
timestamp: new Date().toISOString(),
})
finalize(false)
params.finalize(false)
})
setTimeout(() => {
if (!isResolved()) {
if (!params.isResolved()) {
console.warn('Timeout verifying private message on relay', {
messageEventId,
articleId,
recipientPubkey,
messageEventId: params.ctx.messageEventId,
articleId: params.ctx.articleId,
recipientPubkey: params.ctx.recipientPubkey,
timestamp: new Date().toISOString(),
})
finalize(false)
params.finalize(false)
}
}, 5000)
}
function createMessageVerificationSubscription(
pool: import('nostr-tools').SimplePool,
messageEventId: string,
authorPubkey: string,
recipientPubkey: string,
articleId: string
params: { pool: import('nostr-tools').SimplePool; ctx: MessageVerificationContext }
): ReturnType<typeof createSubscription> {
const filters = createMessageVerificationFilters(messageEventId, authorPubkey, recipientPubkey, articleId)
const filters = createMessageVerificationFilters(
params.ctx.messageEventId,
params.ctx.authorPubkey,
params.ctx.recipientPubkey,
params.ctx.articleId
)
const relayUrl = getPrimaryRelaySync()
return createSubscription(pool, [relayUrl], filters)
return createSubscription(params.pool, [relayUrl], filters)
}
function createVerificationPromise(
sub: import('@/types/nostr-tools-extended').Subscription,
messageEventId: string,
articleId: string,
recipientPubkey: string,
authorPubkey: string
params: { sub: import('@/types/nostr-tools-extended').Subscription; ctx: MessageVerificationContext }
): Promise<boolean> {
return new Promise<boolean>((resolve) => {
let resolved = false
@ -103,11 +104,11 @@ function createVerificationPromise(
return
}
resolved = true
sub.unsub()
params.sub.unsub()
resolve(value)
}
setupMessageVerificationHandlers(sub, messageEventId, articleId, recipientPubkey, authorPubkey, finalize, () => resolved)
setupMessageVerificationHandlers({ sub: params.sub, ctx: params.ctx, finalize, isResolved: () => resolved })
})
}
@ -128,15 +129,9 @@ export function verifyPrivateMessagePublished(
return Promise.resolve(false)
}
const sub = createMessageVerificationSubscription(
pool,
messageEventId,
authorPubkey,
recipientPubkey,
articleId
)
return createVerificationPromise(sub, messageEventId, articleId, recipientPubkey, authorPubkey)
const ctx: MessageVerificationContext = { messageEventId, articleId, recipientPubkey, authorPubkey }
const sub = createMessageVerificationSubscription({ pool, ctx })
return createVerificationPromise({ sub, ctx })
} catch (error) {
console.error('Error verifying private message', {
messageEventId,

View File

@ -77,16 +77,21 @@ async function buildParsedArticleFromDraft(
return { article, hash, version, index }
}
export async function publishPreview(
draft: ArticleDraft,
invoice: AlbyInvoice,
authorPubkey: string,
presentationId: string,
extraTags?: string[][],
encryptedContent?: string,
encryptedKey?: string,
interface PublishPreviewParams {
draft: ArticleDraft
invoice: AlbyInvoice
authorPubkey: string
presentationId: string
extraTags?: string[][]
encryptedContent?: string
encryptedKey?: string
returnStatus?: boolean
}
export async function publishPreview(
params: PublishPreviewParams
): Promise<import('nostr-tools').Event | null | PublishResult> {
const { draft, invoice, authorPubkey, presentationId, extraTags, encryptedContent, encryptedKey, returnStatus } = params
// Build parsed article object
const { article, hash, version, index } = await buildParsedArticleFromDraft(draft, invoice, authorPubkey)
@ -158,17 +163,29 @@ export function buildArticleExtraTags(draft: ArticleDraft, _category: NonNullabl
}
export async function encryptAndPublish(
draft: ArticleDraft,
authorPubkey: string,
authorPrivateKeyForEncryption: string,
category: NonNullable<ArticleDraft['category']>,
params: {
draft: ArticleDraft
authorPubkey: string
authorPrivateKeyForEncryption: string
category: NonNullable<ArticleDraft['category']>
presentationId: string
}
): Promise<PublishedArticle> {
const { draft, authorPubkey, authorPrivateKeyForEncryption, category, presentationId } = params
const { encryptedContent, key, iv } = await encryptArticleContent(draft.content)
const encryptedKey = await encryptDecryptionKey(key, iv, authorPrivateKeyForEncryption, authorPubkey)
const invoice = await createArticleInvoice(draft)
const extraTags = buildArticleExtraTags(draft, category)
const publishResult = await publishPreview(draft, invoice, authorPubkey, presentationId, extraTags, encryptedContent, encryptedKey, true)
const publishResult = await publishPreview({
draft,
invoice,
authorPubkey,
presentationId,
extraTags,
encryptedContent,
encryptedKey,
returnStatus: true,
})
if (!publishResult) {
return buildFailure('Failed to publish article')