@pg-boss/dashboard 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- window.__reactRouterManifest={"entry":{"module":"/assets/entry.client-CqyjuPDB.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/root-qxoeL6W3.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js"],"css":["/assets/root-B0MB8jZH.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/_index-DqpFaaQw.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/jobs":{"id":"routes/jobs","parentId":"root","path":"jobs","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/jobs-CAd_qqLH.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/x-AhXI_F1j.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/queues._index":{"id":"routes/queues._index","parentId":"root","path":"queues","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._index-8YriSqbQ.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/queues.create":{"id":"routes/queues.create","parentId":"root","path":"queues/create","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues.create-DsY0Sc19.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/chevron-down-BFFjfYD4.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/createLucideIcon-C-LI4enx.js"],"css":[]},"routes/queues.$name":{"id":"routes/queues.$name","parentId":"root","path":"queues/:name","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name-Cb17IB2u.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/dialog-D-oczDM2.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/x-AhXI_F1j.js"],"css":[]},"routes/queues.$name.jobs.$jobId":{"id":"routes/queues.$name.jobs.$jobId","parentId":"root","path":"queues/:name/jobs/:jobId","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name.jobs._jobId-Bkv8POBj.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/dialog-D-oczDM2.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/error-card-BH7i86fH.js","/assets/x-AhXI_F1j.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/schedules":{"id":"routes/schedules","parentId":"root","path":"schedules","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules-iYfIJxOD.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js"],"css":[]},"routes/schedules.$name.$key":{"id":"routes/schedules.$name.$key","parentId":"root","path":"schedules/:name/:key","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules._name._key-CJVu73XY.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/dialog-D-oczDM2.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/x-AhXI_F1j.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/createLucideIcon-C-LI4enx.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/schedules.new":{"id":"routes/schedules.new","parentId":"root","path":"schedules/new","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules.new-Cq0Mxa7G.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/send":{"id":"routes/send","parentId":"root","path":"send","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/send-8X9ZisG-.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/migrations":{"id":"routes/migrations","parentId":"root","path":"migrations","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/migrations-D5l0n4Jn.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/warnings":{"id":"routes/warnings","parentId":"root","path":"warnings","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/warnings-C1R_RzIe.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js"],"css":[]}},"url":"/assets/manifest-27e8e133.js","version":"27e8e133"};
1
+ window.__reactRouterManifest={"entry":{"module":"/assets/entry.client-CqyjuPDB.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/root-qxoeL6W3.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/react-dom-D_m_Zgd3.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js"],"css":["/assets/root-B0MB8jZH.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/_index-DqpFaaQw.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/jobs":{"id":"routes/jobs","parentId":"root","path":"jobs","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/jobs-CAd_qqLH.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/x-AhXI_F1j.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/queues._index":{"id":"routes/queues._index","parentId":"root","path":"queues","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._index-8YriSqbQ.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/queues.create":{"id":"routes/queues.create","parentId":"root","path":"queues/create","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues.create-DsY0Sc19.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/chevron-down-BFFjfYD4.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/createLucideIcon-C-LI4enx.js"],"css":[]},"routes/queues.$name":{"id":"routes/queues.$name","parentId":"root","path":"queues/:name","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name-Cb17IB2u.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/chevron-down-BFFjfYD4.js","/assets/chevron-right-DGk5QFJF.js","/assets/MenuTrigger-BNvpjhsQ.js","/assets/dialog-D-oczDM2.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js","/assets/react-dom-D_m_Zgd3.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/x-AhXI_F1j.js"],"css":[]},"routes/queues.$name.jobs.$jobId":{"id":"routes/queues.$name.jobs.$jobId","parentId":"root","path":"queues/:name/jobs/:jobId","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/queues._name.jobs._jobId-DzHZmfcB.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/createLucideIcon-C-LI4enx.js","/assets/check-7jwc5sb1.js","/assets/dialog-D-oczDM2.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/error-card-BH7i86fH.js","/assets/x-AhXI_F1j.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/schedules":{"id":"routes/schedules","parentId":"root","path":"schedules","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules-iYfIJxOD.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js"],"css":[]},"routes/schedules.$name.$key":{"id":"routes/schedules.$name.$key","parentId":"root","path":"schedules/:name/:key","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules._name._key-CJVu73XY.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/dialog-D-oczDM2.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js","/assets/x-AhXI_F1j.js","/assets/useOpenInteractionType-BQ1arb0B.js","/assets/createLucideIcon-C-LI4enx.js","/assets/react-dom-D_m_Zgd3.js"],"css":[]},"routes/schedules.new":{"id":"routes/schedules.new","parentId":"root","path":"schedules/new","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/schedules.new-Cq0Mxa7G.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/send":{"id":"routes/send","parentId":"root","path":"send","hasAction":true,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/send-8X9ZisG-.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/error-card-BH7i86fH.js"],"css":[]},"routes/migrations":{"id":"routes/migrations","parentId":"root","path":"migrations","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/migrations-D5l0n4Jn.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/stat-card-dyg1wY5p.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js"],"css":[]},"routes/warnings":{"id":"routes/warnings","parentId":"root","path":"warnings","hasAction":false,"hasLoader":true,"hasClientAction":false,"hasClientLoader":false,"hasClientMiddleware":false,"hasDefaultExport":true,"hasErrorBoundary":true,"module":"/assets/warnings-C1R_RzIe.js","imports":["/assets/jsx-runtime-RQyiN6Nr.js","/assets/db-link-BajQ1v8I.js","/assets/button-9NpSS9Ow.js","/assets/badge-CMnQO7Lq.js","/assets/table-Cz7ujmH_.js","/assets/error-card-BH7i86fH.js","/assets/pagination-C-ohiBmY.js","/assets/filter-select-Bn_oSiip.js"],"css":[]}},"url":"/assets/manifest-3e8f868c.js","version":"3e8f868c"};
@@ -1 +1 @@
1
- import{o as e,rt as t,s as n,t as r,tt as i}from"./jsx-runtime-RQyiN6Nr.js";import{h as a,j as o,m as s,t as c,u as l}from"./db-link-BajQ1v8I.js";import{t as u}from"./createLucideIcon-C-LI4enx.js";import{t as d}from"./check-7jwc5sb1.js";import{a as f,i as p,n as m,o as h,r as g,t as _}from"./dialog-D-oczDM2.js";import{a as v,i as y,n as b,r as x,t as S}from"./button-9NpSS9Ow.js";import{n as C,t as w}from"./badge-CMnQO7Lq.js";import{t as T}from"./error-card-BH7i86fH.js";var E=u(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),D=t(i(),1),O=r();function k({title:e,description:t,confirmLabel:n,confirmVariant:r=`primary`,triggerVariant:i=`ghost`,trigger:a,onConfirm:o,disabled:s}){let[c,l]=(0,D.useState)(!1);return(0,O.jsxs)(f,{open:c,onOpenChange:l,children:[(0,O.jsx)(S,{variant:i,size:`sm`,disabled:s,onClick:()=>l(!0),className:`cursor-pointer`,children:a}),(0,O.jsxs)(_,{hideCloseButton:!0,className:`w-[28rem] max-w-[calc(100vw-2rem)]`,children:[(0,O.jsxs)(p,{children:[(0,O.jsx)(h,{children:e}),(0,O.jsx)(m,{className:`mt-2`,children:t})]}),(0,O.jsxs)(g,{className:`mt-6 flex justify-end gap-3`,children:[(0,O.jsx)(S,{variant:`outline`,size:`sm`,className:`cursor-pointer`,onClick:()=>l(!1),children:`Cancel`}),(0,O.jsx)(S,{variant:r===`danger`?`danger`:`primary`,size:`sm`,className:`cursor-pointer`,onClick:()=>{o(),l(!1)},children:n})]})]})]})}var A=n(function(){return(0,O.jsx)(T,{title:`Failed to load job`,backTo:{href:`/queues`,label:`Back to Queues`}})}),j=e(function({loaderData:e}){let{job:t,queueName:n}=e,r=o(),i=r.state!==`idle`,[u,f]=(0,D.useState)(!1),p=r.data,m=p&&!p.success&&p.affected===0,h=e=>{r.submit({intent:e},{method:`post`})},g=async()=>{await navigator.clipboard.writeText(t.id),f(!0),setTimeout(()=>f(!1),2e3)},_=t.state===`failed`;return(0,O.jsxs)(`div`,{className:`space-y-4`,children:[(0,O.jsx)(C,{title:(0,O.jsxs)(`span`,{className:`inline-flex items-center gap-3`,children:[`Job detail`,(0,O.jsx)(w,{variant:l[t.state],size:`lg`,dot:!0,children:t.state})]}),action:(0,O.jsxs)(`div`,{className:`flex items-center gap-2`,children:[m&&(0,O.jsx)(`span`,{className:`text-xs text-[var(--warning-600)]`,title:p.message,children:`Action failed`}),t.state===`failed`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`retry`),children:`Retry`}),t.state===`cancelled`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`resume`),children:`Resume`}),(t.state===`created`||t.state===`retry`||t.state===`active`)&&(0,O.jsx)(k,{title:`Cancel Job`,description:`Are you sure you want to cancel job ${t.id.slice(0,8)}...? This will prevent the job from being processed.`,confirmLabel:`Cancel Job`,confirmVariant:`danger`,triggerVariant:`outline`,trigger:`Cancel`,onConfirm:()=>h(`cancel`),disabled:i}),t.state!==`active`&&(0,O.jsx)(k,{title:`Delete Job`,description:`Are you sure you want to delete job ${t.id.slice(0,8)}...? This action cannot be undone.`,confirmLabel:`Delete`,confirmVariant:`danger`,triggerVariant:`danger`,trigger:`Delete`,onConfirm:()=>h(`delete`),disabled:i})]})}),(0,O.jsxs)(b,{children:[(0,O.jsxs)(y,{children:[(0,O.jsx)(v,{children:`Details`}),(0,O.jsxs)(`span`,{className:`text-xs text-[var(--text-tertiary)]`,children:[`in queue`,` `,(0,O.jsx)(c,{to:`/queues/${encodeURIComponent(n)}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:n})]})]}),(0,O.jsxs)(x,{className:`space-y-6`,children:[(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-[2fr_1fr_1fr] gap-6`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1`,children:`Job ID`}),(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,O.jsx)(`code`,{className:`text-sm font-mono break-all text-[var(--text-primary)]`,children:t.id}),(0,O.jsx)(`button`,{onClick:g,className:s(`p-1 rounded-md transition-colors cursor-pointer flex-shrink-0`,`text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--surface-hover)]`),title:u?`Copied!`:`Copy to clipboard`,children:u?(0,O.jsx)(d,{className:`h-4 w-4 text-[var(--success-600)]`}):(0,O.jsx)(E,{className:`h-4 w-4`})})]})]}),(0,O.jsx)(M,{label:`Policy`,value:t.policy||`—`}),(0,O.jsx)(M,{label:`Priority`,value:t.priority,mono:!0})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Data`}),(0,O.jsx)(`pre`,{className:`text-xs px-3.5 py-3 rounded-lg border border-[var(--border-default)] bg-[var(--surface-sunken)] font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,children:t.data?JSON.stringify(t.data,null,2):`null`})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Output`}),(0,O.jsx)(`pre`,{className:s(`text-xs px-3.5 py-3 rounded-lg border font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,_?`border-[var(--error-100)] bg-[var(--error-50)]`:`border-[var(--border-default)] bg-[var(--surface-sunken)]`),children:t.output!==void 0&&t.output!==null?JSON.stringify(t.output,null,2):`—`})]})]}),(0,O.jsx)(`div`,{children:(0,O.jsxs)(`div`,{className:`space-y-6`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:(0,O.jsx)(M,{label:`Priority`,value:t.priority})}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Retry Count`,value:t.retryCount,mono:!0}),(0,O.jsx)(M,{label:`Retry Limit`,value:t.retryLimit,mono:!0}),(0,O.jsx)(M,{label:`Retry Delay`,value:t.retryDelay?`${t.retryDelay}ms`:`—`,mono:!0}),(0,O.jsx)(M,{label:`Retry Backoff`,value:t.retryBackoff?`Enabled`:`Disabled`})]}),(t.singletonKey||t.groupId||t.groupTier||t.deadLetter)&&(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[t.singletonKey&&(0,O.jsx)(M,{label:`Singleton Key`,value:t.singletonKey,mono:!0}),t.groupId&&(0,O.jsx)(M,{label:`Group ID`,value:t.groupId,mono:!0}),t.groupTier&&(0,O.jsx)(M,{label:`Group Tier`,value:t.groupTier,mono:!0}),t.deadLetter&&(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:`Dead Letter`}),(0,O.jsx)(`dd`,{className:`mt-1 text-sm text-[var(--text-primary)]`,children:(0,O.jsx)(c,{to:`/queues/${t.deadLetter}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:t.deadLetter})})]})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Created`,value:a(new Date(t.createdOn)),mono:!0}),(0,O.jsx)(M,{label:`Start After`,value:t.startAfter?a(new Date(t.startAfter)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Started`,value:t.startedOn?a(new Date(t.startedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Completed`,value:t.completedOn?a(new Date(t.completedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Keep Until`,value:t.keepUntil?a(new Date(t.keepUntil)):`—`,mono:!0})]})]})})]})]})]})});function M({label:e,value:t,mono:n=!1}){return(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:e}),(0,O.jsx)(`dd`,{className:s(`mt-1 text-sm text-[var(--text-primary)]`,n&&`pgb-num`),children:t?.toString()||`—`})]})}export{A as ErrorBoundary,j as default};
1
+ import{o as e,rt as t,s as n,t as r,tt as i}from"./jsx-runtime-RQyiN6Nr.js";import{h as a,j as o,m as s,t as c,u as l}from"./db-link-BajQ1v8I.js";import{t as u}from"./createLucideIcon-C-LI4enx.js";import{t as d}from"./check-7jwc5sb1.js";import{a as f,i as p,n as m,o as h,r as g,t as _}from"./dialog-D-oczDM2.js";import{a as v,i as y,n as b,r as x,t as S}from"./button-9NpSS9Ow.js";import{n as C,t as w}from"./badge-CMnQO7Lq.js";import{t as T}from"./error-card-BH7i86fH.js";var E=u(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),D=t(i(),1),O=r();function k({title:e,description:t,confirmLabel:n,confirmVariant:r=`primary`,triggerVariant:i=`ghost`,trigger:a,onConfirm:o,disabled:s}){let[c,l]=(0,D.useState)(!1);return(0,O.jsxs)(f,{open:c,onOpenChange:l,children:[(0,O.jsx)(S,{variant:i,size:`sm`,disabled:s,onClick:()=>l(!0),className:`cursor-pointer`,children:a}),(0,O.jsxs)(_,{hideCloseButton:!0,className:`w-[28rem] max-w-[calc(100vw-2rem)]`,children:[(0,O.jsxs)(p,{children:[(0,O.jsx)(h,{children:e}),(0,O.jsx)(m,{className:`mt-2`,children:t})]}),(0,O.jsxs)(g,{className:`mt-6 flex justify-end gap-3`,children:[(0,O.jsx)(S,{variant:`outline`,size:`sm`,className:`cursor-pointer`,onClick:()=>l(!1),children:`Cancel`}),(0,O.jsx)(S,{variant:r===`danger`?`danger`:`primary`,size:`sm`,className:`cursor-pointer`,onClick:()=>{o(),l(!1)},children:n})]})]})]})}var A=n(function(){return(0,O.jsx)(T,{title:`Failed to load job`,backTo:{href:`/queues`,label:`Back to Queues`}})}),j=e(function({loaderData:e}){let{job:t,queueName:n}=e,r=o(),i=r.state!==`idle`,[u,f]=(0,D.useState)(!1),p=r.data,m=p&&!p.success&&p.affected===0,h=e=>{r.submit({intent:e},{method:`post`})},g=async()=>{await navigator.clipboard.writeText(t.id),f(!0),setTimeout(()=>f(!1),2e3)},_=t.state===`failed`;return(0,O.jsxs)(`div`,{className:`space-y-4`,children:[(0,O.jsx)(C,{title:(0,O.jsxs)(`span`,{className:`inline-flex items-center gap-3`,children:[`Job detail`,(0,O.jsx)(w,{variant:l[t.state],size:`lg`,dot:!0,children:t.state})]}),action:(0,O.jsxs)(`div`,{className:`flex items-center gap-2`,children:[m&&(0,O.jsx)(`span`,{className:`text-xs text-[var(--warning-600)]`,title:p.message,children:`Action failed`}),t.state===`failed`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`retry`),children:`Retry`}),t.state===`cancelled`&&(0,O.jsx)(S,{variant:`outline`,size:`sm`,disabled:i,onClick:()=>h(`resume`),children:`Resume`}),(t.state===`created`||t.state===`retry`||t.state===`active`)&&(0,O.jsx)(k,{title:`Cancel Job`,description:`Are you sure you want to cancel job ${t.id.slice(0,8)}...? This will prevent the job from being processed.`,confirmLabel:`Cancel Job`,confirmVariant:`danger`,triggerVariant:`outline`,trigger:`Cancel`,onConfirm:()=>h(`cancel`),disabled:i}),t.state!==`active`&&(0,O.jsx)(k,{title:`Delete Job`,description:`Are you sure you want to delete job ${t.id.slice(0,8)}...? This action cannot be undone.`,confirmLabel:`Delete`,confirmVariant:`danger`,triggerVariant:`danger`,trigger:`Delete`,onConfirm:()=>h(`delete`),disabled:i})]})}),(0,O.jsxs)(b,{children:[(0,O.jsxs)(y,{children:[(0,O.jsx)(v,{children:`Details`}),(0,O.jsxs)(`span`,{className:`text-xs text-[var(--text-tertiary)]`,children:[`in queue`,` `,(0,O.jsx)(c,{to:`/queues/${encodeURIComponent(n)}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:n})]})]}),(0,O.jsxs)(x,{className:`space-y-6`,children:[(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-[2fr_1fr_1fr] gap-6`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1`,children:`Job ID`}),(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,O.jsx)(`code`,{className:`text-sm font-mono break-all text-[var(--text-primary)]`,children:t.id}),(0,O.jsx)(`button`,{onClick:g,className:s(`p-1 rounded-md transition-colors cursor-pointer flex-shrink-0`,`text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--surface-hover)]`),title:u?`Copied!`:`Copy to clipboard`,children:u?(0,O.jsx)(d,{className:`h-4 w-4 text-[var(--success-600)]`}):(0,O.jsx)(E,{className:`h-4 w-4`})})]})]}),(0,O.jsx)(M,{label:`Policy`,value:t.policy||`—`}),(0,O.jsx)(M,{label:`Priority`,value:t.priority,mono:!0})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Data`}),(0,O.jsx)(`pre`,{className:`text-xs px-3.5 py-3 rounded-lg border border-[var(--border-default)] bg-[var(--surface-sunken)] font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,children:t.data?JSON.stringify(t.data,null,2):`null`})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`div`,{className:`pgb-eyebrow mb-1.5`,children:`Output`}),(0,O.jsx)(`pre`,{className:s(`text-xs px-3.5 py-3 rounded-lg border font-mono leading-relaxed text-[var(--text-primary)] overflow-auto max-h-40`,_?`border-[var(--error-100)] bg-[var(--error-50)]`:`border-[var(--border-default)] bg-[var(--surface-sunken)]`),children:t.output!==void 0&&t.output!==null?JSON.stringify(t.output,null,2):`—`})]})]}),(0,O.jsx)(`div`,{children:(0,O.jsxs)(`div`,{className:`space-y-6`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:(0,O.jsx)(M,{label:`Priority`,value:t.priority})}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Retry Count`,value:t.retryCount,mono:!0}),(0,O.jsx)(M,{label:`Retry Limit`,value:t.retryLimit,mono:!0}),(0,O.jsx)(M,{label:`Retry Delay`,value:t.retryDelay?`${t.retryDelay}ms`:`—`,mono:!0}),(0,O.jsx)(M,{label:`Retry Backoff`,value:t.retryBackoff?`Enabled`:`Disabled`})]}),(t.singletonKey||t.groupId||t.groupTier||t.deadLetter)&&(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[t.singletonKey&&(0,O.jsx)(M,{label:`Singleton Key`,value:t.singletonKey,mono:!0}),t.groupId&&(0,O.jsx)(M,{label:`Group ID`,value:t.groupId,mono:!0}),t.groupTier&&(0,O.jsx)(M,{label:`Group Tier`,value:t.groupTier,mono:!0}),t.deadLetter&&(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:`Dead Letter`}),(0,O.jsx)(`dd`,{className:`mt-1 text-sm text-[var(--text-primary)]`,children:(0,O.jsx)(c,{to:`/queues/${t.deadLetter}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:t.deadLetter})})]})]}),(t.sourceName||t.sourceId)&&(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4`,children:[t.sourceName&&(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:`Source Queue`}),(0,O.jsx)(`dd`,{className:`mt-1 text-sm text-[var(--text-primary)]`,children:(0,O.jsx)(c,{to:`/queues/${t.sourceName}`,className:`font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300`,children:t.sourceName})})]}),t.sourceId&&(0,O.jsx)(M,{label:`Source Job ID`,value:t.sourceId,mono:!0}),t.sourceRetryCount!==null&&t.sourceRetryCount!==void 0&&(0,O.jsx)(M,{label:`Source Retry Count`,value:t.sourceRetryCount,mono:!0}),t.sourceCreatedOn&&(0,O.jsx)(M,{label:`Source Created`,value:a(new Date(t.sourceCreatedOn)),mono:!0})]}),(0,O.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-4`,children:[(0,O.jsx)(M,{label:`Created`,value:a(new Date(t.createdOn)),mono:!0}),(0,O.jsx)(M,{label:`Start After`,value:t.startAfter?a(new Date(t.startAfter)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Started`,value:t.startedOn?a(new Date(t.startedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Completed`,value:t.completedOn?a(new Date(t.completedOn)):`—`,mono:!0}),(0,O.jsx)(M,{label:`Keep Until`,value:t.keepUntil?a(new Date(t.keepUntil)):`—`,mono:!0})]})]})})]})]})]})});function M({label:e,value:t,mono:n=!1}){return(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`dt`,{className:`pgb-eyebrow`,children:e}),(0,O.jsx)(`dd`,{className:s(`mt-1 text-sm text-[var(--text-primary)]`,n&&`pgb-num`),children:t?.toString()||`—`})]})}export{A as ErrorBoundary,j as default};
@@ -1568,7 +1568,8 @@ function createTableVersion(schema) {
1568
1568
  CREATE TABLE ${schema}.version (
1569
1569
  version int primary key,
1570
1570
  cron_on timestamp with time zone,
1571
- bam_on timestamp with time zone
1571
+ bam_on timestamp with time zone,
1572
+ flow_on timestamp with time zone
1572
1573
  )
1573
1574
  `;
1574
1575
  }
@@ -1798,7 +1799,11 @@ function createTableJob(schema, noPartitioning = false) {
1798
1799
  heartbeat_seconds int,
1799
1800
  blocked boolean not null default false,
1800
1801
  blocking boolean not null default false,
1801
- pending_dependencies int not null default 0
1802
+ pending_dependencies int not null default 0,
1803
+ source_name text,
1804
+ source_id uuid,
1805
+ source_created_on timestamp with time zone,
1806
+ source_retry_count int
1802
1807
  ) ${partitionClause}
1803
1808
  `;
1804
1809
  }
