From ccf2fdf759c2e859061d01f7eabf084263f190bc Mon Sep 17 00:00:00 2001 From: Nicolas Cantu Date: Tue, 6 Jan 2026 16:10:08 +0100 Subject: [PATCH] lint fix wip --- components/LanguageSelector.tsx | 4 +- components/LanguageSettingsManager.tsx | 4 +- lib/nostrSubscription.ts | 2 +- lib/nostrTagSystemBuild.ts | 2 +- lib/nostrTagSystemExtract.ts | 54 +++++++++++++++++--------- lib/objectCache.ts | 14 +++---- lib/paymentNotes.ts | 4 +- lib/paymentPollingMain.ts | 7 ++-- lib/purchaseQueries.ts | 3 ++ lib/reviewTipQueries.ts | 4 ++ lib/sponsoringQueries.ts | 4 ++ lib/storage/cryptoHelpers.ts | 14 +++---- lib/storage/indexedDB.ts | 2 +- pages/_app.tsx | 2 +- scripts/lint.js | 5 +-- 15 files changed, 77 insertions(+), 48 deletions(-) diff --git a/components/LanguageSelector.tsx b/components/LanguageSelector.tsx index 3ec3031..fe39e4c 100644 --- a/components/LanguageSelector.tsx +++ b/components/LanguageSelector.tsx @@ -34,7 +34,7 @@ export function LanguageSelector(): React.ReactElement { const loadLocale = (): void => { try { if (typeof window !== 'undefined') { - const savedLocale = localStorage.getItem(LOCALE_STORAGE_KEY) as Locale | null + const savedLocale = window.localStorage.getItem(LOCALE_STORAGE_KEY) as Locale | null if (savedLocale && (savedLocale === 'fr' || savedLocale === 'en')) { setLocale(savedLocale) setCurrentLocale(savedLocale) @@ -52,7 +52,7 @@ export function LanguageSelector(): React.ReactElement { setCurrentLocale(locale) try { if (typeof window !== 'undefined') { - localStorage.setItem(LOCALE_STORAGE_KEY, locale) + window.localStorage.setItem(LOCALE_STORAGE_KEY, locale) } } catch (e) { console.error('Error saving locale:', e) diff --git a/components/LanguageSettingsManager.tsx b/components/LanguageSettingsManager.tsx index e7fa2c0..9fd9c1a 100644 --- a/components/LanguageSettingsManager.tsx +++ b/components/LanguageSettingsManager.tsx @@ -38,7 +38,7 @@ export function LanguageSettingsManager(): React.ReactElement { setLoading(false) return } - const savedLocale = localStorage.getItem(LOCALE_STORAGE_KEY) as Locale | null + const savedLocale = window.localStorage.getItem(LOCALE_STORAGE_KEY) as Locale | null if (savedLocale && (savedLocale === 'fr' || savedLocale === 'en')) { setLocale(savedLocale) setCurrentLocale(savedLocale) @@ -57,7 +57,7 @@ export function LanguageSettingsManager(): React.ReactElement { setCurrentLocale(locale) try { if (typeof window !== 'undefined') { - localStorage.setItem(LOCALE_STORAGE_KEY, locale) + window.localStorage.setItem(LOCALE_STORAGE_KEY, locale) } } catch (e) { console.error('Error saving locale:', e) diff --git a/lib/nostrSubscription.ts b/lib/nostrSubscription.ts index 74dcb7c..d48851e 100644 --- a/lib/nostrSubscription.ts +++ b/lib/nostrSubscription.ts @@ -17,7 +17,7 @@ export function subscribeWithTimeout( const resolved = { value: false } const relayUrl = getPrimaryRelaySync() const sub = createSubscription(pool, [relayUrl], filters) - let timeoutId: NodeJS.Timeout | null = null + let timeoutId: ReturnType | null = null const cleanup = (): void => { if (timeoutId) { diff --git a/lib/nostrTagSystemBuild.ts b/lib/nostrTagSystemBuild.ts index abf0a70..6a31963 100644 --- a/lib/nostrTagSystemBuild.ts +++ b/lib/nostrTagSystemBuild.ts @@ -1,6 +1,6 @@ import type { AuthorTags, SeriesTags, PublicationTags, QuoteTags, PaymentTags } from './nostrTagSystemTypes' -function buildBaseTags(tags: AuthorTags | SeriesTags | PublicationTags | QuoteTags): string[][] { +function buildBaseTags(tags: AuthorTags | SeriesTags | PublicationTags | QuoteTags | PaymentTags): string[][] { const result: string[][] = [] result.push([tags.type]) result.push([tags.category]) diff --git a/lib/nostrTagSystemExtract.ts b/lib/nostrTagSystemExtract.ts index 337ae12..0b40f51 100644 --- a/lib/nostrTagSystemExtract.ts +++ b/lib/nostrTagSystemExtract.ts @@ -42,29 +42,47 @@ export function extractCommonTags(findTag: (key: string) => string | undefined, reviewerPubkey?: string json?: string } { + const id = findTag('id') + const service = findTag('service') + const title = findTag('title') + const preview = findTag('preview') + const description = findTag('description') + const mainnetAddress = findTag('mainnet_address') + const totalSponsoring = parseNumericTag(findTag, 'total_sponsoring') + const pictureUrl = findTag('picture') + const seriesId = findTag('series') + const coverUrl = findTag('cover') + const bannerUrl = findTag('banner') + const zapAmount = parseNumericTag(findTag, 'zap') + const invoice = findTag('invoice') + const paymentHash = findTag('payment_hash') + const encryptedKey = findTag('encrypted_key') + const articleId = findTag('article') + const reviewerPubkey = findTag('reviewer') + const json = findTag('json') return { - id: findTag('id'), - service: findTag('service'), + ...(id ? { id } : {}), + ...(service ? { service } : {}), version: parseNumericTag(findTag, 'version') ?? 0, // Default to 0 if not present hidden: findTag('hidden') === 'true', // true only if tag exists and value is 'true' paywall: hasTag('paywall'), payment: hasTag('payment'), - title: findTag('title'), - preview: findTag('preview'), - description: findTag('description'), - mainnetAddress: findTag('mainnet_address'), - totalSponsoring: parseNumericTag(findTag, 'total_sponsoring'), - pictureUrl: findTag('picture'), - seriesId: findTag('series'), - coverUrl: findTag('cover'), - bannerUrl: findTag('banner'), - zapAmount: parseNumericTag(findTag, 'zap'), - invoice: findTag('invoice'), - paymentHash: findTag('payment_hash'), - encryptedKey: findTag('encrypted_key'), - articleId: findTag('article'), - reviewerPubkey: findTag('reviewer'), - json: findTag('json'), // JSON metadata stored in tag (for all object types) + ...(title ? { title } : {}), + ...(preview ? { preview } : {}), + ...(description ? { description } : {}), + ...(mainnetAddress ? { mainnetAddress } : {}), + ...(totalSponsoring !== undefined ? { totalSponsoring } : {}), + ...(pictureUrl ? { pictureUrl } : {}), + ...(seriesId ? { seriesId } : {}), + ...(coverUrl ? { coverUrl } : {}), + ...(bannerUrl ? { bannerUrl } : {}), + ...(zapAmount !== undefined ? { zapAmount } : {}), + ...(invoice ? { invoice } : {}), + ...(paymentHash ? { paymentHash } : {}), + ...(encryptedKey ? { encryptedKey } : {}), + ...(articleId ? { articleId } : {}), + ...(reviewerPubkey ? { reviewerPubkey } : {}), + ...(json ? { json } : {}), } } diff --git a/lib/objectCache.ts b/lib/objectCache.ts index 18456ff..5cf9c0f 100644 --- a/lib/objectCache.ts +++ b/lib/objectCache.ts @@ -4,7 +4,7 @@ * One database per object type */ -import type { Event } from 'nostr-tools' +import type { Event as NostrEvent } from 'nostr-tools' import type { AuthorPresentationArticle } from '@/types/nostr' import { buildObjectId } from './urlGenerator' @@ -15,7 +15,7 @@ interface CachedObject { hash: string // SHA-256 hash of the object hashId: string // Legacy field for backward compatibility index: number // Index for duplicates - event: Event + event: NostrEvent parsed: unknown // Parsed object (AuthorPresentationArticle, Series, etc.) version: number hidden: boolean @@ -41,7 +41,7 @@ class ObjectCacheService { } const dbName = `${DB_PREFIX}${objectType}` - const request = indexedDB.open(dbName, DB_VERSION) + const request = window.indexedDB.open(dbName, DB_VERSION) request.onerror = (): void => { reject(new Error(`Failed to open IndexedDB: ${request.error}`)) @@ -112,7 +112,7 @@ class ObjectCacheService { async set( objectType: ObjectType, hash: string, - event: Event, + event: NostrEvent, parsed: unknown, version: number, hidden: boolean, @@ -175,7 +175,7 @@ class ObjectCacheService { const request = hashIndex.openCursor(IDBKeyRange.only(hash)) const objects: CachedObject[] = [] - request.onsuccess = (event: Event): void => { + request.onsuccess = (event: globalThis.Event): void => { const cursor = (event.target as IDBRequest).result if (cursor) { const obj = cursor.value as CachedObject @@ -246,7 +246,7 @@ class ObjectCacheService { const request = store.openCursor() const objects: CachedObject[] = [] - request.onsuccess = (event: Event): void => { + request.onsuccess = (event: globalThis.Event): void => { const cursor = (event.target as IDBRequest).result if (cursor) { const obj = cursor.value as CachedObject @@ -288,7 +288,7 @@ class ObjectCacheService { const request = store.openCursor() const objects: unknown[] = [] - request.onsuccess = (event: Event): void => { + request.onsuccess = (event: globalThis.Event): void => { const cursor = (event.target as IDBRequest).result if (cursor) { const obj = cursor.value as CachedObject diff --git a/lib/paymentNotes.ts b/lib/paymentNotes.ts index b093753..505d004 100644 --- a/lib/paymentNotes.ts +++ b/lib/paymentNotes.ts @@ -46,8 +46,8 @@ export async function publishPurchaseNote(params: { payerPubkey: params.payerPubkey, recipientPubkey: params.authorPubkey, paymentHash: params.paymentHash, - zapReceiptId: params.zapReceiptId, articleId: params.articleId, + ...(params.zapReceiptId ? { zapReceiptId: params.zapReceiptId } : {}), ...(params.seriesId ? { seriesId: params.seriesId } : {}), }) @@ -120,9 +120,9 @@ export async function publishReviewTipNote(params: { payerPubkey: params.payerPubkey, recipientPubkey: params.reviewerPubkey, paymentHash: params.paymentHash, - zapReceiptId: params.zapReceiptId, articleId: params.articleId, reviewId: params.reviewId, + ...(params.zapReceiptId ? { zapReceiptId: params.zapReceiptId } : {}), ...(params.seriesId ? { seriesId: params.seriesId } : {}), ...(params.text ? { text: params.text } : {}), }) diff --git a/lib/paymentPollingMain.ts b/lib/paymentPollingMain.ts index 6f66428..c9a1301 100644 --- a/lib/paymentPollingMain.ts +++ b/lib/paymentPollingMain.ts @@ -61,15 +61,16 @@ export async function sendPrivateContentAfterPayment( } } + const category = article.category === 'author-presentation' ? undefined : (article.category === 'science-fiction' || article.category === 'scientific-research' ? article.category : undefined) await publishPurchaseNote({ articleId: article.id, authorPubkey: article.pubkey, payerPubkey: recipientPubkey, amount, paymentHash, - zapReceiptId, - category: article.category, - seriesId: article.seriesId, + ...(zapReceiptId ? { zapReceiptId } : {}), + ...(category ? { category } : {}), + ...(article.seriesId ? { seriesId: article.seriesId } : {}), payerPrivateKey, }) } diff --git a/lib/purchaseQueries.ts b/lib/purchaseQueries.ts index d3958bb..88acc71 100644 --- a/lib/purchaseQueries.ts +++ b/lib/purchaseQueries.ts @@ -28,6 +28,9 @@ function buildPurchaseFilters(articleId?: string, payerPubkey?: string, authorPu kinds: number[] since: number '#kind_type': string[] + authors?: string[] + '#p'?: string[] + '#e'?: string[] } = { kinds: [9735], // Zap receipt since: MIN_EVENT_DATE, diff --git a/lib/reviewTipQueries.ts b/lib/reviewTipQueries.ts index 92ee5b4..a4f19d5 100644 --- a/lib/reviewTipQueries.ts +++ b/lib/reviewTipQueries.ts @@ -22,6 +22,10 @@ function buildReviewTipFilters(articleId?: string, reviewId?: string, authorPubk kinds: number[] since: number '#kind_type': string[] + '#p'?: string[] + '#e'?: string[] + '#review_id'?: string[] + '#reviewer'?: string[] } = { kinds: [9735], // Zap receipt since: MIN_EVENT_DATE, diff --git a/lib/sponsoringQueries.ts b/lib/sponsoringQueries.ts index f3934a5..446c63e 100644 --- a/lib/sponsoringQueries.ts +++ b/lib/sponsoringQueries.ts @@ -22,6 +22,10 @@ function buildSponsoringFilters(authorPubkey?: string, payerPubkey?: string, ser kinds: number[] since: number '#kind_type': string[] + authors?: string[] + '#p'?: string[] + '#series'?: string[] + '#article'?: string[] } = { kinds: [9735], // Zap receipt since: MIN_EVENT_DATE, diff --git a/lib/storage/cryptoHelpers.ts b/lib/storage/cryptoHelpers.ts index be22791..96754d8 100644 --- a/lib/storage/cryptoHelpers.ts +++ b/lib/storage/cryptoHelpers.ts @@ -5,11 +5,11 @@ function toBase64(bytes: Uint8Array): string { bytes.forEach((b) => { binary += String.fromCharCode(b) }) - return btoa(binary) + return window.btoa(binary) } function fromBase64(value: string): Uint8Array { - const binary = atob(value) + const binary = window.atob(value) const bytes = new Uint8Array(binary.length) for (let i = 0; i < binary.length; i += 1) { bytes[i] = binary.charCodeAt(i) @@ -20,8 +20,8 @@ function fromBase64(value: string): Uint8Array { async function importKey(secret: string): Promise { const encoder = new TextEncoder() const keyMaterial = encoder.encode(secret) - const hash = await crypto.subtle.digest('SHA-256', keyMaterial) - return crypto.subtle.importKey('raw', hash, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']) + const hash = await window.crypto.subtle.digest('SHA-256', keyMaterial) + return window.crypto.subtle.importKey('raw', hash, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']) } export interface EncryptedPayload { @@ -31,10 +31,10 @@ export interface EncryptedPayload { export async function encryptPayload(secret: string, value: unknown): Promise { const key = await importKey(secret) - const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH)) + const iv = window.crypto.getRandomValues(new Uint8Array(IV_LENGTH)) const encoder = new TextEncoder() const encoded = encoder.encode(JSON.stringify(value)) - const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded) + const ciphertext = await window.crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded) return { iv: toBase64(iv), ciphertext: toBase64(new Uint8Array(ciphertext)), @@ -47,7 +47,7 @@ export async function decryptPayload(secret: string, payload: EncryptedPayloa const cipherBytes = fromBase64(payload.ciphertext) const ivBuffer = ivBytes.buffer as ArrayBuffer const cipherBuffer = cipherBytes.buffer as ArrayBuffer - const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: ivBuffer }, key, cipherBuffer) + const decrypted = await window.crypto.subtle.decrypt({ name: 'AES-GCM', iv: ivBuffer }, key, cipherBuffer) const decoder = new TextDecoder() return JSON.parse(decoder.decode(decrypted)) as T } diff --git a/lib/storage/indexedDB.ts b/lib/storage/indexedDB.ts index c334891..e44239a 100644 --- a/lib/storage/indexedDB.ts +++ b/lib/storage/indexedDB.ts @@ -48,7 +48,7 @@ export class IndexedDBStorage { return } - const request = indexedDB.open(DB_NAME, DB_VERSION) + const request = window.indexedDB.open(DB_NAME, DB_VERSION) request.onerror = (): void => { reject(new Error(`Failed to open IndexedDB: ${request.error}`)) diff --git a/pages/_app.tsx b/pages/_app.tsx index 3bd3902..107d92b 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -11,7 +11,7 @@ function I18nProvider({ children }: { children: React.ReactNode }) { return 'fr' } try { - const savedLocale = localStorage.getItem('zapwall-locale') as 'fr' | 'en' | null + const savedLocale = window.localStorage.getItem('zapwall-locale') as 'fr' | 'en' | null if (savedLocale === 'fr' || savedLocale === 'en') { return savedLocale } diff --git a/scripts/lint.js b/scripts/lint.js index 8e018a6..0b871f4 100644 --- a/scripts/lint.js +++ b/scripts/lint.js @@ -6,7 +6,6 @@ */ const { execSync } = require('child_process') -const path = require('path') const projectRoot = process.cwd() @@ -18,7 +17,7 @@ try { cwd: projectRoot, env: { ...process.env, PWD: projectRoot }, }) -} catch (error) { +} catch { // If next lint fails, try eslint directly with flat config console.log('Falling back to eslint directly...') try { @@ -35,7 +34,7 @@ try { cwd: projectRoot, }) } - } catch (eslintError) { + } catch { console.error('Both next lint and eslint failed') process.exit(1) }