-
-
Notifications
You must be signed in to change notification settings - Fork 252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(unlock-app): Checkout hooks #15234
base: master
Are you sure you want to change the base?
Conversation
… checkout-hooks
if (!url) return | ||
|
||
if (JSON.stringify(body) === prevBody) { | ||
console.log('DUPLICATE REQUEST!! Skipping...', event, body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please clean this up.
<fieldset className="flex flex-col gap-4"> | ||
<legend>Hooks</legend> | ||
<p className="text-sm text-gray-600"> | ||
Configure URLs for specific events during the checkout process | ||
</p> | ||
<Input | ||
label="Status" | ||
size="small" | ||
description="URL to be called on status change" | ||
{...register('hooks.status')} | ||
/> | ||
<Input | ||
label="Authenticated" | ||
size="small" | ||
description="URL to be called when the user is authenticated" | ||
{...register('hooks.authenticated')} | ||
/> | ||
<Input | ||
label="Transaction Sent" | ||
size="small" | ||
description="URL to be called when a transaction is sent" | ||
{...register('hooks.transactionSent')} | ||
/> | ||
<Input | ||
label="Metadata" | ||
size="small" | ||
description="URL to be called for metadata updates" | ||
{...register('hooks.metadata')} | ||
/> | ||
</fieldset> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do add this. This should be a "developer" only setting and I worry this may complicate things for non-dev users. Hooks should only be "configurable" with the API/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit intrigued about notifications. Can you explain?
must've overlooked this as toast notifications instead of the one in notification menu, adding 👍 |
@iMac7 is attempting to deploy a commit to the Unlock Protocol Team on Vercel. A member of the Team first needs to authorize it. |
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 1 Skipped Deployment
|
added notifications |
|
||
const saveToLocalStorage = (data: any) => { | ||
const hooks = localStorage.getItem('hooks') | ||
const parsed = (hooks && JSON.parse(hooks)) ?? [] | ||
localStorage.setItem( | ||
'hooks', | ||
JSON.stringify([...parsed, { id: parsed.length, ...data }]) | ||
) | ||
} | ||
|
||
let prevBody: string | null = null | ||
export const postToWebhook = async (body: any, config: any, event: string) => { | ||
const url = config?.hooks && config.hooks[event] | ||
|
||
if (!url) return | ||
|
||
if (JSON.stringify(body) === prevBody) { | ||
return | ||
} | ||
|
||
prevBody = JSON.stringify(body) | ||
|
||
const sendWebhookRequest = async (attempt: number) => { | ||
await axios.post(url, body) | ||
const text = `Sent ${event} event data to ${url} on attempt ${attempt}` | ||
toast.success(text) | ||
|
||
const data = { text, created: new Date().toISOString(), success: true } | ||
saveToLocalStorage(data) | ||
} | ||
|
||
const retryRequest = async (maxRetries: number) => { | ||
let lastError: any | ||
let attempt = 0 | ||
|
||
while (attempt < maxRetries) { | ||
try { | ||
attempt++ | ||
await sendWebhookRequest(attempt) | ||
return | ||
} catch (error) { | ||
lastError = error | ||
toast.error( | ||
`Could not post ${event} event data to ${url}. Attempt ${attempt}` | ||
) | ||
if (attempt < maxRetries) { | ||
const delay = attempt === 1 ? 1000 : 3000 | ||
await new Promise((resolve) => setTimeout(resolve, delay)) | ||
} | ||
} | ||
} | ||
|
||
setTimeout(() => { | ||
if (lastError && attempt === maxRetries) { | ||
const text = `Failed to post ${event} event data to ${url}` | ||
toast.error(text) | ||
const data = { text, created: new Date().toISOString(), success: false } | ||
saveToLocalStorage(data) | ||
} | ||
}, 1000) | ||
|
||
throw lastError | ||
} | ||
|
||
try { | ||
await retryRequest(3) | ||
} catch (error) { | ||
console.error('Webhook request failed:', error) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a security issue as well as reliability. No calls should be made to user given urls from frontend. It should go through a proxy and have some sort of verification.
Also exponential backoff is preferred in cases such as this and should account for failure by storing the request data in backend. This should be easy to add as a worker to graphile-worker in locksmith/workers directory.
Description
Issues
Fixes #15067
Refs #
Checklist:
Release Note Draft Snippet
https://www.loom.com/share/3ef701f86f8a4cea9398d05e515be7a6?sid=ef35bc2e-1fc9-4ce6-9479-87b93da5d7bc