@aiolaapp/logger 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +132 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.js +2 -0
- package/dist/index.mjs +2 -0
- package/dist/node.d.mts +132 -0
- package/dist/node.d.ts +132 -0
- package/dist/node.js +2 -0
- package/dist/node.mjs +2 -0
- package/package.json +38 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
interface AiolaOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
environment?: string;
|
|
4
|
+
release?: string;
|
|
5
|
+
/** Ingest endpoint — defaults to Aiola cloud */
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
/** Max breadcrumbs to keep in memory (default: 30) */
|
|
8
|
+
maxBreadcrumbs?: number;
|
|
9
|
+
/** Flush interval in ms (default: 5000) */
|
|
10
|
+
flushInterval?: number;
|
|
11
|
+
/** User context */
|
|
12
|
+
user?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
username?: string;
|
|
16
|
+
ip_address?: string;
|
|
17
|
+
};
|
|
18
|
+
/** Extra tags attached to every event */
|
|
19
|
+
tags?: Record<string, string>;
|
|
20
|
+
/** Promote console.error calls to real error events (default: true) */
|
|
21
|
+
captureConsoleErrors?: boolean;
|
|
22
|
+
/** Filter errors before sending — return null to drop */
|
|
23
|
+
beforeSend?: (event: LogEvent) => LogEvent | null;
|
|
24
|
+
}
|
|
25
|
+
interface StackFrame {
|
|
26
|
+
filename: string;
|
|
27
|
+
function: string;
|
|
28
|
+
lineno: number;
|
|
29
|
+
colno?: number;
|
|
30
|
+
in_app?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface Breadcrumb {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
category: string;
|
|
35
|
+
message: string;
|
|
36
|
+
level?: string;
|
|
37
|
+
data?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
interface LogEvent {
|
|
40
|
+
level?: "fatal" | "error" | "warning" | "info" | "debug";
|
|
41
|
+
message: string;
|
|
42
|
+
exception?: {
|
|
43
|
+
type: string;
|
|
44
|
+
value: string;
|
|
45
|
+
stacktrace?: {
|
|
46
|
+
frames: StackFrame[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
tags?: Record<string, string>;
|
|
50
|
+
breadcrumbs?: Breadcrumb[];
|
|
51
|
+
request?: {
|
|
52
|
+
url?: string;
|
|
53
|
+
method?: string;
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
query_string?: string;
|
|
56
|
+
body?: string;
|
|
57
|
+
};
|
|
58
|
+
environment?: string;
|
|
59
|
+
release?: string;
|
|
60
|
+
timestamp?: string;
|
|
61
|
+
user?: {
|
|
62
|
+
id?: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
username?: string;
|
|
65
|
+
ip_address?: string;
|
|
66
|
+
};
|
|
67
|
+
contexts?: {
|
|
68
|
+
browser?: {
|
|
69
|
+
name?: string;
|
|
70
|
+
version?: string;
|
|
71
|
+
};
|
|
72
|
+
os?: {
|
|
73
|
+
name?: string;
|
|
74
|
+
version?: string;
|
|
75
|
+
};
|
|
76
|
+
device?: {
|
|
77
|
+
type?: string;
|
|
78
|
+
};
|
|
79
|
+
runtime?: {
|
|
80
|
+
name?: string;
|
|
81
|
+
version?: string;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class AiolaClient {
|
|
87
|
+
private options;
|
|
88
|
+
private transport;
|
|
89
|
+
private breadcrumbs;
|
|
90
|
+
private initialized;
|
|
91
|
+
private seen;
|
|
92
|
+
constructor();
|
|
93
|
+
init(options: AiolaOptions): void;
|
|
94
|
+
/** Capture an error/exception */
|
|
95
|
+
captureException(error: unknown, extra?: {
|
|
96
|
+
tags?: Record<string, string>;
|
|
97
|
+
level?: LogEvent["level"];
|
|
98
|
+
}): void;
|
|
99
|
+
/** Capture a plain message */
|
|
100
|
+
captureMessage(message: string, level?: LogEvent["level"], tags?: Record<string, string>): void;
|
|
101
|
+
/** Add a manual breadcrumb */
|
|
102
|
+
addBreadcrumb(category: string, message: string, data?: Record<string, unknown>): void;
|
|
103
|
+
/** Set user context */
|
|
104
|
+
setUser(user: {
|
|
105
|
+
id?: string;
|
|
106
|
+
email?: string;
|
|
107
|
+
username?: string;
|
|
108
|
+
ip_address?: string;
|
|
109
|
+
} | null): void;
|
|
110
|
+
/** Set a tag */
|
|
111
|
+
setTag(key: string, value: string): void;
|
|
112
|
+
/** Flush all pending events */
|
|
113
|
+
flush(): void;
|
|
114
|
+
/** Wrap an async function to auto-capture errors */
|
|
115
|
+
wrap<T extends (...args: unknown[]) => unknown>(fn: T): T;
|
|
116
|
+
/** Wrap a Next.js API route handler to auto-capture errors */
|
|
117
|
+
wrapApiHandler<Req, Res>(handler: (req: Req, res: Res) => Promise<unknown> | unknown): (req: Req, res: Res) => Promise<unknown>;
|
|
118
|
+
/** Wrap a Next.js App Router route handler (GET, POST, etc.) */
|
|
119
|
+
wrapRouteHandler<T extends (...args: unknown[]) => unknown>(handler: T): T;
|
|
120
|
+
/** Wrap a server action to auto-capture errors */
|
|
121
|
+
wrapServerAction<T extends (...args: unknown[]) => unknown>(action: T): T;
|
|
122
|
+
private _buildEvent;
|
|
123
|
+
private _send;
|
|
124
|
+
/** Instrument console — breadcrumbs for all, promote console.error to real errors */
|
|
125
|
+
private _instrumentConsole;
|
|
126
|
+
private _setupGlobalHandlers;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Singleton instance — used via Aiola.init() / Aiola.captureException() */
|
|
130
|
+
declare const Aiola: AiolaClient;
|
|
131
|
+
|
|
132
|
+
export { Aiola, type AiolaOptions, type Breadcrumb, type LogEvent, type StackFrame };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
interface AiolaOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
environment?: string;
|
|
4
|
+
release?: string;
|
|
5
|
+
/** Ingest endpoint — defaults to Aiola cloud */
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
/** Max breadcrumbs to keep in memory (default: 30) */
|
|
8
|
+
maxBreadcrumbs?: number;
|
|
9
|
+
/** Flush interval in ms (default: 5000) */
|
|
10
|
+
flushInterval?: number;
|
|
11
|
+
/** User context */
|
|
12
|
+
user?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
username?: string;
|
|
16
|
+
ip_address?: string;
|
|
17
|
+
};
|
|
18
|
+
/** Extra tags attached to every event */
|
|
19
|
+
tags?: Record<string, string>;
|
|
20
|
+
/** Promote console.error calls to real error events (default: true) */
|
|
21
|
+
captureConsoleErrors?: boolean;
|
|
22
|
+
/** Filter errors before sending — return null to drop */
|
|
23
|
+
beforeSend?: (event: LogEvent) => LogEvent | null;
|
|
24
|
+
}
|
|
25
|
+
interface StackFrame {
|
|
26
|
+
filename: string;
|
|
27
|
+
function: string;
|
|
28
|
+
lineno: number;
|
|
29
|
+
colno?: number;
|
|
30
|
+
in_app?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface Breadcrumb {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
category: string;
|
|
35
|
+
message: string;
|
|
36
|
+
level?: string;
|
|
37
|
+
data?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
interface LogEvent {
|
|
40
|
+
level?: "fatal" | "error" | "warning" | "info" | "debug";
|
|
41
|
+
message: string;
|
|
42
|
+
exception?: {
|
|
43
|
+
type: string;
|
|
44
|
+
value: string;
|
|
45
|
+
stacktrace?: {
|
|
46
|
+
frames: StackFrame[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
tags?: Record<string, string>;
|
|
50
|
+
breadcrumbs?: Breadcrumb[];
|
|
51
|
+
request?: {
|
|
52
|
+
url?: string;
|
|
53
|
+
method?: string;
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
query_string?: string;
|
|
56
|
+
body?: string;
|
|
57
|
+
};
|
|
58
|
+
environment?: string;
|
|
59
|
+
release?: string;
|
|
60
|
+
timestamp?: string;
|
|
61
|
+
user?: {
|
|
62
|
+
id?: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
username?: string;
|
|
65
|
+
ip_address?: string;
|
|
66
|
+
};
|
|
67
|
+
contexts?: {
|
|
68
|
+
browser?: {
|
|
69
|
+
name?: string;
|
|
70
|
+
version?: string;
|
|
71
|
+
};
|
|
72
|
+
os?: {
|
|
73
|
+
name?: string;
|
|
74
|
+
version?: string;
|
|
75
|
+
};
|
|
76
|
+
device?: {
|
|
77
|
+
type?: string;
|
|
78
|
+
};
|
|
79
|
+
runtime?: {
|
|
80
|
+
name?: string;
|
|
81
|
+
version?: string;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class AiolaClient {
|
|
87
|
+
private options;
|
|
88
|
+
private transport;
|
|
89
|
+
private breadcrumbs;
|
|
90
|
+
private initialized;
|
|
91
|
+
private seen;
|
|
92
|
+
constructor();
|
|
93
|
+
init(options: AiolaOptions): void;
|
|
94
|
+
/** Capture an error/exception */
|
|
95
|
+
captureException(error: unknown, extra?: {
|
|
96
|
+
tags?: Record<string, string>;
|
|
97
|
+
level?: LogEvent["level"];
|
|
98
|
+
}): void;
|
|
99
|
+
/** Capture a plain message */
|
|
100
|
+
captureMessage(message: string, level?: LogEvent["level"], tags?: Record<string, string>): void;
|
|
101
|
+
/** Add a manual breadcrumb */
|
|
102
|
+
addBreadcrumb(category: string, message: string, data?: Record<string, unknown>): void;
|
|
103
|
+
/** Set user context */
|
|
104
|
+
setUser(user: {
|
|
105
|
+
id?: string;
|
|
106
|
+
email?: string;
|
|
107
|
+
username?: string;
|
|
108
|
+
ip_address?: string;
|
|
109
|
+
} | null): void;
|
|
110
|
+
/** Set a tag */
|
|
111
|
+
setTag(key: string, value: string): void;
|
|
112
|
+
/** Flush all pending events */
|
|
113
|
+
flush(): void;
|
|
114
|
+
/** Wrap an async function to auto-capture errors */
|
|
115
|
+
wrap<T extends (...args: unknown[]) => unknown>(fn: T): T;
|
|
116
|
+
/** Wrap a Next.js API route handler to auto-capture errors */
|
|
117
|
+
wrapApiHandler<Req, Res>(handler: (req: Req, res: Res) => Promise<unknown> | unknown): (req: Req, res: Res) => Promise<unknown>;
|
|
118
|
+
/** Wrap a Next.js App Router route handler (GET, POST, etc.) */
|
|
119
|
+
wrapRouteHandler<T extends (...args: unknown[]) => unknown>(handler: T): T;
|
|
120
|
+
/** Wrap a server action to auto-capture errors */
|
|
121
|
+
wrapServerAction<T extends (...args: unknown[]) => unknown>(action: T): T;
|
|
122
|
+
private _buildEvent;
|
|
123
|
+
private _send;
|
|
124
|
+
/** Instrument console — breadcrumbs for all, promote console.error to real errors */
|
|
125
|
+
private _instrumentConsole;
|
|
126
|
+
private _setupGlobalHandlers;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Singleton instance — used via Aiola.init() / Aiola.captureException() */
|
|
130
|
+
declare const Aiola: AiolaClient;
|
|
131
|
+
|
|
132
|
+
export { Aiola, type AiolaOptions, type Breadcrumb, type LogEvent, type StackFrame };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var v=(o,t)=>{for(var e in t)l(o,e,{get:t[e],enumerable:!0})},E=(o,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of g(t))!w.call(o,s)&&s!==e&&l(o,s,{get:()=>t[s],enumerable:!(n=m(t,s))||n.enumerable});return o};var y=o=>E(l({},"__esModule",{value:!0}),o);var R={};v(R,{Aiola:()=>x});module.exports=y(R);var c=class{constructor(t,e,n){this.endpoint=t;this.apiKey=e;this.flushInterval=n;this.queue=[];this.timer=null}send(t){this.queue.push(t),this.timer||(this.timer=setTimeout(()=>this.flush(),this.flushInterval)),(t.level==="error"||t.level==="fatal")&&this.flush()}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),this.queue.length===0)return;let t=this.queue.splice(0);for(let e of t)this._send(e)}_send(t){let e=JSON.stringify(t);this._fetch(e)}_fetch(t){try{fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","x-aiola-key":this.apiKey},body:t,keepalive:!0}).catch(()=>{})}catch{}}};var u=class{constructor(t){this.crumbs=[];this.max=t}add(t,e,n,s){this.crumbs.push({timestamp:new Date().toISOString(),category:t,message:e,level:s,data:n}),this.crumbs.length>this.max&&this.crumbs.shift()}getAll(){return[...this.crumbs]}clear(){this.crumbs=[]}instrumentFetch(){if(typeof globalThis.fetch>"u")return;let t=globalThis.fetch,e=this;globalThis.fetch=function(n,s){let r=typeof n=="string"?n:n instanceof URL?n.href:n.url,i=s?.method||"GET",d=Date.now();return t.apply(globalThis,[n,s]).then(a=>(e.add("http",`${i} ${r}`,{status_code:a.status,duration_ms:Date.now()-d}),a),a=>{throw e.add("http",`${i} ${r} (failed)`,{error:String(a),duration_ms:Date.now()-d},"error"),a})}}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;let t=this,e=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(s,r){return this._clawMethod=s,this._clawUrl=typeof r=="string"?r:r.href,e.apply(this,arguments)},XMLHttpRequest.prototype.send=function(){let s=this,r=Date.now();return s.addEventListener("loadend",function(){let i=Date.now()-r;s.status>0?t.add("http",`${s._clawMethod} ${s._clawUrl}`,{status_code:s.status,duration_ms:i,type:"xhr"}):t.add("http",`${s._clawMethod} ${s._clawUrl} (failed)`,{duration_ms:i,type:"xhr"},"error")}),n.apply(this,arguments)}}instrumentClicks(){typeof document>"u"||document.addEventListener("click",t=>{let e=t.target;if(!e)return;let n=e.tagName?.toLowerCase(),s=e.textContent?.slice(0,50)?.trim(),r=e.id?`#${e.id}`:"",i=e.className&&typeof e.className=="string"?`.${e.className.split(" ")[0]}`:"";this.add("click",`${n}${r}${i}${s?` "${s}"`:""}`)},{capture:!0,passive:!0})}instrumentNavigation(){if(typeof window>"u")return;let t=window.location.href,e=()=>{let r=window.location.href;r!==t&&(this.add("navigation",`${t} \u2192 ${r}`),t=r)};window.addEventListener("popstate",e);let n=history.pushState,s=history.replaceState;history.pushState=function(...r){n.apply(this,r),e()},history.replaceState=function(...r){s.apply(this,r),e()}}};var b=/^\s*at (?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+)|([^)]+))\)?$/,k=/^(.+?)@(.+?):(\d+):(\d+)$/;function f(o){let t=[],e=o.split(`
|
|
2
|
+
`);for(let n of e){let s=n.trim();if(!s||s.startsWith("Error"))continue;let r=b.exec(s);if(r){t.push({function:r[1]||"<anonymous>",filename:r[2]||r[5]||"<unknown>",lineno:parseInt(r[3],10)||0,colno:parseInt(r[4],10)||void 0,in_app:h(r[2]||"")});continue}r=k.exec(s),r&&t.push({function:r[1]||"<anonymous>",filename:r[2]||"<unknown>",lineno:parseInt(r[3],10)||0,colno:parseInt(r[4],10)||void 0,in_app:h(r[2]||"")})}return t}function h(o){return!(!o||o.includes("node_modules")||o.startsWith("node:")||o.includes("internal/")||o.includes("<anonymous>"))}var _="https://app.aiola.com/api/app-logs/ingest",L="aiola-js",T="0.1.0",p=class{constructor(){this.initialized=!1;this.seen=new Set;this.options={apiKey:"",environment:"production",endpoint:_,maxBreadcrumbs:30,flushInterval:5e3,captureConsoleErrors:!0},this.transport=new c(this.options.endpoint,"",5e3),this.breadcrumbs=new u(30)}init(t){this.initialized||(this.initialized=!0,this.options={...this.options,...t},this.transport=new c(this.options.endpoint,this.options.apiKey,this.options.flushInterval),this.breadcrumbs=new u(this.options.maxBreadcrumbs),this._setupGlobalHandlers(),this._instrumentConsole(),this.breadcrumbs.instrumentFetch(),this.breadcrumbs.instrumentXHR(),typeof window<"u"&&(this.breadcrumbs.instrumentClicks(),this.breadcrumbs.instrumentNavigation(),window.addEventListener("beforeunload",()=>this.transport.flush()),window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.transport.flush()})))}captureException(t,e){if(!this.initialized)return;let n=t instanceof Error?t:new Error(String(t)),s=n.stack?f(n.stack):[],r=`${n.name}:${n.message}`;if(this.seen.has(r))return;this.seen.add(r),setTimeout(()=>this.seen.delete(r),5e3);let i=this._buildEvent({level:e?.level||"error",message:n.message,exception:{type:n.name||"Error",value:n.message,stacktrace:s.length>0?{frames:s}:void 0},tags:e?.tags});this._send(i)}captureMessage(t,e="info",n){if(!this.initialized)return;let s=this._buildEvent({level:e,message:t,tags:n});this._send(s)}addBreadcrumb(t,e,n){this.breadcrumbs.add(t,e,n)}setUser(t){this.options.user=t||void 0}setTag(t,e){this.options.tags||(this.options.tags={}),this.options.tags[t]=e}flush(){this.transport.flush()}wrap(t){let e=this;return function(...n){try{let s=t.apply(this,n);return s instanceof Promise?s.catch(r=>{throw e.captureException(r),r}):s}catch(s){throw e.captureException(s),s}}}wrapApiHandler(t){let e=this;return async function(n,s){try{return await t(n,s)}catch(r){throw e.captureException(r),e.transport.flush(),r}}}wrapRouteHandler(t){let e=this;return(async function(...n){try{return await t(...n)}catch(s){throw e.captureException(s),e.transport.flush(),s}})}wrapServerAction(t){let e=this;return(async function(...n){try{return await t(...n)}catch(s){throw e.captureException(s),e.transport.flush(),s}})}_buildEvent(t){let e={...t,message:t.message||"",environment:this.options.environment,release:this.options.release,timestamp:new Date().toISOString(),user:this.options.user,tags:{sdk_name:L,sdk_version:T,...this.options.tags,...t.tags},breadcrumbs:this.breadcrumbs.getAll()};return typeof window<"u"&&(e.request={url:window.location.href,method:"GET",query_string:window.location.search}),typeof process<"u"&&process.version&&(e.contexts={runtime:{name:"Node.js",version:process.version}}),e}_send(t){if(this.options.beforeSend){let e=this.options.beforeSend(t);if(!e)return;t=e}this.transport.send(t)}_instrumentConsole(){if(typeof console>"u")return;let t={log:console.log,warn:console.warn,error:console.error,info:console.info},e=this;console.log=function(...n){e.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),t.log.apply(console,n)},console.warn=function(...n){e.breadcrumbs.add("console",n.map(String).join(" "),void 0,"warning"),t.warn.apply(console,n)},console.error=function(...n){let s=n.map(String).join(" ");if(e.breadcrumbs.add("console",s,void 0,"error"),e.options.captureConsoleErrors){let r=n[0]instanceof Error?n[0]:null;r?e.captureException(r,{tags:{source:"console.error"}}):e.captureMessage(s,"error",{source:"console.error"})}t.error.apply(console,n)},console.info=function(...n){e.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),t.info.apply(console,n)}}_setupGlobalHandlers(){if(typeof window<"u"&&(window.addEventListener("error",t=>{let e=t.target;if(e&&e!==window&&e.tagName){let n=e,s=n.tagName.toLowerCase(),r=n.src||n.href||"";this.captureMessage(`Failed to load ${s}: ${r}`,"error",{source:"resource",element:s,url:r});return}t.error?this.captureException(t.error):t.message&&this.captureException(new Error(t.message))},!0),window.addEventListener("unhandledrejection",t=>{let e=t.reason instanceof Error?t.reason:new Error(String(t.reason));this.captureException(e)})),typeof process<"u"&&typeof process.on=="function"){let t=process;t.on("uncaughtException",e=>{this.captureException(e,{level:"fatal"}),this.transport.flush()}),t.on("unhandledRejection",e=>{let n=e instanceof Error?e:new Error(String(e));this.captureException(n),this.transport.flush()})}typeof process>"u"&&typeof globalThis<"u"&&"Deno"in globalThis&&(globalThis.addEventListener("error",t=>{let e=t;e.error?this.captureException(e.error):e.message&&this.captureException(new Error(e.message))}),globalThis.addEventListener("unhandledrejection",t=>{let e=t,n=e.reason instanceof Error?e.reason:new Error(String(e.reason));this.captureException(n),this.transport.flush()}))}};var x=new p;0&&(module.exports={Aiola});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var c=class{constructor(e,t,n){this.endpoint=e;this.apiKey=t;this.flushInterval=n;this.queue=[];this.timer=null}send(e){this.queue.push(e),this.timer||(this.timer=setTimeout(()=>this.flush(),this.flushInterval)),(e.level==="error"||e.level==="fatal")&&this.flush()}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),this.queue.length===0)return;let e=this.queue.splice(0);for(let t of e)this._send(t)}_send(e){let t=JSON.stringify(e);this._fetch(t)}_fetch(e){try{fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","x-aiola-key":this.apiKey},body:e,keepalive:!0}).catch(()=>{})}catch{}}};var u=class{constructor(e){this.crumbs=[];this.max=e}add(e,t,n,s){this.crumbs.push({timestamp:new Date().toISOString(),category:e,message:t,level:s,data:n}),this.crumbs.length>this.max&&this.crumbs.shift()}getAll(){return[...this.crumbs]}clear(){this.crumbs=[]}instrumentFetch(){if(typeof globalThis.fetch>"u")return;let e=globalThis.fetch,t=this;globalThis.fetch=function(n,s){let r=typeof n=="string"?n:n instanceof URL?n.href:n.url,i=s?.method||"GET",l=Date.now();return e.apply(globalThis,[n,s]).then(a=>(t.add("http",`${i} ${r}`,{status_code:a.status,duration_ms:Date.now()-l}),a),a=>{throw t.add("http",`${i} ${r} (failed)`,{error:String(a),duration_ms:Date.now()-l},"error"),a})}}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;let e=this,t=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(s,r){return this._clawMethod=s,this._clawUrl=typeof r=="string"?r:r.href,t.apply(this,arguments)},XMLHttpRequest.prototype.send=function(){let s=this,r=Date.now();return s.addEventListener("loadend",function(){let i=Date.now()-r;s.status>0?e.add("http",`${s._clawMethod} ${s._clawUrl}`,{status_code:s.status,duration_ms:i,type:"xhr"}):e.add("http",`${s._clawMethod} ${s._clawUrl} (failed)`,{duration_ms:i,type:"xhr"},"error")}),n.apply(this,arguments)}}instrumentClicks(){typeof document>"u"||document.addEventListener("click",e=>{let t=e.target;if(!t)return;let n=t.tagName?.toLowerCase(),s=t.textContent?.slice(0,50)?.trim(),r=t.id?`#${t.id}`:"",i=t.className&&typeof t.className=="string"?`.${t.className.split(" ")[0]}`:"";this.add("click",`${n}${r}${i}${s?` "${s}"`:""}`)},{capture:!0,passive:!0})}instrumentNavigation(){if(typeof window>"u")return;let e=window.location.href,t=()=>{let r=window.location.href;r!==e&&(this.add("navigation",`${e} \u2192 ${r}`),e=r)};window.addEventListener("popstate",t);let n=history.pushState,s=history.replaceState;history.pushState=function(...r){n.apply(this,r),t()},history.replaceState=function(...r){s.apply(this,r),t()}}};var f=/^\s*at (?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+)|([^)]+))\)?$/,m=/^(.+?)@(.+?):(\d+):(\d+)$/;function h(o){let e=[],t=o.split(`
|
|
2
|
+
`);for(let n of t){let s=n.trim();if(!s||s.startsWith("Error"))continue;let r=f.exec(s);if(r){e.push({function:r[1]||"<anonymous>",filename:r[2]||r[5]||"<unknown>",lineno:parseInt(r[3],10)||0,colno:parseInt(r[4],10)||void 0,in_app:d(r[2]||"")});continue}r=m.exec(s),r&&e.push({function:r[1]||"<anonymous>",filename:r[2]||"<unknown>",lineno:parseInt(r[3],10)||0,colno:parseInt(r[4],10)||void 0,in_app:d(r[2]||"")})}return e}function d(o){return!(!o||o.includes("node_modules")||o.startsWith("node:")||o.includes("internal/")||o.includes("<anonymous>"))}var g="https://app.aiola.com/api/app-logs/ingest",w="aiola-js",v="0.1.0",p=class{constructor(){this.initialized=!1;this.seen=new Set;this.options={apiKey:"",environment:"production",endpoint:g,maxBreadcrumbs:30,flushInterval:5e3,captureConsoleErrors:!0},this.transport=new c(this.options.endpoint,"",5e3),this.breadcrumbs=new u(30)}init(e){this.initialized||(this.initialized=!0,this.options={...this.options,...e},this.transport=new c(this.options.endpoint,this.options.apiKey,this.options.flushInterval),this.breadcrumbs=new u(this.options.maxBreadcrumbs),this._setupGlobalHandlers(),this._instrumentConsole(),this.breadcrumbs.instrumentFetch(),this.breadcrumbs.instrumentXHR(),typeof window<"u"&&(this.breadcrumbs.instrumentClicks(),this.breadcrumbs.instrumentNavigation(),window.addEventListener("beforeunload",()=>this.transport.flush()),window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.transport.flush()})))}captureException(e,t){if(!this.initialized)return;let n=e instanceof Error?e:new Error(String(e)),s=n.stack?h(n.stack):[],r=`${n.name}:${n.message}`;if(this.seen.has(r))return;this.seen.add(r),setTimeout(()=>this.seen.delete(r),5e3);let i=this._buildEvent({level:t?.level||"error",message:n.message,exception:{type:n.name||"Error",value:n.message,stacktrace:s.length>0?{frames:s}:void 0},tags:t?.tags});this._send(i)}captureMessage(e,t="info",n){if(!this.initialized)return;let s=this._buildEvent({level:t,message:e,tags:n});this._send(s)}addBreadcrumb(e,t,n){this.breadcrumbs.add(e,t,n)}setUser(e){this.options.user=e||void 0}setTag(e,t){this.options.tags||(this.options.tags={}),this.options.tags[e]=t}flush(){this.transport.flush()}wrap(e){let t=this;return function(...n){try{let s=e.apply(this,n);return s instanceof Promise?s.catch(r=>{throw t.captureException(r),r}):s}catch(s){throw t.captureException(s),s}}}wrapApiHandler(e){let t=this;return async function(n,s){try{return await e(n,s)}catch(r){throw t.captureException(r),t.transport.flush(),r}}}wrapRouteHandler(e){let t=this;return(async function(...n){try{return await e(...n)}catch(s){throw t.captureException(s),t.transport.flush(),s}})}wrapServerAction(e){let t=this;return(async function(...n){try{return await e(...n)}catch(s){throw t.captureException(s),t.transport.flush(),s}})}_buildEvent(e){let t={...e,message:e.message||"",environment:this.options.environment,release:this.options.release,timestamp:new Date().toISOString(),user:this.options.user,tags:{sdk_name:w,sdk_version:v,...this.options.tags,...e.tags},breadcrumbs:this.breadcrumbs.getAll()};return typeof window<"u"&&(t.request={url:window.location.href,method:"GET",query_string:window.location.search}),typeof process<"u"&&process.version&&(t.contexts={runtime:{name:"Node.js",version:process.version}}),t}_send(e){if(this.options.beforeSend){let t=this.options.beforeSend(e);if(!t)return;e=t}this.transport.send(e)}_instrumentConsole(){if(typeof console>"u")return;let e={log:console.log,warn:console.warn,error:console.error,info:console.info},t=this;console.log=function(...n){t.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),e.log.apply(console,n)},console.warn=function(...n){t.breadcrumbs.add("console",n.map(String).join(" "),void 0,"warning"),e.warn.apply(console,n)},console.error=function(...n){let s=n.map(String).join(" ");if(t.breadcrumbs.add("console",s,void 0,"error"),t.options.captureConsoleErrors){let r=n[0]instanceof Error?n[0]:null;r?t.captureException(r,{tags:{source:"console.error"}}):t.captureMessage(s,"error",{source:"console.error"})}e.error.apply(console,n)},console.info=function(...n){t.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),e.info.apply(console,n)}}_setupGlobalHandlers(){if(typeof window<"u"&&(window.addEventListener("error",e=>{let t=e.target;if(t&&t!==window&&t.tagName){let n=t,s=n.tagName.toLowerCase(),r=n.src||n.href||"";this.captureMessage(`Failed to load ${s}: ${r}`,"error",{source:"resource",element:s,url:r});return}e.error?this.captureException(e.error):e.message&&this.captureException(new Error(e.message))},!0),window.addEventListener("unhandledrejection",e=>{let t=e.reason instanceof Error?e.reason:new Error(String(e.reason));this.captureException(t)})),typeof process<"u"&&typeof process.on=="function"){let e=process;e.on("uncaughtException",t=>{this.captureException(t,{level:"fatal"}),this.transport.flush()}),e.on("unhandledRejection",t=>{let n=t instanceof Error?t:new Error(String(t));this.captureException(n),this.transport.flush()})}typeof process>"u"&&typeof globalThis<"u"&&"Deno"in globalThis&&(globalThis.addEventListener("error",e=>{let t=e;t.error?this.captureException(t.error):t.message&&this.captureException(new Error(t.message))}),globalThis.addEventListener("unhandledrejection",e=>{let t=e,n=t.reason instanceof Error?t.reason:new Error(String(t.reason));this.captureException(n),this.transport.flush()}))}};var R=new p;export{R as Aiola};
|
package/dist/node.d.mts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
interface AiolaOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
environment?: string;
|
|
4
|
+
release?: string;
|
|
5
|
+
/** Ingest endpoint — defaults to Aiola cloud */
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
/** Max breadcrumbs to keep in memory (default: 30) */
|
|
8
|
+
maxBreadcrumbs?: number;
|
|
9
|
+
/** Flush interval in ms (default: 5000) */
|
|
10
|
+
flushInterval?: number;
|
|
11
|
+
/** User context */
|
|
12
|
+
user?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
username?: string;
|
|
16
|
+
ip_address?: string;
|
|
17
|
+
};
|
|
18
|
+
/** Extra tags attached to every event */
|
|
19
|
+
tags?: Record<string, string>;
|
|
20
|
+
/** Promote console.error calls to real error events (default: true) */
|
|
21
|
+
captureConsoleErrors?: boolean;
|
|
22
|
+
/** Filter errors before sending — return null to drop */
|
|
23
|
+
beforeSend?: (event: LogEvent) => LogEvent | null;
|
|
24
|
+
}
|
|
25
|
+
interface StackFrame {
|
|
26
|
+
filename: string;
|
|
27
|
+
function: string;
|
|
28
|
+
lineno: number;
|
|
29
|
+
colno?: number;
|
|
30
|
+
in_app?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface Breadcrumb {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
category: string;
|
|
35
|
+
message: string;
|
|
36
|
+
level?: string;
|
|
37
|
+
data?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
interface LogEvent {
|
|
40
|
+
level?: "fatal" | "error" | "warning" | "info" | "debug";
|
|
41
|
+
message: string;
|
|
42
|
+
exception?: {
|
|
43
|
+
type: string;
|
|
44
|
+
value: string;
|
|
45
|
+
stacktrace?: {
|
|
46
|
+
frames: StackFrame[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
tags?: Record<string, string>;
|
|
50
|
+
breadcrumbs?: Breadcrumb[];
|
|
51
|
+
request?: {
|
|
52
|
+
url?: string;
|
|
53
|
+
method?: string;
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
query_string?: string;
|
|
56
|
+
body?: string;
|
|
57
|
+
};
|
|
58
|
+
environment?: string;
|
|
59
|
+
release?: string;
|
|
60
|
+
timestamp?: string;
|
|
61
|
+
user?: {
|
|
62
|
+
id?: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
username?: string;
|
|
65
|
+
ip_address?: string;
|
|
66
|
+
};
|
|
67
|
+
contexts?: {
|
|
68
|
+
browser?: {
|
|
69
|
+
name?: string;
|
|
70
|
+
version?: string;
|
|
71
|
+
};
|
|
72
|
+
os?: {
|
|
73
|
+
name?: string;
|
|
74
|
+
version?: string;
|
|
75
|
+
};
|
|
76
|
+
device?: {
|
|
77
|
+
type?: string;
|
|
78
|
+
};
|
|
79
|
+
runtime?: {
|
|
80
|
+
name?: string;
|
|
81
|
+
version?: string;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class AiolaClient {
|
|
87
|
+
private options;
|
|
88
|
+
private transport;
|
|
89
|
+
private breadcrumbs;
|
|
90
|
+
private initialized;
|
|
91
|
+
private seen;
|
|
92
|
+
constructor();
|
|
93
|
+
init(options: AiolaOptions): void;
|
|
94
|
+
/** Capture an error/exception */
|
|
95
|
+
captureException(error: unknown, extra?: {
|
|
96
|
+
tags?: Record<string, string>;
|
|
97
|
+
level?: LogEvent["level"];
|
|
98
|
+
}): void;
|
|
99
|
+
/** Capture a plain message */
|
|
100
|
+
captureMessage(message: string, level?: LogEvent["level"], tags?: Record<string, string>): void;
|
|
101
|
+
/** Add a manual breadcrumb */
|
|
102
|
+
addBreadcrumb(category: string, message: string, data?: Record<string, unknown>): void;
|
|
103
|
+
/** Set user context */
|
|
104
|
+
setUser(user: {
|
|
105
|
+
id?: string;
|
|
106
|
+
email?: string;
|
|
107
|
+
username?: string;
|
|
108
|
+
ip_address?: string;
|
|
109
|
+
} | null): void;
|
|
110
|
+
/** Set a tag */
|
|
111
|
+
setTag(key: string, value: string): void;
|
|
112
|
+
/** Flush all pending events */
|
|
113
|
+
flush(): void;
|
|
114
|
+
/** Wrap an async function to auto-capture errors */
|
|
115
|
+
wrap<T extends (...args: unknown[]) => unknown>(fn: T): T;
|
|
116
|
+
/** Wrap a Next.js API route handler to auto-capture errors */
|
|
117
|
+
wrapApiHandler<Req, Res>(handler: (req: Req, res: Res) => Promise<unknown> | unknown): (req: Req, res: Res) => Promise<unknown>;
|
|
118
|
+
/** Wrap a Next.js App Router route handler (GET, POST, etc.) */
|
|
119
|
+
wrapRouteHandler<T extends (...args: unknown[]) => unknown>(handler: T): T;
|
|
120
|
+
/** Wrap a server action to auto-capture errors */
|
|
121
|
+
wrapServerAction<T extends (...args: unknown[]) => unknown>(action: T): T;
|
|
122
|
+
private _buildEvent;
|
|
123
|
+
private _send;
|
|
124
|
+
/** Instrument console — breadcrumbs for all, promote console.error to real errors */
|
|
125
|
+
private _instrumentConsole;
|
|
126
|
+
private _setupGlobalHandlers;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Singleton instance — used via Aiola.init() / Aiola.captureException() */
|
|
130
|
+
declare const Aiola: AiolaClient;
|
|
131
|
+
|
|
132
|
+
export { Aiola, type AiolaOptions, type Breadcrumb, type LogEvent, type StackFrame };
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
interface AiolaOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
environment?: string;
|
|
4
|
+
release?: string;
|
|
5
|
+
/** Ingest endpoint — defaults to Aiola cloud */
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
/** Max breadcrumbs to keep in memory (default: 30) */
|
|
8
|
+
maxBreadcrumbs?: number;
|
|
9
|
+
/** Flush interval in ms (default: 5000) */
|
|
10
|
+
flushInterval?: number;
|
|
11
|
+
/** User context */
|
|
12
|
+
user?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
username?: string;
|
|
16
|
+
ip_address?: string;
|
|
17
|
+
};
|
|
18
|
+
/** Extra tags attached to every event */
|
|
19
|
+
tags?: Record<string, string>;
|
|
20
|
+
/** Promote console.error calls to real error events (default: true) */
|
|
21
|
+
captureConsoleErrors?: boolean;
|
|
22
|
+
/** Filter errors before sending — return null to drop */
|
|
23
|
+
beforeSend?: (event: LogEvent) => LogEvent | null;
|
|
24
|
+
}
|
|
25
|
+
interface StackFrame {
|
|
26
|
+
filename: string;
|
|
27
|
+
function: string;
|
|
28
|
+
lineno: number;
|
|
29
|
+
colno?: number;
|
|
30
|
+
in_app?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface Breadcrumb {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
category: string;
|
|
35
|
+
message: string;
|
|
36
|
+
level?: string;
|
|
37
|
+
data?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
interface LogEvent {
|
|
40
|
+
level?: "fatal" | "error" | "warning" | "info" | "debug";
|
|
41
|
+
message: string;
|
|
42
|
+
exception?: {
|
|
43
|
+
type: string;
|
|
44
|
+
value: string;
|
|
45
|
+
stacktrace?: {
|
|
46
|
+
frames: StackFrame[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
tags?: Record<string, string>;
|
|
50
|
+
breadcrumbs?: Breadcrumb[];
|
|
51
|
+
request?: {
|
|
52
|
+
url?: string;
|
|
53
|
+
method?: string;
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
query_string?: string;
|
|
56
|
+
body?: string;
|
|
57
|
+
};
|
|
58
|
+
environment?: string;
|
|
59
|
+
release?: string;
|
|
60
|
+
timestamp?: string;
|
|
61
|
+
user?: {
|
|
62
|
+
id?: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
username?: string;
|
|
65
|
+
ip_address?: string;
|
|
66
|
+
};
|
|
67
|
+
contexts?: {
|
|
68
|
+
browser?: {
|
|
69
|
+
name?: string;
|
|
70
|
+
version?: string;
|
|
71
|
+
};
|
|
72
|
+
os?: {
|
|
73
|
+
name?: string;
|
|
74
|
+
version?: string;
|
|
75
|
+
};
|
|
76
|
+
device?: {
|
|
77
|
+
type?: string;
|
|
78
|
+
};
|
|
79
|
+
runtime?: {
|
|
80
|
+
name?: string;
|
|
81
|
+
version?: string;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class AiolaClient {
|
|
87
|
+
private options;
|
|
88
|
+
private transport;
|
|
89
|
+
private breadcrumbs;
|
|
90
|
+
private initialized;
|
|
91
|
+
private seen;
|
|
92
|
+
constructor();
|
|
93
|
+
init(options: AiolaOptions): void;
|
|
94
|
+
/** Capture an error/exception */
|
|
95
|
+
captureException(error: unknown, extra?: {
|
|
96
|
+
tags?: Record<string, string>;
|
|
97
|
+
level?: LogEvent["level"];
|
|
98
|
+
}): void;
|
|
99
|
+
/** Capture a plain message */
|
|
100
|
+
captureMessage(message: string, level?: LogEvent["level"], tags?: Record<string, string>): void;
|
|
101
|
+
/** Add a manual breadcrumb */
|
|
102
|
+
addBreadcrumb(category: string, message: string, data?: Record<string, unknown>): void;
|
|
103
|
+
/** Set user context */
|
|
104
|
+
setUser(user: {
|
|
105
|
+
id?: string;
|
|
106
|
+
email?: string;
|
|
107
|
+
username?: string;
|
|
108
|
+
ip_address?: string;
|
|
109
|
+
} | null): void;
|
|
110
|
+
/** Set a tag */
|
|
111
|
+
setTag(key: string, value: string): void;
|
|
112
|
+
/** Flush all pending events */
|
|
113
|
+
flush(): void;
|
|
114
|
+
/** Wrap an async function to auto-capture errors */
|
|
115
|
+
wrap<T extends (...args: unknown[]) => unknown>(fn: T): T;
|
|
116
|
+
/** Wrap a Next.js API route handler to auto-capture errors */
|
|
117
|
+
wrapApiHandler<Req, Res>(handler: (req: Req, res: Res) => Promise<unknown> | unknown): (req: Req, res: Res) => Promise<unknown>;
|
|
118
|
+
/** Wrap a Next.js App Router route handler (GET, POST, etc.) */
|
|
119
|
+
wrapRouteHandler<T extends (...args: unknown[]) => unknown>(handler: T): T;
|
|
120
|
+
/** Wrap a server action to auto-capture errors */
|
|
121
|
+
wrapServerAction<T extends (...args: unknown[]) => unknown>(action: T): T;
|
|
122
|
+
private _buildEvent;
|
|
123
|
+
private _send;
|
|
124
|
+
/** Instrument console — breadcrumbs for all, promote console.error to real errors */
|
|
125
|
+
private _instrumentConsole;
|
|
126
|
+
private _setupGlobalHandlers;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Singleton instance — used via Aiola.init() / Aiola.captureException() */
|
|
130
|
+
declare const Aiola: AiolaClient;
|
|
131
|
+
|
|
132
|
+
export { Aiola, type AiolaOptions, type Breadcrumb, type LogEvent, type StackFrame };
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var E=(o,t)=>{for(var e in t)l(o,e,{get:t[e],enumerable:!0})},y=(o,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of w(t))!v.call(o,r)&&r!==e&&l(o,r,{get:()=>t[r],enumerable:!(n=g(t,r))||n.enumerable});return o};var b=o=>y(l({},"__esModule",{value:!0}),o);var R={};E(R,{Aiola:()=>m});module.exports=b(R);var c=class{constructor(t,e,n){this.endpoint=t;this.apiKey=e;this.flushInterval=n;this.queue=[];this.timer=null}send(t){this.queue.push(t),this.timer||(this.timer=setTimeout(()=>this.flush(),this.flushInterval)),(t.level==="error"||t.level==="fatal")&&this.flush()}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),this.queue.length===0)return;let t=this.queue.splice(0);for(let e of t)this._send(e)}_send(t){let e=JSON.stringify(t);this._fetch(e)}_fetch(t){try{fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","x-aiola-key":this.apiKey},body:t,keepalive:!0}).catch(()=>{})}catch{}}};var u=class{constructor(t){this.crumbs=[];this.max=t}add(t,e,n,r){this.crumbs.push({timestamp:new Date().toISOString(),category:t,message:e,level:r,data:n}),this.crumbs.length>this.max&&this.crumbs.shift()}getAll(){return[...this.crumbs]}clear(){this.crumbs=[]}instrumentFetch(){if(typeof globalThis.fetch>"u")return;let t=globalThis.fetch,e=this;globalThis.fetch=function(n,r){let s=typeof n=="string"?n:n instanceof URL?n.href:n.url,i=r?.method||"GET",d=Date.now();return t.apply(globalThis,[n,r]).then(a=>(e.add("http",`${i} ${s}`,{status_code:a.status,duration_ms:Date.now()-d}),a),a=>{throw e.add("http",`${i} ${s} (failed)`,{error:String(a),duration_ms:Date.now()-d},"error"),a})}}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;let t=this,e=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(r,s){return this._clawMethod=r,this._clawUrl=typeof s=="string"?s:s.href,e.apply(this,arguments)},XMLHttpRequest.prototype.send=function(){let r=this,s=Date.now();return r.addEventListener("loadend",function(){let i=Date.now()-s;r.status>0?t.add("http",`${r._clawMethod} ${r._clawUrl}`,{status_code:r.status,duration_ms:i,type:"xhr"}):t.add("http",`${r._clawMethod} ${r._clawUrl} (failed)`,{duration_ms:i,type:"xhr"},"error")}),n.apply(this,arguments)}}instrumentClicks(){typeof document>"u"||document.addEventListener("click",t=>{let e=t.target;if(!e)return;let n=e.tagName?.toLowerCase(),r=e.textContent?.slice(0,50)?.trim(),s=e.id?`#${e.id}`:"",i=e.className&&typeof e.className=="string"?`.${e.className.split(" ")[0]}`:"";this.add("click",`${n}${s}${i}${r?` "${r}"`:""}`)},{capture:!0,passive:!0})}instrumentNavigation(){if(typeof window>"u")return;let t=window.location.href,e=()=>{let s=window.location.href;s!==t&&(this.add("navigation",`${t} \u2192 ${s}`),t=s)};window.addEventListener("popstate",e);let n=history.pushState,r=history.replaceState;history.pushState=function(...s){n.apply(this,s),e()},history.replaceState=function(...s){r.apply(this,s),e()}}};var k=/^\s*at (?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+)|([^)]+))\)?$/,_=/^(.+?)@(.+?):(\d+):(\d+)$/;function f(o){let t=[],e=o.split(`
|
|
2
|
+
`);for(let n of e){let r=n.trim();if(!r||r.startsWith("Error"))continue;let s=k.exec(r);if(s){t.push({function:s[1]||"<anonymous>",filename:s[2]||s[5]||"<unknown>",lineno:parseInt(s[3],10)||0,colno:parseInt(s[4],10)||void 0,in_app:h(s[2]||"")});continue}s=_.exec(r),s&&t.push({function:s[1]||"<anonymous>",filename:s[2]||"<unknown>",lineno:parseInt(s[3],10)||0,colno:parseInt(s[4],10)||void 0,in_app:h(s[2]||"")})}return t}function h(o){return!(!o||o.includes("node_modules")||o.startsWith("node:")||o.includes("internal/")||o.includes("<anonymous>"))}var x="https://app.aiola.com/api/app-logs/ingest",L="aiola-js",T="0.1.0",p=class{constructor(){this.initialized=!1;this.seen=new Set;this.options={apiKey:"",environment:"production",endpoint:x,maxBreadcrumbs:30,flushInterval:5e3,captureConsoleErrors:!0},this.transport=new c(this.options.endpoint,"",5e3),this.breadcrumbs=new u(30)}init(t){this.initialized||(this.initialized=!0,this.options={...this.options,...t},this.transport=new c(this.options.endpoint,this.options.apiKey,this.options.flushInterval),this.breadcrumbs=new u(this.options.maxBreadcrumbs),this._setupGlobalHandlers(),this._instrumentConsole(),this.breadcrumbs.instrumentFetch(),this.breadcrumbs.instrumentXHR(),typeof window<"u"&&(this.breadcrumbs.instrumentClicks(),this.breadcrumbs.instrumentNavigation(),window.addEventListener("beforeunload",()=>this.transport.flush()),window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.transport.flush()})))}captureException(t,e){if(!this.initialized)return;let n=t instanceof Error?t:new Error(String(t)),r=n.stack?f(n.stack):[],s=`${n.name}:${n.message}`;if(this.seen.has(s))return;this.seen.add(s),setTimeout(()=>this.seen.delete(s),5e3);let i=this._buildEvent({level:e?.level||"error",message:n.message,exception:{type:n.name||"Error",value:n.message,stacktrace:r.length>0?{frames:r}:void 0},tags:e?.tags});this._send(i)}captureMessage(t,e="info",n){if(!this.initialized)return;let r=this._buildEvent({level:e,message:t,tags:n});this._send(r)}addBreadcrumb(t,e,n){this.breadcrumbs.add(t,e,n)}setUser(t){this.options.user=t||void 0}setTag(t,e){this.options.tags||(this.options.tags={}),this.options.tags[t]=e}flush(){this.transport.flush()}wrap(t){let e=this;return function(...n){try{let r=t.apply(this,n);return r instanceof Promise?r.catch(s=>{throw e.captureException(s),s}):r}catch(r){throw e.captureException(r),r}}}wrapApiHandler(t){let e=this;return async function(n,r){try{return await t(n,r)}catch(s){throw e.captureException(s),e.transport.flush(),s}}}wrapRouteHandler(t){let e=this;return(async function(...n){try{return await t(...n)}catch(r){throw e.captureException(r),e.transport.flush(),r}})}wrapServerAction(t){let e=this;return(async function(...n){try{return await t(...n)}catch(r){throw e.captureException(r),e.transport.flush(),r}})}_buildEvent(t){let e={...t,message:t.message||"",environment:this.options.environment,release:this.options.release,timestamp:new Date().toISOString(),user:this.options.user,tags:{sdk_name:L,sdk_version:T,...this.options.tags,...t.tags},breadcrumbs:this.breadcrumbs.getAll()};return typeof window<"u"&&(e.request={url:window.location.href,method:"GET",query_string:window.location.search}),typeof process<"u"&&process.version&&(e.contexts={runtime:{name:"Node.js",version:process.version}}),e}_send(t){if(this.options.beforeSend){let e=this.options.beforeSend(t);if(!e)return;t=e}this.transport.send(t)}_instrumentConsole(){if(typeof console>"u")return;let t={log:console.log,warn:console.warn,error:console.error,info:console.info},e=this;console.log=function(...n){e.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),t.log.apply(console,n)},console.warn=function(...n){e.breadcrumbs.add("console",n.map(String).join(" "),void 0,"warning"),t.warn.apply(console,n)},console.error=function(...n){let r=n.map(String).join(" ");if(e.breadcrumbs.add("console",r,void 0,"error"),e.options.captureConsoleErrors){let s=n[0]instanceof Error?n[0]:null;s?e.captureException(s,{tags:{source:"console.error"}}):e.captureMessage(r,"error",{source:"console.error"})}t.error.apply(console,n)},console.info=function(...n){e.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),t.info.apply(console,n)}}_setupGlobalHandlers(){if(typeof window<"u"&&(window.addEventListener("error",t=>{let e=t.target;if(e&&e!==window&&e.tagName){let n=e,r=n.tagName.toLowerCase(),s=n.src||n.href||"";this.captureMessage(`Failed to load ${r}: ${s}`,"error",{source:"resource",element:r,url:s});return}t.error?this.captureException(t.error):t.message&&this.captureException(new Error(t.message))},!0),window.addEventListener("unhandledrejection",t=>{let e=t.reason instanceof Error?t.reason:new Error(String(t.reason));this.captureException(e)})),typeof process<"u"&&typeof process.on=="function"){let t=process;t.on("uncaughtException",e=>{this.captureException(e,{level:"fatal"}),this.transport.flush()}),t.on("unhandledRejection",e=>{let n=e instanceof Error?e:new Error(String(e));this.captureException(n),this.transport.flush()})}typeof process>"u"&&typeof globalThis<"u"&&"Deno"in globalThis&&(globalThis.addEventListener("error",t=>{let e=t;e.error?this.captureException(e.error):e.message&&this.captureException(new Error(e.message))}),globalThis.addEventListener("unhandledrejection",t=>{let e=t,n=e.reason instanceof Error?e.reason:new Error(String(e.reason));this.captureException(n),this.transport.flush()}))}};var m=new p;0&&(module.exports={Aiola});
|
package/dist/node.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var c=class{constructor(e,t,n){this.endpoint=e;this.apiKey=t;this.flushInterval=n;this.queue=[];this.timer=null}send(e){this.queue.push(e),this.timer||(this.timer=setTimeout(()=>this.flush(),this.flushInterval)),(e.level==="error"||e.level==="fatal")&&this.flush()}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),this.queue.length===0)return;let e=this.queue.splice(0);for(let t of e)this._send(t)}_send(e){let t=JSON.stringify(e);this._fetch(t)}_fetch(e){try{fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","x-aiola-key":this.apiKey},body:e,keepalive:!0}).catch(()=>{})}catch{}}};var u=class{constructor(e){this.crumbs=[];this.max=e}add(e,t,n,r){this.crumbs.push({timestamp:new Date().toISOString(),category:e,message:t,level:r,data:n}),this.crumbs.length>this.max&&this.crumbs.shift()}getAll(){return[...this.crumbs]}clear(){this.crumbs=[]}instrumentFetch(){if(typeof globalThis.fetch>"u")return;let e=globalThis.fetch,t=this;globalThis.fetch=function(n,r){let s=typeof n=="string"?n:n instanceof URL?n.href:n.url,i=r?.method||"GET",l=Date.now();return e.apply(globalThis,[n,r]).then(a=>(t.add("http",`${i} ${s}`,{status_code:a.status,duration_ms:Date.now()-l}),a),a=>{throw t.add("http",`${i} ${s} (failed)`,{error:String(a),duration_ms:Date.now()-l},"error"),a})}}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;let e=this,t=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(r,s){return this._clawMethod=r,this._clawUrl=typeof s=="string"?s:s.href,t.apply(this,arguments)},XMLHttpRequest.prototype.send=function(){let r=this,s=Date.now();return r.addEventListener("loadend",function(){let i=Date.now()-s;r.status>0?e.add("http",`${r._clawMethod} ${r._clawUrl}`,{status_code:r.status,duration_ms:i,type:"xhr"}):e.add("http",`${r._clawMethod} ${r._clawUrl} (failed)`,{duration_ms:i,type:"xhr"},"error")}),n.apply(this,arguments)}}instrumentClicks(){typeof document>"u"||document.addEventListener("click",e=>{let t=e.target;if(!t)return;let n=t.tagName?.toLowerCase(),r=t.textContent?.slice(0,50)?.trim(),s=t.id?`#${t.id}`:"",i=t.className&&typeof t.className=="string"?`.${t.className.split(" ")[0]}`:"";this.add("click",`${n}${s}${i}${r?` "${r}"`:""}`)},{capture:!0,passive:!0})}instrumentNavigation(){if(typeof window>"u")return;let e=window.location.href,t=()=>{let s=window.location.href;s!==e&&(this.add("navigation",`${e} \u2192 ${s}`),e=s)};window.addEventListener("popstate",t);let n=history.pushState,r=history.replaceState;history.pushState=function(...s){n.apply(this,s),t()},history.replaceState=function(...s){r.apply(this,s),t()}}};var f=/^\s*at (?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+)|([^)]+))\)?$/,m=/^(.+?)@(.+?):(\d+):(\d+)$/;function h(o){let e=[],t=o.split(`
|
|
2
|
+
`);for(let n of t){let r=n.trim();if(!r||r.startsWith("Error"))continue;let s=f.exec(r);if(s){e.push({function:s[1]||"<anonymous>",filename:s[2]||s[5]||"<unknown>",lineno:parseInt(s[3],10)||0,colno:parseInt(s[4],10)||void 0,in_app:d(s[2]||"")});continue}s=m.exec(r),s&&e.push({function:s[1]||"<anonymous>",filename:s[2]||"<unknown>",lineno:parseInt(s[3],10)||0,colno:parseInt(s[4],10)||void 0,in_app:d(s[2]||"")})}return e}function d(o){return!(!o||o.includes("node_modules")||o.startsWith("node:")||o.includes("internal/")||o.includes("<anonymous>"))}var g="https://app.aiola.com/api/app-logs/ingest",w="aiola-js",v="0.1.0",p=class{constructor(){this.initialized=!1;this.seen=new Set;this.options={apiKey:"",environment:"production",endpoint:g,maxBreadcrumbs:30,flushInterval:5e3,captureConsoleErrors:!0},this.transport=new c(this.options.endpoint,"",5e3),this.breadcrumbs=new u(30)}init(e){this.initialized||(this.initialized=!0,this.options={...this.options,...e},this.transport=new c(this.options.endpoint,this.options.apiKey,this.options.flushInterval),this.breadcrumbs=new u(this.options.maxBreadcrumbs),this._setupGlobalHandlers(),this._instrumentConsole(),this.breadcrumbs.instrumentFetch(),this.breadcrumbs.instrumentXHR(),typeof window<"u"&&(this.breadcrumbs.instrumentClicks(),this.breadcrumbs.instrumentNavigation(),window.addEventListener("beforeunload",()=>this.transport.flush()),window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.transport.flush()})))}captureException(e,t){if(!this.initialized)return;let n=e instanceof Error?e:new Error(String(e)),r=n.stack?h(n.stack):[],s=`${n.name}:${n.message}`;if(this.seen.has(s))return;this.seen.add(s),setTimeout(()=>this.seen.delete(s),5e3);let i=this._buildEvent({level:t?.level||"error",message:n.message,exception:{type:n.name||"Error",value:n.message,stacktrace:r.length>0?{frames:r}:void 0},tags:t?.tags});this._send(i)}captureMessage(e,t="info",n){if(!this.initialized)return;let r=this._buildEvent({level:t,message:e,tags:n});this._send(r)}addBreadcrumb(e,t,n){this.breadcrumbs.add(e,t,n)}setUser(e){this.options.user=e||void 0}setTag(e,t){this.options.tags||(this.options.tags={}),this.options.tags[e]=t}flush(){this.transport.flush()}wrap(e){let t=this;return function(...n){try{let r=e.apply(this,n);return r instanceof Promise?r.catch(s=>{throw t.captureException(s),s}):r}catch(r){throw t.captureException(r),r}}}wrapApiHandler(e){let t=this;return async function(n,r){try{return await e(n,r)}catch(s){throw t.captureException(s),t.transport.flush(),s}}}wrapRouteHandler(e){let t=this;return(async function(...n){try{return await e(...n)}catch(r){throw t.captureException(r),t.transport.flush(),r}})}wrapServerAction(e){let t=this;return(async function(...n){try{return await e(...n)}catch(r){throw t.captureException(r),t.transport.flush(),r}})}_buildEvent(e){let t={...e,message:e.message||"",environment:this.options.environment,release:this.options.release,timestamp:new Date().toISOString(),user:this.options.user,tags:{sdk_name:w,sdk_version:v,...this.options.tags,...e.tags},breadcrumbs:this.breadcrumbs.getAll()};return typeof window<"u"&&(t.request={url:window.location.href,method:"GET",query_string:window.location.search}),typeof process<"u"&&process.version&&(t.contexts={runtime:{name:"Node.js",version:process.version}}),t}_send(e){if(this.options.beforeSend){let t=this.options.beforeSend(e);if(!t)return;e=t}this.transport.send(e)}_instrumentConsole(){if(typeof console>"u")return;let e={log:console.log,warn:console.warn,error:console.error,info:console.info},t=this;console.log=function(...n){t.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),e.log.apply(console,n)},console.warn=function(...n){t.breadcrumbs.add("console",n.map(String).join(" "),void 0,"warning"),e.warn.apply(console,n)},console.error=function(...n){let r=n.map(String).join(" ");if(t.breadcrumbs.add("console",r,void 0,"error"),t.options.captureConsoleErrors){let s=n[0]instanceof Error?n[0]:null;s?t.captureException(s,{tags:{source:"console.error"}}):t.captureMessage(r,"error",{source:"console.error"})}e.error.apply(console,n)},console.info=function(...n){t.breadcrumbs.add("console",n.map(String).join(" "),void 0,"info"),e.info.apply(console,n)}}_setupGlobalHandlers(){if(typeof window<"u"&&(window.addEventListener("error",e=>{let t=e.target;if(t&&t!==window&&t.tagName){let n=t,r=n.tagName.toLowerCase(),s=n.src||n.href||"";this.captureMessage(`Failed to load ${r}: ${s}`,"error",{source:"resource",element:r,url:s});return}e.error?this.captureException(e.error):e.message&&this.captureException(new Error(e.message))},!0),window.addEventListener("unhandledrejection",e=>{let t=e.reason instanceof Error?e.reason:new Error(String(e.reason));this.captureException(t)})),typeof process<"u"&&typeof process.on=="function"){let e=process;e.on("uncaughtException",t=>{this.captureException(t,{level:"fatal"}),this.transport.flush()}),e.on("unhandledRejection",t=>{let n=t instanceof Error?t:new Error(String(t));this.captureException(n),this.transport.flush()})}typeof process>"u"&&typeof globalThis<"u"&&"Deno"in globalThis&&(globalThis.addEventListener("error",e=>{let t=e;t.error?this.captureException(t.error):t.message&&this.captureException(new Error(t.message))}),globalThis.addEventListener("unhandledrejection",e=>{let t=e,n=t.reason instanceof Error?t.reason:new Error(String(t.reason));this.captureException(n),this.transport.flush()}))}};var E=new p;export{E as Aiola};
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aiolaapp/logger",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight error tracking SDK for Aiola App Logs",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./node": {
|
|
15
|
+
"types": "./dist/node.d.ts",
|
|
16
|
+
"import": "./dist/node.mjs",
|
|
17
|
+
"require": "./dist/node.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"dev": "tsup --watch"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25.5.0",
|
|
29
|
+
"tsup": "^8.0.0",
|
|
30
|
+
"typescript": "^5.0.0"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"error-tracking",
|
|
35
|
+
"logging",
|
|
36
|
+
"aiola"
|
|
37
|
+
]
|
|
38
|
+
}
|