@@ -1825,7 +1830,11 @@ var JOB_COLUMNS_ALL = `${JOB_COLUMNS_MIN},
1825
1830
  blocked,
1826
1831
  blocking,
1827
1832
  pending_dependencies as "pendingDependencies",
1828
- output
1833
+ output,
1834
+ source_name as "sourceName",
1835
+ source_id as "sourceId",
1836
+ source_created_on as "sourceCreatedOn",
1837
+ source_retry_count as "sourceRetryCount"
1829
1838
  `;
1830
1839
  function createTableJobCommon(schema) {
1831
1840
  return `
@@ -1843,6 +1852,7 @@ function createTableJobCommon(schema) {
1843
1852
  SELECT ${schema}.job_table_run($cmd$${createIndexJobThrottle(schema)}$cmd$, '${COMMON_JOB_TABLE}');
1844
1853
  SELECT ${schema}.job_table_run($cmd$${createIndexJobFetch(schema)}$cmd$, '${COMMON_JOB_TABLE}');
1845
1854
  SELECT ${schema}.job_table_run($cmd$${createIndexJobGroupConcurrency(schema)}$cmd$, '${COMMON_JOB_TABLE}');
1855
+ SELECT ${schema}.job_table_run($cmd$${createIndexJobBlocking(schema)}$cmd$, '${COMMON_JOB_TABLE}');
1846
1856
 
1847
1857
  ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.${COMMON_JOB_TABLE} DEFAULT;
1848
1858
  `;
@@ -1860,6 +1870,7 @@ function createTableJobIndexes(schema, noDeferrableConstraints = false, noCoveri
1860
1870
  ${createIndexJobThrottle(schema)};
1861
1871
  ${createIndexJobFetch(schema, noCoveringIndex)};
1862
1872
  ${createIndexJobGroupConcurrency(schema)};
1873
+ ${createIndexJobBlocking(schema)};
1863
1874
  `;
1864
1875
  }
1865
1876
  function createQueueFunction(schema, noPartitioning = false) {
@@ -1970,6 +1981,7 @@ function createQueueFunction(schema, noPartitioning = false) {
1970
1981
  EXECUTE ${schema}.job_table_format($cmd$${createIndexJobFetch(schema)}$cmd$, tablename);
1971
1982
  EXECUTE ${schema}.job_table_format($cmd$${createIndexJobThrottle(schema)}$cmd$, tablename);
1972
1983
  EXECUTE ${schema}.job_table_format($cmd$${createIndexJobGroupConcurrency(schema)}$cmd$, tablename);
1984
+ EXECUTE ${schema}.job_table_format($cmd$${createIndexJobBlocking(schema)}$cmd$, tablename);
1973
1985
 
1974
1986
  IF options->>'policy' = 'short' THEN
1975
1987
  EXECUTE ${schema}.job_table_format($cmd$${createIndexJobPolicyShort(schema)}$cmd$, tablename);
@@ -2053,7 +2065,7 @@ function createIndexJobThrottle(schema) {
2053
2065
  return `CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> '${JOB_STATES.cancelled}' AND singleton_on IS NOT NULL`;
2054
2066
  }
2055
2067
  function createIndexJobFetch(schema, noCoveringIndex = false) {
2056
- return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after) ${noCoveringIndex ? "" : "INCLUDE (priority, created_on, id) "}WHERE state < '${JOB_STATES.active}' AND NOT blocked`;
2068
+ return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < '${JOB_STATES.active}' AND NOT blocked`;
2057
2069
  }
2058
2070
  function createIndexJobPolicyExclusive(schema) {
2059
2071
  return `CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.exclusive}'`;
@@ -2067,6 +2079,9 @@ function createCheckConstraintKeyStrictFifo(schema) {
2067
2079
  function createIndexJobGroupConcurrency(schema) {
2068
2080
  return `CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = '${JOB_STATES.active}' AND group_id IS NOT NULL`;
2069
2081
  }
2082
+ function createIndexJobBlocking(schema) {
2083
+ return `CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = '${JOB_STATES.completed}'`;
2084
+ }
2070
2085
  function trySetQueueMonitorTime(schema, queues, seconds) {
2071
2086
  return trySetQueueTimestamp(schema, queues, "monitor_on", seconds);
2072
2087
  }
@@ -2079,6 +2094,9 @@ function trySetCronTime(schema, seconds) {
2079
2094
  function trySetBamTime(schema, seconds) {
2080
2095
  return trySetTimestamp(schema, "bam_on", seconds);
2081
2096
  }
2097
+ function trySetFlowTime(schema, seconds) {
2098
+ return trySetTimestamp(schema, "flow_on", seconds);
2099
+ }
2082
2100
  function trySetTimestamp(schema, column, seconds) {
2083
2101
  return `
2084
2102
  UPDATE ${schema}.version
@@ -2163,7 +2181,7 @@ function deleteJobsById(schema, table) {
2163
2181
  WITH results as (
2164
2182
  DELETE FROM ${schema}.${table}
2165
2183
  WHERE name = $1
2166
- AND id IN (SELECT UNNEST($2::uuid[]))
2184
+ AND id = ANY($2::uuid[])
2167
2185
  RETURNING 1
2168
2186
  )
2169
2187
  SELECT COUNT(*) from results
@@ -2426,7 +2444,7 @@ function completeJobsUpdate(schema, table, includeQueued) {
2426
2444
  blocked = ${includeQueued ? "false" : "blocked"},
2427
2445
  pending_dependencies = ${includeQueued ? "0" : "pending_dependencies"}
2428
2446
  WHERE name = $1
2429
- AND id IN (SELECT UNNEST($2::uuid[]))
2447
+ AND id = ANY($2::uuid[])
2430
2448
  AND ${includeQueued ? `state < '${JOB_STATES.completed}'` : `state = '${JOB_STATES.active}'`}`;
2431
2449
  }
2432
2450
  function lockedChildrenCte(schema) {
@@ -2450,24 +2468,11 @@ function unblockChildrenUpdate(schema) {
2450
2468
  }
2451
2469
  function completeJobs(schema, table, includeQueued) {
2452
2470
  return `
2453
- WITH completed AS (
2471
+ WITH results AS (
2454
2472
  ${completeJobsUpdate(schema, table, includeQueued)}
2455
- RETURNING name, id, blocking
2456
- ),
2457
- decremented AS (
2458
- SELECT d.child_name, d.child_id, COUNT(*)::int AS n
2459
- FROM ${schema}.job_dependency d
2460
- JOIN completed c ON c.blocking
2461
- AND d.parent_name = c.name
2462
- AND d.parent_id = c.id
2463
- GROUP BY d.child_name, d.child_id
2464
- ),
2465
- ${lockedChildrenCte(schema)},
2466
- unblocked AS (
2467
- ${unblockChildrenUpdate(schema)}
2468
2473
  RETURNING 1
2469
2474
  )
2470
- SELECT COUNT(*) FROM completed
2475
+ SELECT COUNT(*) FROM results
2471
2476
  `;
2472
2477
  }
2473
2478
  function completeJobsWithOutputs(schema, table) {
@@ -2475,7 +2480,7 @@ function completeJobsWithOutputs(schema, table) {
2475
2480
  WITH input AS (
2476
2481
  SELECT * FROM json_to_recordset($2::json) AS x (id uuid, output jsonb)
2477
2482
  ),
2478
- completed AS (
2483
+ results AS (
2479
2484
  UPDATE ${schema}.${table} j
2480
2485
  SET completed_on = now(),
2481
2486
  state = '${JOB_STATES.completed}',
@@ -2484,22 +2489,9 @@ function completeJobsWithOutputs(schema, table) {
2484
2489
  WHERE j.name = $1
2485
2490
  AND j.id = i.id
2486
2491
  AND j.state = '${JOB_STATES.active}'
2487
- RETURNING j.name, j.id, j.blocking
2488
- ),
2489
- decremented AS (
2490
- SELECT d.child_name, d.child_id, COUNT(*)::int AS n
2491
- FROM ${schema}.job_dependency d
2492
- JOIN completed c ON c.blocking
2493
- AND d.parent_name = c.name
2494
- AND d.parent_id = c.id
2495
- GROUP BY d.child_name, d.child_id
2496
- ),
2497
- ${lockedChildrenCte(schema)},
2498
- unblocked AS (
2499
- ${unblockChildrenUpdate(schema)}
2500
2492
  RETURNING 1
2501
2493
  )
2502
- SELECT COUNT(*) FROM completed
2494
+ SELECT COUNT(*) FROM results
2503
2495
  `;
2504
2496
  }
2505
2497
  function completeJobsWithOutputsDistributed(schema, table) {
@@ -2515,7 +2507,7 @@ function completeJobsWithOutputsDistributed(schema, table) {
2515
2507
  WHERE j.name = $1
2516
2508
  AND j.id = i.id
2517
2509
  AND j.state = '${JOB_STATES.active}'
2518
- RETURNING j.id, j.blocking
2510
+ RETURNING j.id
2519
2511
  `;
2520
2512
  }
2521
2513
  function cancelJobs(schema, table) {
@@ -2525,7 +2517,7 @@ function cancelJobs(schema, table) {
2525
2517
  SET completed_on = now(),
2526
2518
  state = '${JOB_STATES.cancelled}'
2527
2519
  WHERE name = $1
2528
- AND id IN (SELECT UNNEST($2::uuid[]))
2520
+ AND id = ANY($2::uuid[])
2529
2521
  AND state < '${JOB_STATES.completed}'
2530
2522
  RETURNING 1
2531
2523
  )
@@ -2539,7 +2531,7 @@ function resumeJobs(schema, table) {
2539
2531
  SET completed_on = NULL,
2540
2532
  state = '${JOB_STATES.created}'
2541
2533
  WHERE name = $1
2542
- AND id IN (SELECT UNNEST($2::uuid[]))
2534
+ AND id = ANY($2::uuid[])
2543
2535
  AND state = '${JOB_STATES.cancelled}'
2544
2536
  RETURNING 1
2545
2537
  )
@@ -2553,7 +2545,7 @@ function restoreJobs(schema, table) {
2553
2545
  started_on = NULL,
2554
2546
  heartbeat_on = NULL
2555
2547
  WHERE name = $1
2556
- AND id IN (SELECT UNNEST($2::uuid[]))
2548
+ AND id = ANY($2::uuid[])
2557
2549
  `;
2558
2550
  }
2559
2551
  function insertJobs(schema, { table, name, returnId = true, notify = false }) {
@@ -2668,7 +2660,7 @@ function insertFlowJobs(schema, { table, name }, jobs) {
2668
2660
  `;
2669
2661
  }
2670
2662
  function failJobsById(schema, table) {
2671
- return failJobs(schema, table, `name = $1 AND id IN (SELECT UNNEST($2::uuid[])) AND state < '${JOB_STATES.completed}'`, "$3::jsonb");
2663
+ return failJobs(schema, table, `name = $1 AND id = ANY($2::uuid[]) AND state < '${JOB_STATES.completed}'`, "$3::jsonb");
2672
2664
  }
2673
2665
  function failJobsByTimeout(schema, table, queues, noAdvisoryLocks) {
2674
2666
  return locked(schema, failJobs(schema, table, `state = '${JOB_STATES.active}'
@@ -2687,7 +2679,7 @@ function touchJobs(schema, table) {
2687
2679
  UPDATE ${schema}.${table}
2688
2680
  SET heartbeat_on = now()
2689
2681
  WHERE name = $1
2690
- AND id IN (SELECT UNNEST($2::uuid[]))
2682
+ AND id = ANY($2::uuid[])
2691
2683
  AND state = '${JOB_STATES.active}'
2692
2684
  RETURNING 1
2693
2685
  )
@@ -2856,16 +2848,21 @@ function failJobsBody(schema, table, where, output, forceTerminal = false) {
2856
2848
  SELECT * FROM failed_jobs
2857
2849
  ),
2858
2850
  dlq_jobs as (
2859
- INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds)
2851
+ INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds,
2852
+ source_name, source_id, source_created_on, source_retry_count)
2860
2853
  SELECT
2861
2854
  r.dead_letter,
2862
- data,
2863
- output,
2855
+ r.data,
2856
+ r.output,
2864
2857
  q.retry_limit,
2865
2858
  q.retry_backoff,
2866
2859
  q.retry_delay,
2867
2860
  now() + q.retention_seconds * interval '1s',
2868
- q.deletion_seconds
2861
+ q.deletion_seconds,
2862
+ r.name,
2863
+ r.id,
2864
+ r.created_on,
2865
+ r.retry_count
2869
2866
  FROM results r
2870
2867
  JOIN ${schema}.queue q ON q.name = r.dead_letter
2871
2868
  WHERE state = '${JOB_STATES.failed}'
@@ -2891,13 +2888,13 @@ function deadLetterJobsByIdWithOutputs(schema, table) {
2891
2888
  }
2892
2889
  function selectJobsToFailById(schema, table) {
2893
2890
  return {
2894
- text: `SELECT * FROM ${schema}.${table} WHERE name = $1 AND id IN (SELECT UNNEST($2::uuid[])) AND state < '${JOB_STATES.completed}'`,
2891
+ text: `SELECT * FROM ${schema}.${table} WHERE name = $1 AND id = ANY($2::uuid[]) AND state < '${JOB_STATES.completed}'`,
2895
2892
  values: []
2896
2893
  };
2897
2894
  }
2898
2895
  function deleteJobsToFail(schema, table) {
2899
2896
  return {
2900
- text: `DELETE FROM ${schema}.${table} WHERE name = $1 AND id IN (SELECT UNNEST($2::uuid[]))`,
2897
+ text: `DELETE FROM ${schema}.${table} WHERE name = $1 AND id = ANY($2::uuid[])`,
2901
2898
  values: []
2902
2899
  };
2903
2900
  }
@@ -2922,14 +2919,14 @@ function selectJobsToFailByHeartbeat(schema, table, queues) {
2922
2919
  }
2923
2920
  function deleteJobsByIds(schema, table) {
2924
2921
  return {
2925
- text: `DELETE FROM ${schema}.${table} WHERE id IN (SELECT UNNEST($1::uuid[]))`,
2922
+ text: `DELETE FROM ${schema}.${table} WHERE id = ANY($1::uuid[])`,
2926
2923
  values: []
2927
2924
  };
2928
2925
  }
2929
2926
  function completeJobsDistributed(schema, table, includeQueued) {
2930
2927
  return `
2931
2928
  ${completeJobsUpdate(schema, table, includeQueued)}
2932
- RETURNING id, blocking
2929
+ RETURNING id
2933
2930
  `;
2934
2931
  }
2935
2932
  function decrementDependents(schema) {
@@ -2938,13 +2935,75 @@ function decrementDependents(schema) {
2938
2935
  SELECT d.child_name, d.child_id, COUNT(*)::int AS n
2939
2936
  FROM ${schema}.job_dependency d
2940
2937
  WHERE d.parent_name = $1
2941
- AND d.parent_id IN (SELECT UNNEST($2::uuid[]))
2938
+ AND d.parent_id = ANY($2::uuid[])
2942
2939
  GROUP BY d.child_name, d.child_id
2943
2940
  ),
2944
2941
  ${lockedChildrenCte(schema)}
2945
2942
  ${unblockChildrenUpdate(schema)}
2946
2943
  `;
2947
2944
  }
2945
+ var FLOW_BATCH_SIZE = 1e3;
2946
+ function resolveFlowJobs(schema, table, names) {
2947
+ return {
2948
+ text: `
2949
+ WITH locked_parents AS (
2950
+ SELECT j.name, j.id
2951
+ FROM ${schema}.${table} j
2952
+ WHERE j.blocking
2953
+ AND j.state = '${JOB_STATES.completed}'
2954
+ AND j.name = ANY($1::text[])
2955
+ ORDER BY j.name, j.id
2956
+ FOR UPDATE OF j SKIP LOCKED
2957
+ LIMIT ${FLOW_BATCH_SIZE}
2958
+ ),
2959
+ decremented AS (
2960
+ SELECT d.child_name, d.child_id, COUNT(*)::int AS n
2961
+ FROM ${schema}.job_dependency d
2962
+ JOIN locked_parents p ON d.parent_name = p.name
2963
+ AND d.parent_id = p.id
2964
+ GROUP BY d.child_name, d.child_id
2965
+ ),
2966
+ ${lockedChildrenCte(schema)},
2967
+ unblocked AS (
2968
+ ${unblockChildrenUpdate(schema)}
2969
+ RETURNING 1
2970
+ ),
2971
+ cleared AS (
2972
+ UPDATE ${schema}.${table} j
2973
+ SET blocking = false
2974
+ FROM locked_parents p
2975
+ WHERE j.name = p.name
2976
+ AND j.id = p.id
2977
+ RETURNING 1
2978
+ )
2979
+ SELECT COUNT(*)::int AS resolved FROM cleared
2980
+ `,
2981
+ values: [names]
2982
+ };
2983
+ }
2984
+ function selectBlockingParents(schema, table, names, noSkipLocked) {
2985
+ return {
2986
+ text: `
2987
+ SELECT name, id
2988
+ FROM ${schema}.${table}
2989
+ WHERE blocking
2990
+ AND state = '${JOB_STATES.completed}'
2991
+ AND name = ANY($1::text[])
2992
+ ORDER BY name, id
2993
+ FOR UPDATE${noSkipLocked ? "" : " SKIP LOCKED"}
2994
+ LIMIT ${FLOW_BATCH_SIZE}
2995
+ `,
2996
+ values: [names]
2997
+ };
2998
+ }
2999
+ function clearBlocking(schema) {
3000
+ return `
3001
+ UPDATE ${schema}.job
3002
+ SET blocking = false
3003
+ WHERE name = $1
3004
+ AND id = ANY($2::uuid[])
3005
+ `;
3006
+ }
2948
3007
  function insertRetryJob(schema, table) {
2949
3008
  return `
2950
3009
  INSERT INTO ${schema}.${table} (
@@ -2962,11 +3021,44 @@ function insertRetryJob(schema, table) {
2962
3021
  }
2963
3022
  function insertDeadLetterJob(schema) {
2964
3023
  return `
2965
- INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds)
2966
- SELECT $1, $2, $3, q.retry_limit, q.retry_backoff, q.retry_delay, now() + q.retention_seconds * interval '1s', q.deletion_seconds
3024
+ INSERT INTO ${schema}.job (name, data, output, retry_limit, retry_backoff, retry_delay, keep_until, deletion_seconds,
3025
+ source_name, source_id, source_created_on, source_retry_count)
3026
+ SELECT $1, $2, $3, q.retry_limit, q.retry_backoff, q.retry_delay, now() + q.retention_seconds * interval '1s', q.deletion_seconds,
3027
+ $4, $5, $6, $7
2967
3028
  FROM ${schema}.queue q WHERE q.name = $1
2968
3029
  `;
2969
3030
  }
3031
+ function redriveJobs(schema, table) {
3032
+ return `
3033
+ WITH candidates AS (
3034
+ SELECT j.id
3035
+ FROM ${schema}.${table} j
3036
+ JOIN ${schema}.queue q ON q.name = COALESCE($2, j.source_name)
3037
+ WHERE j.name = $1
3038
+ AND j.state < '${JOB_STATES.active}'
3039
+ AND ($3::text IS NULL OR j.source_name = $3)
3040
+ ORDER BY j.created_on
3041
+ LIMIT $4
3042
+ FOR UPDATE OF j SKIP LOCKED
3043
+ ),
3044
+ moved AS (
3045
+ DELETE FROM ${schema}.${table}
3046
+ WHERE id IN (SELECT id FROM candidates)
3047
+ RETURNING *
3048
+ ),
3049
+ ins AS (
3050
+ INSERT INTO ${schema}.job
3051
+ (name, data, priority, retry_limit, retry_backoff, retry_delay, retry_delay_max,
3052
+ expire_seconds, keep_until, deletion_seconds, policy)
3053
+ SELECT COALESCE($2, m.source_name), m.data, m.priority, q.retry_limit, q.retry_backoff,
3054
+ q.retry_delay, q.retry_delay_max, q.expire_seconds,
3055
+ now() + q.retention_seconds * interval '1s', q.deletion_seconds, q.policy
3056
+ FROM moved m JOIN ${schema}.queue q ON q.name = COALESCE($2, m.source_name)
3057
+ RETURNING 1
3058
+ )
3059
+ SELECT count(*)::int AS moved FROM ins
3060
+ `;
3061
+ }
2970
3062
  function deletion(schema, table, queues, noAdvisoryLocks) {
2971
3063
  return locked(schema, `
2972
3064
  DELETE FROM ${schema}.${table}
@@ -2986,7 +3078,7 @@ function retryJobs(schema, table) {
2986
3078
  SET state = '${JOB_STATES.retry}',
2987
3079
  retry_limit = retry_limit + 1
2988
3080
  WHERE name = $1
2989
- AND id IN (SELECT UNNEST($2::uuid[]))
3081
+ AND id = ANY($2::uuid[])
2990
3082
  AND state = '${JOB_STATES.failed}'
2991
3083
  RETURNING 1
2992
3084
  )
@@ -3464,6 +3556,7 @@ function getConfig(value) {
3464
3556
  applyOpsConfig(config);
3465
3557
  applyScheduleConfig(config);
3466
3558
  applyBamConfig(config);
3559
+ applyFlowConfig(config);
3467
3560
  validateWarningConfig(config);
3468
3561
  return config;
3469
3562
  }
@@ -3566,6 +3659,11 @@ function applyBamConfig(config) {
3566
3659
  assert(!("bamIntervalSeconds" in config) || config.bamIntervalSeconds >= minInterval, `configuration assert: bamIntervalSeconds must be at least ${minInterval} seconds`);
3567
3660
  config.bamIntervalSeconds = config.bamIntervalSeconds || 60;
3568
3661
  }
3662
+ function applyFlowConfig(config) {
3663
+ const minInterval = config.__test__bypass_flow_interval_check ? .5 : 1;
3664
+ assert(!("flowIntervalSeconds" in config) || config.flowIntervalSeconds >= minInterval, `configuration assert: flowIntervalSeconds must be at least ${minInterval} seconds`);
3665
+ config.flowIntervalSeconds = config.flowIntervalSeconds || 5;
3666
+ }
3569
3667
  //#endregion
3570
3668
  //#region ../../src/migrationStore.ts
3571
3669
  function formatJobTable(command, table) {
@@ -4113,6 +4211,92 @@ var createQueueFn = {
4113
4211
  END;
4114
4212
  $$
4115
4213
  LANGUAGE plpgsql;
4214
+ `,
4215
+ 33: (schema) => `
4216
+ CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
4217
+ RETURNS VOID AS
4218
+ $$
4219
+ DECLARE
4220
+ tablename varchar := CASE WHEN options->>'partition' = 'true'
4221
+ THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
4222
+ ELSE 'job_common'
4223
+ END;
4224
+ queue_created_on timestamptz;
4225
+ BEGIN
4226
+
4227
+ WITH q as (
4228
+ INSERT INTO ${schema}.queue (
4229
+ name,
4230
+ policy,
4231
+ retry_limit,
4232
+ retry_delay,
4233
+ retry_backoff,
4234
+ retry_delay_max,
4235
+ expire_seconds,
4236
+ retention_seconds,
4237
+ deletion_seconds,
4238
+ warning_queued,
4239
+ dead_letter,
4240
+ partition,
4241
+ table_name,
4242
+ heartbeat_seconds,
4243
+ notify
4244
+ )
4245
+ VALUES (
4246
+ queue_name,
4247
+ options->>'policy',
4248
+ COALESCE((options->>'retryLimit')::int, 2),
4249
+ COALESCE((options->>'retryDelay')::int, 0),
4250
+ COALESCE((options->>'retryBackoff')::bool, false),
4251
+ (options->>'retryDelayMax')::int,
4252
+ COALESCE((options->>'expireInSeconds')::int, 900),
4253
+ COALESCE((options->>'retentionSeconds')::int, 1209600),
4254
+ COALESCE((options->>'deleteAfterSeconds')::int, 604800),
4255
+ COALESCE((options->>'warningQueueSize')::int, 0),
4256
+ options->>'deadLetter',
4257
+ COALESCE((options->>'partition')::bool, false),
4258
+ tablename,
4259
+ (options->>'heartbeatSeconds')::int,
4260
+ COALESCE((options->>'notify')::bool, false)
4261
+ )
4262
+ ON CONFLICT DO NOTHING
4263
+ RETURNING created_on
4264
+ )
4265
+ SELECT created_on into queue_created_on from q;
4266
+
4267
+ IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
4268
+ RETURN;
4269
+ END IF;
4270
+
4271
+ EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
4272
+
4273
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
4274
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
4275
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
4276
+
4277
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
4278
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
4279
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
4280
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$, tablename);
4281
+
4282
+ IF options->>'policy' = 'short' THEN
4283
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
4284
+ ELSIF options->>'policy' = 'singleton' THEN
4285
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
4286
+ ELSIF options->>'policy' = 'stately' THEN
4287
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
4288
+ ELSIF options->>'policy' = 'exclusive' THEN
4289
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
4290
+ ELSIF options->>'policy' = 'key_strict_fifo' THEN
4291
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
4292
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
4293
+ END IF;
4294
+
4295
+ EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
4296
+ EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
4297
+ END;
4298
+ $$
4299
+ LANGUAGE plpgsql;
4116
4300
  `
4117
4301
  };
4118
4302
  function getAll(schema) {
@@ -4361,6 +4545,42 @@ function getAll(schema) {
4361
4545
  createQueueFn[31](schema),
4362
4546
  `ALTER TABLE ${schema}.queue DROP COLUMN notify`
4363
4547
  ]
4548
+ },
4549
+ {
4550
+ release: "12.22.0",
4551
+ version: 33,
4552
+ previous: 32,
4553
+ install: [
4554
+ `ALTER TABLE ${schema}.version ADD COLUMN IF NOT EXISTS flow_on timestamp with time zone`,
4555
+ `SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$)`,
4556
+ `SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
4557
+ `SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < 'active' AND NOT blocked$cmd$)`,
4558
+ createQueueFn[33](schema)
4559
+ ],
4560
+ uninstall: [
4561
+ createQueueFn[32](schema),
4562
+ `SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
4563
+ `SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$)`,
4564
+ `SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i9$cmd$)`,
4565
+ `ALTER TABLE ${schema}.version DROP COLUMN flow_on`
4566
+ ]
4567
+ },
4568
+ {
4569
+ release: "12.23.0",
4570
+ version: 34,
4571
+ previous: 33,
4572
+ install: [
4573
+ `ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_name text`,
4574
+ `ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_id uuid`,
4575
+ `ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_created_on timestamp with time zone`,
4576
+ `ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS source_retry_count int`
4577
+ ],
4578
+ uninstall: [
4579
+ `ALTER TABLE ${schema}.job DROP COLUMN source_name`,
4580
+ `ALTER TABLE ${schema}.job DROP COLUMN source_id`,
4581
+ `ALTER TABLE ${schema}.job DROP COLUMN source_created_on`,
4582
+ `ALTER TABLE ${schema}.job DROP COLUMN source_retry_count`
4583
+ ]
4364
4584
  }
4365
4585
  ];
4366
4586
  }
@@ -4368,7 +4588,7 @@ function getAll(schema) {
4368
4588
  //#region ../../src/contractor.ts
4369
4589
  var schemaVersion = {
4370
4590
  name: "pg-boss",
4371
- version: "12.21.0",
4591
+ version: "12.23.0",
4372
4592
  description: "Queueing jobs in Postgres from Node.js like a boss",
4373
4593
  type: "module",
4374
4594
  main: "./dist/index.js",
@@ -4376,7 +4596,7 @@ var schemaVersion = {
4376
4596
  bin: { "pg-boss": "./dist/cli.js" },
4377
4597
  engines: { "node": ">=22.12.0" },
4378
4598
  dependencies: {
4379
- "cron-parser": "^5.6.0",
4599
+ "cron-parser": "^5.6.1",
4380
4600
  "pg": "^8.22.0",
4381
4601
  "serialize-error": "^13.0.1"
4382
4602
  },
@@ -4424,7 +4644,7 @@ var schemaVersion = {
4424
4644
  "docs": "npm run docs:dev --prefix docs",
4425
4645
  "docs:readme": "node ./scripts/sync-readme.js"
4426
4646
  },
4427
- pgboss: { "schema": 32 },
4647
+ pgboss: { "schema": 34 },
4428
4648
  repository: {
4429
4649
  "type": "git",
4430
4650
  "url": "git+https://github.com/timgit/pg-boss.git"
@@ -4938,7 +5158,7 @@ var NUMERIC_QUEUE_FIELDS = [
4938
5158
  "activeCount",
4939
5159
  "totalCount"
4940
5160
  ];
4941
- var events$4 = {
5161
+ var events$5 = {
4942
5162
  error: "error",
4943
5163
  wip: "wip"
4944
5164
  };
@@ -4947,7 +5167,7 @@ function rethrowWriteError(err) {
4947
5167
  throw err;
4948
5168
  }
4949
5169
  var Manager = class extends EventEmitter {
4950
- events = events$4;
5170
+ events = events$5;
4951
5171
  db;
4952
5172
  config;
4953
5173
  wipTs;
@@ -5110,17 +5330,15 @@ var Manager = class extends EventEmitter {
5110
5330
  output: this.mapCompletionDataArg(item.output)
5111
5331
  }));
5112
5332
  const ids = items.map((item) => item.id);
5113
- if (this.config.noMultiMutationCte) return this.withDistributedTransaction(this.db, async (tx) => {
5333
+ if (this.config.noMultiMutationCte) {
5114
5334
  const sql = completeJobsWithOutputsDistributed(this.config.schema, table);
5115
- const { rows } = await tx.executeSql(sql, [name, JSON.stringify(payload)]);
5116
- const blockingIds = rows.filter((row) => row.blocking).map((row) => row.id);
5117
- if (blockingIds.length > 0) await tx.executeSql(decrementDependents(this.config.schema), [name, blockingIds]);
5335
+ const { rows } = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
5118
5336
  return {
5119
5337
  jobs: ids,
5120
5338
  requested: ids.length,
5121
5339
  affected: rows.length
5122
5340
  };
5123
- });
5341
+ }
5124
5342
  const sql = completeJobsWithOutputs(this.config.schema, table);
5125
5343
  const result = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
5126
5344
  return this.mapCommandResponse(ids, result);
@@ -5208,7 +5426,7 @@ var Manager = class extends EventEmitter {
5208
5426
  try {
5209
5427
  await this.touch(name, jobIds);
5210
5428
  } catch (err) {
5211
- this.emit(events$4.error, err);
5429
+ this.emit(events$5.error, err);
5212
5430
  }
5213
5431
  }, intervalMs);
5214
5432
  }
@@ -5245,7 +5463,7 @@ var Manager = class extends EventEmitter {
5245
5463
  if (now - this.wipTs < 2e3) return;
5246
5464
  const wip = this.getWipData();
5247
5465
  if (wip.some((w) => w.count > 0)) {
5248
- this.emit(events$4.wip, wip);
5466
+ this.emit(events$5.wip, wip);
5249
5467
  this.wipTs = now;
5250
5468
  }
5251
5469
  }, 2e3);
@@ -5260,7 +5478,7 @@ var Manager = class extends EventEmitter {
5260
5478
  return acc;
5261
5479
  }, {});
5262
5480
  } catch (error) {
5263
- emit && this.emit(events$4.error, {
5481
+ emit && this.emit(events$5.error, {
5264
5482
  ...error,
5265
5483
  message: error.message,
5266
5484
  stack: error.stack
@@ -5340,7 +5558,7 @@ var Manager = class extends EventEmitter {
5340
5558
  this.emitWip(name);
5341
5559
  };
5342
5560
  const onError = (error) => {
5343
- this.emit(events$4.error, {
5561
+ this.emit(events$5.error, {
5344
5562
  ...error,
5345
5563
  message: error.message,
5346
5564
  stack: error.stack,
@@ -5379,7 +5597,7 @@ var Manager = class extends EventEmitter {
5379
5597
  if (!INTERNAL_QUEUES[name]) {
5380
5598
  const now = Date.now();
5381
5599
  if (now - this.wipTs > 2e3) {
5382
- this.emit(events$4.wip, this.getWipData());
5600
+ this.emit(events$5.wip, this.getWipData());
5383
5601
  this.wipTs = now;
5384
5602
  }
5385
5603
  }
@@ -5714,24 +5932,17 @@ var Manager = class extends EventEmitter {
5714
5932
  return fn(db);
5715
5933
  }
5716
5934
  async completeDistributed(name, ids, outputData, table, db, includeQueued) {
5717
- return this.withDistributedTransaction(db, async (tx) => {
5718
- const completeSql = completeJobsDistributed(this.config.schema, table, includeQueued);
5719
- const { rows } = await tx.executeSql(completeSql, [
5720
- name,
5721
- ids,
5722
- outputData
5723
- ]);
5724
- const blockingIds = rows.filter((row) => row.blocking).map((row) => row.id);
5725
- if (blockingIds.length > 0) {
5726
- const decrementSql = decrementDependents(this.config.schema);
5727
- await tx.executeSql(decrementSql, [name, blockingIds]);
5728
- }
5729
- return {
5730
- jobs: ids,
5731
- requested: ids.length,
5732
- affected: rows.length
5733
- };
5734
- });
5935
+ const sql = completeJobsDistributed(this.config.schema, table, includeQueued);
5936
+ const { rows } = await db.executeSql(sql, [
5937
+ name,
5938
+ ids,
5939
+ outputData
5940
+ ]);
5941
+ return {
5942
+ jobs: ids,
5943
+ requested: ids.length,
5944
+ affected: rows.length
5945
+ };
5735
5946
  }
5736
5947
  async fail(name, id, data, options = {}) {
5737
5948
  assertQueueName(name);
@@ -5775,6 +5986,26 @@ var Manager = class extends EventEmitter {
5775
5986
  const select = selectJobsToFailByHeartbeat(this.config.schema, table, queues);
5776
5987
  return this.expireJobsDistributed(table, select, { value: { message: "job heartbeat timeout" } });
5777
5988
  }
5989
+ async resolveFlowJobsDistributed(table, names) {
5990
+ const select = selectBlockingParents(this.config.schema, table, names, this.config.noSkipLocked);
5991
+ return this.withDistributedTransaction(this.db, async (tx) => {
5992
+ const { rows } = await tx.executeSql(select.text, select.values);
5993
+ if (rows.length === 0) return 0;
5994
+ const idsByName = /* @__PURE__ */ new Map();
5995
+ for (const row of rows) {
5996
+ const list = idsByName.get(row.name) || [];
5997
+ list.push(row.id);
5998
+ idsByName.set(row.name, list);
5999
+ }
6000
+ const decrementSql = decrementDependents(this.config.schema);
6001
+ const clearSql = clearBlocking(this.config.schema);
6002
+ for (const [name, ids] of idsByName) {
6003
+ await tx.executeSql(decrementSql, [name, ids]);
6004
+ await tx.executeSql(clearSql, [name, ids]);
6005
+ }
6006
+ return rows.length;
6007
+ });
6008
+ }
5778
6009
  async expireJobsDistributed(table, select, outputData) {
5779
6010
  return this.withDistributedTransaction(this.db, async (tx) => {
5780
6011
  const { rows: jobs } = await tx.executeSql(select.text, []);
@@ -5874,7 +6105,11 @@ var Manager = class extends EventEmitter {
5874
6105
  if (job.dead_letter) await tx.executeSql(dlqSql, [
5875
6106
  job.dead_letter,
5876
6107
  job.data,
5877
- jobOutput
6108
+ jobOutput,
6109
+ job.name,
6110
+ job.id,
6111
+ job.created_on,
6112
+ job.retry_count
5878
6113
  ]);
5879
6114
  }
5880
6115
  count++;
@@ -5890,6 +6125,22 @@ var Manager = class extends EventEmitter {
5890
6125
  const result = await db.executeSql(sql, [name, ids]);
5891
6126
  return this.mapCommandResponse(ids, result);
5892
6127
  }
6128
+ async redrive(name, options = {}) {
6129
+ assertQueueName(name);
6130
+ const { destination, sourceName, limit = 1e3 } = options;
6131
+ if (destination !== void 0) assertQueueName(destination);
6132
+ if (sourceName !== void 0) assertQueueName(sourceName);
6133
+ assert(Number.isInteger(limit) && limit >= 1, "limit must be an integer >= 1");
6134
+ const db = this.assertDb(options);
6135
+ const { table } = await this.getQueueCache(name);
6136
+ const sql = redriveJobs(this.config.schema, table);
6137
+ return (await db.executeSql(sql, [
6138
+ name,
6139
+ destination ?? null,
6140
+ sourceName ?? null,
6141
+ limit
6142
+ ])).rows[0].moved;
6143
+ }
5893
6144
  async cancel(name, id, options = {}) {
5894
6145
  assertQueueName(name);
5895
6146
  const db = this.assertDb(options);
@@ -6099,7 +6350,7 @@ var Manager = class extends EventEmitter {
6099
6350
  };
6100
6351
  //#endregion
6101
6352
  //#region ../../src/boss.ts
6102
- var events$3 = {
6353
+ var events$4 = {
6103
6354
  error: "error",
6104
6355
  warning: "warning"
6105
6356
  };
@@ -6125,7 +6376,7 @@ var Boss = class extends EventEmitter {
6125
6376
  #db;
6126
6377
  #config;
6127
6378
  #manager;
6128
- events = events$3;
6379
+ events = events$4;
6129
6380
  constructor(db, manager, config) {
6130
6381
  super();
6131
6382
  this.#db = db;
@@ -6160,8 +6411,8 @@ var Boss = class extends EventEmitter {
6160
6411
  db: this.#db,
6161
6412
  schema: this.#config.schema,
6162
6413
  persistWarnings: this.#config.persistWarnings,
6163
- warningEvent: events$3.warning,
6164
- errorEvent: events$3.error
6414
+ warningEvent: events$4.warning,
6415
+ errorEvent: events$4.error
6165
6416
  };
6166
6417
  }
6167
6418
  async #executeQuery(query) {
@@ -6190,7 +6441,7 @@ var Boss = class extends EventEmitter {
6190
6441
  !this.#stopped && await this.supervise(queues);
6191
6442
  !this.#stopped && await this.#maintainWarnings();
6192
6443
  } catch (err) {
6193
- this.emit(events$3.error, err);
6444
+ this.emit(events$4.error, err);
6194
6445
  } finally {
6195
6446
  this.#maintaining = false;
6196
6447
  }
@@ -6268,7 +6519,7 @@ var Boss = class extends EventEmitter {
6268
6519
  };
6269
6520
  //#endregion
6270
6521
  //#region ../../src/bam.ts
6271
- var events$2 = {
6522
+ var events$3 = {
6272
6523
  error: "error",
6273
6524
  bam: "bam"
6274
6525
  };
@@ -6278,7 +6529,7 @@ var Bam = class extends EventEmitter {
6278
6529
  #pollInterval;
6279
6530
  #db;
6280
6531
  #config;
6281
- events = events$2;
6532
+ events = events$3;
6282
6533
  constructor(db, config) {
6283
6534
  super();
6284
6535
  this.#db = db;
@@ -6314,7 +6565,7 @@ var Bam = class extends EventEmitter {
6314
6565
  const { rows } = await this.#db.executeSql(sql);
6315
6566
  if (rows.length === 1) await this.#processCommands();
6316
6567
  } catch (err) {
6317
- this.emit(events$2.error, err);
6568
+ this.emit(events$3.error, err);
6318
6569
  } finally {
6319
6570
  this.#working = false;
6320
6571
  }
@@ -6323,7 +6574,7 @@ var Bam = class extends EventEmitter {
6323
6574
  if (this.#stopped) return;
6324
6575
  const entry = await this.#getNextCommand();
6325
6576
  if (!entry || this.#stopped) return;
6326
- this.emit(events$2.bam, {
6577
+ this.emit(events$3.bam, {
6327
6578
  id: entry.id,
6328
6579
  name: entry.name,
6329
6580
  status: "in_progress",
@@ -6334,7 +6585,7 @@ var Bam = class extends EventEmitter {
6334
6585
  await this.#db.executeSql(entry.command);
6335
6586
  if (this.#stopped) return;
6336
6587
  await this.#markCompleted(entry.id);
6337
- this.emit(events$2.bam, {
6588
+ this.emit(events$3.bam, {
6338
6589
  id: entry.id,
6339
6590
  name: entry.name,
6340
6591
  status: "completed",
@@ -6344,8 +6595,8 @@ var Bam = class extends EventEmitter {
6344
6595
  } catch (err) {
6345
6596
  if (this.#stopped) return;
6346
6597
  await this.#markFailed(entry.id, err);
6347
- this.emit(events$2.error, err);
6348
- this.emit(events$2.bam, {
6598
+ this.emit(events$3.error, err);
6599
+ this.emit(events$3.bam, {
6349
6600
  id: entry.id,
6350
6601
  name: entry.name,
6351
6602
  status: "failed",
@@ -6370,6 +6621,111 @@ var Bam = class extends EventEmitter {
6370
6621
  }
6371
6622
  };
6372
6623
  //#endregion
6624
+ //#region ../../src/navigator.ts
6625
+ var events$2 = {
6626
+ error: "error",
6627
+ flow: "flow"
6628
+ };
6629
+ var MAX_BATCHES_PER_PASS = 100;
6630
+ var Navigator = class extends EventEmitter {
6631
+ #stopped;
6632
+ #stopping;
6633
+ #working;
6634
+ #pollInterval;
6635
+ #db;
6636
+ #manager;
6637
+ #config;
6638
+ events = events$2;
6639
+ constructor(db, manager, config) {
6640
+ super();
6641
+ this.#db = db;
6642
+ this.#manager = manager;
6643
+ this.#config = config;
6644
+ this.#stopped = true;
6645
+ this.#stopping = false;
6646
+ this.#working = false;
6647
+ }
6648
+ get working() {
6649
+ return this.#working;
6650
+ }
6651
+ async start() {
6652
+ if (!this.#stopped) return;
6653
+ this.#stopped = false;
6654
+ this.#stopping = false;
6655
+ setImmediate(() => this.#onPoll());
6656
+ this.#pollInterval = setInterval(() => this.#onPoll(), this.#config.flowIntervalSeconds * 1e3);
6657
+ }
6658
+ async stop() {
6659
+ if (this.#stopped) return;
6660
+ this.#stopping = true;
6661
+ this.#stopped = true;
6662
+ if (this.#pollInterval) {
6663
+ clearInterval(this.#pollInterval);
6664
+ this.#pollInterval = void 0;
6665
+ }
6666
+ while (this.#working) await delay(10);
6667
+ }
6668
+ async #onPoll() {
6669
+ if (this.#stopped || this.#working) return;
6670
+ this.#working = true;
6671
+ try {
6672
+ if (this.#config.__test__throw_flow) throw new Error(this.#config.__test__throw_flow);
6673
+ if (this.#config.__test__delay_flow_ms) await delay(this.#config.__test__delay_flow_ms);
6674
+ const gate = trySetFlowTime(this.#config.schema, this.#config.flowIntervalSeconds);
6675
+ const { rows } = await this.#db.executeSql(gate);
6676
+ if (rows.length === 1) await this.#resolve();
6677
+ } catch (err) {
6678
+ this.emit(events$2.error, err);
6679
+ } finally {
6680
+ this.#working = false;
6681
+ }
6682
+ }
6683
+ async resolveNow() {
6684
+ while (this.#working) await delay(10);
6685
+ if (this.#stopping) return;
6686
+ this.#working = true;
6687
+ try {
6688
+ await this.#resolve();
6689
+ } finally {
6690
+ this.#working = false;
6691
+ }
6692
+ }
6693
+ async #resolve() {
6694
+ const queueGroups = (await this.#manager.getQueues()).reduce((acc, q) => {
6695
+ acc[q.table] = acc[q.table] || {
6696
+ table: q.table,
6697
+ names: []
6698
+ };
6699
+ acc[q.table].names.push(q.name);
6700
+ return acc;
6701
+ }, {});
6702
+ for (const group of Object.values(queueGroups)) {
6703
+ if (this.#stopping) return;
6704
+ const { table } = group;
6705
+ const names = [...group.names];
6706
+ while (names.length) {
6707
+ if (this.#stopping) return;
6708
+ const chunk = names.splice(0, 100);
6709
+ let batches = 0;
6710
+ let resolved = 0;
6711
+ do {
6712
+ if (this.#stopping) return;
6713
+ resolved = this.#config.noMultiMutationCte ? await this.#manager.resolveFlowJobsDistributed(table, chunk) : await this.#resolveStandard(table, chunk);
6714
+ if (resolved > 0) this.emit(events$2.flow, {
6715
+ table,
6716
+ resolved
6717
+ });
6718
+ } while (resolved >= 1e3 && ++batches < MAX_BATCHES_PER_PASS && !this.#stopping);
6719
+ }
6720
+ }
6721
+ }
6722
+ async #resolveStandard(table, names) {
6723
+ const query = resolveFlowJobs(this.#config.schema, table, names);
6724
+ const { rows } = await this.#db.executeSql(query.text, query.values);
6725
+ return Number(rows[0]?.resolved ?? 0);
6726
+ }
6727
+ };
6728
+ //#endregion
6373
6729
  //#region ../../src/notifier.ts
6374
6730
  var events$1 = {
6375
6731
  error: "error",
@@ -6450,7 +6806,7 @@ var Db = class extends EventEmitter {
6450
6806
  constructor(config) {
6451
6807
  super();
6452
6808
  config.application_name = config.application_name || "pgboss";
6453
- config.connectionTimeoutMillis = config.connectionTimeoutMillis || 1e4;
6809
+ config.connectionTimeoutMillis ??= 1e4;
6454
6810
  this.config = config;
6455
6811
  this._pgbdb = true;
6456
6812
  this.opened = false;
@@ -6551,7 +6907,8 @@ var events = Object.freeze({
6551
6907
  warning: "warning",
6552
6908
  wip: "wip",
6553
6909
  stopped: "stopped",
6554
- bam: "bam"
6910
+ bam: "bam",
6911
+ flow: "flow"
6555
6912
  });
6556
6913
  var PgBoss = class extends EventEmitter {
6557
6914
  #stoppingOn;
@@ -6565,6 +6922,7 @@ var PgBoss = class extends EventEmitter {
6565
6922
  #manager;
6566
6923
  #timekeeper;
6567
6924
  #bam;
6925
+ #navigator;
6568
6926
  #notifier;
6569
6927
  constructor(value) {
6570
6928
  super();
@@ -6581,18 +6939,21 @@ var PgBoss = class extends EventEmitter {
6581
6939
  const timekeeper = new Timekeeper(db, manager, config);
6582
6940
  manager.timekeeper = timekeeper;
6583
6941
  const bam = new Bam(db, config);
6942
+ const navigator = new Navigator(db, manager, config);
6584
6943
  const notifier = new Notifier(db, manager, config);
6585
6944
  manager.notifier = notifier;
6586
6945
  this.#promoteEvents(manager);
6587
6946
  this.#promoteEvents(boss);
6588
6947
  this.#promoteEvents(timekeeper);
6589
6948
  this.#promoteEvents(bam);
6949
+ this.#promoteEvents(navigator);
6590
6950
  this.#promoteEvents(notifier);
6591
6951
  this.#boss = boss;
6592
6952
  this.#contractor = contractor;
6593
6953
  this.#manager = manager;
6594
6954
  this.#timekeeper = timekeeper;
6595
6955
  this.#bam = bam;
6956
+ this.#navigator = navigator;
6596
6957
  this.#notifier = notifier;
6597
6958
  }
6598
6959
  #promoteEvents(emitter) {
@@ -6608,7 +6969,10 @@ var PgBoss = class extends EventEmitter {
6608
6969
  else await this.#contractor.check();
6609
6970
  await this.#manager.start();
6610
6971
  if (this.#config.useListenNotify) await this.#notifier.start();
6611
- if (this.#config.supervise) await this.#boss.start();
6972
+ if (this.#config.supervise) {
6973
+ await this.#boss.start();
6974
+ await this.#navigator.start();
6975
+ }
6612
6976
  if (this.#config.schedule) await this.#timekeeper.start();
6613
6977
  if (this.#config.migrate) await this.#bam.start();
6614
6978
  } catch (err) {
@@ -6641,6 +7005,7 @@ var PgBoss = class extends EventEmitter {
6641
7005
  await this.#manager.stop();
6642
7006
  await this.#timekeeper.stop();
6643
7007
  await this.#boss.stop();
7008
+ await this.#navigator.stop();
6644
7009
  await this.#bam.stop();
6645
7010
  const shutdown = async () => {
6646
7011
  await this.#manager.failWip();
@@ -6708,6 +7073,9 @@ var PgBoss = class extends EventEmitter {
6708
7073
  deleteJob(name, id, options) {
6709
7074
  return this.#manager.deleteJob(name, id, options);
6710
7075
  }
7076
+ redrive(name, options) {
7077
+ return this.#manager.redrive(name, options);
7078
+ }
6711
7079
  deleteQueuedJobs(name) {
6712
7080
  return this.#manager.deleteQueuedJobs(name);
6713
7081
  }
@@ -6754,7 +7122,7 @@ var PgBoss = class extends EventEmitter {
6754
7122
  return this.#manager.deleteQueue(name);
6755
7123
  }
6756
7124
  getQueues(names) {
6757
- return this.#manager.getQueues();
7125
+ return this.#manager.getQueues(names);
6758
7126
  }
6759
7127
  getQueue(name) {
6760
7128
  return this.#manager.getQueue(name);
@@ -6768,12 +7136,18 @@ var PgBoss = class extends EventEmitter {
6768
7136
  isBamWorking() {
6769
7137
  return this.#bam.working;
6770
7138
  }
7139
+ isResolvingFlow() {
7140
+ return this.#navigator.working;
7141
+ }
6771
7142
  isCheckingSkew() {
6772
7143
  return this.#timekeeper.checkingSkew;
6773
7144
  }
6774
7145
  supervise(name) {
6775
7146
  return this.#boss.supervise(name);
6776
7147
  }
7148
+ resolveFlow() {
7149
+ return this.#navigator.resolveNow();
7150
+ }
6777
7151
  getWipData(options) {
6778
7152
  return this.#manager.getWipData(options);
6779
7153
  }
@@ -10239,6 +10613,37 @@ var queues_$name_jobs_$jobId_default = UNSAFE_withComponentProps(function JobDet
10239
10613
  })] })
10240
10614
  ]
10241
10615
  }),
10616
+ (job.sourceName || job.sourceId) && /* @__PURE__ */ jsxs("div", {
10617
+ className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-4",
10618
+ children: [
10619
+ job.sourceName && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
10620
+ className: "pgb-eyebrow",
10621
+ children: "Source Queue"
10622
+ }), /* @__PURE__ */ jsx("dd", {
10623
+ className: "mt-1 text-sm text-[var(--text-primary)]",
10624
+ children: /* @__PURE__ */ jsx(DbLink, {
10625
+ to: `/queues/${job.sourceName}`,
10626
+ className: "font-mono text-xs text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300",
10627
+ children: job.sourceName
10628
+ })
10629
+ })] }),
10630
+ job.sourceId && /* @__PURE__ */ jsx(ConfigItem, {
10631
+ label: "Source Job ID",
10632
+ value: job.sourceId,
10633
+ mono: true
10634
+ }),
10635
+ job.sourceRetryCount !== null && job.sourceRetryCount !== void 0 && /* @__PURE__ */ jsx(ConfigItem, {
10636
+ label: "Source Retry Count",
10637
+ value: job.sourceRetryCount,
10638
+ mono: true
10639
+ }),
10640
+ job.sourceCreatedOn && /* @__PURE__ */ jsx(ConfigItem, {
10641
+ label: "Source Created",
10642
+ value: formatDate(new Date(job.sourceCreatedOn)),
10643
+ mono: true
10644
+ })
10645
+ ]
10646
+ }),
10242
10647
  /* @__PURE__ */ jsxs("div", {
10243
10648
  className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-x-6 gap-y-4",
10244
10649
  children: [
@@ -11708,7 +12113,7 @@ var server_manifest_default = {
11708
12113
  "hasClientMiddleware": false,
11709
12114
  "hasDefaultExport": true,
11710
12115
  "hasErrorBoundary": true,
11711
- "module": "/assets/queues._name.jobs._jobId-Bkv8POBj.js",
12116
+ "module": "/assets/queues._name.jobs._jobId-DzHZmfcB.js",
11712
12117
  "imports": [
11713
12118
  "/assets/jsx-runtime-RQyiN6Nr.js",
11714
12119
  "/assets/db-link-BajQ1v8I.js",
@@ -11902,8 +12307,8 @@ var server_manifest_default = {
11902
12307
  "hydrateFallbackModule": void 0
11903
12308
  }
11904
12309
  },
11905
- "url": "/assets/manifest-27e8e133.js",
11906
- "version": "27e8e133",
12310
+ "url": "/assets/manifest-3e8f868c.js",
12311
+ "version": "3e8f868c",
11907
12312
  "sri": void 0
11908
12313
  };
11909
12314
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pg-boss/dashboard",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Web dashboard for monitoring and managing pg-boss job queues",
5
5
  "keywords": [
6
6
  "pg-boss",
@@ -53,7 +53,7 @@
53
53
  "isbot": "^5.1.44",
54
54
  "lucide-react": "^1.21.0",
55
55
  "pg": "^8.22.0",
56
- "pg-boss": "^12.21.0",
56
+ "pg-boss": "^12.23.0",
57
57
  "react": "^19.2.7",
58
58
  "react-dom": "^19.2.7",
59
59
  "react-router": "^8.0.1",