lint fix wip
This commit is contained in:
parent
38941147cb
commit
bb5cfa758c
@ -24,14 +24,14 @@ export function useArticlePayment(
|
|||||||
|
|
||||||
const checkPaymentStatus = async (hash: string, userPubkey: string): Promise<void> => {
|
const checkPaymentStatus = async (hash: string, userPubkey: string): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const hasPaid = await paymentService.waitForArticlePayment(
|
const hasPaid = await paymentService.waitForArticlePayment({
|
||||||
hash,
|
paymentHash: hash,
|
||||||
article.id,
|
articleId: article.id,
|
||||||
article.pubkey,
|
articlePubkey: article.pubkey,
|
||||||
article.zapAmount,
|
amount: article.zapAmount,
|
||||||
userPubkey,
|
recipientPubkey: userPubkey,
|
||||||
300000
|
timeout: 300000,
|
||||||
)
|
})
|
||||||
|
|
||||||
if (hasPaid) {
|
if (hasPaid) {
|
||||||
const content = await nostrService.getPrivateContent(article.id, article.pubkey)
|
const content = await nostrService.getPrivateContent(article.id, article.pubkey)
|
||||||
|
|||||||
@ -48,16 +48,16 @@ export async function writeObjectToCache(params: WriteObjectParams): Promise<voi
|
|||||||
const tags = extractTagsFromEvent(event)
|
const tags = extractTagsFromEvent(event)
|
||||||
const writeService = await getWriteService()
|
const writeService = await getWriteService()
|
||||||
|
|
||||||
await writeService.writeObject(
|
await writeService.writeObject({
|
||||||
objectType,
|
objectType,
|
||||||
hash,
|
hash,
|
||||||
event,
|
event,
|
||||||
parsed,
|
parsed,
|
||||||
version ?? tags.version ?? 0,
|
version: version ?? tags.version ?? 0,
|
||||||
hidden ?? tags.hidden ?? false,
|
hidden: hidden ?? tags.hidden ?? false,
|
||||||
index ?? 0,
|
index: index ?? 0,
|
||||||
published ?? false
|
published: published ?? false,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
26
lib/nostr.ts
26
lib/nostr.ts
@ -107,14 +107,23 @@ class NostrService {
|
|||||||
if (result.status === 'fulfilled') {
|
if (result.status === 'fulfilled') {
|
||||||
successfulRelays.push(relayUrl)
|
successfulRelays.push(relayUrl)
|
||||||
// Log successful publication
|
// Log successful publication
|
||||||
void publishLog.logPublication(event.id, relayUrl, true, undefined)
|
void publishLog.logPublication({
|
||||||
|
eventId: event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: true,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
const error = result.reason
|
const error = result.reason
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||||
console.error(`[NostrService] Relay ${relayUrl} failed during publish:`, error)
|
console.error(`[NostrService] Relay ${relayUrl} failed during publish:`, error)
|
||||||
relaySessionManager.markRelayFailed(relayUrl)
|
relaySessionManager.markRelayFailed(relayUrl)
|
||||||
// Log failed publication
|
// Log failed publication
|
||||||
void publishLog.logPublication(event.id, relayUrl, false, errorMessage)
|
void publishLog.logPublication({
|
||||||
|
eventId: event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -143,14 +152,23 @@ class NostrService {
|
|||||||
if (result.status === 'fulfilled') {
|
if (result.status === 'fulfilled') {
|
||||||
successfulRelays.push(relayUrl)
|
successfulRelays.push(relayUrl)
|
||||||
// Log successful publication
|
// Log successful publication
|
||||||
void publishLog.logPublication(event.id, relayUrl, true, undefined)
|
void publishLog.logPublication({
|
||||||
|
eventId: event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: true,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
const error = result.reason
|
const error = result.reason
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||||
console.error(`[NostrService] Relay ${relayUrl} failed during publish:`, error)
|
console.error(`[NostrService] Relay ${relayUrl} failed during publish:`, error)
|
||||||
relaySessionManager.markRelayFailed(relayUrl)
|
relaySessionManager.markRelayFailed(relayUrl)
|
||||||
// Log failed publication
|
// Log failed publication
|
||||||
void publishLog.logPublication(event.id, relayUrl, false, errorMessage)
|
void publishLog.logPublication({
|
||||||
|
eventId: event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,13 @@ async function isValidZapReceipt(
|
|||||||
// Import verification service dynamically to avoid circular dependencies
|
// Import verification service dynamically to avoid circular dependencies
|
||||||
const { zapVerificationService } = await import('./zapVerification')
|
const { zapVerificationService } = await import('./zapVerification')
|
||||||
|
|
||||||
return zapVerificationService.verifyZapReceiptForArticle(params.event, params.targetEventId, params.targetPubkey, params.userPubkey, params.amount)
|
return zapVerificationService.verifyZapReceiptForArticle({
|
||||||
|
zapReceipt: params.event,
|
||||||
|
articleId: params.targetEventId,
|
||||||
|
articlePubkey: params.targetPubkey,
|
||||||
|
userPubkey: params.userPubkey,
|
||||||
|
expectedAmount: params.amount,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -75,7 +75,13 @@ class NotificationService {
|
|||||||
|
|
||||||
// Utiliser writeService pour créer la notification via Web Worker
|
// Utiliser writeService pour créer la notification via Web Worker
|
||||||
const { writeService } = await import('./writeService')
|
const { writeService } = await import('./writeService')
|
||||||
await writeService.createNotification(type, objectType, objectId, eventId, data)
|
await writeService.createNotification({
|
||||||
|
type,
|
||||||
|
objectType,
|
||||||
|
objectId,
|
||||||
|
eventId,
|
||||||
|
...(data !== undefined ? { data } : {}),
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[NotificationService] Error creating notification:', error)
|
console.error('[NotificationService] Error creating notification:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ class ObjectCacheService {
|
|||||||
*/
|
*/
|
||||||
private async initDB(objectType: ObjectType): Promise<IDBDatabase> {
|
private async initDB(objectType: ObjectType): Promise<IDBDatabase> {
|
||||||
const helper = this.getDBHelper(objectType)
|
const helper = this.getDBHelper(objectType)
|
||||||
return await helper.init()
|
return helper.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,51 +102,52 @@ class ObjectCacheService {
|
|||||||
* Verifies and sets the index before insertion
|
* Verifies and sets the index before insertion
|
||||||
* @param published - false if not published, or array of relay URLs that successfully published
|
* @param published - false if not published, or array of relay URLs that successfully published
|
||||||
*/
|
*/
|
||||||
async set(
|
async set(params: {
|
||||||
objectType: ObjectType,
|
objectType: ObjectType
|
||||||
hash: string,
|
hash: string
|
||||||
event: NostrEvent,
|
event: NostrEvent
|
||||||
parsed: unknown,
|
parsed: unknown
|
||||||
version: number,
|
version: number
|
||||||
hidden: boolean,
|
hidden: boolean
|
||||||
index?: number,
|
index?: number
|
||||||
published: false | string[] = false
|
published?: false | string[]
|
||||||
): Promise<void> {
|
}): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const helper = this.getDBHelper(objectType)
|
const helper = this.getDBHelper(params.objectType)
|
||||||
|
|
||||||
// If index is not provided, calculate it by counting objects with the same hash
|
// If index is not provided, calculate it by counting objects with the same hash
|
||||||
let finalIndex = index
|
let finalIndex = params.index
|
||||||
if (finalIndex === undefined) {
|
if (finalIndex === undefined) {
|
||||||
const count = await this.countObjectsWithHash(objectType, hash)
|
const count = await this.countObjectsWithHash(params.objectType, params.hash)
|
||||||
finalIndex = count
|
finalIndex = count
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = buildObjectId(hash, finalIndex, version)
|
const id = buildObjectId(params.hash, finalIndex, params.version)
|
||||||
|
|
||||||
// Check if object already exists to preserve published status if updating
|
// Check if object already exists to preserve published status if updating
|
||||||
const existing = await helper.get<CachedObject>(id).catch(() => null)
|
const existing = await helper.get<CachedObject>(id).catch(() => null)
|
||||||
|
|
||||||
// If updating and published is not provided, preserve existing published status
|
// If updating and published is not provided, preserve existing published status
|
||||||
|
const published = params.published ?? false
|
||||||
const finalPublished = existing && published === false ? existing.published : published
|
const finalPublished = existing && published === false ? existing.published : published
|
||||||
|
|
||||||
const cached: CachedObject = {
|
const cached: CachedObject = {
|
||||||
id,
|
id,
|
||||||
hash,
|
hash: params.hash,
|
||||||
hashId: hash, // Legacy field for backward compatibility
|
hashId: params.hash, // Legacy field for backward compatibility
|
||||||
index: finalIndex,
|
index: finalIndex,
|
||||||
event,
|
event: params.event,
|
||||||
parsed,
|
parsed: params.parsed,
|
||||||
version,
|
version: params.version,
|
||||||
hidden,
|
hidden: params.hidden,
|
||||||
createdAt: event.created_at,
|
createdAt: params.event.created_at,
|
||||||
cachedAt: Date.now(),
|
cachedAt: Date.now(),
|
||||||
published: finalPublished,
|
published: finalPublished,
|
||||||
}
|
}
|
||||||
|
|
||||||
await helper.put(cached)
|
await helper.put(cached)
|
||||||
} catch (cacheError) {
|
} catch (cacheError) {
|
||||||
console.error(`Error caching ${objectType} object:`, cacheError)
|
console.error(`Error caching ${params.objectType} object:`, cacheError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -81,21 +81,21 @@ export class PaymentService {
|
|||||||
/**
|
/**
|
||||||
* Check if payment for an article has been completed
|
* Check if payment for an article has been completed
|
||||||
*/
|
*/
|
||||||
async checkArticlePayment(
|
async checkArticlePayment(params: {
|
||||||
_paymentHash: string,
|
paymentHash: string
|
||||||
articleId: string,
|
articleId: string
|
||||||
articlePubkey: string,
|
articlePubkey: string
|
||||||
amount: number,
|
amount: number
|
||||||
userPubkey?: string
|
userPubkey?: string
|
||||||
): Promise<boolean> {
|
}): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
// With Alby/WebLN, we rely on zap receipts for payment verification
|
// With Alby/WebLN, we rely on zap receipts for payment verification
|
||||||
// since WebLN doesn't provide payment status checking
|
// since WebLN doesn't provide payment status checking
|
||||||
const zapReceiptExists = await nostrService.checkZapReceipt(
|
const zapReceiptExists = await nostrService.checkZapReceipt(
|
||||||
articlePubkey,
|
params.articlePubkey,
|
||||||
articleId,
|
params.articleId,
|
||||||
amount,
|
params.amount,
|
||||||
userPubkey
|
params.userPubkey
|
||||||
)
|
)
|
||||||
|
|
||||||
return zapReceiptExists
|
return zapReceiptExists
|
||||||
@ -109,22 +109,22 @@ export class PaymentService {
|
|||||||
* Wait for payment completion with polling
|
* Wait for payment completion with polling
|
||||||
* After payment is confirmed, sends private content to the user
|
* After payment is confirmed, sends private content to the user
|
||||||
*/
|
*/
|
||||||
waitForArticlePayment(
|
waitForArticlePayment(params: {
|
||||||
paymentHash: string,
|
paymentHash: string
|
||||||
articleId: string,
|
articleId: string
|
||||||
articlePubkey: string,
|
articlePubkey: string
|
||||||
amount: number,
|
amount: number
|
||||||
recipientPubkey: string,
|
recipientPubkey: string
|
||||||
timeout: number = 300000 // 5 minutes
|
timeout?: number
|
||||||
): Promise<boolean> {
|
}): Promise<boolean> {
|
||||||
return waitForArticlePaymentHelper(
|
return waitForArticlePaymentHelper({
|
||||||
paymentHash,
|
paymentHash: params.paymentHash,
|
||||||
articleId,
|
articleId: params.articleId,
|
||||||
articlePubkey,
|
articlePubkey: params.articlePubkey,
|
||||||
amount,
|
amount: params.amount,
|
||||||
recipientPubkey,
|
recipientPubkey: params.recipientPubkey,
|
||||||
timeout
|
...(params.timeout !== undefined ? { timeout: params.timeout } : {}),
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -7,49 +7,61 @@ import { sendPrivateContentAfterPayment } from './paymentPollingMain'
|
|||||||
* After payment is confirmed, sends private content to the user
|
* After payment is confirmed, sends private content to the user
|
||||||
*/
|
*/
|
||||||
async function pollPaymentUntilDeadline(
|
async function pollPaymentUntilDeadline(
|
||||||
articleId: string,
|
params: {
|
||||||
articlePubkey: string,
|
articleId: string
|
||||||
amount: number,
|
articlePubkey: string
|
||||||
recipientPubkey: string,
|
amount: number
|
||||||
interval: number,
|
recipientPubkey: string
|
||||||
deadline: number
|
interval: number
|
||||||
|
deadline: number
|
||||||
|
}
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const zapReceiptExists = await nostrService.checkZapReceipt(articlePubkey, articleId, amount, recipientPubkey)
|
const zapReceiptExists = await nostrService.checkZapReceipt(params.articlePubkey, params.articleId, params.amount, params.recipientPubkey)
|
||||||
if (zapReceiptExists) {
|
if (zapReceiptExists) {
|
||||||
const zapReceiptId = await getZapReceiptId(articlePubkey, articleId, amount, recipientPubkey)
|
const zapReceiptId = await getZapReceiptId(params.articlePubkey, params.articleId, params.amount, params.recipientPubkey)
|
||||||
await sendPrivateContentAfterPayment(articleId, recipientPubkey, amount, zapReceiptId)
|
await sendPrivateContentAfterPayment(params.articleId, params.recipientPubkey, params.amount, zapReceiptId)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking zap receipt:', error)
|
console.error('Error checking zap receipt:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Date.now() > deadline) {
|
if (Date.now() > params.deadline) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<boolean>((resolve) => {
|
return new Promise<boolean>((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
void pollPaymentUntilDeadline(articleId, articlePubkey, amount, recipientPubkey, interval, deadline)
|
void pollPaymentUntilDeadline(params)
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.catch(() => resolve(false))
|
.catch(() => resolve(false))
|
||||||
}, interval)
|
}, params.interval)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitForArticlePayment(
|
export async function waitForArticlePayment(
|
||||||
_paymentHash: string,
|
params: {
|
||||||
articleId: string,
|
paymentHash: string
|
||||||
articlePubkey: string,
|
articleId: string
|
||||||
amount: number,
|
articlePubkey: string
|
||||||
recipientPubkey: string,
|
amount: number
|
||||||
timeout: number = 300000 // 5 minutes
|
recipientPubkey: string
|
||||||
|
timeout?: number
|
||||||
|
}
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const interval = 2000
|
const interval = 2000
|
||||||
|
const timeout = params.timeout ?? 300000
|
||||||
const deadline = Date.now() + timeout
|
const deadline = Date.now() + timeout
|
||||||
try {
|
try {
|
||||||
return pollPaymentUntilDeadline(articleId, articlePubkey, amount, recipientPubkey, interval, deadline)
|
return pollPaymentUntilDeadline({
|
||||||
|
articleId: params.articleId,
|
||||||
|
articlePubkey: params.articlePubkey,
|
||||||
|
amount: params.amount,
|
||||||
|
recipientPubkey: params.recipientPubkey,
|
||||||
|
interval,
|
||||||
|
deadline,
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Wait for payment error:', error)
|
console.error('Wait for payment error:', error)
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -19,6 +19,15 @@ interface PublicationLogEntry {
|
|||||||
objectId?: string // ID of the object in cache
|
objectId?: string // ID of the object in cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LogPublicationParams {
|
||||||
|
eventId: string
|
||||||
|
relayUrl: string
|
||||||
|
success: boolean
|
||||||
|
error?: string
|
||||||
|
objectType?: string
|
||||||
|
objectId?: string
|
||||||
|
}
|
||||||
|
|
||||||
class PublishLogService {
|
class PublishLogService {
|
||||||
private readonly dbHelper: IndexedDBHelper
|
private readonly dbHelper: IndexedDBHelper
|
||||||
|
|
||||||
@ -52,17 +61,10 @@ class PublishLogService {
|
|||||||
* Log a publication attempt
|
* Log a publication attempt
|
||||||
* Utilise writeService pour écrire via Web Worker
|
* Utilise writeService pour écrire via Web Worker
|
||||||
*/
|
*/
|
||||||
async logPublication(
|
async logPublication(params: LogPublicationParams): Promise<void> {
|
||||||
eventId: string,
|
|
||||||
relayUrl: string,
|
|
||||||
success: boolean,
|
|
||||||
error?: string,
|
|
||||||
objectType?: string,
|
|
||||||
objectId?: string
|
|
||||||
): Promise<void> {
|
|
||||||
// Utiliser writeService pour logger via Web Worker
|
// Utiliser writeService pour logger via Web Worker
|
||||||
const { writeService } = await import('./writeService')
|
const { writeService } = await import('./writeService')
|
||||||
await writeService.logPublication(eventId, relayUrl, success, error, objectType, objectId)
|
await writeService.logPublication(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,24 +72,17 @@ class PublishLogService {
|
|||||||
* @deprecated Utiliser logPublication qui utilise writeService
|
* @deprecated Utiliser logPublication qui utilise writeService
|
||||||
* @internal Utilisé uniquement par writeService en fallback
|
* @internal Utilisé uniquement par writeService en fallback
|
||||||
*/
|
*/
|
||||||
async logPublicationDirect(
|
async logPublicationDirect(params: LogPublicationParams): Promise<void> {
|
||||||
eventId: string,
|
|
||||||
relayUrl: string,
|
|
||||||
success: boolean,
|
|
||||||
error?: string,
|
|
||||||
objectType?: string,
|
|
||||||
objectId?: string
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
try {
|
||||||
const entry: PublicationLogEntry = {
|
const entry: PublicationLogEntry = {
|
||||||
id: `${eventId}_${relayUrl}_${Date.now()}`, // Unique ID
|
id: `${params.eventId}_${params.relayUrl}_${Date.now()}`, // Unique ID
|
||||||
eventId,
|
eventId: params.eventId,
|
||||||
relayUrl,
|
relayUrl: params.relayUrl,
|
||||||
success,
|
success: params.success,
|
||||||
...(error !== undefined ? { error } : {}),
|
...(params.error !== undefined ? { error: params.error } : {}),
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
...(objectType !== undefined ? { objectType } : {}),
|
...(params.objectType !== undefined ? { objectType: params.objectType } : {}),
|
||||||
...(objectId !== undefined ? { objectId } : {}),
|
...(params.objectId !== undefined ? { objectId: params.objectId } : {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.dbHelper.add(entry)
|
await this.dbHelper.add(entry)
|
||||||
|
|||||||
@ -179,13 +179,26 @@ class PublishWorkerService {
|
|||||||
if (status.success) {
|
if (status.success) {
|
||||||
successfulRelays.push(relayUrl)
|
successfulRelays.push(relayUrl)
|
||||||
// Log successful publication
|
// Log successful publication
|
||||||
void publishLog.logPublication(obj.event.id, relayUrl, true, undefined, obj.objectType, obj.id)
|
void publishLog.logPublication({
|
||||||
|
eventId: obj.event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: true,
|
||||||
|
objectType: obj.objectType,
|
||||||
|
objectId: obj.id,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
const errorMessage = status.error ?? 'Unknown error'
|
const errorMessage = status.error ?? 'Unknown error'
|
||||||
console.warn(`[PublishWorker] Relay ${relayUrl} failed for ${obj.objectType}:${obj.id}:`, errorMessage)
|
console.warn(`[PublishWorker] Relay ${relayUrl} failed for ${obj.objectType}:${obj.id}:`, errorMessage)
|
||||||
relaySessionManager.markRelayFailed(relayUrl)
|
relaySessionManager.markRelayFailed(relayUrl)
|
||||||
// Log failed publication
|
// Log failed publication
|
||||||
void publishLog.logPublication(obj.event.id, relayUrl, false, errorMessage, obj.objectType, obj.id)
|
void publishLog.logPublication({
|
||||||
|
eventId: obj.event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
objectType: obj.objectType,
|
||||||
|
objectId: obj.id,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { getCachedObjectById } from './helpers/queryHelpers'
|
|||||||
import { objectCache } from './objectCache'
|
import { objectCache } from './objectCache'
|
||||||
|
|
||||||
export async function getPurchaseById(purchaseId: string, _timeoutMs: number = 5000): Promise<Purchase | null> {
|
export async function getPurchaseById(purchaseId: string, _timeoutMs: number = 5000): Promise<Purchase | null> {
|
||||||
return await getCachedObjectById<Purchase>('purchase', purchaseId)
|
return getCachedObjectById<Purchase>('purchase', purchaseId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPurchasesForArticle(articleId: string, _timeoutMs: number = 5000): Promise<Purchase[]> {
|
export async function getPurchasesForArticle(articleId: string, _timeoutMs: number = 5000): Promise<Purchase[]> {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { objectCache } from './objectCache'
|
|||||||
import { getCachedObjectById } from './helpers/queryHelpers'
|
import { getCachedObjectById } from './helpers/queryHelpers'
|
||||||
|
|
||||||
export async function getReviewTipById(reviewTipId: string, _timeoutMs: number = 5000): Promise<ReviewTip | null> {
|
export async function getReviewTipById(reviewTipId: string, _timeoutMs: number = 5000): Promise<ReviewTip | null> {
|
||||||
return await getCachedObjectById<ReviewTip>('review_tip', reviewTipId)
|
return getCachedObjectById<ReviewTip>('review_tip', reviewTipId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getReviewTipsForArticle(articleId: string, _timeoutMs: number = 5000): Promise<ReviewTip[]> {
|
export async function getReviewTipsForArticle(articleId: string, _timeoutMs: number = 5000): Promise<ReviewTip[]> {
|
||||||
|
|||||||
@ -22,5 +22,5 @@ export async function getSeriesByAuthor(authorPubkey: string, _timeoutMs: number
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getSeriesById(seriesId: string, _timeoutMs: number = 2000): Promise<Series | null> {
|
export async function getSeriesById(seriesId: string, _timeoutMs: number = 2000): Promise<Series | null> {
|
||||||
return await getCachedObjectById<Series>('series', seriesId)
|
return getCachedObjectById<Series>('series', seriesId)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,11 +28,13 @@ export async function verifyTransactionBeforeTracking(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildTrackingData(
|
export function buildTrackingData(
|
||||||
transactionId: string,
|
params: {
|
||||||
authorPubkey: string,
|
transactionId: string
|
||||||
authorMainnetAddress: string,
|
authorPubkey: string
|
||||||
split: { total: number; authorSats: number; platformSats: number },
|
authorMainnetAddress: string
|
||||||
verification: { confirmed: boolean; confirmations: number }
|
split: { total: number; authorSats: number; platformSats: number; authorMainnetAddress?: string }
|
||||||
|
verification: { confirmed: boolean; confirmations: number }
|
||||||
|
}
|
||||||
): {
|
): {
|
||||||
transactionId: string
|
transactionId: string
|
||||||
authorPubkey: string
|
authorPubkey: string
|
||||||
@ -45,15 +47,15 @@ export function buildTrackingData(
|
|||||||
confirmations: number
|
confirmations: number
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
transactionId,
|
transactionId: params.transactionId,
|
||||||
authorPubkey,
|
authorPubkey: params.authorPubkey,
|
||||||
authorMainnetAddress,
|
authorMainnetAddress: params.authorMainnetAddress,
|
||||||
amount: split.total,
|
amount: params.split.total,
|
||||||
authorAmount: split.authorSats,
|
authorAmount: params.split.authorSats,
|
||||||
platformCommission: split.platformSats,
|
platformCommission: params.split.platformSats,
|
||||||
timestamp: Math.floor(Date.now() / 1000),
|
timestamp: Math.floor(Date.now() / 1000),
|
||||||
confirmed: verification.confirmed,
|
confirmed: params.verification.confirmed,
|
||||||
confirmations: verification.confirmations,
|
confirmations: params.verification.confirmations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,11 +91,13 @@ export async function trackSponsoringPayment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const trackingData = buildTrackingData(
|
const trackingData = buildTrackingData(
|
||||||
transactionId,
|
{
|
||||||
authorPubkey,
|
transactionId,
|
||||||
authorMainnetAddress,
|
authorPubkey,
|
||||||
split,
|
authorMainnetAddress,
|
||||||
verification
|
split,
|
||||||
|
verification,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await sponsoringTrackingService.trackSponsoringPayment(trackingData, authorPrivateKey)
|
await sponsoringTrackingService.trackSponsoringPayment(trackingData, authorPrivateKey)
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { objectCache } from './objectCache'
|
|||||||
import { getCachedObjectById } from './helpers/queryHelpers'
|
import { getCachedObjectById } from './helpers/queryHelpers'
|
||||||
|
|
||||||
export async function getSponsoringById(sponsoringId: string, _timeoutMs: number = 5000): Promise<Sponsoring | null> {
|
export async function getSponsoringById(sponsoringId: string, _timeoutMs: number = 5000): Promise<Sponsoring | null> {
|
||||||
return await getCachedObjectById<Sponsoring>('sponsoring', sponsoringId)
|
return getCachedObjectById<Sponsoring>('sponsoring', sponsoringId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSponsoringByAuthor(authorPubkey: string, _timeoutMs: number = 5000): Promise<Sponsoring[]> {
|
export async function getSponsoringByAuthor(authorPubkey: string, _timeoutMs: number = 5000): Promise<Sponsoring[]> {
|
||||||
|
|||||||
@ -152,12 +152,21 @@ class ServiceWorkerSyncHandler {
|
|||||||
if (status.success) {
|
if (status.success) {
|
||||||
successfulRelays.push(relayUrl)
|
successfulRelays.push(relayUrl)
|
||||||
// Log successful publication
|
// Log successful publication
|
||||||
void publishLog.logPublication(event.id, relayUrl, true, undefined)
|
void publishLog.logPublication({
|
||||||
|
eventId: event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: true,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
const errorMessage = status.error ?? 'Unknown error'
|
const errorMessage = status.error ?? 'Unknown error'
|
||||||
console.error(`[SWSyncHandler] Relay ${relayUrl} failed:`, errorMessage)
|
console.error(`[SWSyncHandler] Relay ${relayUrl} failed:`, errorMessage)
|
||||||
// Log failed publication
|
// Log failed publication
|
||||||
void publishLog.logPublication(event.id, relayUrl, false, errorMessage)
|
void publishLog.logPublication({
|
||||||
|
eventId: event.id,
|
||||||
|
relayUrl,
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,16 @@ class WriteOrchestrator {
|
|||||||
.filter((relay): relay is string => relay !== null)
|
.filter((relay): relay is string => relay !== null)
|
||||||
}),
|
}),
|
||||||
// 2. Write to IndexedDB via Web Worker (en parallèle, avec published: false initialement)
|
// 2. Write to IndexedDB via Web Worker (en parallèle, avec published: false initialement)
|
||||||
writeService.writeObject(objectType, hash, event, parsed, version, hidden, index, false),
|
writeService.writeObject({
|
||||||
|
objectType,
|
||||||
|
hash,
|
||||||
|
event,
|
||||||
|
parsed,
|
||||||
|
version,
|
||||||
|
hidden,
|
||||||
|
...(index !== undefined ? { index } : {}),
|
||||||
|
published: false,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
// Traiter le résultat réseau
|
// Traiter le résultat réseau
|
||||||
@ -85,24 +94,24 @@ class WriteOrchestrator {
|
|||||||
/**
|
/**
|
||||||
* Create and publish event from template
|
* Create and publish event from template
|
||||||
*/
|
*/
|
||||||
async createAndPublishEvent(
|
async createAndPublishEvent(params: {
|
||||||
eventTemplate: EventTemplate,
|
eventTemplate: EventTemplate
|
||||||
relays: string[],
|
relays: string[]
|
||||||
objectType: ObjectType,
|
objectType: ObjectType
|
||||||
hash: string,
|
hash: string
|
||||||
parsed: unknown,
|
parsed: unknown
|
||||||
version: number,
|
version: number
|
||||||
hidden: boolean,
|
hidden: boolean
|
||||||
index?: number
|
index?: number
|
||||||
): Promise<{ success: boolean; event: NostrEvent; published: false | string[] }> {
|
}): Promise<{ success: boolean; event: NostrEvent; published: false | string[] }> {
|
||||||
if (!this.privateKey) {
|
if (!this.privateKey) {
|
||||||
throw new Error('Private key not set')
|
throw new Error('Private key not set')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create event
|
// Create event
|
||||||
const unsignedEvent: EventTemplate = {
|
const unsignedEvent: EventTemplate = {
|
||||||
...eventTemplate,
|
...params.eventTemplate,
|
||||||
created_at: eventTemplate.created_at ?? Math.floor(Date.now() / 1000),
|
created_at: params.eventTemplate.created_at ?? Math.floor(Date.now() / 1000),
|
||||||
}
|
}
|
||||||
|
|
||||||
const secretKey = hexToBytes(this.privateKey)
|
const secretKey = hexToBytes(this.privateKey)
|
||||||
@ -111,15 +120,15 @@ class WriteOrchestrator {
|
|||||||
// Write and publish
|
// Write and publish
|
||||||
const result = await this.writeAndPublish(
|
const result = await this.writeAndPublish(
|
||||||
{
|
{
|
||||||
objectType,
|
objectType: params.objectType,
|
||||||
hash,
|
hash: params.hash,
|
||||||
event: finalizedEvent,
|
event: finalizedEvent,
|
||||||
parsed,
|
parsed: params.parsed,
|
||||||
version,
|
version: params.version,
|
||||||
hidden,
|
hidden: params.hidden,
|
||||||
...(index !== undefined ? { index } : {}),
|
...(params.index !== undefined ? { index: params.index } : {}),
|
||||||
},
|
},
|
||||||
relays
|
params.relays
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -7,6 +7,34 @@
|
|||||||
import type { NostrEvent } from 'nostr-tools'
|
import type { NostrEvent } from 'nostr-tools'
|
||||||
import type { ObjectType } from './objectCache'
|
import type { ObjectType } from './objectCache'
|
||||||
|
|
||||||
|
interface WriteObjectParams {
|
||||||
|
objectType: ObjectType
|
||||||
|
hash: string
|
||||||
|
event: NostrEvent
|
||||||
|
parsed: unknown
|
||||||
|
version: number
|
||||||
|
hidden: boolean
|
||||||
|
index?: number
|
||||||
|
published?: false | string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateNotificationParams {
|
||||||
|
type: string
|
||||||
|
objectType: string
|
||||||
|
objectId: string
|
||||||
|
eventId: string
|
||||||
|
data?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LogPublicationParams {
|
||||||
|
eventId: string
|
||||||
|
relayUrl: string
|
||||||
|
success: boolean
|
||||||
|
error?: string
|
||||||
|
objectType?: string
|
||||||
|
objectId?: string
|
||||||
|
}
|
||||||
|
|
||||||
class WriteService {
|
class WriteService {
|
||||||
private writeWorker: Worker | null = null
|
private writeWorker: Worker | null = null
|
||||||
private initPromise: Promise<void> | null = null
|
private initPromise: Promise<void> | null = null
|
||||||
@ -91,19 +119,12 @@ class WriteService {
|
|||||||
/**
|
/**
|
||||||
* Write object to IndexedDB (via Web Worker)
|
* Write object to IndexedDB (via Web Worker)
|
||||||
*/
|
*/
|
||||||
async writeObject(
|
async writeObject(params: WriteObjectParams): Promise<void> {
|
||||||
objectType: ObjectType,
|
|
||||||
hash: string,
|
|
||||||
event: NostrEvent,
|
|
||||||
parsed: unknown,
|
|
||||||
version: number,
|
|
||||||
hidden: boolean,
|
|
||||||
index?: number,
|
|
||||||
published: false | string[] = false
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
try {
|
||||||
await this.init()
|
await this.init()
|
||||||
|
|
||||||
|
const published = params.published ?? false
|
||||||
|
|
||||||
if (this.writeWorker) {
|
if (this.writeWorker) {
|
||||||
// Send to worker
|
// Send to worker
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -113,7 +134,7 @@ class WriteService {
|
|||||||
|
|
||||||
const handler = (event: MessageEvent): void => {
|
const handler = (event: MessageEvent): void => {
|
||||||
const { type, data } = event.data
|
const { type, data } = event.data
|
||||||
if (type === 'WRITE_OBJECT_SUCCESS' && data.hash === hash) {
|
if (type === 'WRITE_OBJECT_SUCCESS' && data.hash === params.hash) {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
this.writeWorker?.removeEventListener('message', handler)
|
this.writeWorker?.removeEventListener('message', handler)
|
||||||
resolve()
|
resolve()
|
||||||
@ -129,13 +150,13 @@ class WriteService {
|
|||||||
this.writeWorker.postMessage({
|
this.writeWorker.postMessage({
|
||||||
type: 'WRITE_OBJECT',
|
type: 'WRITE_OBJECT',
|
||||||
data: {
|
data: {
|
||||||
objectType,
|
objectType: params.objectType,
|
||||||
hash,
|
hash: params.hash,
|
||||||
event,
|
event: params.event,
|
||||||
parsed,
|
parsed: params.parsed,
|
||||||
version,
|
version: params.version,
|
||||||
hidden,
|
hidden: params.hidden,
|
||||||
index,
|
index: params.index,
|
||||||
published,
|
published,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -144,7 +165,16 @@ class WriteService {
|
|||||||
}
|
}
|
||||||
// Fallback: direct write
|
// Fallback: direct write
|
||||||
const { objectCache } = await import('./objectCache')
|
const { objectCache } = await import('./objectCache')
|
||||||
await objectCache.set(objectType, hash, event, parsed, version, hidden, index, published)
|
await objectCache.set({
|
||||||
|
objectType: params.objectType,
|
||||||
|
hash: params.hash,
|
||||||
|
event: params.event,
|
||||||
|
parsed: params.parsed,
|
||||||
|
version: params.version,
|
||||||
|
hidden: params.hidden,
|
||||||
|
...(params.index !== undefined ? { index: params.index } : {}),
|
||||||
|
...(params.published !== undefined ? { published: params.published } : {}),
|
||||||
|
})
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[WriteService] Error writing object:', error)
|
console.error('[WriteService] Error writing object:', error)
|
||||||
@ -205,13 +235,7 @@ class WriteService {
|
|||||||
/**
|
/**
|
||||||
* Create notification (via Web Worker)
|
* Create notification (via Web Worker)
|
||||||
*/
|
*/
|
||||||
async createNotification(
|
async createNotification(params: CreateNotificationParams): Promise<void> {
|
||||||
type: string,
|
|
||||||
objectType: string,
|
|
||||||
objectId: string,
|
|
||||||
eventId: string,
|
|
||||||
data?: Record<string, unknown>
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
try {
|
||||||
await this.init()
|
await this.init()
|
||||||
|
|
||||||
@ -224,7 +248,7 @@ class WriteService {
|
|||||||
|
|
||||||
const handler = (event: MessageEvent): void => {
|
const handler = (event: MessageEvent): void => {
|
||||||
const { type: responseType, data: responseData } = event.data
|
const { type: responseType, data: responseData } = event.data
|
||||||
if (responseType === 'CREATE_NOTIFICATION_SUCCESS' && responseData.eventId === eventId) {
|
if (responseType === 'CREATE_NOTIFICATION_SUCCESS' && responseData.eventId === params.eventId) {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
this.writeWorker?.removeEventListener('message', handler)
|
this.writeWorker?.removeEventListener('message', handler)
|
||||||
resolve()
|
resolve()
|
||||||
@ -239,7 +263,13 @@ class WriteService {
|
|||||||
this.writeWorker.addEventListener('message', handler)
|
this.writeWorker.addEventListener('message', handler)
|
||||||
this.writeWorker.postMessage({
|
this.writeWorker.postMessage({
|
||||||
type: 'CREATE_NOTIFICATION',
|
type: 'CREATE_NOTIFICATION',
|
||||||
data: { type, objectType, objectId, eventId, notificationData: data },
|
data: {
|
||||||
|
type: params.type,
|
||||||
|
objectType: params.objectType,
|
||||||
|
objectId: params.objectId,
|
||||||
|
eventId: params.eventId,
|
||||||
|
notificationData: params.data,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -247,13 +277,13 @@ class WriteService {
|
|||||||
// Fallback: direct write
|
// Fallback: direct write
|
||||||
const { notificationService } = await import('./notificationService')
|
const { notificationService } = await import('./notificationService')
|
||||||
const notificationParams: Parameters<typeof notificationService.createNotification>[0] = {
|
const notificationParams: Parameters<typeof notificationService.createNotification>[0] = {
|
||||||
type: type as Parameters<typeof notificationService.createNotification>[0]['type'],
|
type: params.type as Parameters<typeof notificationService.createNotification>[0]['type'],
|
||||||
objectType,
|
objectType: params.objectType,
|
||||||
objectId,
|
objectId: params.objectId,
|
||||||
eventId,
|
eventId: params.eventId,
|
||||||
}
|
}
|
||||||
if (data !== undefined) {
|
if (params.data !== undefined) {
|
||||||
notificationParams.data = data
|
notificationParams.data = params.data
|
||||||
}
|
}
|
||||||
await notificationService.createNotification(notificationParams)
|
await notificationService.createNotification(notificationParams)
|
||||||
|
|
||||||
@ -267,14 +297,7 @@ class WriteService {
|
|||||||
/**
|
/**
|
||||||
* Log publication (via Web Worker)
|
* Log publication (via Web Worker)
|
||||||
*/
|
*/
|
||||||
async logPublication(
|
async logPublication(params: LogPublicationParams): Promise<void> {
|
||||||
eventId: string,
|
|
||||||
relayUrl: string,
|
|
||||||
success: boolean,
|
|
||||||
error?: string,
|
|
||||||
objectType?: string,
|
|
||||||
objectId?: string
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
try {
|
||||||
await this.init()
|
await this.init()
|
||||||
|
|
||||||
@ -282,13 +305,20 @@ class WriteService {
|
|||||||
// Send to worker
|
// Send to worker
|
||||||
this.writeWorker.postMessage({
|
this.writeWorker.postMessage({
|
||||||
type: 'LOG_PUBLICATION',
|
type: 'LOG_PUBLICATION',
|
||||||
data: { eventId, relayUrl, success, error, objectType, objectId },
|
data: {
|
||||||
|
eventId: params.eventId,
|
||||||
|
relayUrl: params.relayUrl,
|
||||||
|
success: params.success,
|
||||||
|
error: params.error,
|
||||||
|
objectType: params.objectType,
|
||||||
|
objectId: params.objectId,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
// Don't wait for response for logs (fire and forget)
|
// Don't wait for response for logs (fire and forget)
|
||||||
} else {
|
} else {
|
||||||
// Fallback: direct write
|
// Fallback: direct write
|
||||||
const { publishLog } = await import('./publishLog')
|
const { publishLog } = await import('./publishLog')
|
||||||
await publishLog.logPublicationDirect(eventId, relayUrl, success, error, objectType, objectId)
|
await publishLog.logPublicationDirect(params)
|
||||||
}
|
}
|
||||||
} catch (logError) {
|
} catch (logError) {
|
||||||
console.error('[WriteService] Error logging publication:', logError)
|
console.error('[WriteService] Error logging publication:', logError)
|
||||||
|
|||||||
@ -19,23 +19,23 @@ export class ZapVerificationService {
|
|||||||
/**
|
/**
|
||||||
* Check if a zap receipt is valid for a specific article and user
|
* Check if a zap receipt is valid for a specific article and user
|
||||||
*/
|
*/
|
||||||
verifyZapReceiptForArticle(
|
verifyZapReceiptForArticle(params: {
|
||||||
zapReceipt: Event,
|
zapReceipt: Event
|
||||||
articleId: string,
|
articleId: string
|
||||||
articlePubkey: string,
|
articlePubkey: string
|
||||||
_userPubkey: string,
|
userPubkey: string
|
||||||
expectedAmount: number
|
expectedAmount: number
|
||||||
): boolean {
|
}): boolean {
|
||||||
if (!this.verifyZapReceiptSignature(zapReceipt)) {
|
if (!this.verifyZapReceiptSignature(params.zapReceipt)) {
|
||||||
console.warn('Zap receipt signature verification failed')
|
console.warn('Zap receipt signature verification failed')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
this.isRecipientValid(zapReceipt, articlePubkey) &&
|
this.isRecipientValid(params.zapReceipt, params.articlePubkey) &&
|
||||||
this.isArticleReferenced(zapReceipt, articleId) &&
|
this.isArticleReferenced(params.zapReceipt, params.articleId) &&
|
||||||
this.isAmountValid(zapReceipt, expectedAmount) &&
|
this.isAmountValid(params.zapReceipt, params.expectedAmount) &&
|
||||||
this.isZapKind(zapReceipt)
|
this.isZapKind(params.zapReceipt)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user