Webhooks-DA-y9GWA.js 16 KB

1234567891011
  1. import{a as e,n as t}from"./react-dom-stZKkA6x.js";import{a as n,d as r,r as i}from"./theme-CVfSdO4m.js";import{At as a,J as o,ct as s,i as c,n as l,t as u}from"./jsx-runtime-C5RSiriy.js";import{r as d}from"./card-DMbCO2Fu.js";import{n as ee,t as te}from"./table-DDUhevyo.js";import{n as ne,r as re,t as f}from"./StatusPill-BYj3zI1_.js";import{t as p}from"./descriptions-gniVz27W.js";import{t as m}from"./form-y5mvm6Rb.js";import{t as ie}from"./input-7g-iBRng.js";import{t as ae}from"./modal-C7xDa6TW.js";import{t as oe}from"./popconfirm-D_VEsRZH.js";import{t as se}from"./switch-CKxlbFCo.js";import{t as ce}from"./CopyOutlined-BbN7wZaI.js";import{t as le}from"./DeleteOutlined-J0odQPKG.js";import{t as ue}from"./EditOutlined-CO1ElKoL.js";import{t as de}from"./PlusOutlined-B79Dovl9.js";import{t as h}from"./ReloadOutlined-By3LF9WE.js";import{t as fe}from"./ThunderboltOutlined-C6K0mmNg.js";import{a as pe,d as me,f as he,g,m as ge,y as _e}from"./index-Dy4xV4t8.js";import{t as _}from"./EmptyState-CeUjt5Wb.js";import{t as ve}from"./CodeBlock-Cehl-9Ci.js";import{n as ye,t as be}from"./navigation-state-ixI_efPF.js";var v=e(t(),1),y=u(),xe=[`sent`,`bounced`,`failed`,`opened`,`clicked`],Se=[...xe,`received`],Ce=[`pending`,`processing`,`success`,`dead`];function b({domainId:e,mailboxId:t,domains:u=[],mailboxes:b=[],onCopy:ke}){let{message:x}=r.useApp(),{t:S}=n(),C=me(),Ae=he(),[w,je]=ge(),Me=Number(w.get(`domainId`)||0)||void 0,Ne=Number(w.get(`mailboxId`)||0)||void 0,T=Te(w.get(`webhookId`)),E=Ee(w.get(`deliveryStatus`)),D=De(w.get(`deliveryEvent`)),O=e??Me,k=t??Ne,Pe=e!=null||t!=null,[A,Fe]=(0,v.useState)([]),[Ie,Le]=(0,v.useState)([]),[j,M]=(0,v.useState)([]),[Re,N]=(0,v.useState)(!1),[ze,P]=(0,v.useState)(``),[Be,Ve]=(0,v.useState)(u),[He,Ue]=(0,v.useState)(b),[F,We]=(0,v.useState)(!0),[I,L]=(0,v.useState)(``),[Ge,Ke]=(0,v.useState)(!1),[R,z]=(0,v.useState)(null),[B,V]=(0,v.useState)(null),[H]=m.useForm(),U=(0,v.useRef)(0),W=k!=null,G=O!=null||W,K=W?[`received`]:xe,qe=(0,v.useMemo)(()=>new Map(Be.map(e=>[e.id,e.domain])),[Be]),Je=(0,v.useMemo)(()=>new Map(He.map(e=>[e.id,e.address])),[He]),q=(0,v.useMemo)(()=>T&&A.find(e=>e.id===T)||null,[T,A]),J=(0,v.useCallback)(async()=>{We(!0);try{let e=!u.length||!b.length?[i.domains(),i.inboundMailboxes()]:null,[t,n,r]=await Promise.all([i.webhooks(W?void 0:O??void 0,k),i.webhookDeliveries({limit:100}),e?Promise.all(e):Promise.resolve(null)]);r&&(Ve(r[0].domains||[]),Ue(r[1].mailboxes||[]));let a=(t.webhooks||[]).filter(e=>G||e.mailboxId==null);Fe(a);let o=new Set(a.map(e=>e.id)),s=(n.deliveries||[]).filter(e=>G?o.has(e.webhookId):!0);Le(s)}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{We(!1)}},[O,u.length,k,W,b.length,x,G,S]);(0,v.useEffect)(()=>{u.length&&Ve(u)},[u]),(0,v.useEffect)(()=>{b.length&&Ue(b)},[b]),(0,v.useEffect)(()=>{J()},[J]);let Ye=(0,v.useMemo)(()=>{let e=new Map;for(let t of Ie)e.has(t.webhookId)||e.set(t.webhookId,t);return e},[Ie]),Y=(0,v.useCallback)(async()=>{let e=++U.current;if(!T){M([]),P(``),N(!1);return}M([]),P(``),N(!0);try{let t=await i.webhookDeliveries({webhookId:T,status:E===`all`?void 0:E,eventType:D===`all`?void 0:D,limit:200});e===U.current&&M(t.deliveries||[])}catch(t){e===U.current&&P(t instanceof Error?t.message:S(`common.error`))}finally{e===U.current&&N(!1)}},[D,E,T,S]);(0,v.useEffect)(()=>{Y()},[Y]);async function X(e){if(e){if(ke){ke(e);return}await navigator.clipboard.writeText(e),x.success(S(`common.copied`))}}function Xe(){z(null),H.setFieldsValue({name:``,url:``,events:[...K],domainId:W?void 0:O??void 0,enabled:!0}),Ke(!0)}function Ze(e){z(e),H.setFieldsValue({name:e.name,url:e.url,events:e.events?.length?[...e.events]:[...K],domainId:e.domainId??void 0,enabled:e.enabled}),Ke(!0)}function Z(){Ke(!1),z(null),H.resetFields()}async function Qe(){let e=await H.validateFields(),t=R?`save:${R.id}`:`create`;L(t);try{let t={name:e.name.trim(),url:e.url.trim(),events:e.events,domainId:W?null:O??e.domainId??null,mailboxId:W?k:null,enabled:e.enabled};if(R)await i.updateWebhook(R.id,t),x.success(S(`actions.webhookUpdated`)),Z(),await J();else{let e=await i.createWebhook(t);x.success(S(`actions.webhookCreated`)),Z(),e.webhook?.secret&&V({webhook:e.webhook,mode:`created`}),await J()}}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{L(``)}}async function $e(e,t){L(`toggle:${e.id}`);try{await i.updateWebhook(e.id,{enabled:t}),Fe(n=>n.map(n=>n.id===e.id?{...n,enabled:t}:n))}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{L(``)}}async function et(e){L(`delete:${e.id}`);try{await i.deleteWebhook(e.id),x.success(S(`actions.webhookDeleted`)),T===e.id&&at(),await J()}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{L(``)}}async function tt(e){L(`rotate:${e.id}`);try{let t=await i.rotateWebhookSecret(e.id);x.success(S(`actions.webhookSecretRotated`)),t.webhook?.secret&&V({webhook:t.webhook,mode:`rotated`}),await J()}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{L(``)}}async function nt(e){L(`test:${e.id}`);try{await i.testWebhook(e.id),x.success(S(`actions.webhookTestQueued`)),await J(),it(e)}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{L(``)}}async function rt(e){L(`replay:${e.id}`);try{await i.replayWebhookDelivery(e.id),x.success(S(`actions.webhookDeliveryReplayed`)),await Promise.all([J(),Y()])}catch(e){x.error(e instanceof Error?e.message:S(`common.error`))}finally{L(``)}}function it(e){let t=new URLSearchParams(w);t.set(`webhookId`,String(e.id)),t.delete(`deliveryStatus`),t.delete(`deliveryEvent`),je(t,{state:be(`${C.pathname}${C.search}`,1)})}function at(){let e=ye(C.state);if(e){Ae(-e.depth);return}let t=new URLSearchParams(w);t.delete(`webhookId`),t.delete(`deliveryStatus`),t.delete(`deliveryEvent`),je(t,{replace:!0,state:null})}function ot(e,t){let n=new URLSearchParams(w);t===`all`?n.delete(e):n.set(e,t);let r=ye(C.state);if(!r){je(n,{replace:!0});return}let i=n.toString();Ae({pathname:C.pathname,search:i?`?${i}`:``},{state:be(r.listPath,r.depth+1)})}function st(e){if(e.mailboxId!=null){let t=Je.get(e.mailboxId);return t?`${S(`webhooks.scopeMailbox`)} · ${t}`:S(`webhooks.scopeMailbox`)}if(e.domainId==null)return S(`webhooks.scopeAccount`);let t=qe.get(e.domainId);return t?`${S(`webhooks.scopeDomain`)} · ${t}`:S(`webhooks.scopeDomain`)}function Q(e){return e===`sent`?S(`webhooks.eventSent`):e===`bounced`?S(`webhooks.eventBounced`):e===`failed`?S(`webhooks.eventFailed`):e===`opened`?S(`webhooks.eventOpened`):e===`clicked`?S(`webhooks.eventClicked`):e===`received`?S(`webhooks.eventReceived`):e}function $(e){return e===`pending`?S(`webhooks.statusPending`):e===`processing`?S(`webhooks.statusProcessing`):e===`success`?S(`webhooks.statusSuccess`):e===`dead`?S(`webhooks.statusDead`):e}function ct(e){return e===`success`?`success`:e===`pending`?`info`:e===`processing`?`warning`:e===`dead`?`error`:`neutral`}function lt(e){let t=Ye.get(e.id);if(!t)return(0,y.jsx)(l.Text,{type:`secondary`,children:`—`});let n=t.error||(t.responseStatus==null?``:`HTTP ${t.responseStatus}`)||$(String(t.status));return(0,y.jsxs)(c,{size:6,wrap:!0,children:[(0,y.jsx)(f,{tone:ct(String(t.status)),children:$(String(t.status))}),(0,y.jsxs)(l.Text,{type:`secondary`,ellipsis:!0,className:`inline-code-value`,children:[Q(String(t.eventType)),` · `,n]})]})}let ut=[{title:S(`webhooks.name`),dataIndex:`name`,render:(e,t)=>(0,y.jsxs)(c,{direction:`vertical`,size:0,children:[(0,y.jsx)(l.Text,{strong:!0,children:e}),(0,y.jsxs)(l.Text,{type:`secondary`,code:!0,children:[t.secretPrefix,`…`]})]})},{title:S(`webhooks.scope`),render:(e,t)=>st(t)},{title:S(`webhooks.url`),dataIndex:`url`,ellipsis:!0,render:e=>(0,y.jsx)(l.Text,{code:!0,ellipsis:!0,title:e,className:`inline-code-value`,children:we(e)})},{title:S(`webhooks.events`),dataIndex:`events`,render:e=>(0,y.jsx)(c,{size:[4,4],wrap:!0,children:(e||[]).map(e=>(0,y.jsx)(g,{children:Q(e)},e))})},{title:S(`webhooks.enabled`),dataIndex:`enabled`,width:100,render:(e,t)=>(0,y.jsx)(se,{checked:e,loading:I===`toggle:${t.id}`,onChange:e=>void $e(t,e),checkedChildren:S(`webhooks.enabled`),unCheckedChildren:S(`webhooks.disabled`)})},{title:S(`webhooks.lastAttemptAt`),render:(e,t)=>lt(t)},{title:S(`webhooks.actions`),fixed:`right`,width:280,render:(e,t)=>(0,y.jsxs)(c,{wrap:!0,size:4,children:[(0,y.jsx)(a,{size:`small`,icon:(0,y.jsx)(fe,{}),loading:I===`test:${t.id}`,onClick:()=>void nt(t),children:S(`webhooks.test`)}),(0,y.jsx)(a,{size:`small`,onClick:()=>it(t),children:S(`webhooks.viewDeliveries`)}),(0,y.jsx)(a,{size:`small`,icon:(0,y.jsx)(ue,{}),onClick:()=>Ze(t)}),(0,y.jsx)(oe,{title:S(`webhooks.rotateConfirm`),onConfirm:()=>void tt(t),children:(0,y.jsx)(a,{"aria-label":S(`webhooks.rotateSecret`),size:`small`,icon:(0,y.jsx)(pe,{}),loading:I===`rotate:${t.id}`})}),(0,y.jsx)(oe,{title:S(`webhooks.deleteConfirm`),onConfirm:()=>void et(t),children:(0,y.jsx)(a,{"aria-label":S(`common.delete`),size:`small`,danger:!0,icon:(0,y.jsx)(le,{}),loading:I===`delete:${t.id}`})})]})}],dt=[{title:S(`webhooks.createdAt`),dataIndex:`createdAt`,width:170,render:e=>e?new Date(e).toLocaleString():`—`},{title:S(`webhooks.events`),dataIndex:`eventType`,render:e=>(0,y.jsx)(g,{children:Q(e)})},{title:S(`common.status`),dataIndex:`status`,render:e=>(0,y.jsx)(f,{tone:ct(e),children:$(e)})},{title:S(`webhooks.attemptCount`),dataIndex:`attemptCount`,width:90},{title:S(`webhooks.responseStatus`),dataIndex:`responseStatus`,width:100,render:e=>e??`—`},{title:S(`webhooks.error`),dataIndex:`error`,ellipsis:!0,render:(e,t)=>e||t.responseBodyPreview||`—`},{title:S(`webhooks.lastAttemptAt`),dataIndex:`lastAttemptAt`,width:170,render:e=>e?new Date(e).toLocaleString():`—`},{title:S(`webhooks.actions`),fixed:`right`,width:110,render:(e,t)=>(0,y.jsx)(a,{size:`small`,disabled:t.status===`processing`,loading:I===`replay:${t.id}`,onClick:()=>void rt(t),children:S(`webhooks.replay`)})}],ft=B?.webhook.secret||``,pt=Oe(ft||`whsec_your_secret`);return(0,y.jsxs)(c,{direction:`vertical`,size:20,className:`full-width`,children:[Pe?(0,y.jsxs)(c,{direction:`vertical`,size:12,className:`full-width`,children:[(0,y.jsx)(d,{type:`info`,showIcon:!0,message:S(W?`webhooks.mailboxReceiptHelp`:`webhooks.domainOverrideHelp`)}),(0,y.jsxs)(c,{children:[(0,y.jsx)(a,{icon:(0,y.jsx)(h,{}),onClick:()=>void J(),loading:F,children:S(`common.refresh`)}),(0,y.jsx)(a,{type:`primary`,icon:(0,y.jsx)(de,{}),onClick:Xe,children:S(`webhooks.create`)})]})]}):(0,y.jsx)(re,{title:S(`webhooks.title`),subtitle:S(`webhooks.subtitle`),extra:(0,y.jsxs)(c,{children:[(0,y.jsx)(a,{icon:(0,y.jsx)(h,{}),onClick:()=>void J(),loading:F,children:S(`common.refresh`)}),(0,y.jsx)(a,{type:`primary`,icon:(0,y.jsx)(de,{}),onClick:Xe,children:S(`webhooks.create`)})]})}),Pe?null:(0,y.jsx)(d,{type:`info`,showIcon:!0,message:S(W?`webhooks.mailboxReceiptHelp`:`webhooks.domainOverrideHelp`)}),(0,y.jsx)(ne,{title:S(`webhooks.listTitle`),extra:(0,y.jsx)(f,{tone:`neutral`,children:A.length}),children:A.length?(0,y.jsx)(te,{rowKey:`id`,columns:ut,dataSource:A,loading:F,scroll:{x:1200},pagination:{pageSize:10}}):(0,y.jsx)(_,{description:S(`webhooks.empty`),action:(0,y.jsx)(a,{icon:(0,y.jsx)(de,{}),onClick:Xe,children:S(`webhooks.create`)})})}),(0,y.jsx)(_e,{title:S(R?`webhooks.editTitle`:`webhooks.createTitle`),width:520,open:Ge,onClose:Z,destroyOnHidden:!0,footer:(0,y.jsxs)(`div`,{className:`drawer-footer`,children:[(0,y.jsx)(a,{onClick:Z,children:S(`common.cancel`)}),(0,y.jsx)(a,{type:`primary`,loading:I===`create`||I.startsWith(`save:`),onClick:()=>void Qe(),children:S(R?`common.save`:`webhooks.create`)})]}),children:(0,y.jsxs)(m,{form:H,layout:`vertical`,initialValues:{enabled:!0,events:xe},children:[(0,y.jsx)(m.Item,{name:`name`,label:S(`webhooks.name`),rules:[{required:!0,message:S(`webhooks.nameRequired`)}],children:(0,y.jsx)(ie,{placeholder:S(`webhooks.namePlaceholder`)})}),(0,y.jsx)(m.Item,{name:`url`,label:S(`webhooks.url`),extra:S(`webhooks.urlHint`),rules:[{required:!0,message:S(`webhooks.urlRequired`)}],children:(0,y.jsx)(ie,{placeholder:S(`webhooks.urlPlaceholder`)})}),(0,y.jsx)(m.Item,{name:`events`,label:S(`webhooks.events`),rules:[{required:!0,type:`array`,min:1,message:S(`webhooks.eventsRequired`)}],children:(0,y.jsx)(ee.Group,{options:K.map(e=>({value:e,label:Q(e)})),disabled:W})}),G?null:(0,y.jsx)(m.Item,{name:`domainId`,label:S(`webhooks.domain`),extra:S(`webhooks.domainAccount`),children:(0,y.jsx)(o,{allowClear:!0,placeholder:S(`webhooks.domainAccount`),options:Be.map(e=>({value:e.id,label:e.domain}))})}),(0,y.jsx)(m.Item,{name:`enabled`,label:S(`webhooks.enabled`),valuePropName:`checked`,children:(0,y.jsx)(se,{})})]})}),(0,y.jsx)(_e,{title:q?`${q.name} · ${S(`webhooks.deliveriesTitle`)}`:S(`webhooks.deliveriesTitle`),width:760,open:!!T,onClose:at,children:F&&!q?(0,y.jsx)(`div`,{role:`status`,"aria-label":S(`webhooks.deliveriesTitle`),children:(0,y.jsx)(s,{active:!0,paragraph:{rows:8}})}):q?(0,y.jsxs)(c,{direction:`vertical`,size:20,className:`full-width`,children:[(0,y.jsxs)(p,{bordered:!0,column:1,size:`small`,children:[(0,y.jsx)(p.Item,{label:S(`webhooks.url`),children:(0,y.jsx)(l.Text,{code:!0,copyable:{onCopy:()=>void X(q.url)},children:q.url})}),(0,y.jsx)(p.Item,{label:S(`webhooks.scope`),children:st(q)}),(0,y.jsx)(p.Item,{label:S(`webhooks.events`),children:(0,y.jsx)(c,{wrap:!0,children:q.events.map(e=>(0,y.jsx)(g,{children:Q(e)},e))})}),(0,y.jsx)(p.Item,{label:S(`webhooks.secretPrefix`),children:(0,y.jsxs)(l.Text,{code:!0,children:[q.secretPrefix,`…`]})}),(0,y.jsx)(p.Item,{label:S(`common.status`),children:(0,y.jsx)(f,{tone:q.enabled?`success`:`neutral`,children:q.enabled?S(`webhooks.enabled`):S(`webhooks.disabled`)})})]}),(0,y.jsxs)(c,{wrap:!0,children:[(0,y.jsx)(o,{"aria-label":S(`webhooks.deliveriesFilterStatus`),style:{minWidth:160},value:E,onChange:e=>ot(`deliveryStatus`,e),options:[{value:`all`,label:S(`webhooks.allStatuses`)},...Ce.map(e=>({value:e,label:$(e)}))]}),(0,y.jsx)(o,{"aria-label":S(`webhooks.deliveriesFilterEvent`),style:{minWidth:160},value:D,onChange:e=>ot(`deliveryEvent`,e),options:[{value:`all`,label:S(`webhooks.allEvents`)},...Se.map(e=>({value:e,label:Q(e)}))]})]}),ze?(0,y.jsx)(d,{type:`error`,showIcon:!0,message:ze,action:(0,y.jsx)(a,{icon:(0,y.jsx)(h,{}),onClick:()=>void Y(),children:S(`common.refresh`)})}):Re&&!j.length?(0,y.jsx)(`div`,{role:`status`,"aria-label":S(`webhooks.deliveriesTitle`),children:(0,y.jsx)(s,{active:!0,paragraph:{rows:6}})}):j.length?(0,y.jsx)(te,{rowKey:`id`,columns:dt,dataSource:j,loading:Re,scroll:{x:920},pagination:{pageSize:10}}):(0,y.jsx)(_,{description:S(`webhooks.deliveriesEmpty`)}),(0,y.jsx)(d,{type:`info`,showIcon:!0,message:S(`webhooks.docsSignature`),description:S(`webhooks.docsEvents`)}),(0,y.jsx)(ve,{value:Oe(`whsec_your_secret`),onCopy:X})]}):T?(0,y.jsx)(_,{description:S(`common.notFound`)}):null}),(0,y.jsx)(ae,{title:B?.mode===`rotated`?S(`webhooks.secretRotatedTitle`):S(`webhooks.secretCreatedTitle`),open:!!B,closable:!1,maskClosable:!1,keyboard:!1,destroyOnHidden:!0,footer:[(0,y.jsx)(a,{icon:(0,y.jsx)(ce,{}),onClick:()=>void X(ft),children:S(`webhooks.copySecret`)},`copy`),(0,y.jsx)(a,{type:`primary`,onClick:()=>V(null),children:S(`common.confirm`)},`done`)],children:(0,y.jsxs)(c,{direction:`vertical`,size:16,className:`full-width`,children:[(0,y.jsx)(d,{type:`error`,showIcon:!0,message:S(`webhooks.secretCreatedWarning`)}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(l.Text,{type:`secondary`,children:S(`webhooks.secret`)}),(0,y.jsx)(ve,{value:ft,onCopy:X})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(l.Text,{type:`secondary`,children:S(`webhooks.docsSignature`)}),(0,y.jsx)(ve,{value:pt,onCopy:X})]})]})})]})}function we(e,t=48){return e?e.length<=t?e:`${e.slice(0,t-1)}…`:``}function Te(e){let t=Number(e);return Number.isInteger(t)&&t>0?t:null}function Ee(e){return Ce.includes(e)?e:`all`}function De(e){return Se.includes(e)?e:`all`}function Oe(e){return`// Verify X-MailHub-Signature (Node.js)
  2. const crypto = require('crypto');
  3. function verify(rawBody, signatureHeader, secret = ${JSON.stringify(e)}) {
  4. const parts = Object.fromEntries(
  5. signatureHeader.split(',').map((p) => p.trim().split('='))
  6. );
  7. const signed = \`\${parts.t}.\${rawBody}\`;
  8. const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex');
  9. return crypto.timingSafeEqual(Buffer.from(parts.v1, 'hex'), Buffer.from(expected, 'hex'));
  10. }`}export{b as default};