diff --git a/frontend/src/Composer.vue b/frontend/src/Composer.vue
index 32f32b9..f052d0c 100644
--- a/frontend/src/Composer.vue
+++ b/frontend/src/Composer.vue
@@ -18,6 +18,9 @@ const props = defineProps({
// kept — e.g. the contact panel's first-message name/email fields are
// still empty.
sendDisabled: { type: Boolean, default: false },
+ // Visitor side: an upload hit the end of the PoW quota (429 "pow") —
+ // re-prove and resolve, then the upload retries once.
+ reauthorize: { type: Function, default: null },
})
const emit = defineEmits(['send'])
@@ -86,7 +89,13 @@ async function uploadFiles(files) {
const path = `/_${props.token ? 'contact' : 'api'}/files/${encodeURIComponent(file.name)}`
const init = { method: 'PUT', body: file }
if (props.token) init.headers = { 'x-contact-token': props.token }
- const r = await (props.token ? fetch(path, init) : apiFetch(path, init))
+ const put = () => (props.token ? fetch(path, init) : apiFetch(path, init))
+ let r = await put()
+ if (!r.ok && r.status === 429 && props.reauthorize) {
+ // The PoW quota (shared with messages) ran out: re-prove, retry once.
+ const detail = await r.json().then((d) => d?.detail, () => null)
+ if (detail === 'pow' && (await props.reauthorize())) r = await put()
+ }
if (!r.ok) {
const detail = await r.json().then((d) => d?.detail, () => null)
throw new Error(detail || `status ${r.status}`)
diff --git a/frontend/src/ContactOverlay.vue b/frontend/src/ContactOverlay.vue
index 55065a2..bdc35b5 100644
--- a/frontend/src/ContactOverlay.vue
+++ b/frontend/src/ContactOverlay.vue
@@ -12,6 +12,8 @@ import MessagesView from './MessagesView.vue'
const props = defineProps({
state: { type: Object, required: true },
token: { type: String, required: true },
+ // Visitor-side PoW quota re-grant for the composer's upload retries.
+ reauthorize: { type: Function, default: null },
})
const emit = defineEmits(['send', 'close'])
@@ -45,7 +47,13 @@ onUnmounted(() => removeEventListener('keydown', onKey))
{{ state.email }}
- emit('send', p)" />
+ emit('send', p)"
+ />
diff --git a/frontend/src/ContactPanel.vue b/frontend/src/ContactPanel.vue
index 12be646..76380e0 100644
--- a/frontend/src/ContactPanel.vue
+++ b/frontend/src/ContactPanel.vue
@@ -11,6 +11,9 @@ import Composer from './Composer.vue'
const props = defineProps({
state: { type: Object, required: true },
token: { type: String, required: true },
+ // Re-grant the PoW quota (an upload hit its end): resolves once the
+ // fresh proof is accepted, so the upload can retry.
+ reauthorize: { type: Function, default: null },
})
const emit = defineEmits(['send'])
@@ -81,7 +84,13 @@ function onSend(md) {
-
+