@eiaifactory/monitor 0.1.2 → 0.1.3
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/README.md +24 -2
- package/dist/browser.js +1 -1
- package/dist/deno.d.ts +16 -2
- package/dist/deno.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ Instalado, captura solo los errores no manejados (`error`) y las promesas rechaz
|
|
|
81
81
|
## Edge functions (Supabase)
|
|
82
82
|
|
|
83
83
|
```ts
|
|
84
|
-
import { initMonitor, withHandler } from 'npm:@eiaifactory/monitor@0.1.
|
|
84
|
+
import { initMonitor, marcarFalla, withHandler } from 'npm:@eiaifactory/monitor@0.1.3/deno';
|
|
85
85
|
|
|
86
86
|
const monitor = initMonitor({
|
|
87
87
|
clave: Deno.env.get('MONITOR_CLAVE'),
|
|
@@ -109,6 +109,28 @@ respuestas 5xx (como `cobrar: respondió 503`, **sin el cuerpo**: puede traer da
|
|
|
109
109
|
la función contestando que no, y no se reportan. Lo que se capture a mano con
|
|
110
110
|
`monitor.capturar(error)` durante el request también sale al final.
|
|
111
111
|
|
|
112
|
+
**Qué paso falló (0.1.3).** Una 5xx que la función arma a mano puede decir en qué paso falló y con
|
|
113
|
+
qué código, sin que el body ni un header lo lleven. El body trae el mensaje crudo de Postgres, y un
|
|
114
|
+
header llegaría al navegador. Va fuera de banda:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
if (rpc.error) {
|
|
118
|
+
return marcarFalla(
|
|
119
|
+
new Response(JSON.stringify({ error: 'db_error' }), { status: 500, headers: corsHeaders }),
|
|
120
|
+
{ paso: 'stock_loss_apply', codigo: rpc.error.code },
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`marcarFalla` devuelve la misma respuesta sin tocarla. `withHandler` reporta
|
|
126
|
+
`cobrar: respondió 500 en stock_loss_apply (57014)` con `codigo: '57014'`.
|
|
127
|
+
- El paso es un identificador fijo del código: la RPC, la tabla o el servicio de afuera
|
|
128
|
+
(`[A-Za-z_][\w.]*`, lo que finance lee del mensaje).
|
|
129
|
+
- El código es un SQLSTATE o un `PGRSTnnn`.
|
|
130
|
+
- Lo que no tenga esa forma se descarta y queda el mensaje de siempre, así nunca viaja un valor.
|
|
131
|
+
- Sin código, `codigo` es el status. Un `PT4xx` queda sólo en el mensaje: el usuario vio un 5xx, y
|
|
132
|
+
como `codigo` lo descartaría como rechazo de negocio.
|
|
133
|
+
|
|
112
134
|
| Opción de `withHandler` | |
|
|
113
135
|
|---|---|
|
|
114
136
|
| `esEsperado(error)` | Además de los esperados de siempre. |
|
|
@@ -131,7 +153,7 @@ Decisión del spec: los rechazos de negocio y los `toast.error` no son incidente
|
|
|
131
153
|
|
|
132
154
|
| | Navegador | Servidor |
|
|
133
155
|
|---|---|---|
|
|
134
|
-
| Colapso | El mismo error en 10 s viaja una vez, con `repeticiones` | — |
|
|
156
|
+
| Colapso | El mismo error, en el mismo lugar (`ubicacion`) y con el mismo `codigo`, en 10 s viaja una vez, con `repeticiones` | — |
|
|
135
157
|
| Tope | 20 eventos nuevos por minuto (`maxPorMinuto`) | — |
|
|
136
158
|
| Ráfaga | Hasta 100 errores esperando a ser procesados; lo que llega con eso lleno se pierde | — |
|
|
137
159
|
| Cola | 50 (`maxBuffer`) en `localStorage`, hasta 128 KB; descarta lo más viejo | 50 en memoria |
|
package/dist/browser.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
function ue(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0}function N(e){let t=(e.stack??"").split(`
|
|
2
|
-
`).find(n=>/^\s*at\s|@/.test(n))??"";return ue([e.origen,e.tipo_error??"",e.mensaje,t.trim()].join("|"))}function I(){return{items:[],minuto:0,enMinuto:0}}function L(e,t,n,r,i){let o=N(t),l=e.items.find(v=>!v.v&&v.h===o&&n-v.t<1e4);if(l)return l.e.repeticiones=(l.e.repeticiones??1)+1,"colapsado";let P=Math.floor(n/6e4);return P!==e.minuto&&(e.minuto=P,e.enMinuto=0),e.enMinuto>=i?"tope_por_minuto":(e.enMinuto++,e.items.push({e:t,h:o,t:n}),e.items.length>r&&e.items.splice(0,e.items.length-r),"encolado")}var le=128*1024;function V(e){let t=e.map(({e:i,h:o,t:l})=>JSON.stringify({e:i,h:o,t:l})),n=2,r=t.length;for(;r>0&&(n+t[r-1].length+1)*2<=le;)n+=t[--r].length+1;return`[${t.slice(r).join(",")}]`}function U(e){try{let t=e?JSON.parse(e):[];return Array.isArray(t)?t.filter(n=>!!n&&typeof n=="object"&&!!n.e&&typeof n.e.id_externo=="string"&&typeof n.e.mensaje=="string"&&typeof n.h=="number"&&typeof n.t=="number"):[]}catch{return[]}}var z="https://qoyskdjcjyjxcnhruhni.supabase.co/functions/v1/monitor-ingesta";var s={mensaje:1024,tipo_error:128,codigo:64,stack:8192,ubicacion:256,ruta:512,release:64,usuario_id:64,rol:64,dispositivo_id:64,user_agent:512,huella_manual:128},D="\u2026[cortado]";function g(e,t){return e.length<=t?e:e.slice(0,t-D.length)+D}var k=[1e3,2e3,4e3,3e4],X=e=>new TextEncoder().encode(e).length;function B(e,t=20){let n=[],r=X('{"eventos":[]}');for(let i of e){if(n.length>=t)break;let o=X(JSON.stringify(i.e))+(n.length?1:0);if(n.length&&r+o>61440)break;r+=o,n.push(i)}return n}function de(e){return 6e4-e%6e4}function fe(e,t,n){if(e>=200&&e<300)return{r:"ok"};if(e===429){let r=Number(t);return{r:"cuota",esperaMs:t&&r>0?r*1e3:de(n)}}return e===401?{r:"apagar"}:e===413?{r:"partir"}:e>=500?{r:"reintentar"}:{r:"descartar"}}async function $(e){let t;try{let n=typeof AbortController=="function"?new AbortController:void 0,r=new Promise(o=>{t=setTimeout(()=>{e.debug?.("timeout"),n?.abort(),o({r:"reintentar"})},e.timeoutMs)}),i=(async()=>{try{let o=await fetch(e.url,{method:"POST",headers:{authorization:`Bearer ${e.clave}`,"content-type":"application/json"},body:JSON.stringify({eventos:e.eventos}),keepalive:!!e.keepalive,signal:n?.signal}),l=await o.text();return e.debug?.(o.status,l),fe(o.status,o.headers.get("retry-after"),Date.now())}catch(o){return e.debug?.("sin respuesta",o),{r:"reintentar"}}})();return await Promise.race([i,r])}catch{return{r:"reintentar"}}finally{clearTimeout(t)}}function pe(e){return e.status??e.statusCode??e.context?.status}function J(e){try{if(!e||typeof e!="object")return!1;let t=e;if(t.name==="AbortError"||typeof t.code=="string"&&t.code.startsWith("PT4"))return!0;let n=Number(pe(t));return n===401||n===403?!0:typeof t.name=="string"&&t.name.startsWith("Auth")&&n>=400&&n<500}catch{return!1}}function q(e,t){return t.some(n=>typeof n=="string"?e.includes(n):e.search(n)>=0)}function m(){let e=typeof crypto>"u"?void 0:crypto;if(e&&typeof e.randomUUID=="function")try{return e.randomUUID()}catch{}let t=new Uint8Array(16);if(e&&typeof e.getRandomValues=="function")e.getRandomValues(t);else for(let r=0;r<16;r++)t[r]=Math.random()*256|0;t[6]=t[6]&15|64,t[8]=t[8]&63|128;let n=Array.from(t,r=>r.toString(16).padStart(2,"0")).join("");return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`}var x="[redactado]",ge=/mail|tel|phone|dni|cuit|pass|token|secret|key|clave/i,me=/[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,xe=/(^|[^\w.-])\+?\d(?:[\s-]?\d){7,14}(?![\w.-])/g;function R(e){return e.replace(me,x).replace(xe,`$1${x}`)}function K(e){return e===void 0?e:R(e)}function Y(e){let t;if(e.contexto){t={};for(let n of Object.keys(e.contexto)){let r=e.contexto[n];t[n]=ge.test(n)?x:typeof r=="string"?R(r):r}}return{...e,mensaje:R(e.mensaje),stack:K(e.stack),ruta:K(e.ruta),usuario_id:e.usuario_id&&e.usuario_id.includes("@")?x:e.usuario_id,contexto:t}}function u(e,t){if((typeof e=="number"||typeof e=="boolean")&&(e=String(e)),typeof e!="string")return;let n=e.trim();return n?g(n,t):void 0}function be(e){let t=Object.prototype.toString.call(e);if(t==="[object Object]"||t==="[object Array]")try{let n=JSON.stringify(e);if(n&&n!=="{}")return n}catch{}return t}function Ee(e){try{if(e===null||typeof e!="object"&&typeof e!="function")return{mensaje:u(String(e),s.mensaje)??"Error sin mensaje"};let t=e,n=t.context,r=typeof t.code=="string"&&("details"in t||"hint"in t);return{mensaje:u(t.message,s.mensaje)??g(be(t),s.mensaje),tipo_error:u(t.name,s.tipo_error)??(r?"PostgrestError":void 0),codigo:u(t.code??t.status??t.statusCode??n?.status,s.codigo),stack:u(t.stack,s.stack)}}catch{return{mensaje:"Error no legible"}}}function _e(e){if(!e||typeof e!="object")return;let t={};for(let r of Object.keys(e)){let i=e[r];i===null||typeof i=="boolean"?t[r]=i:typeof i=="number"?t[r]=Number.isFinite(i)?i:null:typeof i=="string"&&(t[r]=g(i,256))}let n=Object.keys(t);if(n.length){for(;n.length&&new TextEncoder().encode(JSON.stringify(t)).length>2048;)delete t[n.pop()],t._cortado=!0;return t}}function he(e){return u(e?.split(/[?#]/)[0],s.ruta)}function F(e){return Y({id_externo:m(),origen:e.origen,...Ee(e.error),ocurrido_at:new Date(e.ocurrido).toISOString(),ubicacion:u(e.ubicacion,s.ubicacion),ruta:he(e.ruta),release:u(e.release,s.release),usuario_id:u(e.usuario_id,s.usuario_id),rol:u(e.rol,s.rol),dispositivo_id:u(e.dispositivo_id,s.dispositivo_id),user_agent:u(e.user_agent,s.user_agent),contexto:_e(e.contexto),repeticiones:1})}var ee="eiai_monitor_cola",Z="eiai_monitor_dispositivo",te=2e3,ne=10,ve=3e3,Oe=100,a,b=[],c,f,T={},M,y=!1,w=!1,d,G=0,W,E=!1,H=0,C=0,S=20;function p(...e){try{a?.debug&&console.debug("[monitor]",...e)}catch{}}function Q(e){try{return localStorage.getItem(e)}catch{return null}}function re(e,t){try{localStorage.setItem(e,t)}catch{}}function Fe(e){try{if(a)return;if(typeof window>"u"||!e?.clave){e?.debug&&console.debug("[monitor] no-op: sin clave");return}a={clave:e.clave,url:e.url??z,release:e.release,ignorar:e.ignorar??[],maxBuffer:e.maxBuffer??50,maxPorMinuto:e.maxPorMinuto??20,debug:!!e.debug},addEventListener("error",ke),addEventListener("unhandledrejection",Re),addEventListener("pagehide",ie),document.addEventListener("visibilitychange",Se),ae(),p("iniciado",a.url)}catch{}}function h(e,t){try{if(!a||E||y||b.length>=Oe)return;b.push({error:e,extra:t,t:Date.now(),ruta:location.pathname,contexto:T,usuario:M}),ae()}catch{}}function Ze(e){try{T={...T,...e}}catch{}}function Ge(e){M=e}function We(){M=void 0}async function He(){try{if(!a)return;for(_();;){let e=await j();if(!e||e.r!=="ok"&&e.r!=="descartar"&&e.r!=="partir")return}}catch{}}function Qe(e,t){try{h(e,{ubicacion:oe(t?.queryKey)})}catch{}}function et(e,t,n,r){try{h(e,{ubicacion:oe(r?.options?.mutationKey)})}catch{}}function oe(e){return Array.isArray(e)&&typeof e[0]=="string"?e[0]:void 0}function ke(e){try{h(e.error??{message:e.message,stack:e.filename?`at ${e.filename}:${e.lineno}:${e.colno}`:void 0})}catch{}}function Re(e){try{h(e.reason)}catch{}}function ie(){try{_(),clearTimeout(d),d=void 0,j(!0)}catch{}}function Se(){document.visibilityState==="hidden"&&ie()}function ae(){w||(w=!0,typeof requestIdleCallback=="function"?requestIdleCallback(_,{timeout:1e3}):setTimeout(_,0))}function Te(){return c||(c=I(),c.items=U(Q(ee)),f=Q(Z)??void 0,f||(f=m(),re(Z,f)),c.items.length&&p("recuperados",c.items.length),c)}function se(){c&&re(ee,V(c.items))}function _(){if(w=!1,!(!a||y)){y=!0;try{let e=Te(),t=b;b=[];let n=0;for(let r of t)try{if(J(r.error))continue;let i=F({error:r.error,origen:"browser",ocurrido:r.t,ruta:r.extra?.ruta??r.ruta,ubicacion:r.extra?.ubicacion,release:a.release,usuario_id:r.usuario?.id,rol:r.usuario?.rol,dispositivo_id:f,user_agent:navigator.userAgent,contexto:{...r.contexto,...r.extra?.contexto}});if(q(i.mensaje,a.ignorar))continue;let o=L(e,i,r.t,a.maxBuffer,a.maxPorMinuto);p(o,i.mensaje),o!=="tope_por_minuto"&&n++}catch{}n&&se(),e.items.length&&A(e.items.length>=ne?0:te)}catch{}finally{y=!1}}}function A(e){if(E)return;let t=Math.max(Date.now()+e,C);if(d!==void 0){if(t>=G)return;clearTimeout(d)}G=t,d=setTimeout(()=>{d=void 0,j()},t-Date.now())}function j(e=!1){return W??(W=we(e).catch(()=>{}).finally(()=>{W=void 0}))}async function we(e){try{if(!a||!c||E)return;let t=c;if(Date.now()<C){A(0);return}let n=B(t.items,S);if(!n.length)return;for(let o of n)o.v=!0;let r=await $({url:a.url,clave:a.clave,eventos:n.map(o=>o.e),timeoutMs:ve,keepalive:e,debug:a.debug?p:void 0});for(let o of n)o.v=!1;let i=()=>{t.items=t.items.filter(o=>!n.includes(o))};return r.r==="ok"||r.r==="descartar"||r.r==="partir"&&n.length===1?(i(),r.r==="ok"&&(H=0),S=20):r.r==="partir"?S=n.length>>1:r.r==="apagar"?(E=!0,clearTimeout(d),p("clave rechazada: apagado")):C=Date.now()+(r.r==="cuota"?r.esperaMs:k[Math.min(H++,k.length-1)]),se(),t.items.length&&A(t.items.length>=ne||r.r!=="ok"&&r.r!=="descartar"?0:te),r}catch{return}}export{h as capturar,J as esEsperado,He as flush,Fe as initMonitor,We as limpiarUsuario,et as onErrorMutation,Qe as onErrorQuery,Ze as setContext,Ge as setUsuario};
|
|
2
|
+
`).find(n=>/^\s*at\s|@/.test(n))??"";return ue([e.origen,e.tipo_error??"",e.mensaje,t.trim(),e.ubicacion??"",e.codigo??""].join("|"))}function I(){return{items:[],minuto:0,enMinuto:0}}function L(e,t,n,r,i){let o=N(t),l=e.items.find(v=>!v.v&&v.h===o&&n-v.t<1e4);if(l)return l.e.repeticiones=(l.e.repeticiones??1)+1,"colapsado";let P=Math.floor(n/6e4);return P!==e.minuto&&(e.minuto=P,e.enMinuto=0),e.enMinuto>=i?"tope_por_minuto":(e.enMinuto++,e.items.push({e:t,h:o,t:n}),e.items.length>r&&e.items.splice(0,e.items.length-r),"encolado")}var le=128*1024;function V(e){let t=e.map(({e:i,h:o,t:l})=>JSON.stringify({e:i,h:o,t:l})),n=2,r=t.length;for(;r>0&&(n+t[r-1].length+1)*2<=le;)n+=t[--r].length+1;return`[${t.slice(r).join(",")}]`}function U(e){try{let t=e?JSON.parse(e):[];return Array.isArray(t)?t.filter(n=>!!n&&typeof n=="object"&&!!n.e&&typeof n.e.id_externo=="string"&&typeof n.e.mensaje=="string"&&typeof n.h=="number"&&typeof n.t=="number"):[]}catch{return[]}}var z="https://qoyskdjcjyjxcnhruhni.supabase.co/functions/v1/monitor-ingesta";var s={mensaje:1024,tipo_error:128,codigo:64,stack:8192,ubicacion:256,ruta:512,release:64,usuario_id:64,rol:64,dispositivo_id:64,user_agent:512,huella_manual:128},D="\u2026[cortado]";function g(e,t){return e.length<=t?e:e.slice(0,t-D.length)+D}var k=[1e3,2e3,4e3,3e4],X=e=>new TextEncoder().encode(e).length;function B(e,t=20){let n=[],r=X('{"eventos":[]}');for(let i of e){if(n.length>=t)break;let o=X(JSON.stringify(i.e))+(n.length?1:0);if(n.length&&r+o>61440)break;r+=o,n.push(i)}return n}function de(e){return 6e4-e%6e4}function fe(e,t,n){if(e>=200&&e<300)return{r:"ok"};if(e===429){let r=Number(t);return{r:"cuota",esperaMs:t&&r>0?r*1e3:de(n)}}return e===401?{r:"apagar"}:e===413?{r:"partir"}:e>=500?{r:"reintentar"}:{r:"descartar"}}async function $(e){let t;try{let n=typeof AbortController=="function"?new AbortController:void 0,r=new Promise(o=>{t=setTimeout(()=>{e.debug?.("timeout"),n?.abort(),o({r:"reintentar"})},e.timeoutMs)}),i=(async()=>{try{let o=await fetch(e.url,{method:"POST",headers:{authorization:`Bearer ${e.clave}`,"content-type":"application/json"},body:JSON.stringify({eventos:e.eventos}),keepalive:!!e.keepalive,signal:n?.signal}),l=await o.text();return e.debug?.(o.status,l),fe(o.status,o.headers.get("retry-after"),Date.now())}catch(o){return e.debug?.("sin respuesta",o),{r:"reintentar"}}})();return await Promise.race([i,r])}catch{return{r:"reintentar"}}finally{clearTimeout(t)}}function pe(e){return e.status??e.statusCode??e.context?.status}function J(e){try{if(!e||typeof e!="object")return!1;let t=e;if(t.name==="AbortError"||typeof t.code=="string"&&t.code.startsWith("PT4"))return!0;let n=Number(pe(t));return n===401||n===403?!0:typeof t.name=="string"&&t.name.startsWith("Auth")&&n>=400&&n<500}catch{return!1}}function q(e,t){return t.some(n=>typeof n=="string"?e.includes(n):e.search(n)>=0)}function m(){let e=typeof crypto>"u"?void 0:crypto;if(e&&typeof e.randomUUID=="function")try{return e.randomUUID()}catch{}let t=new Uint8Array(16);if(e&&typeof e.getRandomValues=="function")e.getRandomValues(t);else for(let r=0;r<16;r++)t[r]=Math.random()*256|0;t[6]=t[6]&15|64,t[8]=t[8]&63|128;let n=Array.from(t,r=>r.toString(16).padStart(2,"0")).join("");return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`}var x="[redactado]",ge=/mail|tel|phone|dni|cuit|pass|token|secret|key|clave/i,me=/[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,xe=/(^|[^\w.-])\+?\d(?:[\s-]?\d){7,14}(?![\w.-])/g;function R(e){return e.replace(me,x).replace(xe,`$1${x}`)}function K(e){return e===void 0?e:R(e)}function Y(e){let t;if(e.contexto){t={};for(let n of Object.keys(e.contexto)){let r=e.contexto[n];t[n]=ge.test(n)?x:typeof r=="string"?R(r):r}}return{...e,mensaje:R(e.mensaje),stack:K(e.stack),ruta:K(e.ruta),usuario_id:e.usuario_id&&e.usuario_id.includes("@")?x:e.usuario_id,contexto:t}}function u(e,t){if((typeof e=="number"||typeof e=="boolean")&&(e=String(e)),typeof e!="string")return;let n=e.trim();return n?g(n,t):void 0}function be(e){let t=Object.prototype.toString.call(e);if(t==="[object Object]"||t==="[object Array]")try{let n=JSON.stringify(e);if(n&&n!=="{}")return n}catch{}return t}function Ee(e){try{if(e===null||typeof e!="object"&&typeof e!="function")return{mensaje:u(String(e),s.mensaje)??"Error sin mensaje"};let t=e,n=t.context,r=typeof t.code=="string"&&("details"in t||"hint"in t);return{mensaje:u(t.message,s.mensaje)??g(be(t),s.mensaje),tipo_error:u(t.name,s.tipo_error)??(r?"PostgrestError":void 0),codigo:u(t.code??t.status??t.statusCode??n?.status,s.codigo),stack:u(t.stack,s.stack)}}catch{return{mensaje:"Error no legible"}}}function _e(e){if(!e||typeof e!="object")return;let t={};for(let r of Object.keys(e)){let i=e[r];i===null||typeof i=="boolean"?t[r]=i:typeof i=="number"?t[r]=Number.isFinite(i)?i:null:typeof i=="string"&&(t[r]=g(i,256))}let n=Object.keys(t);if(n.length){for(;n.length&&new TextEncoder().encode(JSON.stringify(t)).length>2048;)delete t[n.pop()],t._cortado=!0;return t}}function he(e){return u(e?.split(/[?#]/)[0],s.ruta)}function F(e){return Y({id_externo:m(),origen:e.origen,...Ee(e.error),ocurrido_at:new Date(e.ocurrido).toISOString(),ubicacion:u(e.ubicacion,s.ubicacion),ruta:he(e.ruta),release:u(e.release,s.release),usuario_id:u(e.usuario_id,s.usuario_id),rol:u(e.rol,s.rol),dispositivo_id:u(e.dispositivo_id,s.dispositivo_id),user_agent:u(e.user_agent,s.user_agent),contexto:_e(e.contexto),repeticiones:1})}var ee="eiai_monitor_cola",Z="eiai_monitor_dispositivo",te=2e3,ne=10,ve=3e3,Oe=100,a,b=[],c,f,T={},M,y=!1,w=!1,d,G=0,W,E=!1,H=0,C=0,S=20;function p(...e){try{a?.debug&&console.debug("[monitor]",...e)}catch{}}function Q(e){try{return localStorage.getItem(e)}catch{return null}}function re(e,t){try{localStorage.setItem(e,t)}catch{}}function Fe(e){try{if(a)return;if(typeof window>"u"||!e?.clave){e?.debug&&console.debug("[monitor] no-op: sin clave");return}a={clave:e.clave,url:e.url??z,release:e.release,ignorar:e.ignorar??[],maxBuffer:e.maxBuffer??50,maxPorMinuto:e.maxPorMinuto??20,debug:!!e.debug},addEventListener("error",ke),addEventListener("unhandledrejection",Re),addEventListener("pagehide",ie),document.addEventListener("visibilitychange",Se),ae(),p("iniciado",a.url)}catch{}}function h(e,t){try{if(!a||E||y||b.length>=Oe)return;b.push({error:e,extra:t,t:Date.now(),ruta:location.pathname,contexto:T,usuario:M}),ae()}catch{}}function Ze(e){try{T={...T,...e}}catch{}}function Ge(e){M=e}function We(){M=void 0}async function He(){try{if(!a)return;for(_();;){let e=await j();if(!e||e.r!=="ok"&&e.r!=="descartar"&&e.r!=="partir")return}}catch{}}function Qe(e,t){try{h(e,{ubicacion:oe(t?.queryKey)})}catch{}}function et(e,t,n,r){try{h(e,{ubicacion:oe(r?.options?.mutationKey)})}catch{}}function oe(e){return Array.isArray(e)&&typeof e[0]=="string"?e[0]:void 0}function ke(e){try{h(e.error??{message:e.message,stack:e.filename?`at ${e.filename}:${e.lineno}:${e.colno}`:void 0})}catch{}}function Re(e){try{h(e.reason)}catch{}}function ie(){try{_(),clearTimeout(d),d=void 0,j(!0)}catch{}}function Se(){document.visibilityState==="hidden"&&ie()}function ae(){w||(w=!0,typeof requestIdleCallback=="function"?requestIdleCallback(_,{timeout:1e3}):setTimeout(_,0))}function Te(){return c||(c=I(),c.items=U(Q(ee)),f=Q(Z)??void 0,f||(f=m(),re(Z,f)),c.items.length&&p("recuperados",c.items.length),c)}function se(){c&&re(ee,V(c.items))}function _(){if(w=!1,!(!a||y)){y=!0;try{let e=Te(),t=b;b=[];let n=0;for(let r of t)try{if(J(r.error))continue;let i=F({error:r.error,origen:"browser",ocurrido:r.t,ruta:r.extra?.ruta??r.ruta,ubicacion:r.extra?.ubicacion,release:a.release,usuario_id:r.usuario?.id,rol:r.usuario?.rol,dispositivo_id:f,user_agent:navigator.userAgent,contexto:{...r.contexto,...r.extra?.contexto}});if(q(i.mensaje,a.ignorar))continue;let o=L(e,i,r.t,a.maxBuffer,a.maxPorMinuto);p(o,i.mensaje),o!=="tope_por_minuto"&&n++}catch{}n&&se(),e.items.length&&A(e.items.length>=ne?0:te)}catch{}finally{y=!1}}}function A(e){if(E)return;let t=Math.max(Date.now()+e,C);if(d!==void 0){if(t>=G)return;clearTimeout(d)}G=t,d=setTimeout(()=>{d=void 0,j()},t-Date.now())}function j(e=!1){return W??(W=we(e).catch(()=>{}).finally(()=>{W=void 0}))}async function we(e){try{if(!a||!c||E)return;let t=c;if(Date.now()<C){A(0);return}let n=B(t.items,S);if(!n.length)return;for(let o of n)o.v=!0;let r=await $({url:a.url,clave:a.clave,eventos:n.map(o=>o.e),timeoutMs:ve,keepalive:e,debug:a.debug?p:void 0});for(let o of n)o.v=!1;let i=()=>{t.items=t.items.filter(o=>!n.includes(o))};return r.r==="ok"||r.r==="descartar"||r.r==="partir"&&n.length===1?(i(),r.r==="ok"&&(H=0),S=20):r.r==="partir"?S=n.length>>1:r.r==="apagar"?(E=!0,clearTimeout(d),p("clave rechazada: apagado")):C=Date.now()+(r.r==="cuota"?r.esperaMs:k[Math.min(H++,k.length-1)]),se(),t.items.length&&A(t.items.length>=ne||r.r!=="ok"&&r.r!=="descartar"?0:te),r}catch{return}}export{h as capturar,J as esEsperado,He as flush,Fe as initMonitor,We as limpiarUsuario,et as onErrorMutation,Qe as onErrorQuery,Ze as setContext,Ge as setUsuario};
|
package/dist/deno.d.ts
CHANGED
|
@@ -30,12 +30,26 @@ interface OpcionesHandler {
|
|
|
30
30
|
/** La respuesta cuando la función lanza (con los headers de CORS de la función). Default: 500 JSON. */
|
|
31
31
|
aRespuesta?: (error: unknown) => Response;
|
|
32
32
|
}
|
|
33
|
+
/** Qué paso de la función falló y con qué código: lo lee `withHandler` al reportar una 5xx. */
|
|
34
|
+
interface Falla {
|
|
35
|
+
/** Un identificador fijo del código: la RPC, la tabla o el servicio de afuera. Nunca un valor. */
|
|
36
|
+
paso: string;
|
|
37
|
+
/** El SQLSTATE (`57014`) o el código de PostgREST (`PGRST202`). */
|
|
38
|
+
codigo?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Anota en qué paso falló una respuesta 5xx, sin tocarla: devuelve la misma instancia, con el mismo
|
|
42
|
+
* body y los mismos headers. Lo que no tiene forma de identificador o de código se descarta al
|
|
43
|
+
* reportar. Nunca lanza.
|
|
44
|
+
*/
|
|
45
|
+
declare function marcarFalla(respuesta: Response, falla: Falla): Response;
|
|
33
46
|
/**
|
|
34
47
|
* Envuelve el handler de `Deno.serve`. Si responde, devuelve esa respuesta tal cual y reporta
|
|
35
|
-
* las 5xx (sin el cuerpo: puede traer datos)
|
|
48
|
+
* las 5xx (sin el cuerpo: puede traer datos), con el paso de `marcarFalla` si lo tiene. Si lanza,
|
|
49
|
+
* lo reporta y devuelve `aRespuesta(error)`
|
|
36
50
|
* o un 500 JSON. Al final manda todo lo capturado en el request, también lo que la función
|
|
37
51
|
* capturó a mano antes de contestar un 200.
|
|
38
52
|
*/
|
|
39
53
|
declare function withHandler<A extends unknown[]>(monitor: Monitor, handler: (req: Request, ...args: A) => Response | Promise<Response>, opciones?: OpcionesHandler): (req: Request, ...args: A) => Promise<Response>;
|
|
40
54
|
|
|
41
|
-
export { type Extra, type Monitor, type OpcionesHandler, type OpcionesServidor, ValorContexto, initMonitor, withHandler };
|
|
55
|
+
export { type Extra, type Falla, type Monitor, type OpcionesHandler, type OpcionesServidor, ValorContexto, initMonitor, marcarFalla, withHandler };
|
package/dist/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var x="https://qoyskdjcjyjxcnhruhni.supabase.co/functions/v1/monitor-ingesta";var s={mensaje:1024,tipo_error:128,codigo:64,stack:8192,ubicacion:256,ruta:512,release:64,usuario_id:64,rol:64,dispositivo_id:64,user_agent:512,huella_manual:128},m="\u2026[cortado]";function p(t,e){return t.length<=e?t:t.slice(0,e-m.length)+m}var E=t=>new TextEncoder().encode(t).length;function _(t,e=20){let n=[],r=E('{"eventos":[]}');for(let o of t){if(n.length>=e)break;let i=E(JSON.stringify(o.e))+(n.length?1:0);if(n.length&&r+i>61440)break;r+=i,n.push(o)}return n}function S(t){return 6e4-t%6e4}function A(t,e,n){if(t>=200&&t<300)return{r:"ok"};if(t===429){let r=Number(e);return{r:"cuota",esperaMs:e&&r>0?r*1e3:S(n)}}return t===401?{r:"apagar"}:t===413?{r:"partir"}:t>=500?{r:"reintentar"}:{r:"descartar"}}async function b(t){let e;try{let n=typeof AbortController=="function"?new AbortController:void 0,r=new Promise(i=>{e=setTimeout(()=>{t.debug?.("timeout"),n?.abort(),i({r:"reintentar"})},t.timeoutMs)}),o=(async()=>{try{let i=await fetch(t.url,{method:"POST",headers:{authorization:`Bearer ${t.clave}`,"content-type":"application/json"},body:JSON.stringify({eventos:t.eventos}),keepalive:!!t.keepalive,signal:n?.signal}),a=await i.text();return t.debug?.(i.status,a),A(i.status,i.headers.get("retry-after"),Date.now())}catch(i){return t.debug?.("sin respuesta",i),{r:"reintentar"}}})();return await Promise.race([o,r])}catch{return{r:"reintentar"}}finally{clearTimeout(e)}}function j(t){return t.status??t.statusCode??t.context?.status}function h(t){try{if(!t||typeof t!="object")return!1;let e=t;if(e.name==="AbortError"||typeof e.code=="string"&&e.code.startsWith("PT4"))return!0;let n=Number(j(e));return n===401||n===403?!0:typeof e.name=="string"&&e.name.startsWith("Auth")&&n>=400&&n<500}catch{return!1}}function R(){let t=typeof crypto>"u"?void 0:crypto;if(t&&typeof t.randomUUID=="function")try{return t.randomUUID()}catch{}let e=new Uint8Array(16);if(t&&typeof t.getRandomValues=="function")t.getRandomValues(e);else for(let r=0;r<16;r++)e[r]=Math.random()*256|0;e[6]=e[6]&15|64,e[8]=e[8]&63|128;let n=Array.from(e,r=>r.toString(16).padStart(2,"0")).join("");return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`}var l="[redactado]",P=/mail|tel|phone|dni|cuit|pass|token|secret|key|clave/i,M=/[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,N=/(^|[^\w.-])\+?\d(?:[\s-]?\d){7,14}(?![\w.-])/g;function g(t){return t.replace(M,l).replace(N,`$1${l}`)}function O(t){return t===void 0?t:g(t)}function w(t){let e;if(t.contexto){e={};for(let n of Object.keys(t.contexto)){let r=t.contexto[n];e[n]=P.test(n)?l:typeof r=="string"?g(r):r}}return{...t,mensaje:g(t.mensaje),stack:O(t.stack),ruta:O(t.ruta),usuario_id:t.usuario_id&&t.usuario_id.includes("@")?l:t.usuario_id,contexto:e}}function u(t,e){if((typeof t=="number"||typeof t=="boolean")&&(t=String(t)),typeof t!="string")return;let n=t.trim();return n?p(n,e):void 0}function V(t){let e=Object.prototype.toString.call(t);if(e==="[object Object]"||e==="[object Array]")try{let n=JSON.stringify(t);if(n&&n!=="{}")return n}catch{}return e}function $(t){try{if(t===null||typeof t!="object"&&typeof t!="function")return{mensaje:u(String(t),s.mensaje)??"Error sin mensaje"};let e=t,n=e.context,r=typeof e.code=="string"&&("details"in e||"hint"in e);return{mensaje:u(e.message,s.mensaje)??p(V(e),s.mensaje),tipo_error:u(e.name,s.tipo_error)??(r?"PostgrestError":void 0),codigo:u(e.code??e.status??e.statusCode??n?.status,s.codigo),stack:u(e.stack,s.stack)}}catch{return{mensaje:"Error no legible"}}}function I(t){if(!t||typeof t!="object")return;let e={};for(let r of Object.keys(t)){let o=t[r];o===null||typeof o=="boolean"?e[r]=o:typeof o=="number"?e[r]=Number.isFinite(o)?o:null:typeof o=="string"&&(e[r]=p(o,256))}let n=Object.keys(e);if(n.length){for(;n.length&&new TextEncoder().encode(JSON.stringify(e)).length>2048;)delete e[n.pop()],e._cortado=!0;return e}}function L(t){return u(t?.split(/[?#]/)[0],s.ruta)}function v(t){return w({id_externo:R(),origen:t.origen,...$(t.error),ocurrido_at:new Date(t.ocurrido).toISOString(),ubicacion:u(t.ubicacion,s.ubicacion),ruta:L(t.ruta),release:u(t.release,s.release),usuario_id:u(t.usuario_id,s.usuario_id),rol:u(t.rol,s.rol),dispositivo_id:u(t.dispositivo_id,s.dispositivo_id),user_agent:u(t.user_agent,s.user_agent),contexto:I(t.contexto),repeticiones:1})}var X=2e3,U=50;function D(t){return new Promise(e=>setTimeout(e,t))}function at(t){let e=[],n=!t.clave,r,o=a=>b({url:t.url??x,clave:t.clave??"",eventos:a,timeoutMs:X});async function i(){let a=20;for(;e.length&&!n;){let c=_(e.map(f=>({e:f})),a).map(f=>f.e),d=await o(c);if((d.r==="reintentar"||d.r==="cuota")&&(await D(d.r==="cuota"?Math.min(d.esperaMs,1e4):1e3),d=await o(c)),d.r==="apagar"){n=!0,e.length=0;return}if(d.r==="partir"&&c.length>1){a=c.length>>1;continue}e.splice(0,c.length)}}return{funcion:t.funcion,capturar(a,c){try{if(n||h(a))return;e.length>=U&&e.shift(),e.push(v({error:a,origen:t.origen??"edge",ocurrido:Date.now(),ruta:c?.ruta,ubicacion:c?.ubicacion??t.funcion,release:t.release,contexto:c?.contexto}))}catch{}},flush(){return r??(r=i().catch(()=>{}).finally(()=>{r=void 0}))}}}var T=new WeakMap,z=/^[A-Za-z_][\w.]{0,63}$/,F=/^(?:[0-9A-Z]{5}|PGRST\d{3})$/;function ut(t,e){try{T.set(t,e)}catch{}return t}function B(t,e){let n=T.get(e),r=typeof n?.paso=="string"&&z.test(n.paso)?n.paso:void 0,o=typeof n?.codigo=="string"&&F.test(n.codigo)?n.codigo:void 0;return{name:"HttpError",message:`${t}: respondi\xF3 ${e.status}${r?` en ${r}`:""}${o?` (${o})`:""}`,status:e.status,code:o&&!o.startsWith("PT4")?o:void 0}}function G(t){let e=t.flush();try{globalThis.EdgeRuntime?.waitUntil(e)}catch{}}function k(t){try{return new URL(t.url).pathname}catch{return}}function q(t,e){try{if(e.aRespuesta)return e.aRespuesta(t)}catch{}return new Response(JSON.stringify({error:"error_interno"}),{status:500,headers:{"content-type":"application/json"}})}function ct(t,e,n={}){return async(r,...o)=>{try{let i=await e(r,...o);if(i.status>=500)try{t.capturar(B(t.funcion,i),{ruta:k(r)})}catch{}return i}catch(i){let a=!1;try{a=!!n.esEsperado?.(i)}catch{}return a||t.capturar(i,{ruta:k(r)}),q(i,n)}finally{G(t)}}}export{h as esEsperado,at as initMonitor,ut as marcarFalla,ct as withHandler};
|
package/package.json
CHANGED