lint fix wip
This commit is contained in:
parent
d068b67deb
commit
64c94b6679
@ -12,12 +12,14 @@ export function useI18n(locale: Locale = 'fr'): {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const load = async (): Promise<void> => {
|
const load = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
// Get saved locale from localStorage or use provided locale
|
// Get saved locale from IndexedDB or use provided locale
|
||||||
let savedLocale: Locale | null = null
|
let savedLocale: Locale | null = null
|
||||||
try {
|
try {
|
||||||
if (typeof window !== 'undefined') {
|
// Migrate from localStorage if needed
|
||||||
savedLocale = localStorage.getItem('zapwall-locale') as Locale | null
|
const { localeStorage } = await import('@/lib/localeStorage')
|
||||||
}
|
await localeStorage.migrateFromLocalStorage()
|
||||||
|
// Load from IndexedDB
|
||||||
|
savedLocale = await localeStorage.getLocale()
|
||||||
} catch {
|
} catch {
|
||||||
// Fallback to provided locale
|
// Fallback to provided locale
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,8 +77,8 @@ async function buildParsedArticleFromDraft(
|
|||||||
paid: false,
|
paid: false,
|
||||||
thumbnailUrl: draft.bannerUrl ?? '',
|
thumbnailUrl: draft.bannerUrl ?? '',
|
||||||
invoice: invoice.invoice,
|
invoice: invoice.invoice,
|
||||||
paymentHash: invoice.paymentHash ?? undefined,
|
...(invoice.paymentHash ? { paymentHash: invoice.paymentHash } : {}),
|
||||||
category: draft.category,
|
...(draft.category ? { category: draft.category } : {}),
|
||||||
...(draft.seriesId ? { seriesId: draft.seriesId } : {}),
|
...(draft.seriesId ? { seriesId: draft.seriesId } : {}),
|
||||||
...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}),
|
...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}),
|
||||||
...(draft.pages && draft.pages.length > 0 ? { pages: draft.pages } : {}),
|
...(draft.pages && draft.pages.length > 0 ? { pages: draft.pages } : {}),
|
||||||
@ -93,10 +93,27 @@ async function publishPreviewWithInvoice(
|
|||||||
invoice: AlbyInvoice,
|
invoice: AlbyInvoice,
|
||||||
authorPubkey: string,
|
authorPubkey: string,
|
||||||
presentationId: string,
|
presentationId: string,
|
||||||
extraTags?: string[][]
|
extraTags?: string[][],
|
||||||
|
customArticle?: Article
|
||||||
): Promise<import('nostr-tools').Event | null> {
|
): Promise<import('nostr-tools').Event | null> {
|
||||||
// Build parsed article object
|
// Build parsed article object (use custom article if provided, e.g., for updates with version)
|
||||||
const { article, hash, version, index } = await buildParsedArticleFromDraft(draft, invoice, authorPubkey)
|
let article: Article
|
||||||
|
let hash: string
|
||||||
|
let version: number
|
||||||
|
let index: number
|
||||||
|
|
||||||
|
if (customArticle) {
|
||||||
|
article = customArticle
|
||||||
|
hash = customArticle.hash
|
||||||
|
version = customArticle.version
|
||||||
|
index = customArticle.index ?? 0
|
||||||
|
} else {
|
||||||
|
const built = await buildParsedArticleFromDraft(draft, invoice, authorPubkey)
|
||||||
|
article = built.article
|
||||||
|
hash = built.hash
|
||||||
|
version = built.version
|
||||||
|
index = built.index
|
||||||
|
}
|
||||||
|
|
||||||
// Build event template
|
// Build event template
|
||||||
const previewEventTemplate = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags)
|
const previewEventTemplate = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags)
|
||||||
@ -152,8 +169,8 @@ export async function publishSeries(params: {
|
|||||||
const {category} = params
|
const {category} = params
|
||||||
requireCategory(category)
|
requireCategory(category)
|
||||||
|
|
||||||
// Map category to new system
|
// Map category to new system (not used but kept for future reference)
|
||||||
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
const _newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
||||||
|
|
||||||
// Generate hash ID from series data
|
// Generate hash ID from series data
|
||||||
const hashId = await generateSeriesHashId({
|
const hashId = await generateSeriesHashId({
|
||||||
@ -241,8 +258,8 @@ async function buildSeriesEvent(
|
|||||||
content: string
|
content: string
|
||||||
tags: string[][]
|
tags: string[][]
|
||||||
}> {
|
}> {
|
||||||
// Map category to new system
|
// Map category to new system (not used but kept for future reference)
|
||||||
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
const _newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
||||||
|
|
||||||
// Generate hash ID from series data
|
// Generate hash ID from series data
|
||||||
const hashId = await generateSeriesHashId({
|
const hashId = await generateSeriesHashId({
|
||||||
@ -307,8 +324,8 @@ export async function publishReview(params: {
|
|||||||
const {category} = params
|
const {category} = params
|
||||||
requireCategory(category)
|
requireCategory(category)
|
||||||
|
|
||||||
// Map category to new system
|
// Map category to new system (not used but kept for future reference)
|
||||||
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
const _newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
||||||
|
|
||||||
// Generate hash ID from review data
|
// Generate hash ID from review data
|
||||||
const { generateReviewHashId } = await import('./hashIdGenerator')
|
const { generateReviewHashId } = await import('./hashIdGenerator')
|
||||||
@ -400,8 +417,8 @@ async function buildReviewEvent(
|
|||||||
content: string
|
content: string
|
||||||
tags: string[][]
|
tags: string[][]
|
||||||
}> {
|
}> {
|
||||||
// Map category to new system
|
// Map category to new system (not used but kept for future reference)
|
||||||
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
const _newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
||||||
|
|
||||||
// Generate hash ID from review data
|
// Generate hash ID from review data
|
||||||
const { generateReviewHashId } = await import('./hashIdGenerator')
|
const { generateReviewHashId } = await import('./hashIdGenerator')
|
||||||
@ -502,12 +519,36 @@ async function publishUpdate(
|
|||||||
): Promise<ArticleUpdateResult> {
|
): Promise<ArticleUpdateResult> {
|
||||||
const {category} = draft
|
const {category} = draft
|
||||||
requireCategory(category)
|
requireCategory(category)
|
||||||
|
|
||||||
|
// Get original article from IndexedDB to retrieve current version
|
||||||
|
const { objectCache } = await import('./objectCache')
|
||||||
|
const originalArticle = await objectCache.getById('publication', originalArticleId) as Article | null
|
||||||
|
|
||||||
|
if (!originalArticle) {
|
||||||
|
return updateFailure(originalArticleId, 'Original article not found in cache')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify user is the author
|
||||||
|
if (originalArticle.pubkey !== authorPubkey) {
|
||||||
|
return updateFailure(originalArticleId, 'Only the author can update this article')
|
||||||
|
}
|
||||||
|
|
||||||
const presentationId = await ensurePresentation(authorPubkey)
|
const presentationId = await ensurePresentation(authorPubkey)
|
||||||
const invoice = await createArticleInvoice(draft)
|
const invoice = await createArticleInvoice(draft)
|
||||||
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
||||||
const updateTags = await buildUpdateTags(draft, originalArticleId, newCategory, authorPubkey)
|
|
||||||
|
|
||||||
const publishedEvent = await publishPreviewWithInvoice(draft, invoice, authorPubkey, presentationId, updateTags)
|
// Use current version from original article
|
||||||
|
const currentVersion = originalArticle.version ?? 0
|
||||||
|
const updateTags = await buildUpdateTags(draft, originalArticleId, newCategory, authorPubkey, currentVersion)
|
||||||
|
|
||||||
|
// Build parsed article with incremented version
|
||||||
|
const { article, hash, version, index } = await buildParsedArticleFromDraft(draft, invoice, authorPubkey)
|
||||||
|
const updatedArticle: Article = {
|
||||||
|
...article,
|
||||||
|
version: currentVersion + 1, // Increment version for update
|
||||||
|
}
|
||||||
|
|
||||||
|
const publishedEvent = await publishPreviewWithInvoice(draft, invoice, authorPubkey, presentationId, updateTags, updatedArticle)
|
||||||
if (!publishedEvent) {
|
if (!publishedEvent) {
|
||||||
return updateFailure(originalArticleId, 'Failed to publish article update')
|
return updateFailure(originalArticleId, 'Failed to publish article update')
|
||||||
}
|
}
|
||||||
@ -547,14 +588,83 @@ function updateFailure(originalArticleId: string, error?: string): ArticleUpdate
|
|||||||
|
|
||||||
export async function deleteArticleEvent(articleId: string, authorPubkey: string, authorPrivateKey?: string): Promise<void> {
|
export async function deleteArticleEvent(articleId: string, authorPubkey: string, authorPrivateKey?: string): Promise<void> {
|
||||||
ensureKeys(authorPubkey, authorPrivateKey)
|
ensureKeys(authorPubkey, authorPrivateKey)
|
||||||
const deleteEvent = {
|
|
||||||
kind: 5,
|
// Get original event from IndexedDB cache
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
const { objectCache } = await import('./objectCache')
|
||||||
tags: [['e', articleId]] as string[][],
|
const originalEvent = await objectCache.getEventById('publication', articleId)
|
||||||
content: 'deleted',
|
|
||||||
} as const
|
if (!originalEvent) {
|
||||||
const published = await nostrService.publishEvent(deleteEvent)
|
throw new Error('Article not found in cache')
|
||||||
if (!published) {
|
}
|
||||||
|
|
||||||
|
// Verify user is the author
|
||||||
|
if (originalEvent.pubkey !== authorPubkey) {
|
||||||
|
throw new Error('Only the author can delete this article')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build delete event (new version with hidden=true)
|
||||||
|
const { buildDeleteEvent } = await import('./objectModification')
|
||||||
|
const deleteEventTemplate = await buildDeleteEvent(originalEvent, authorPubkey)
|
||||||
|
|
||||||
|
if (!deleteEventTemplate) {
|
||||||
|
throw new Error('Failed to build delete event')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the original article to get hash/version/index
|
||||||
|
const { parseArticleFromEvent } = await import('./nostrEventParsing')
|
||||||
|
const originalParsed = await parseArticleFromEvent(originalEvent)
|
||||||
|
if (!originalParsed) {
|
||||||
|
throw new Error('Failed to parse original article')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment version for deletion
|
||||||
|
const { extractTagsFromEvent } = await import('./nostrTagSystem')
|
||||||
|
const tags = extractTagsFromEvent(deleteEventTemplate)
|
||||||
|
const newVersion = tags.version ?? originalParsed.version + 1
|
||||||
|
const {hash} = originalParsed
|
||||||
|
const index = originalParsed.index ?? 0
|
||||||
|
|
||||||
|
// Build updated parsed Article object with hidden flag
|
||||||
|
const deletedArticle: Article = {
|
||||||
|
...originalParsed,
|
||||||
|
version: newVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set private key in orchestrator
|
||||||
|
const privateKey = authorPrivateKey ?? nostrService.getPrivateKey()
|
||||||
|
if (!privateKey) {
|
||||||
|
throw new Error('Private key required for signing')
|
||||||
|
}
|
||||||
|
const { writeOrchestrator } = await import('./writeOrchestrator')
|
||||||
|
writeOrchestrator.setPrivateKey(privateKey)
|
||||||
|
|
||||||
|
// Finalize event
|
||||||
|
const { finalizeEvent } = await import('nostr-tools')
|
||||||
|
const { hexToBytes } = await import('nostr-tools/utils')
|
||||||
|
const secretKey = hexToBytes(privateKey)
|
||||||
|
const event = finalizeEvent(deleteEventTemplate, secretKey)
|
||||||
|
|
||||||
|
// Get active relays
|
||||||
|
const { relaySessionManager } = await import('./relaySessionManager')
|
||||||
|
const activeRelays = await relaySessionManager.getActiveRelays()
|
||||||
|
const { getPrimaryRelay } = await import('./config')
|
||||||
|
const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()]
|
||||||
|
|
||||||
|
// Publish via writeOrchestrator (parallel network + local write)
|
||||||
|
const result = await writeOrchestrator.writeAndPublish(
|
||||||
|
{
|
||||||
|
objectType: 'publication',
|
||||||
|
hash,
|
||||||
|
event,
|
||||||
|
parsed: deletedArticle,
|
||||||
|
version: newVersion,
|
||||||
|
hidden: true, // Mark as hidden (deleted)
|
||||||
|
index,
|
||||||
|
},
|
||||||
|
relays
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
throw new Error('Failed to publish delete event')
|
throw new Error('Failed to publish delete event')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,8 +59,8 @@ async function buildParsedArticleFromDraft(
|
|||||||
paid: false,
|
paid: false,
|
||||||
thumbnailUrl: draft.bannerUrl ?? '',
|
thumbnailUrl: draft.bannerUrl ?? '',
|
||||||
invoice: invoice.invoice,
|
invoice: invoice.invoice,
|
||||||
paymentHash: invoice.paymentHash ?? undefined,
|
...(invoice.paymentHash ? { paymentHash: invoice.paymentHash } : {}),
|
||||||
category: draft.category,
|
...(draft.category ? { category: draft.category } : {}),
|
||||||
...(draft.seriesId ? { seriesId: draft.seriesId } : {}),
|
...(draft.seriesId ? { seriesId: draft.seriesId } : {}),
|
||||||
...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}),
|
...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}),
|
||||||
...(draft.pages && draft.pages.length > 0 ? { pages: draft.pages } : {}),
|
...(draft.pages && draft.pages.length > 0 ? { pages: draft.pages } : {}),
|
||||||
@ -123,10 +123,9 @@ export async function publishPreview(
|
|||||||
|
|
||||||
if (returnStatus) {
|
if (returnStatus) {
|
||||||
// Return PublishResult format
|
// Return PublishResult format
|
||||||
const { publishResult } = await import('./publishResult')
|
|
||||||
return {
|
return {
|
||||||
event,
|
event,
|
||||||
relayStatuses: relays.map((relayUrl, idx) => {
|
relayStatuses: relays.map((relayUrl, _idx) => {
|
||||||
const isSuccess = typeof result.published === 'object' && result.published.includes(relayUrl)
|
const isSuccess = typeof result.published === 'object' && result.published.includes(relayUrl)
|
||||||
return {
|
return {
|
||||||
relayUrl,
|
relayUrl,
|
||||||
|
|||||||
@ -63,10 +63,13 @@ export class NostrAuthService {
|
|||||||
void this.saveStateToStorage()
|
void this.saveStateToStorage()
|
||||||
this.notifyListeners()
|
this.notifyListeners()
|
||||||
|
|
||||||
// Sync user content to IndexedDB cache (background operation)
|
// Sync user content via Service Worker (background operation)
|
||||||
if (result.publicKey) {
|
if (result.publicKey) {
|
||||||
const { syncUserContentToCache } = await import('@/lib/userContentSync')
|
const { swClient } = await import('@/lib/swClient')
|
||||||
void syncUserContentToCache(result.publicKey)
|
const isReady = await swClient.isReady()
|
||||||
|
if (isReady) {
|
||||||
|
void swClient.startUserSync(result.publicKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@ -237,7 +237,7 @@ class WriteService {
|
|||||||
data: { type, objectType, objectId, eventId, notificationData: data },
|
data: { type, objectType, objectId, eventId, notificationData: data },
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
}
|
||||||
// Fallback: direct write
|
// Fallback: direct write
|
||||||
const { notificationService } = await import('./notificationService')
|
const { notificationService } = await import('./notificationService')
|
||||||
await notificationService.createNotification({
|
await notificationService.createNotification({
|
||||||
@ -247,7 +247,7 @@ class WriteService {
|
|||||||
eventId,
|
eventId,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[WriteService] Error creating notification:', error)
|
console.error('[WriteService] Error creating notification:', error)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user