@stoker-platform/node-client 0.5.93 → 0.5.94
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.
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.js +2 -2
- package/package.json +1 -1
package/dist/bundle.cjs
CHANGED
|
@@ -11,4 +11,4 @@ ${i}`)}})()]),r.length>0)throw new Error(r.join(", "))},mr=async(t,e,n,s,r,i,o,a
|
|
|
11
11
|
<a href="${E}">${E}</a>`)}catch{throw await u(r,m),new Error(m)}}}return f.uid},gr=async(t,e)=>{const{labels:n,parentCollection:s}=e;if(s){const r=t.at(-2);if(!r)throw new Error("PERMISSION_DENIED");const i=[...t].slice(0,-2),o=await Be(i,r).catch(()=>{throw new Error("PERMISSION_DENIED")}),a=o.Collection_Path;if(a.push(o.id),a.push(n.collection),!Xe(t,a))throw new Error("PERMISSION_DENIED")}else if(t.length>1)throw new Error("PERMISSION_DENIED")},Qn=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),fu=t=>{const e=n=>{Object.entries(n).forEach(([s,r])=>{Qn(r)&&Object.keys(r).length===2&&typeof r.seconds=="number"&&typeof r.nanoseconds=="number"?n[s]=new oe.Timestamp(r.seconds,r.nanoseconds):Qn(r)&&e(r)})};e(t)},wr=t=>{const e=n=>{Object.entries(n).forEach(([s,r])=>{Qn(r)&&Object.keys(r).length===2&&typeof r._seconds=="number"&&typeof r._nanoseconds=="number"?n[s]=new oe.Timestamp(r._seconds,r._nanoseconds):Qn(r)&&e(r)})};e(t)},os=t=>{if(typeof t=="object")for(const e in t)Object.prototype.hasOwnProperty.call(t,e)&&(t[e]==="_DELETE_FIELD"?t[e]=oe.FieldValue.delete():os(t[e]))},hu=(t,e,n)=>{if(X(n)&&n.includeFields){const s={};return n.includeFields.forEach(r=>{if(e[r]!==void 0){s[r]=e[r];const i=P(t.fields,r);Rt(t,[i]).size===1&&(s[`${r}_Lowercase`]=e[`${r}_Lowercase`])}}),s}return{}},wi=async(t,e,n,s,r,i,o)=>{if(!X(n)||!n.enforceHierarchy)return;const{fields:a}=e,l=de(),c=Object.entries(s[n.name]);if(!c.length)throw new Error(`VALIDATION_ERROR: relation ${n.name} is required`);const[d,m]=c[0];if(!m)throw new Error(`VALIDATION_ERROR: Relation ${n.name} is required`);const u=De(l,m.Collection_Path,t);if(i.size++,!o&&i.size>500)throw new Error("VALIDATION ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks, entity restrictions (in permissions when dealing with user collections) or relation hierarchy checks.");const f=await r.get(u.doc(d));if(!f.exists)throw new Error(`VALIDATION_ERROR: Record ${d} not found in collection ${n.collection}`);const g=f.data(),b=P(a,n.enforceHierarchy.field),p=n.enforceHierarchy;if(!g[p.recordLinkField]||!s[b.name]||!Object.keys(s[b.name]).every(E=>Object.keys(g[p.recordLinkField]).includes(E)))throw new Error("VALIDATION_ERROR: Invalid relation hierarchy")},In=async(t,e,n)=>{delete e[t.name][n],e[`${t.name}_Array`]=e[`${t.name}_Array`]?.filter(s=>s!==n),delete e[`${t.name}_Single`]},Ts=async(t,e,n,s,r)=>{e[t.name]||={},e[t.name][s]=n,e[`${t.name}_Array`]||=[],e[`${t.name}_Array`].push(s),r&&(e[`${t.name}_Single`]={id:s,...n})},mu=(t,e,n,s,r,i)=>{const o=[],a=[];for(const l of s.fields)X(l)&&l.twoWay&&l.collection===n&&((t==="Create"||!i?.[l.name]?.[e])&&r[l.name]?.[e]&&o.push(l),t==="Update"&&i?.[l.name]?.[e]&&!r[l.name]?.[e]&&a.push(l));return{addedFields:o,removedFields:a}},_r=async(t,e,n,s,r,i,o,a,l,c,d,m,u)=>{const{fields:f}=i,g=de(),b=new Map,p=new Map,E=new Map;for(const _ of f)X(_)&&["OneToOne","OneToMany"].includes(_.type)&&_.enforceHierarchy&&s[_.name]&&(t==="Create"||t==="Update"&&!Xe(m?.[_.name],s[_.name]))&&await wi(e,i,_,s,a,l);for(const _ of f)if(X(_)&&_.twoWay){const x=o.collections[_.collection],k=P(x.fields,_.twoWay),v=wt(x,[k]);if(s[_.name]){const A=Object.entries(s[_.name]);for(const V of A){const[O,H]=V;if(t==="Create"||!m?.[_.name]?.[O]){let y;const w=E.get(_.collection)?.[O];if(w)y=w;else{l.size++,l&&l.size>500&&console.error(new Error(`VALIDATION_ERROR: ${l.size} operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of two way updates, unique field checks, entity restrictions (in permissions when dealing with user collections) or relation hierarchy checks.`));const q=De(g,H.Collection_Path,e),Z=await a.get(q.doc(O));if(!Z.exists){In(_,r,O);continue}const h=Z.data();p.set(_.collection,{...p.get(_.collection)||{},[O]:h}),y=ge({...h,...Mn(s)})}const S={...y[k.name],[n]:{Collection_Path:s.Collection_Path,...hu(i,s,k)}};y[k.name]=S,y[`${k.name}_Array`]||=[],y[`${k.name}_Array`].push(n),v.size===1&&(y[`${k.name}_Single`]={id:n,...S}),E.set(_.collection,{...E.get(_.collection)||{},[O]:y})}}}if(t==="Update"){const A=Object.entries(m?.[_.name]||{});for(const V of A){const[O,H]=V;if(!s[_.name]?.[O]){let y;const w=E.get(_.collection)?.[O];if(w)y=w;else{l.size++,l&&l.size>500&&console.error(new Error(`VALIDATION_ERROR: ${l.size} operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of two way updates, unique field checks, entity restrictions (in permissions when dealing with user collections) or relation hierarchy checks.`));const S=De(g,H.Collection_Path,e),q=await a.get(S.doc(O));if(!q.exists){b.set(_.name,[...b.get(_.name)||[],O]);continue}const Z=q.data();p.set(_.collection,{...p.get(_.collection)||{},[O]:Z}),y=ge({...Z,...Mn(s)})}y[k.name][n]&&delete y[k.name][n],Array.isArray(y[`${k.name}_Array`])&&(y[`${k.name}_Array`]=y[`${k.name}_Array`].filter(S=>S!==n)),v.size===1&&delete y[`${k.name}_Single`],E.set(_.collection,{...E.get(_.collection)||{},[O]:y})}}}}for(const[_,x]of E.entries()){const k=o.collections[_],v=rt(_,o);for(const[A,V]of Object.entries(x)){const{addedFields:O,removedFields:H}=mu(t,A,_,i,s,m);if(c&&d){for(const y of O){const w=P(k.fields,y.twoWay);if(!Or(k,w,d,u??{})){In(y,r,A);continue}}for(const y of H){const w=P(k.fields,y.twoWay),S=wt(k,[w]);if(!Or(k,w,d,u??{})){Ts(y,r,m?.[y.name]?.[A],A,S.size===1);continue}}if(!ft("Update",k,o,c,d,p.get(_)?.[A])){for(const y of O)In(y,r,A);for(const y of H){const w=P(k.fields,y.twoWay),S=wt(k,[w]);Ts(y,r,m?.[y.name]?.[A],A,S.size===1)}}if(!ft("Update",k,o,c,d,V)){for(const y of O)In(y,r,A);for(const y of H){const w=P(k.fields,y.twoWay),S=wt(k,[w]);Ts(y,r,m?.[y.name]?.[A],A,S.size===1)}}}try{await fn("update",V,k,v,{operation:"update",data:V,context:{},originalRecord:V},o)}catch(y){throw new Error(`VALIDATION_ERROR: Two way relation update would invalidate record ${A} in ${_}: ${y.message}`)}for(const y of O){const w=P(k.fields,y.twoWay);["OneToOne","OneToMany"].includes(w.type)&&X(w)&&w.enforceHierarchy&&await wi(e,k,w,V,a,l,!0)}}}return b},Yo=(t,e,n)=>{t==="create"&&ct.forEach(s=>{if(!Xe(e[s],n[s]))throw new Error(`Updating system fields in hooks is not allowed: ${s}`)}),t==="update"&&(["id","Collection_Path","Created_At","Saved_At","Created_By"].forEach(s=>{if(s in e)throw new Error(`Cannot update system field: ${s}`)}),ct.forEach(s=>{if(!["id","Collection_Path","Created_At","Saved_At","Created_By"].includes(s)&&!Xe(e[s],n[s]))throw new Error(`Updating system fields in hooks is not allowed: ${s}`)}))},Er=(t,e,n,s)=>{const{softDelete:r}=e;if(!r)return;const i=r?.archivedField,o=r?.timestampField;if(n[i]===!0)if(t==="create")n[o]=oe.FieldValue.serverTimestamp();else{if(!s)throw new Error("Original record is required for update");if(!s[i])n[o]=oe.FieldValue.serverTimestamp();else if(n[o]&&n[o]?.valueOf()!==s[o]?.valueOf())throw new Error("Soft delete timestamp cannot be changed")}},Rs=async(t,e,n,s,r)=>{if(!Ae("Read",r.collections?.[e.labels.collection]))return!1;try{await Be([e.labels.collection],n,{userId:s,providedTransaction:t})}catch{return!1}return!0},pu=10,yu=async(t,e)=>{if(t.length===0)return;const n=Math.min(e,t.length);let s=0;const r=async()=>{for(;s<t.length;){const i=s;s+=1,await t[i]()}};await Promise.all(Array.from({length:n},r))},Jo=async(t,e,n,s,r,i,o)=>{for(const[a,l]of Object.entries(e?.collections||{})){if(!r.collections[a])throw new Error("PERMISSION_DENIED");const c=r.collections[a].access,d=r.collections[a];if(s.collections?.[a]?.restrictEntities||s?.collections?.[a]?.recordOwner?.active||s?.collections?.[a]?.recordUser?.active||s?.collections?.[a]?.recordProperty?.active){const u=i?.collections?.[a],f=[];if(l.individualEntities){const g=l.individualEntities,b=u?.individualEntities||[],p=i?g.filter(E=>!b.includes(E)):g;for(const E of p){if(o&&o.size++,o&&o.size>500)throw new Error("VALIDATION_ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks or entity restrictions (in permissions when dealing with user collections).");f.push(async()=>{if(!await Rs(t,d,E,n,s))throw new Error("PERMISSION_DENIED")})}}if(l.parentEntities){const g=c.entityRestrictions?.restrictions?.find(k=>k.type==="Parent"&&k.roles.some(v=>v.role===e.Role));if(!g)throw new Error("PERMISSION_DENIED");const b=P(d.fields,g.collectionField),p=r.collections[b.collection],E=l.parentEntities,_=u?.parentEntities||[],x=i?E.filter(k=>!_.includes(k)):E;for(const k of x){if(o&&o.size++,o&&o.size>500)throw new Error("VALIDATION_ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks or entity restrictions (in permissions when dealing with user collections).");f.push(async()=>{if(!await Rs(t,p,k,n,s))throw new Error("PERMISSION_DENIED")})}}if(l.parentPropertyEntities){const g=c.entityRestrictions?.restrictions?.find(x=>x.type==="Parent_Property"&&x.roles.some(k=>k.role===e.Role));if(!g)throw new Error("PERMISSION_DENIED");const b=P(d.fields,g.collectionField),p=r.collections[b.collection],E=l.parentPropertyEntities,_=u?.parentPropertyEntities||{};for(const[x,k]of Object.entries(E)){const v=_[x]||[],A=i?k.filter(V=>!v.includes(V)):k;for(const V of A){if(o&&o.size++,o&&o.size>500)throw new Error("VALIDATION_ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks or entity restrictions (in permissions when dealing with user collections).");f.push(async()=>{if(!await Rs(t,p,V,n,s))throw new Error("PERMISSION_DENIED")})}}}await yu(f,pu)}}},gu=async(t,e,n)=>{const s=n?.userId,r=n?.user;let i=n?.context;const o=Je(),a=xt();if(n?.providedTransaction&&s)throw new Error("PERMISSION_DENIED");if(n?.providedSchema&&s)throw new Error("PERMISSION_DENIED");let l=n?.providedSchema||await Ye();if(t.length===0)throw new Error("EMPTY_PATH");const c=t.at(-1),d=Object.keys(l.collections).includes(c),m=a.disabledCollections?.includes(c);if(!d||m)throw new Error("COLLECTION_NOT_FOUND");const u=l.collections[c],{labels:f,fields:g,enableWriteLog:b,softDelete:p}=u,E=rt(f.collection,l),_=await ae(a.appName),x=de(),k=Tt.getAuth(),v=s?await k.getUser(s):void 0,A=v?.customClaims?.role;let V,O;s&&await gr(t,u);const H=De(x,t,o),y=n?.id||H.doc().id;i=i||{},i.collection=f.collection,e.id=y,wr(e),os(e);const w=Ks("create",t,e,l,_,"Online",s||"System",oe.Timestamp.now(),oe.FieldValue.serverTimestamp());n?.createdAt&&(w.Created_At=n.createdAt),n?.createdBy&&(w.Created_By=n.createdBy);const S=ge(w);p&&(w[p.archivedField]=!1),Ze(e),_t(u,w,l),b&&!n?.providedTransaction&&await bt("create","started",w,o,t,y,u),await le("preOperation",a,E,{operation:"create",data:w,recordId:y,context:i}),await le("preWrite",a,E,{operation:"create",data:w,recordId:y,context:i}),_t(u,w,l),Pn(u,w);const I=(s?await x.collection("tenants").doc(o).collection("system_user_permissions").doc(s).get():void 0)?.data();await ba(w,u,E,I,v?.customClaims||{}),Ze(w);try{if(u.auth&&r){if(!r.password)throw new Error("Password is required");if(!w.Role)throw new Error("Role field is required");if(!w.Email)throw new Error("Email field is required");if(w.Enabled===void 0||w.Enabled===null)throw new Error("Enabled field is required")}n?.providedTransaction||await fn("create",w,u,E,{operation:"create",data:w,context:i},l)}catch(D){throw new Error(`VALIDATION_ERROR: ${D.message}`)}Ze(w),e.id=y,p&&(w[p.archivedField]=!1),_t(u,w,l),Pn(u,w);try{Yo("create",w,S),Er("create",u,w),await fn("create",w,u,E,{operation:"create",data:w,context:i},l)}catch(D){throw new Error(`VALIDATION_ERROR: ${D.message}`)}if(s){const D=A;if(!D)throw new Error("USER_ERROR");if(!(E.custom?.serverAccess?.create!==void 0?await ae(E.custom.serverAccess.create,[D,w]):!0))throw new Error("PERMISSION_DENIED");for(const B of u.fields){if(!(B.name in w))continue;const F=Ue(B,E);if(F?.custom?.serverAccess?.create!==void 0&&!await ae(F.custom.serverAccess.create,[D,w]))throw new Error("PERMISSION_DENIED")}}r&&(r.permissions||={},r.permissions.Role||=w.Role,r.permissions.Enabled||=w.Enabled);const T=async(D,L)=>{const[B,F,R,Q,ee]=await Promise.all([n?.providedTransaction?Promise.resolve({}):D.get(x.collection("system_deployment").doc("latest_deploy")),n?.providedTransaction?Promise.resolve({}):D.get(x.collection("system_deployment").doc("maintenance_mode")),s?D.get(x.collection("tenants").doc(o).collection("system_user_permissions").doc(s)):Promise.resolve({}),n?.providedSchema?Promise.resolve(n.providedSchema):Ye(),s?_n(s):Promise.resolve(void 0)]);if(L&&(L.size+=3),!n?.providedTransaction){if(!B.exists)throw new Error("VERSION_ERROR");const pe=B.data();if(pe.force&&w.Last_Write_At.valueOf()<pe.time.valueOf())throw new Error("VERSION_ERROR");if(!F.exists)throw new Error("MAINTENANCE_MODE");if(F.data().active)throw new Error("MAINTENANCE_MODE")}if(l=Q,s){if(!R?.exists)throw new Error("PERMISSION_DENIED");if(V=R.data(),!V.Role)throw new Error("USER_ERROR");if(!V.Enabled)throw new Error("PERMISSION_DENIED");O=ee?.customClaims??{}}if(!n?.providedTransaction){const Re=g.filter(fe=>"unique"in fe&&fe.unique).map(async fe=>{if(!s||!fe.access||He(fe,V,u,O)){if(!w[fe.name])return;const ye=Ue(fe,E);if(!(s&&ye?.custom?.serverAccess?.read!==void 0?await ae(ye.custom.serverAccess.read,[V?.Role,w]):!0))throw new Error("PERMISSION_DENIED");const Qe=w[fe.name].toString().toLowerCase().replace(/\s/g,"---").replaceAll("/","|||");if(Vo(Qe)){if(L&&L.size++,L&&L.size>500)throw new Error("VALIDATION_ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks.");if((await D.get(x.collection("tenants").doc(o).collection("system_unique").doc(f.collection).collection(`Unique-${f.collection}-${fe.name}`).doc(Qe)))?.exists)throw new Error(`VALIDATION_ERROR: ${fe.name} "${w[fe.name]}" already exists`)}else throw new Error(`VALIDATION_ERROR: ${fe.name} "${w[fe.name]}" is invalid`)}});await Promise.all(Re)}kr(w,y,u,l,s,V,r?.permissions,O),r?.permissions&&s&&V&&await Jo(D,r.permissions,s,V,l),kr(w,y,u,l,s,V,r?.permissions,O)};if(u.auth&&r){await x.runTransaction(async L=>{await T(L)},{maxAttempts:10});const D=await yr(o,y,a,u,w,r.permissions,r.password);w.User_ID=D}const $=async D=>{try{const L={size:1};await T(D,L),n?.noTwoWay||await _r("Create",o,y,w,w,u,l,D,L,s,V,void 0,O);const B=Qs(l);lr("create",D,t,y,w,l,u,n,B,oe.FieldValue.arrayUnion,oe.FieldValue.arrayRemove,oe.FieldValue.delete,F=>x.collection("tenants").doc(o).collection("system_fields").doc(f.collection).collection(`${f.collection}-${F.name}`).doc(y),(F,R)=>x.collection("tenants").doc(o).collection("system_unique").doc(f.collection).collection(`Unique-${f.collection}-${F.name}`).doc(R),F=>x.collection("tenants").doc(o).collection("system_fields").doc(f.collection).collection(`${f.collection}-${F}`).doc(y),(F,R)=>De(x,F,o).doc(R),(F,R,Q)=>x.collection("tenants").doc(o).collection("system_fields").doc(F.collection).collection(`${F.collection}-${R}`).doc(Q),(F,R,Q)=>x.collection("tenants").doc(o).collection("system_fields").doc(F.collection).collection(`${F.collection}-${R.replaceAll(" ","-")}`).doc(Q),void 0,void 0,L),D.set(H.doc(y),w)}catch(L){if(n?.providedTransaction)throw L;{const F=await le("postWriteError",a,E,{operation:"create",data:w,recordId:y,context:i,error:L});if(b&&(await new Promise(R=>{setTimeout(R,250)}),await bt("create",F?.resolved?"success":"failed",w,o,t,y,u,F?.resolved?void 0:L)),!F?.resolved)throw u.auth&&r&&await Gt(w),L}}};if(n?.providedTransaction?await $(n.providedTransaction):await x.runTransaction(async D=>{await $(D)},{maxAttempts:10}),!n?.providedTransaction){const D={operation:"create",data:w,recordId:y,context:i},L={...D};await le("postWrite",a,E,D),await le("postOperation",a,E,L)}return{id:y,...w}},sn=async(t,e,n,s)=>{const r=Je(),i=Tt.getAuth(),o=de(),a=e.customClaims||{};let l=!1;try{await i.updateUser(t,{email:e.email,disabled:e.disabled,displayName:e.displayName,photoURL:e.photoURL,emailVerified:!!e.emailVerified})}catch{l=!0}try{await i.setCustomUserClaims(t,{...a})}catch{l=!0}try{await o.collection("tenants").doc(r).collection("system_user_permissions").doc(t).update({...n,Collection:a.collection,Doc_ID:a.doc,Role:a.role,Enabled:!e.disabled})}catch{l=!0}if(l)throw new Error(`ROLLBACK_FAILED: ${s}`)},Qo=async(t,e,n,s,r,i,o,a,l,c,d)=>{const m=Tt.getAuth(),u=de(),f={};for(const p of r.fields)p.saveToAuthToken&&!pr(p.name)&&i[p.name]!==void 0&&p.type!=="Timestamp"&&p.type!=="Computed"&&p.type!=="Embedding"&&(ve(i[p.name])?f[p.name]=null:f[p.name]=i[p.name]);const g="USER_ERROR";let b="";if(t==="create"){if(!d)throw new Error("VALIDATION_ERROR: Password is required");if(!l)throw new Error("VALIDATION_ERROR: Permissions are required");try{b=await yr(e,n,s,r,i,l,d)}catch(p){throw new Error(p.message)}}else if(t==="update"){if(!c||!a)throw new Error("USER_ERROR");const p={};if(o.Name!==i.Name&&(p.displayName=i.Name),o.Email!==i.Email&&(p.email=i.Email,p.emailVerified=!1),o.Photo_URL!==i.Photo_URL&&(p.photoURL=i.Photo_URL?i.Photo_URL:void 0),o.Enabled!==i.Enabled&&(p.disabled=!i.Enabled),d&&(p.password=d),Object.keys(p).length)try{await m.updateUser(o.User_ID,p),p.disabled===!0&&await m.revokeRefreshTokens(o.User_ID)}catch{throw await sn(o.User_ID,a,c,g),new Error(g)}if(i.Role&&i.Role!==o.Role||Object.keys(f).length)try{const E={...du(a.customClaims),...f};await m.setCustomUserClaims(o.User_ID,{...E,tenant:e,role:i.Role,collection:r.labels.collection,doc:n}),await m.revokeRefreshTokens(o.User_ID)}catch{throw await sn(o.User_ID,a,c,g),new Error(g)}try{await u.collection("tenants").doc(e).collection("system_user_permissions").doc(o.User_ID).set({...l||c,Collection:r.labels.collection,Doc_ID:n,Role:i.Role,Enabled:i.Enabled??o.Enabled??!1})}catch{throw await sn(o.User_ID,a,c,g),new Error(g)}if(o.Email!==i.Email){const E=s.auth.enableMultiFactorAuth;if(E===!0||typeof E=="object"&&E.includes(i.Role)){let _=await m.generateEmailVerificationLink(i.Email).catch(()=>{throw new Error("Error generating email verification link")});if(_.includes("apiKey=&")){const x=JSON.parse(process.env.STOKER_FB_WEB_APP_CONFIG);_=_.replace("apiKey=&",`apiKey=${x.apiKey}&`)}if(_){const x=`https://${m.app.options.projectId}.firebaseapp.com/__/auth/action${_}`,k=await ae(s.appName),v=s?.mail?.emailVerification&&s.mail.emailVerification(x,k);try{await mr(i.Email,v?.subject||"Please verify your email address",void 0,v?.html||`Please verify your email address by clicking the link:
|
|
12
12
|
</br>
|
|
13
13
|
</br>
|
|
14
|
-
<a href="${x}">${x}</a>`)}catch{throw await sn(o.User_ID,a,c,g),new Error(g)}}}}}else if(t==="delete")try{await Gt(o)}catch(p){throw new Error(p.message)}if(b)return b},wu=async(t,e,n)=>{const s=Je(),r=de(),i=[e];n&&n.trim()!==""&&i.push(n),i.sort();const o=[];for(const a of i){const l=r.collection("tenants").doc(s).collection("system_locks").doc(a);if((await t.get(l)).exists)throw new Error("DOCUMENT_LOCKED");o.push(l)}for(const a of o)t.set(a,{locked:!0})},_i=async(t,e)=>{const n=Je(),s=de(),r=[t];e&&e.trim()!==""&&r.push(e),r.sort();const i=s.batch();for(const o of r){const a=s.collection("tenants").doc(n).collection("system_locks").doc(o);i.delete(a)}await i.commit()},Ko=async(t,e,n,s)=>{const r=s?.userId;let i=s?.user,o=s?.context;const a=Je(),l=xt();if(s?.providedTransaction&&r)throw new Error("PERMISSION_DENIED");if(s?.providedSchema&&r)throw new Error("PERMISSION_DENIED");if(s?.providedTransaction&&!s?.originalRecord)throw new Error("PERMISSION_DENIED");let c=s?.providedSchema||await Ye(!0);if(t.length===0)throw new Error("EMPTY_PATH");const d=t.at(-1),m=Object.keys(c.collections).includes(d),u=l.disabledCollections?.includes(d);if(!m||u)throw new Error("COLLECTION_NOT_FOUND");const f=c.collections[d],{labels:g,fields:b,enableWriteLog:p}=f,E=rt(g.collection,c),_=await ae(l.appName),x=Tt.getAuth(),k=de();let v,A;r&&await gr(t,f);const V=De(k,t,a);o=o||{},o.collection=g.collection;let O=s?.originalRecord||await Be(t,e,{userId:r,noComputedFields:!0,noEmbeddingFields:!0}),H=O;r&&(H=await Be(t,e,{noComputedFields:!0,noEmbeddingFields:!0}));for(const R of b)R.type==="Computed"&&(delete n[R.name],delete O[R.name]);if(c={...c,collections:Object.fromEntries(Object.entries(c.collections).map(([R,Q])=>[R,{...Q,fields:Q.fields.filter(ee=>ee.type!=="Computed")}]))},i&&!i.operation)throw new Error("VALIDATION_ERROR: User operation is required");if(i&&!f.auth)throw new Error("VALIDATION_ERROR: User operations are only permitted for auth collections");if(i?.operation==="delete"&&i.permissions)throw new Error("VALIDATION_ERROR: Permissions are not allowed for delete operations");const y=f.fields.filter(R=>R.saveToAuthToken&&!pr(R.name)),w=f.auth&&i?.operation==="create",S=f.auth&&i?.operation==="delete",q=f.auth&&!w&&!S&&(i?.operation==="update"||n.Role||n.Enabled!==void 0||n.Name||n.Email||n.Photo_URL||y.some(R=>n[R.name]!==void 0)),Z=R=>R.User_ID&&(f.auth&&!w&&!S&&i?.operation==="update"||n.Role&&n.Role!==R.Role||n.Enabled!==void 0&&n.Enabled!==R.Enabled||n.Name&&n.Name!==R.Name||n.Email&&n.Email!==R.Email||n.Photo_URL&&n.Photo_URL!==R.Photo_URL||y.some(Q=>n[Q.name]!==void 0&&n[Q.name]!==R[Q.name]));delete n.id,wr(n),os(n);const h=Ks("update",t,n,c,_,"Online",r||"System",oe.Timestamp.now(),oe.FieldValue.serverTimestamp()),I=ge(h);for(const R of b)!X(R)&&ve(h[R.name])&&R.nullable&&(h[R.name]=null);Ze(h),Ze(O),_t(f,h,c),_t(f,O,c),p&&!s?.providedTransaction&&await bt("update","started",h,a,t,e,f,void 0,O);const T={operation:"update",data:h,recordId:e,context:o,originalRecord:ge(O)};await le("preOperation",l,E,T);const $={operation:"update",data:h,recordId:e,context:o,originalRecord:ge(O)};await le("preWrite",l,E,$),_t(f,h,c),Pn(f,h),Ze(h);try{if(w&&!i?.password)throw new Error("Password is required");if(!s?.providedTransaction){const R={...H,...h};et(R),await fn("update",R,f,E,{operation:"update",data:h,context:o,originalRecord:ge(O)},c)}}catch(R){throw new Error(`VALIDATION_ERROR: ${R.message}`)}Ze(h),delete n.id,_t(f,h,c),Pn(f,h);for(const R of b)!X(R)&&ve(h[R.name])&&R.nullable&&(h[R.name]=null);try{const R={...H,...h};et(R),Er("update",f,h,O),Yo("update",h,I),await fn("update",R,f,E,{operation:"update",data:h,context:o,originalRecord:ge(O)},c)}catch(R){throw new Error(`VALIDATION_ERROR: ${R.message}`)}let j;i&&(i.permissions||={});const D=async(R,Q,ee)=>{const[pe,Re,fe,ye,je,Qe]=await Promise.all([s?.providedTransaction?Promise.resolve({}):R.get(k.collection("system_deployment").doc("latest_deploy")),s?.providedTransaction?Promise.resolve({}):R.get(k.collection("system_deployment").doc("maintenance_mode")),s?.providedTransaction?Promise.resolve(O):Be(t,e,{userId:r,providedTransaction:R,noComputedFields:!0}),r?R.get(k.collection("tenants").doc(a).collection("system_user_permissions").doc(r)):Promise.resolve({}),s?.providedSchema?Promise.resolve(s.providedSchema):Ye(),r?_n(r):Promise.resolve(void 0)]);if(ee&&(ee.size+=3),!s?.providedTransaction){if(!pe.exists)throw new Error("VERSION_ERROR");const _e=pe.data();if(_e.force&&h.Last_Write_At.valueOf()<_e.time.valueOf())throw new Error("VERSION_ERROR");if(!Re.exists)throw new Error("MAINTENANCE_MODE");if(Re.data().active)throw new Error("MAINTENANCE_MODE")}if(!fe)throw new Error("NOT_FOUND");if(O=fe,c=je,r){if(!ye?.exists)throw new Error("PERMISSION_DENIED");if(v=ye.data(),!v.Role)throw new Error("USER_ERROR");if(!v.Enabled)throw new Error("PERMISSION_DENIED");A=Qe?.customClaims??{}}if(ee&&(ee.size+=dr(a,t,e,c,v,A).length),w&&O.User_ID||S&&!O.User_ID)throw new Error("USER_ERROR");if(Z(O)){const _e=await R.get(k.collection("tenants").doc(a).collection("system_user_permissions").doc(O.User_ID));if(ee&&ee.size++,!_e?.exists)throw new Error("PERMISSION_DENIED");j=_e.data();const mt=i?.permissions&&Object.keys(i.permissions).length>0?i.permissions:void 0;if(h.Role&&h.Role!==O.Role&&!mt&&(i||={operation:"update",permissions:{}},i.permissions=ge(j),i.permissions.Role=h.Role),i?.permissions){if(i.permissions.Role||=h.Role||O.Role,i.permissions.Enabled??=h.Enabled??O.Enabled,ve(i.permissions.Role)||!i.permissions.Role)throw new Error("VALIDATION_ERROR: Role field is required");if(ve(i.permissions.Enabled)||i.permissions.Enabled===void 0||i.permissions.Enabled===null)throw new Error("VALIDATION_ERROR: Enabled field is required")}}if(w){const _e={...O,...h};if(et(_e),!_e.Role)throw new Error("VALIDATION_ERROR: Role field is required");if(_e.Enabled===void 0||_e.Enabled===null)throw new Error("VALIDATION_ERROR: Enabled field is required");if(!_e.Email)throw new Error("VALIDATION_ERROR: Email field is required")}if(!s?.providedTransaction){const mt=b.filter(ke=>"unique"in ke&&ke.unique).map(async ke=>{if(!r||!ke.access||He(ke,v,f,A)){if(h[ke.name]===void 0||ve(h[ke.name]))return;const Yt=Ue(ke,E),En={...O,...h};if(!(r&&Yt?.custom?.serverAccess?.read!==void 0?await ae(Yt.custom.serverAccess.read,[v?.Role,En]):!0))throw new Error("PERMISSION_DENIED");const as=h[ke.name].toString().toLowerCase().replace(/\s/g,"---").replaceAll("/","|||");if(Vo(as)){if(ee&&ee.size++,ee&&ee.size>500)throw new Error("VALIDATION_ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks.");const vr=await R.get(k.collection("tenants").doc(a).collection("system_unique").doc(g.collection).collection(`Unique-${g.collection}-${ke.name}`).doc(as));if(vr.exists&&vr.data().id!==e)throw new Error(`VALIDATION_ERROR: ${ke.name} "${h[ke.name]}" already exists`)}else throw new Error(`VALIDATION_ERROR: ${ke.name} "${h[ke.name]}" is invalid`)}});await Promise.all(mt)}if(r&&v?.Role){const _e=v.Role,mt={...O,...h};if(!(E.custom?.serverAccess?.update!==void 0?await ae(E.custom.serverAccess.update,[_e,mt,O]):!0))throw new Error("PERMISSION_DENIED");for(const Yt of f.fields){const En=Ue(Yt,E);if(Object.prototype.hasOwnProperty.call(h,Yt.name)&&En?.custom?.serverAccess?.update!==void 0&&!await ae(En.custom.serverAccess.update,[_e,mt,O]))throw new Error("PERMISSION_DENIED")}}br(h,O,e,f,c,r,v,i?.operation?i.operation:q?"update":void 0,i?.permissions,j,A),i?.permissions&&r&&v&&await Jo(R,i.permissions,r,v,c,j,ee),br(h,O,e,f,c,r,v,i?.operation?i.operation:q?"update":void 0,i?.permissions,j,A),Q&&(w||Z(O)||S)&&await wu(R,e,O.User_ID)};(w||q||S)&&await k.runTransaction(async R=>{await D(R,!0)},{maxAttempts:10});const L=async(R,Q)=>{if(!O)throw new Error("NOT_FOUND");try{const ee={size:1},pe={...O,...h};await D(R,!1,ee);let Re;!s?.noTwoWay&&!s?.providedTransaction&&(Re=await _r("Update",a,e,pe,h,f,c,R,ee,r,v,O,A));const fe=Qs(c);lr("update",R,t,e,h,c,f,s,fe,oe.FieldValue.arrayUnion,oe.FieldValue.arrayRemove,oe.FieldValue.delete,ye=>k.collection("tenants").doc(a).collection("system_fields").doc(g.collection).collection(`${g.collection}-${ye.name}`).doc(e),(ye,je)=>k.collection("tenants").doc(a).collection("system_unique").doc(g.collection).collection(`Unique-${g.collection}-${ye.name}`).doc(je),ye=>k.collection("tenants").doc(a).collection("system_fields").doc(g.collection).collection(`${g.collection}-${ye}`).doc(e),(ye,je)=>De(k,ye,a).doc(je),(ye,je,Qe)=>k.collection("tenants").doc(a).collection("system_fields").doc(ye.collection).collection(`${ye.collection}-${je}`).doc(Qe),(ye,je,Qe)=>k.collection("tenants").doc(a).collection("system_fields").doc(ye.collection).collection(`${ye.collection}-${je.replaceAll(" ","-")}`).doc(Qe),O,Re,ee),R.update(V.doc(e),h)}catch(ee){if(s?.providedTransaction)throw ee;{const pe={operation:"update",data:h,recordId:e,context:o,error:ee,originalRecord:ge(O)},Re=await le("postWriteError",l,E,pe);if(p&&(await new Promise(fe=>{setTimeout(fe,250)}),await bt("update",Re?.resolved?"success":"failed",h,a,t,e,f,Re?.resolved?void 0:ee,O)),!Re?.resolved)throw w&&await Gt(O),Z(O)&&await sn(O.User_ID,Q,j,"USER_ERROR"),S&&await k.collection("tenants").doc(a).collection(g.collection).doc(e).update({User_ID:oe.FieldValue.delete()}),ee}}(w||Z(O)||S)&&await pi(_i,[e,O.User_ID]).catch(()=>{throw new Error("USER_ERROR")})};try{let R;if(w||Z(O)||S){if(Z(O)){R=await x.getUser(O.User_ID);const pe=R.customClaims;if(!(pe&&pe.role&&pe.collection&&pe.doc))throw new Error("USER_ERROR")}const Q={...O,...h};et(Q);const ee=await Qo(i?.operation||"update",a,e,l,f,Q,O,R,i?.permissions,j,i?.password);w&&(h.User_ID=ee),S&&(h.User_ID=oe.FieldValue.delete())}s?.providedTransaction?await L(s.providedTransaction,R):await k.runTransaction(async Q=>{await L(Q,R)},{maxAttempts:10})}catch(R){throw(w||Z(O)||S)&&await pi(_i,[e,O.User_ID]).catch(()=>{throw new Error("USER_ERROR")}),R}if(!s?.providedTransaction){const R={operation:"update",data:h,recordId:e,context:o,originalRecord:ge(O)},Q={...R};await le("postWrite",l,E,R),await le("postOperation",l,E,Q)}const B={...O,...h};return et(B),{id:e,...B}},_u=async(t,e,n)=>{const s=n?.userId;let r=n?.context;const i=Je(),o=xt();let a=await Ye();if(t.length===0)throw new Error("EMPTY_PATH");const l=t.at(-1),c=Object.keys(a.collections).includes(l),d=o.disabledCollections?.includes(l);if(!c||d)throw new Error("COLLECTION_NOT_FOUND");const m=a.collections[l],{labels:u,auth:f,enableWriteLog:g,softDelete:b}=m,p=rt(u.collection,a),E=await ae(o.appName);if(b&&!f&&!n?.force)return await Ko(t,e,{[b.archivedField]:!0,[b.timestampField]:oe.FieldValue.serverTimestamp()},{userId:s});const _=de();let x;s&&await gr(t,m);const k=De(_,t,i);r=r||{},r.collection=u.collection;const v=await Be(t,e,{userId:s});let A=Ks("delete",t,v,a,E,"Online",s||"System",oe.Timestamp.now(),oe.FieldValue.serverTimestamp());const V=Mn(A);Ze(A),g&&await bt("delete","started",A,i,t,e,m),await le("preOperation",o,p,{operation:"delete",data:A,recordId:e,context:r}),await le("preWrite",o,p,{operation:"delete",data:A,recordId:e,context:r}),Ze(A);const y=async Z=>{const[h,I,T,$]=await Promise.all([Z.get(_.collection("system_deployment").doc("maintenance_mode")),Be(t,e,{userId:s,providedTransaction:Z}),s?Z.get(_.collection("tenants").doc(i).collection("system_user_permissions").doc(s)):Promise.resolve({}),Ye()]);if(!h.exists)throw new Error("MAINTENANCE_MODE");if(h.data().active)throw new Error("MAINTENANCE_MODE");if(!I)throw new Error("NOT_FOUND");if(A={...I,...V},a=$,s){if(!T?.exists)throw new Error("PERMISSION_DENIED");if(x=T.data(),!x.Role)throw new Error("USER_ERROR");if(!x.Enabled)throw new Error("PERMISSION_DENIED");fa(A,e,m,a,s,x)}if(s&&x?.Role){const D=x.Role;if(!(p.custom?.serverAccess?.delete!==void 0?await ae(p.custom.serverAccess.delete,[D,A]):!0))throw new Error("PERMISSION_DENIED")}};m.auth&&(await _.runTransaction(async Z=>{await y(Z)},{maxAttempts:10}),A.User_ID&&await Gt(A));try{await _.runTransaction(async Z=>{await y(Z);const h=Qs(a);lr("delete",Z,t,e,A,a,m,n,h,oe.FieldValue.arrayUnion,oe.FieldValue.arrayRemove,oe.FieldValue.delete,I=>_.collection("tenants").doc(i).collection("system_fields").doc(u.collection).collection(`${u.collection}-${I.name}`).doc(e),(I,T)=>_.collection("tenants").doc(i).collection("system_unique").doc(u.collection).collection(`Unique-${u.collection}-${I.name}`).doc(T),I=>_.collection("tenants").doc(i).collection("system_fields").doc(u.collection).collection(`${u.collection}-${I}`).doc(e),(I,T)=>De(_,I,i).doc(T),(I,T,$)=>_.collection("tenants").doc(i).collection("system_fields").doc(I.collection).collection(`${I.collection}-${T}`).doc($),(I,T,$)=>_.collection("tenants").doc(i).collection("system_fields").doc(I.collection).collection(`${I.collection}-${T.replaceAll(" ","-")}`).doc($)),Z.delete(k.doc(e))},{maxAttempts:10})}catch(Z){const I=await le("postWriteError",o,p,{operation:"delete",data:A,recordId:e,context:r,error:Z});if(g&&(await new Promise(T=>{setTimeout(T,250)}),await bt("delete",I?.resolved?"success":"failed",A,i,t,e,m,I?.resolved?void 0:Z)),!I?.resolved)throw m.auth&&A.User_ID&&await _.collection("tenants").doc(i).collection(u.collection).doc(e).update({User_ID:oe.FieldValue.delete()}),Z}const w={operation:"delete",data:A,recordId:e,context:r},S={...w};return await le("postWrite",o,p,w),await le("postOperation",o,p,S),{id:e,...A}},Eu=async(t,e)=>{const n=de(),s=cr(),r=process.env.ADMIN_SMS;if(s==="development")if(r)t=r;else throw new Error("Admin phone not set");const i={to:t,body:e};await n.collection("system_messages").add(i)},vu=t=>t!==null&&typeof t=="object",Ou=t=>{const e=n=>{Object.entries(n).forEach(([s,r])=>{r instanceof oe.Timestamp?n[s]={_seconds:r.seconds,_nanoseconds:r.nanoseconds}:vu(r)&&e(r)})};e(t)},ku=t=>{const e=ur();return U.fromJSDate(t).setZone(e)},Xo=t=>{const e=ur();return U.fromJSDate(t.toDate()).setZone(e)},bu=(t,e)=>{const s=U.fromJSDate(t,{zone:e}).offset,i=U.fromJSDate(t).offset,o=s-i;return U.fromJSDate(t).plus({minutes:o}).toJSDate()},Tu=(t,e)=>{const s=U.fromJSDate(t,{zone:e}).offset,i=U.fromJSDate(t).offset,o=s-i;return U.fromJSDate(t).minus({minutes:o}).toJSDate()},Ru=t=>"seconds"in t&&"nanoseconds"in t?Xo(new oe.Timestamp(t.seconds,t.nanoseconds)).toFormat("MMMM d, yyyy '@' h:mm a"):"";exports.addRecord=gu;exports.addUser=yr;exports.convertDateToTimezone=ku;exports.convertTimestampToTimezone=Xo;exports.deleteRecord=_u;exports.deleteUser=Gt;exports.deserializeDeleteSentinels=os;exports.deserializeTimestamps=wr;exports.deserializeTimestampsWithoutUnderscores=fu;exports.displayDate=Ru;exports.fetchCurrentSchema=Ye;exports.fetchLastSchema=cu;exports.getCachedConfigValue=wa;exports.getCollectionRefs=zo;exports.getCustomizationFile=rt;exports.getCustomizationFiles=Uo;exports.getDocumentRefs=dr;exports.getFirestorePathRef=De;exports.getGlobalConfigModule=xt;exports.getInputSchema=eu;exports.getMaintenanceInfo=ou;exports.getMode=cr;exports.getOne=Be;exports.getSome=hr;exports.getStokerFirestore=de;exports.getTenant=Je;exports.getTimezone=ur;exports.getUser=_n;exports.getVersionInfo=iu;exports.getZodSchema=$i;exports.initializeFirebase=lu;exports.initializeStoker=su;exports.isDeleteSentinel=ve;exports.keepTimezone=bu;exports.removeTimezone=Tu;exports.runChildProcess=au;exports.sendMail=mr;exports.sendMessage=Eu;exports.serializeTimestamps=Ou;exports.setTenant=ru;exports.tryPromise=ae;exports.updateRecord=Ko;exports.updateUser=Qo;exports.validateRelations=_r;exports.validateSoftDelete=Er;exports.writeLog=bt;
|
|
14
|
+
<a href="${x}">${x}</a>`)}catch{throw await sn(o.User_ID,a,c,g),new Error(g)}}}}}else if(t==="delete")try{await Gt(o)}catch(p){throw new Error(p.message)}if(b)return b},wu=async(t,e,n)=>{const s=Je(),r=de(),i=[e];n&&n.trim()!==""&&i.push(n),i.sort();const o=[];for(const a of i){const l=r.collection("tenants").doc(s).collection("system_locks").doc(a);if((await t.get(l)).exists)throw new Error("DOCUMENT_LOCKED");o.push(l)}for(const a of o)t.set(a,{locked:!0})},_i=async(t,e)=>{const n=Je(),s=de(),r=[t];e&&e.trim()!==""&&r.push(e),r.sort();const i=s.batch();for(const o of r){const a=s.collection("tenants").doc(n).collection("system_locks").doc(o);i.delete(a)}await i.commit()},Ko=async(t,e,n,s)=>{const r=s?.userId;let i=s?.user,o=s?.context;const a=Je(),l=xt();if(s?.providedTransaction&&r)throw new Error("PERMISSION_DENIED");if(s?.providedSchema&&r)throw new Error("PERMISSION_DENIED");if(s?.providedTransaction&&!s?.originalRecord)throw new Error("PERMISSION_DENIED");let c=s?.providedSchema||await Ye(!0);if(t.length===0)throw new Error("EMPTY_PATH");const d=t.at(-1),m=Object.keys(c.collections).includes(d),u=l.disabledCollections?.includes(d);if(!m||u)throw new Error("COLLECTION_NOT_FOUND");const f=c.collections[d],{labels:g,fields:b,enableWriteLog:p}=f,E=rt(g.collection,c),_=await ae(l.appName),x=Tt.getAuth(),k=de();let v,A;r&&await gr(t,f);const V=De(k,t,a);o=o||{},o.collection=g.collection;let O=s?.originalRecord||await Be(t,e,{userId:r,noComputedFields:!0,noEmbeddingFields:!0}),H=O;r&&(H=await Be(t,e,{noComputedFields:!0,noEmbeddingFields:!0}));for(const R of b)R.type==="Computed"&&(delete n[R.name],delete O[R.name]);if(c={...c,collections:Object.fromEntries(Object.entries(c.collections).map(([R,Q])=>[R,{...Q,fields:Q.fields.filter(ee=>ee.type!=="Computed")}]))},i&&!i.operation)throw new Error("VALIDATION_ERROR: User operation is required");if(i&&!f.auth)throw new Error("VALIDATION_ERROR: User operations are only permitted for auth collections");if(i?.operation==="delete"&&i.permissions)throw new Error("VALIDATION_ERROR: Permissions are not allowed for delete operations");const y=f.fields.filter(R=>R.saveToAuthToken&&!pr(R.name)),w=f.auth&&i?.operation==="create",S=f.auth&&i?.operation==="delete",q=f.auth&&!w&&!S&&(i?.operation==="update"||O.User_ID&&(n.Role||n.Enabled!==void 0||n.Name||n.Email||n.Photo_URL||y.some(R=>n[R.name]!==void 0))),Z=R=>R.User_ID&&(f.auth&&!w&&!S&&i?.operation==="update"||n.Role&&n.Role!==R.Role||n.Enabled!==void 0&&n.Enabled!==R.Enabled||n.Name&&n.Name!==R.Name||n.Email&&n.Email!==R.Email||n.Photo_URL&&n.Photo_URL!==R.Photo_URL||y.some(Q=>n[Q.name]!==void 0&&n[Q.name]!==R[Q.name]));delete n.id,wr(n),os(n);const h=Ks("update",t,n,c,_,"Online",r||"System",oe.Timestamp.now(),oe.FieldValue.serverTimestamp()),I=ge(h);for(const R of b)!X(R)&&ve(h[R.name])&&R.nullable&&(h[R.name]=null);Ze(h),Ze(O),_t(f,h,c),_t(f,O,c),p&&!s?.providedTransaction&&await bt("update","started",h,a,t,e,f,void 0,O);const T={operation:"update",data:h,recordId:e,context:o,originalRecord:ge(O)};await le("preOperation",l,E,T);const $={operation:"update",data:h,recordId:e,context:o,originalRecord:ge(O)};await le("preWrite",l,E,$),_t(f,h,c),Pn(f,h),Ze(h);try{if(w&&!i?.password)throw new Error("Password is required");if(!s?.providedTransaction){const R={...H,...h};et(R),await fn("update",R,f,E,{operation:"update",data:h,context:o,originalRecord:ge(O)},c)}}catch(R){throw new Error(`VALIDATION_ERROR: ${R.message}`)}Ze(h),delete n.id,_t(f,h,c),Pn(f,h);for(const R of b)!X(R)&&ve(h[R.name])&&R.nullable&&(h[R.name]=null);try{const R={...H,...h};et(R),Er("update",f,h,O),Yo("update",h,I),await fn("update",R,f,E,{operation:"update",data:h,context:o,originalRecord:ge(O)},c)}catch(R){throw new Error(`VALIDATION_ERROR: ${R.message}`)}let j;i&&(i.permissions||={});const D=async(R,Q,ee)=>{const[pe,Re,fe,ye,je,Qe]=await Promise.all([s?.providedTransaction?Promise.resolve({}):R.get(k.collection("system_deployment").doc("latest_deploy")),s?.providedTransaction?Promise.resolve({}):R.get(k.collection("system_deployment").doc("maintenance_mode")),s?.providedTransaction?Promise.resolve(O):Be(t,e,{userId:r,providedTransaction:R,noComputedFields:!0}),r?R.get(k.collection("tenants").doc(a).collection("system_user_permissions").doc(r)):Promise.resolve({}),s?.providedSchema?Promise.resolve(s.providedSchema):Ye(),r?_n(r):Promise.resolve(void 0)]);if(ee&&(ee.size+=3),!s?.providedTransaction){if(!pe.exists)throw new Error("VERSION_ERROR");const _e=pe.data();if(_e.force&&h.Last_Write_At.valueOf()<_e.time.valueOf())throw new Error("VERSION_ERROR");if(!Re.exists)throw new Error("MAINTENANCE_MODE");if(Re.data().active)throw new Error("MAINTENANCE_MODE")}if(!fe)throw new Error("NOT_FOUND");if(O=fe,c=je,r){if(!ye?.exists)throw new Error("PERMISSION_DENIED");if(v=ye.data(),!v.Role)throw new Error("USER_ERROR");if(!v.Enabled)throw new Error("PERMISSION_DENIED");A=Qe?.customClaims??{}}if(ee&&(ee.size+=dr(a,t,e,c,v,A).length),w&&O.User_ID||S&&!O.User_ID)throw new Error("USER_ERROR");if(Z(O)){const _e=await R.get(k.collection("tenants").doc(a).collection("system_user_permissions").doc(O.User_ID));if(ee&&ee.size++,!_e?.exists)throw new Error("PERMISSION_DENIED");j=_e.data();const mt=i?.permissions&&Object.keys(i.permissions).length>0?i.permissions:void 0;if(h.Role&&h.Role!==O.Role&&!mt&&(i||={operation:"update",permissions:{}},i.permissions=ge(j),i.permissions.Role=h.Role),i?.permissions){if(i.permissions.Role||=h.Role||O.Role,i.permissions.Enabled??=h.Enabled??O.Enabled,ve(i.permissions.Role)||!i.permissions.Role)throw new Error("VALIDATION_ERROR: Role field is required");if(ve(i.permissions.Enabled)||i.permissions.Enabled===void 0||i.permissions.Enabled===null)throw new Error("VALIDATION_ERROR: Enabled field is required")}}if(w){const _e={...O,...h};if(et(_e),!_e.Role)throw new Error("VALIDATION_ERROR: Role field is required");if(_e.Enabled===void 0||_e.Enabled===null)throw new Error("VALIDATION_ERROR: Enabled field is required");if(!_e.Email)throw new Error("VALIDATION_ERROR: Email field is required")}if(!s?.providedTransaction){const mt=b.filter(ke=>"unique"in ke&&ke.unique).map(async ke=>{if(!r||!ke.access||He(ke,v,f,A)){if(h[ke.name]===void 0||ve(h[ke.name]))return;const Yt=Ue(ke,E),En={...O,...h};if(!(r&&Yt?.custom?.serverAccess?.read!==void 0?await ae(Yt.custom.serverAccess.read,[v?.Role,En]):!0))throw new Error("PERMISSION_DENIED");const as=h[ke.name].toString().toLowerCase().replace(/\s/g,"---").replaceAll("/","|||");if(Vo(as)){if(ee&&ee.size++,ee&&ee.size>500)throw new Error("VALIDATION_ERROR: The number of operations in the Firestore transaction has exceeded the limit of 500. This is likely due to a large number of unique field checks.");const vr=await R.get(k.collection("tenants").doc(a).collection("system_unique").doc(g.collection).collection(`Unique-${g.collection}-${ke.name}`).doc(as));if(vr.exists&&vr.data().id!==e)throw new Error(`VALIDATION_ERROR: ${ke.name} "${h[ke.name]}" already exists`)}else throw new Error(`VALIDATION_ERROR: ${ke.name} "${h[ke.name]}" is invalid`)}});await Promise.all(mt)}if(r&&v?.Role){const _e=v.Role,mt={...O,...h};if(!(E.custom?.serverAccess?.update!==void 0?await ae(E.custom.serverAccess.update,[_e,mt,O]):!0))throw new Error("PERMISSION_DENIED");for(const Yt of f.fields){const En=Ue(Yt,E);if(Object.prototype.hasOwnProperty.call(h,Yt.name)&&En?.custom?.serverAccess?.update!==void 0&&!await ae(En.custom.serverAccess.update,[_e,mt,O]))throw new Error("PERMISSION_DENIED")}}br(h,O,e,f,c,r,v,i?.operation?i.operation:q?"update":void 0,i?.permissions,j,A),i?.permissions&&r&&v&&await Jo(R,i.permissions,r,v,c,j,ee),br(h,O,e,f,c,r,v,i?.operation?i.operation:q?"update":void 0,i?.permissions,j,A),Q&&(w||Z(O)||S)&&await wu(R,e,O.User_ID)};(w||q||S)&&await k.runTransaction(async R=>{await D(R,!0)},{maxAttempts:10});const L=async(R,Q)=>{if(!O)throw new Error("NOT_FOUND");try{const ee={size:1},pe={...O,...h};await D(R,!1,ee);let Re;!s?.noTwoWay&&!s?.providedTransaction&&(Re=await _r("Update",a,e,pe,h,f,c,R,ee,r,v,O,A));const fe=Qs(c);lr("update",R,t,e,h,c,f,s,fe,oe.FieldValue.arrayUnion,oe.FieldValue.arrayRemove,oe.FieldValue.delete,ye=>k.collection("tenants").doc(a).collection("system_fields").doc(g.collection).collection(`${g.collection}-${ye.name}`).doc(e),(ye,je)=>k.collection("tenants").doc(a).collection("system_unique").doc(g.collection).collection(`Unique-${g.collection}-${ye.name}`).doc(je),ye=>k.collection("tenants").doc(a).collection("system_fields").doc(g.collection).collection(`${g.collection}-${ye}`).doc(e),(ye,je)=>De(k,ye,a).doc(je),(ye,je,Qe)=>k.collection("tenants").doc(a).collection("system_fields").doc(ye.collection).collection(`${ye.collection}-${je}`).doc(Qe),(ye,je,Qe)=>k.collection("tenants").doc(a).collection("system_fields").doc(ye.collection).collection(`${ye.collection}-${je.replaceAll(" ","-")}`).doc(Qe),O,Re,ee),R.update(V.doc(e),h)}catch(ee){if(s?.providedTransaction)throw ee;{const pe={operation:"update",data:h,recordId:e,context:o,error:ee,originalRecord:ge(O)},Re=await le("postWriteError",l,E,pe);if(p&&(await new Promise(fe=>{setTimeout(fe,250)}),await bt("update",Re?.resolved?"success":"failed",h,a,t,e,f,Re?.resolved?void 0:ee,O)),!Re?.resolved)throw w&&await Gt(O),Z(O)&&await sn(O.User_ID,Q,j,"USER_ERROR"),S&&await k.collection("tenants").doc(a).collection(g.collection).doc(e).update({User_ID:oe.FieldValue.delete()}),ee}}(w||Z(O)||S)&&await pi(_i,[e,O.User_ID]).catch(()=>{throw new Error("USER_ERROR")})};try{let R;if(w||Z(O)||S){if(Z(O)){R=await x.getUser(O.User_ID);const pe=R.customClaims;if(!(pe&&pe.role&&pe.collection&&pe.doc))throw new Error("USER_ERROR")}const Q={...O,...h};et(Q);const ee=await Qo(i?.operation||"update",a,e,l,f,Q,O,R,i?.permissions,j,i?.password);w&&(h.User_ID=ee),S&&(h.User_ID=oe.FieldValue.delete())}s?.providedTransaction?await L(s.providedTransaction,R):await k.runTransaction(async Q=>{await L(Q,R)},{maxAttempts:10})}catch(R){throw(w||Z(O)||S)&&await pi(_i,[e,O.User_ID]).catch(()=>{throw new Error("USER_ERROR")}),R}if(!s?.providedTransaction){const R={operation:"update",data:h,recordId:e,context:o,originalRecord:ge(O)},Q={...R};await le("postWrite",l,E,R),await le("postOperation",l,E,Q)}const B={...O,...h};return et(B),{id:e,...B}},_u=async(t,e,n)=>{const s=n?.userId;let r=n?.context;const i=Je(),o=xt();let a=await Ye();if(t.length===0)throw new Error("EMPTY_PATH");const l=t.at(-1),c=Object.keys(a.collections).includes(l),d=o.disabledCollections?.includes(l);if(!c||d)throw new Error("COLLECTION_NOT_FOUND");const m=a.collections[l],{labels:u,auth:f,enableWriteLog:g,softDelete:b}=m,p=rt(u.collection,a),E=await ae(o.appName);if(b&&!f&&!n?.force)return await Ko(t,e,{[b.archivedField]:!0,[b.timestampField]:oe.FieldValue.serverTimestamp()},{userId:s});const _=de();let x;s&&await gr(t,m);const k=De(_,t,i);r=r||{},r.collection=u.collection;const v=await Be(t,e,{userId:s});let A=Ks("delete",t,v,a,E,"Online",s||"System",oe.Timestamp.now(),oe.FieldValue.serverTimestamp());const V=Mn(A);Ze(A),g&&await bt("delete","started",A,i,t,e,m),await le("preOperation",o,p,{operation:"delete",data:A,recordId:e,context:r}),await le("preWrite",o,p,{operation:"delete",data:A,recordId:e,context:r}),Ze(A);const y=async Z=>{const[h,I,T,$]=await Promise.all([Z.get(_.collection("system_deployment").doc("maintenance_mode")),Be(t,e,{userId:s,providedTransaction:Z}),s?Z.get(_.collection("tenants").doc(i).collection("system_user_permissions").doc(s)):Promise.resolve({}),Ye()]);if(!h.exists)throw new Error("MAINTENANCE_MODE");if(h.data().active)throw new Error("MAINTENANCE_MODE");if(!I)throw new Error("NOT_FOUND");if(A={...I,...V},a=$,s){if(!T?.exists)throw new Error("PERMISSION_DENIED");if(x=T.data(),!x.Role)throw new Error("USER_ERROR");if(!x.Enabled)throw new Error("PERMISSION_DENIED");fa(A,e,m,a,s,x)}if(s&&x?.Role){const D=x.Role;if(!(p.custom?.serverAccess?.delete!==void 0?await ae(p.custom.serverAccess.delete,[D,A]):!0))throw new Error("PERMISSION_DENIED")}};m.auth&&(await _.runTransaction(async Z=>{await y(Z)},{maxAttempts:10}),A.User_ID&&await Gt(A));try{await _.runTransaction(async Z=>{await y(Z);const h=Qs(a);lr("delete",Z,t,e,A,a,m,n,h,oe.FieldValue.arrayUnion,oe.FieldValue.arrayRemove,oe.FieldValue.delete,I=>_.collection("tenants").doc(i).collection("system_fields").doc(u.collection).collection(`${u.collection}-${I.name}`).doc(e),(I,T)=>_.collection("tenants").doc(i).collection("system_unique").doc(u.collection).collection(`Unique-${u.collection}-${I.name}`).doc(T),I=>_.collection("tenants").doc(i).collection("system_fields").doc(u.collection).collection(`${u.collection}-${I}`).doc(e),(I,T)=>De(_,I,i).doc(T),(I,T,$)=>_.collection("tenants").doc(i).collection("system_fields").doc(I.collection).collection(`${I.collection}-${T}`).doc($),(I,T,$)=>_.collection("tenants").doc(i).collection("system_fields").doc(I.collection).collection(`${I.collection}-${T.replaceAll(" ","-")}`).doc($)),Z.delete(k.doc(e))},{maxAttempts:10})}catch(Z){const I=await le("postWriteError",o,p,{operation:"delete",data:A,recordId:e,context:r,error:Z});if(g&&(await new Promise(T=>{setTimeout(T,250)}),await bt("delete",I?.resolved?"success":"failed",A,i,t,e,m,I?.resolved?void 0:Z)),!I?.resolved)throw m.auth&&A.User_ID&&await _.collection("tenants").doc(i).collection(u.collection).doc(e).update({User_ID:oe.FieldValue.delete()}),Z}const w={operation:"delete",data:A,recordId:e,context:r},S={...w};return await le("postWrite",o,p,w),await le("postOperation",o,p,S),{id:e,...A}},Eu=async(t,e)=>{const n=de(),s=cr(),r=process.env.ADMIN_SMS;if(s==="development")if(r)t=r;else throw new Error("Admin phone not set");const i={to:t,body:e};await n.collection("system_messages").add(i)},vu=t=>t!==null&&typeof t=="object",Ou=t=>{const e=n=>{Object.entries(n).forEach(([s,r])=>{r instanceof oe.Timestamp?n[s]={_seconds:r.seconds,_nanoseconds:r.nanoseconds}:vu(r)&&e(r)})};e(t)},ku=t=>{const e=ur();return U.fromJSDate(t).setZone(e)},Xo=t=>{const e=ur();return U.fromJSDate(t.toDate()).setZone(e)},bu=(t,e)=>{const s=U.fromJSDate(t,{zone:e}).offset,i=U.fromJSDate(t).offset,o=s-i;return U.fromJSDate(t).plus({minutes:o}).toJSDate()},Tu=(t,e)=>{const s=U.fromJSDate(t,{zone:e}).offset,i=U.fromJSDate(t).offset,o=s-i;return U.fromJSDate(t).minus({minutes:o}).toJSDate()},Ru=t=>"seconds"in t&&"nanoseconds"in t?Xo(new oe.Timestamp(t.seconds,t.nanoseconds)).toFormat("MMMM d, yyyy '@' h:mm a"):"";exports.addRecord=gu;exports.addUser=yr;exports.convertDateToTimezone=ku;exports.convertTimestampToTimezone=Xo;exports.deleteRecord=_u;exports.deleteUser=Gt;exports.deserializeDeleteSentinels=os;exports.deserializeTimestamps=wr;exports.deserializeTimestampsWithoutUnderscores=fu;exports.displayDate=Ru;exports.fetchCurrentSchema=Ye;exports.fetchLastSchema=cu;exports.getCachedConfigValue=wa;exports.getCollectionRefs=zo;exports.getCustomizationFile=rt;exports.getCustomizationFiles=Uo;exports.getDocumentRefs=dr;exports.getFirestorePathRef=De;exports.getGlobalConfigModule=xt;exports.getInputSchema=eu;exports.getMaintenanceInfo=ou;exports.getMode=cr;exports.getOne=Be;exports.getSome=hr;exports.getStokerFirestore=de;exports.getTenant=Je;exports.getTimezone=ur;exports.getUser=_n;exports.getVersionInfo=iu;exports.getZodSchema=$i;exports.initializeFirebase=lu;exports.initializeStoker=su;exports.isDeleteSentinel=ve;exports.keepTimezone=bu;exports.removeTimezone=Tu;exports.runChildProcess=au;exports.sendMail=mr;exports.sendMessage=Eu;exports.serializeTimestamps=Ou;exports.setTenant=ru;exports.tryPromise=ae;exports.updateRecord=Ko;exports.updateUser=Qo;exports.validateRelations=_r;exports.validateSoftDelete=Er;exports.writeLog=bt;
|
package/dist/bundle.js
CHANGED
|
@@ -11148,8 +11148,8 @@ const qo = async (t, e, n, s, r, i, o) => {
|
|
|
11148
11148
|
throw new Error("VALIDATION_ERROR: User operations are only permitted for auth collections");
|
|
11149
11149
|
if (i?.operation === "delete" && i.permissions)
|
|
11150
11150
|
throw new Error("VALIDATION_ERROR: Permissions are not allowed for delete operations");
|
|
11151
|
-
const y = f.fields.filter((T) => T.saveToAuthToken && !ur(T.name)), w = f.auth && i?.operation === "create", S = f.auth && i?.operation === "delete", q = f.auth && !w && !S && (i?.operation === "update" || n.Role || n.Enabled !== void 0 || n.Name || n.Email || n.Photo_URL || // eslint-disable-next-line security/detect-object-injection
|
|
11152
|
-
y.some((T) => n[T.name] !== void 0)), Z = (T) => T.User_ID && (f.auth && !w && !S && i?.operation === "update" || n.Role && n.Role !== T.Role || n.Enabled !== void 0 && n.Enabled !== T.Enabled || n.Name && n.Name !== T.Name || n.Email && n.Email !== T.Email || n.Photo_URL && n.Photo_URL !== T.Photo_URL || y.some(
|
|
11151
|
+
const y = f.fields.filter((T) => T.saveToAuthToken && !ur(T.name)), w = f.auth && i?.operation === "create", S = f.auth && i?.operation === "delete", q = f.auth && !w && !S && (i?.operation === "update" || O.User_ID && (n.Role || n.Enabled !== void 0 || n.Name || n.Email || n.Photo_URL || // eslint-disable-next-line security/detect-object-injection
|
|
11152
|
+
y.some((T) => n[T.name] !== void 0))), Z = (T) => T.User_ID && (f.auth && !w && !S && i?.operation === "update" || n.Role && n.Role !== T.Role || n.Enabled !== void 0 && n.Enabled !== T.Enabled || n.Name && n.Name !== T.Name || n.Email && n.Email !== T.Email || n.Photo_URL && n.Photo_URL !== T.Photo_URL || y.some(
|
|
11153
11153
|
// eslint-disable-next-line security/detect-object-injection
|
|
11154
11154
|
(Q) => n[Q.name] !== void 0 && n[Q.name] !== T[Q.name]
|
|
11155
11155
|
));
|