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
1 lines • 5.48 kB
JavaScript
import{cookies as r}from"next/headers";import{generateErrorMessage as e}from"zod-error";import{toast as n}from"sonner";import{useState as t,useRef as o,useCallback as i}from"react";function l(r,e,n,t){return new(n||(n=Promise))((function(o,i){function l(r){try{s(t.next(r))}catch(r){i(r)}}function a(r){try{s(t.throw(r))}catch(r){i(r)}}function s(r){var e;r.done?o(r.value):(e=r.value,e instanceof n?e:new n((function(r){r(e)}))).then(l,a)}s((t=t.apply(r,e||[])).next())}))}function a(r,e){var n,t,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},l=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return l.next=a(0),l.throw=a(1),l.return=a(2),"function"==typeof Symbol&&(l[Symbol.iterator]=function(){return this}),l;function a(a){return function(s){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;l&&(l=0,a[0]&&(i=0)),i;)try{if(n=1,t&&(o=2&a[0]?t.return:a[0]?t.throw||((o=t.return)&&o.call(t),0):t.next)&&!(o=o.call(t,a[1])).done)return o;switch(t=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,t=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=e.call(r,i)}catch(r){a=[6,r],t=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,s])}}}"function"==typeof SuppressedError&&SuppressedError;var s=function(n){var t=n.action,o=n.actionType;return function(n){return l(void 0,void 0,void 0,(function(){var i,l,s,u,c,d;return a(this,(function(a){switch(a.label){case 0:return o.isPrivate?(i=fetch,l=["".concat(process.env.NEXT_PUBLIC_BASE_URL,"/api/").concat(process.env.SAFE_ACTIONS_STATE_ROUTE)],c={},d={},[4,r()]):[3,4];case 1:return[4,i.apply(void 0,l.concat([(c.headers=(d.Cookie=a.sent().toString(),d),c)]))];case 2:return[4,a.sent().json()];case 3:if(!(s=a.sent()).authenticated)return[2,{error:"Un-authenticated"}];if("allowedRoles"in o&&o.allowedRoles&&o.allowedRoles.length>0){if(!s.role)return[2,{error:"No role found in session"}];if(!o.allowedRoles.includes(s.role))return[2,{error:"Un-authorized"}]}a.label=4;case 4:return t.withInputs?[3,6]:[4,t.handler()];case 5:return[2,a.sent()];case 6:return(u=t.schema.safeParse(n)).success?[4,t.handler(u.data)]:[2,{fieldErrors:u.error.flatten().fieldErrors,error:e(u.error.issues,{maxErrors:1,delimiter:{component:": "},message:{enabled:!0,label:""},code:{enabled:!1}})}];case 7:return[2,a.sent()]}}))}))}},u=function(r){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];return l(void 0,function(r,e,n){if(n||2===arguments.length)for(var t,o=0,i=e.length;o<i;o++)!t&&o in e||(t||(t=Array.prototype.slice.call(e,0,o)),t[o]=e[o]);return r.concat(t||Array.prototype.slice.call(e))}([r],e,!0),void 0,(function(r,e,n){var t,o;return void 0===e&&(e=3),a(this,(function(i){switch(i.label){case 0:t=0,i.label=1;case 1:if(!(t<e))return[3,7];if(null==n?void 0:n.aborted)throw new Error("Server Action aborted");i.label=2;case 2:return i.trys.push([2,4,,6]),[4,r()];case 3:return[2,i.sent()];case 4:if(o=i.sent(),t===e-1)throw o;return[4,new Promise((function(r){return setTimeout(r,1e3)}))];case 5:return i.sent(),[3,6];case 6:return t++,[3,1];case 7:throw new Error("Max retries reached")}}))}))},c=function(r,e){void 0===e&&(e={});var s=t(void 0),c=s[0],d=s[1],f=o(null),v=o(null),p=t(!1),h=p[0],b=p[1],w=t(void 0),y=w[0],m=w[1],E=t(void 0),g=E[0],S=E[1],A=i((function(t){return l(void 0,void 0,void 0,(function(){var o,i,s,c,p,h,w,y,E,g,A,x;return a(this,(function(R){switch(R.label){case 0:v.current=new AbortController,b(!0),S(void 0),d(void 0),m(void 0),null===(c=e.onStart)||void 0===c||c.call(e),f.current=n.loading((null===(p=null==e?void 0:e.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,u((function(){return l(void 0,void 0,void 0,(function(){return a(this,(function(e){switch(e.label){case 0:return[4,r(t)];case 1:return[2,e.sent()]}}))}))}),e.retries,v.current.signal)];case 2:return o=R.sent(),d(null==o?void 0:o.fieldErrors),(null==o?void 0:o.error)?(S(null==o?void 0:o.error),n.error(o.error,{id:f.current,duration:5e3}),null===(h=e.onError)||void 0===h||h.call(e,o.error)):(null==o?void 0:o.data)?(m(null==o?void 0:o.data),null===(w=e.onSuccess)||void 0===w||w.call(e,null==o?void 0:o.data),n.success((null===(y=null==e?void 0:e.toastMessages)||void 0===y?void 0:y.success)||"Request successful",{id:f.current,duration:5e3})):(null===(E=e.onSuccess)||void 0===E||E.call(e),n.success((null===(g=null==e?void 0:e.toastMessages)||void 0===g?void 0:g.success)||"Request successful",{id:f.current,duration:5e3})),[3,5];case 3:return i=R.sent(),s=i instanceof Error?i.message:"An unknown error occurred",S(s),n.error(s,{id:f.current,duration:5e3}),null===(A=e.onError)||void 0===A||A.call(e,s),[3,5];case 4:return b(!1),v.current=null,null===(x=e.onComplete)||void 0===x||x.call(e),[7];case 5:return[2]}}))}))}),[r,e]);return{clientAction:A,abortAction:function(){var r;return null===(r=v.current)||void 0===r?void 0:r.abort()},error:g,data:y,isPending:h,fieldErrors:c,setFieldErrors:d}};export{s as createSafeAction,c as useSafeAction};