safe-actions-state
Version:
A lightweight, type-safe utility for Next.js server & client actions with built-in authentication and RBAC(role based access control) checks, Zod validation, auto retries if server action fails, and real-time toast feedback out of the box. Just write your
2 lines (1 loc) • 5.52 kB
JavaScript
;var e=require("next/headers"),r=require("zod-error"),t=require("sonner"),n=require("react");function o(e,r,t,n){return new(t||(t=Promise))((function(o,s){function a(e){try{u(n.next(e))}catch(e){s(e)}}function i(e){try{u(n.throw(e))}catch(e){s(e)}}function u(e){var r;e.done?o(e.value):(r=e.value,r instanceof t?r:new t((function(e){e(r)}))).then(a,i)}u((n=n.apply(e,r||[])).next())}))}function s(e,r){var t,n,o,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},a=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return a.next=i(0),a.throw=i(1),a.return=i(2),"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function i(i){return function(u){return function(i){if(t)throw new TypeError("Generator is already executing.");for(;a&&(a=0,i[0]&&(s=0)),s;)try{if(t=1,n&&(o=2&i[0]?n.return:i[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,i[1])).done)return o;switch(n=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return s.label++,{value:i[1],done:!1};case 5:s.label++,n=i[1],i=[0];continue;case 7:i=s.ops.pop(),s.trys.pop();continue;default:if(!(o=s.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]<o[3])){s.label=i[1];break}if(6===i[0]&&s.label<o[1]){s.label=o[1],o=i;break}if(o&&s.label<o[2]){s.label=o[2],s.ops.push(i);break}o[2]&&s.ops.pop(),s.trys.pop();continue}i=r.call(e,s)}catch(e){i=[6,e],n=0}finally{t=o=0}if(5&i[0])throw i[1];return{value:i[0]?i[1]:void 0,done:!0}}([i,u])}}}"function"==typeof SuppressedError&&SuppressedError;var a=function(e){for(var r=[],t=1;t<arguments.length;t++)r[t-1]=arguments[t];return o(void 0,function(e,r,t){if(t||2===arguments.length)for(var n,o=0,s=r.length;o<s;o++)!n&&o in r||(n||(n=Array.prototype.slice.call(r,0,o)),n[o]=r[o]);return e.concat(n||Array.prototype.slice.call(r))}([e],r,!0),void 0,(function(e,r,t){var n,o;return void 0===r&&(r=3),s(this,(function(s){switch(s.label){case 0:n=0,s.label=1;case 1:if(!(n<r))return[3,7];if(null==t?void 0:t.aborted)throw new Error("Server Action aborted");s.label=2;case 2:return s.trys.push([2,4,,6]),[4,e()];case 3:return[2,s.sent()];case 4:if(o=s.sent(),n===r-1)throw o;return[4,new Promise((function(e){return setTimeout(e,1e3)}))];case 5:return s.sent(),[3,6];case 6:return n++,[3,1];case 7:throw new Error("Max retries reached")}}))}))};exports.createSafeAction=function(t){var n=t.action,a=t.actionType;return function(t){return o(void 0,void 0,void 0,(function(){var o,i,u,l,c,d;return s(this,(function(s){switch(s.label){case 0:return a.isPrivate?(o=fetch,i=["".concat(process.env.NEXT_PUBLIC_BASE_URL,"/api/").concat(process.env.SAFE_ACTIONS_STATE_ROUTE)],c={},d={},[4,e.cookies()]):[3,4];case 1:return[4,o.apply(void 0,i.concat([(c.headers=(d.Cookie=s.sent().toString(),d),c)]))];case 2:return[4,s.sent().json()];case 3:if(!(u=s.sent()).authenticated)return[2,{error:"Un-authenticated"}];if("allowedRoles"in a&&a.allowedRoles&&a.allowedRoles.length>0){if(!u.role)return[2,{error:"No role found in session"}];if(!a.allowedRoles.includes(u.role))return[2,{error:"Un-authorized"}]}s.label=4;case 4:return n.withInputs?[3,6]:[4,n.handler()];case 5:return[2,s.sent()];case 6:return(l=n.schema.safeParse(t)).success?[4,n.handler(l.data)]:[2,{fieldErrors:l.error.flatten().fieldErrors,error:r.generateErrorMessage(l.error.issues,{maxErrors:1,delimiter:{component:": "},message:{enabled:!0,label:""},code:{enabled:!1}})}];case 7:return[2,s.sent()]}}))}))}},exports.useSafeAction=function(e,r){void 0===r&&(r={});var i=n.useState(void 0),u=i[0],l=i[1],c=n.useRef(null),d=n.useRef(null),f=n.useState(!1),v=f[0],h=f[1],p=n.useState(void 0),b=p[0],w=p[1],y=n.useState(void 0),g=y[0],E=y[1],S=n.useCallback((function(n){return o(void 0,void 0,void 0,(function(){var i,u,f,v,p,b,y,g,S,A,m,x;return s(this,(function(R){switch(R.label){case 0:d.current=new AbortController,h(!0),E(void 0),l(void 0),w(void 0),null===(v=r.onStart)||void 0===v||v.call(r),c.current=t.toast.loading((null===(p=null==r?void 0:r.toastMessages)||void 0===p?void 0:p.loading)||"Processing request...",{duration:1/0}),R.label=1;case 1:return R.trys.push([1,3,4,5]),[4,a((function(){return o(void 0,void 0,void 0,(function(){return s(this,(function(r){switch(r.label){case 0:return[4,e(n)];case 1:return[2,r.sent()]}}))}))}),r.retries,d.current.signal)];case 2:return i=R.sent(),l(null==i?void 0:i.fieldErrors),(null==i?void 0:i.error)?(E(null==i?void 0:i.error),t.toast.error(i.error,{id:c.current,duration:5e3}),null===(b=r.onError)||void 0===b||b.call(r,i.error)):(null==i?void 0:i.data)?(w(null==i?void 0:i.data),null===(y=r.onSuccess)||void 0===y||y.call(r,null==i?void 0:i.data),t.toast.success((null===(g=null==r?void 0:r.toastMessages)||void 0===g?void 0:g.success)||"Request successful",{id:c.current,duration:5e3})):(null===(S=r.onSuccess)||void 0===S||S.call(r),t.toast.success((null===(A=null==r?void 0:r.toastMessages)||void 0===A?void 0:A.success)||"Request successful",{id:c.current,duration:5e3})),[3,5];case 3:return u=R.sent(),f=u instanceof Error?u.message:"An unknown error occurred",E(f),t.toast.error(f,{id:c.current,duration:5e3}),null===(m=r.onError)||void 0===m||m.call(r,f),[3,5];case 4:return h(!1),d.current=null,null===(x=r.onComplete)||void 0===x||x.call(r),[7];case 5:return[2]}}))}))}),[e,r]);return{clientAction:S,abortAction:function(){var e;return null===(e=d.current)||void 0===e?void 0:e.abort()},error:g,data:b,isPending:v,fieldErrors:u,setFieldErrors:l}};