Email digest: GET-first restore on boot so reloads stop re-sending confirmations
All checks were successful
CI / lint-check-build (pull_request) Successful in 3m25s
All checks were successful
CI / lint-check-build (pull_request) Successful in 3m25s
Mail.sync's boot reconcile now GETs the existing subscription (NIP-98 auth) before deciding what to do. When a subscription already exists for the pubkey with the same email and frequency, its key/callback are restored in memory and the PUT is skipped entirely. Only a matching subscription missing the requested params triggers a PUT, so a page refresh of an unconfirmed address no longer makes mailship re-send a confirmation email (previously each reload sent one).
This commit is contained in:
parent
63cf801ef1
commit
609a2f65ea
1 changed files with 56 additions and 1 deletions
|
|
@ -150,6 +150,42 @@ export class MailNotifications {
|
||||||
return this._register
|
return this._register
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the existing subscription for this pubkey (if any) without creating
|
||||||
|
// or changing anything. Used at boot to restore state instead of re-PUTting,
|
||||||
|
// which would otherwise re-send a confirmation email for an unconfirmed
|
||||||
|
// address on every reload.
|
||||||
|
async lookup(): Promise<
|
||||||
|
| {
|
||||||
|
key: string
|
||||||
|
callback: string
|
||||||
|
email: string
|
||||||
|
frequency: string
|
||||||
|
confirmed: boolean
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
> {
|
||||||
|
const $signer = app.get().user?.signer
|
||||||
|
if (!$signer || !EMAIL_NOTIFICATION_SERVER) return undefined
|
||||||
|
|
||||||
|
try {
|
||||||
|
const authEvent = await $signer.sign(
|
||||||
|
await makeHttpAuth(buildUrl(EMAIL_NOTIFICATION_SERVER, "subscription", "email"), "GET"),
|
||||||
|
)
|
||||||
|
const authHeader = makeHttpAuthHeader(authEvent)
|
||||||
|
|
||||||
|
const res = await fetch(buildUrl(EMAIL_NOTIFICATION_SERVER, "subscription", "email"), {
|
||||||
|
method: "GET",
|
||||||
|
headers: {Authorization: authHeader},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!res.ok) return undefined
|
||||||
|
|
||||||
|
return await res.json()
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async unregister() {
|
async unregister() {
|
||||||
const {key} = emailNotificationState.get()
|
const {key} = emailNotificationState.get()
|
||||||
if (!key) return
|
if (!key) return
|
||||||
|
|
@ -231,8 +267,27 @@ export class MailNotifications {
|
||||||
|
|
||||||
reconciledPubkey = $pubkey
|
reconciledPubkey = $pubkey
|
||||||
|
|
||||||
|
// GET-first: if a subscription already exists for this pubkey with the
|
||||||
|
// same email and cadence, restore its state (key/callback) instead of
|
||||||
|
// PUTting. A PUT here would make mailship re-send a confirmation email
|
||||||
|
// for an unconfirmed address on every app reload. Only register when
|
||||||
|
// there's nothing to restore or the settings changed.
|
||||||
|
const existing = await this.lookup()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.register(emailAddress, emailFrequency)
|
if (!existing) {
|
||||||
|
await this.register(emailAddress, emailFrequency)
|
||||||
|
} else if (existing.email !== emailAddress || existing.frequency !== emailFrequency) {
|
||||||
|
await this.register(emailAddress, emailFrequency)
|
||||||
|
} else {
|
||||||
|
emailNotificationState.set({
|
||||||
|
key: existing.key,
|
||||||
|
callback: existing.callback,
|
||||||
|
email: existing.email,
|
||||||
|
frequency: existing.frequency,
|
||||||
|
error: undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue