@php-wasm/logger 0.7.1 → 0.7.4

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/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=function(){var r;return typeof process<"u"&&((r=process.release)==null?void 0:r.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}();if(p==="NODE"){let r=function(t){return new Promise(function(s,o){t.onload=t.onerror=function(n){t.onload=t.onerror=null,n.type==="load"?s(t.result):o(new Error("Failed to read the blob/file"))}})},e=function(){const t=new Uint8Array([1,2,3,4]),o=new File([t],"test").stream();try{return o.getReader({mode:"byob"}),!0}catch{return!1}};if(typeof File>"u"){class t extends Blob{constructor(o,n,i){super(o);let a;i!=null&&i.lastModified&&(a=new Date),(!a||isNaN(a.getFullYear()))&&(a=new Date),this.lastModifiedDate=a,this.lastModified=a.getMilliseconds(),this.name=n||""}}global.File=t}typeof Blob.prototype.arrayBuffer>"u"&&(Blob.prototype.arrayBuffer=function(){const s=new FileReader;return s.readAsArrayBuffer(this),r(s)}),typeof Blob.prototype.text>"u"&&(Blob.prototype.text=function(){const s=new FileReader;return s.readAsText(this),r(s)}),(typeof Blob.prototype.stream>"u"||!e())&&(Blob.prototype.stream=function(){let t=0;const s=this;return new ReadableStream({type:"bytes",autoAllocateChunkSize:512*1024,async pull(o){const n=o.byobRequest.view,a=await s.slice(t,t+n.byteLength).arrayBuffer(),c=new Uint8Array(a);new Uint8Array(n.buffer).set(c);const f=c.byteLength;o.byobRequest.respond(f),t+=f,t>=s.size&&o.close()}})})}if(p==="NODE"&&typeof CustomEvent>"u"){class r extends Event{constructor(t,s={}){super(t,s),this.detail=s.detail}initCustomEvent(){}}globalThis.CustomEvent=r}const L=(r,...e)=>{switch(r.severity){case"Debug":console.debug(r.message,...e);break;case"Info":console.info(r.message,...e);break;case"Warn":console.warn(r.message,...e);break;case"Error":console.error(r.message,...e);break;case"Fatal":console.error(r.message,...e);break;default:console.log(r.message,...e)}},v=(r,...e)=>[typeof r=="object"?JSON.stringify(r):r,...e.map(t=>JSON.stringify(t))].join(" "),h=[],u=r=>{h.push(r)},b=r=>{if(r.raw===!0)u(r.message);else{const e=E(typeof r.message=="object"?v(r.message):r.message,r.severity??"Info",r.prefix??"JavaScript");u(e)}};class w extends EventTarget{constructor(e=[]){super(),this.handlers=e,this.fatalErrorEvent="playground-fatal-error"}getLogs(){return this.handlers.includes(b)?[...h]:(this.error(`Logs aren't stored because the logToMemory handler isn't registered.
2
+ If you're using a custom logger instance, make sure to register logToMemory handler.
3
+ `),[])}logMessage(e,...t){for(const s of this.handlers)s(e,...t)}log(e,...t){this.logMessage({message:e,severity:void 0,prefix:"JavaScript",raw:!1},...t)}debug(e,...t){this.logMessage({message:e,severity:"Debug",prefix:"JavaScript",raw:!1},...t)}info(e,...t){this.logMessage({message:e,severity:"Info",prefix:"JavaScript",raw:!1},...t)}warn(e,...t){this.logMessage({message:e,severity:"Warn",prefix:"JavaScript",raw:!1},...t)}error(e,...t){this.logMessage({message:e,severity:"Error",prefix:"JavaScript",raw:!1},...t)}}const M=new w([b,L]),E=(r,e,t)=>{const s=new Date,o=new Intl.DateTimeFormat("en-GB",{year:"numeric",month:"short",day:"2-digit",timeZone:"UTC"}).format(s).replace(/ /g,"-"),n=new Intl.DateTimeFormat("en-GB",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1,timeZone:"UTC",timeZoneName:"short"}).format(s);return`[${o+" "+n}] ${t} ${e}: ${r}`},T=(r,e)=>{r.addEventListener(r.fatalErrorEvent,e)};let l=0;const g="/wordpress/wp-content/debug.log",S=async r=>await r.fileExists(g)?await r.readFileAsText(g):"",O=(r,e)=>{e.addEventListener("request.end",async()=>{const t=await S(e);if(t.length>l){const s=t.substring(l);r.logMessage({message:s,raw:!0}),l=t.length}}),e.addEventListener("request.error",t=>{t=t,t.error&&(r.logMessage({message:`${t.error.message} ${t.error.stack}`,severity:"Fatal",prefix:t.source==="request"?"PHP":"WASM Crash"}),r.dispatchEvent(new CustomEvent(r.fatalErrorEvent,{detail:{logs:r.getLogs(),source:t.source}})))})},P=(r,e)=>{r.logMessage({message:`${e.message} in ${e.filename} on line ${e.lineno}:${e.colno}`,severity:"Error"})},y=(r,e)=>{if(!(e!=null&&e.reason))return;const t=(e==null?void 0:e.reason.stack)??e.reason;r.logMessage({message:t,severity:"Error"})};let d=0;const B=r=>{navigator.serviceWorker.addEventListener("message",e=>{var t,s,o;((t=e.data)==null?void 0:t.numberOfOpenPlaygroundTabs)!==void 0&&d!==((s=e.data)==null?void 0:s.numberOfOpenPlaygroundTabs)&&(d=(o=e.data)==null?void 0:o.numberOfOpenPlaygroundTabs,r.debug(`Number of open Playground tabs is: ${d}`))})};let m=!1;const k=r=>{m||(B(r),!(typeof window>"u")&&(window.addEventListener("error",e=>P(r,e)),window.addEventListener("unhandledrejection",e=>y(r,e)),window.addEventListener("rejectionhandled",e=>y(r,e)),m=!0))},x=r=>{r.addEventListener("activate",()=>{r.clients.matchAll().then(e=>{const t={numberOfOpenPlaygroundTabs:e.filter(s=>s.frameType==="top-level").length};for(const s of e)s.postMessage(t)})})};exports.Logger=w;exports.addCrashListener=T;exports.collectPhpLogs=O;exports.collectWindowErrors=k;exports.formatLogEntry=E;exports.logger=M;exports.reportServiceWorkerMetrics=x;
package/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './lib/logger';
2
+ export * from './lib/log-collector';
package/index.js CHANGED
@@ -1 +1,319 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=function(){var o;return typeof process<"u"&&((o=process.release)==null?void 0:o.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}();if(u==="NODE"){let o=function(t){return new Promise(function(r,n){t.onload=t.onerror=function(i){t.onload=t.onerror=null,i.type==="load"?r(t.result):n(new Error("Failed to read the blob/file"))}})},e=function(){const t=new Uint8Array([1,2,3,4]),n=new File([t],"test").stream();try{return n.getReader({mode:"byob"}),!0}catch{return!1}};if(typeof File>"u"){class t extends Blob{constructor(n,i,a){super(n);let s;a!=null&&a.lastModified&&(s=new Date),(!s||isNaN(s.getFullYear()))&&(s=new Date),this.lastModifiedDate=s,this.lastModified=s.getMilliseconds(),this.name=i||""}}global.File=t}typeof Blob.prototype.arrayBuffer>"u"&&(Blob.prototype.arrayBuffer=function(){const r=new FileReader;return r.readAsArrayBuffer(this),o(r)}),typeof Blob.prototype.text>"u"&&(Blob.prototype.text=function(){const r=new FileReader;return r.readAsText(this),o(r)}),(typeof Blob.prototype.stream>"u"||!e())&&(Blob.prototype.stream=function(){let t=0;const r=this;return new ReadableStream({type:"bytes",autoAllocateChunkSize:512*1024,async pull(n){const i=n.byobRequest.view,s=await r.slice(t,t+i.byteLength).arrayBuffer(),d=new Uint8Array(s);new Uint8Array(i.buffer).set(d);const l=d.byteLength;n.byobRequest.respond(l),t+=l,t>=r.size&&n.close()}})})}if(u==="NODE"&&typeof CustomEvent>"u"){class o extends Event{constructor(t,r={}){super(t,r),this.detail=r.detail}initCustomEvent(){}}globalThis.CustomEvent=o}class c extends EventTarget{constructor(e){super(),this.fatalErrorEvent="playground-fatal-error",this.logs=[],this.windowConnected=!1,this.lastPHPLogLength=0,this.context={},this.errorLogPath="/wordpress/wp-content/debug.log",e&&(this.errorLogPath=e)}async getRequestPhpErrorLog(e){return await e.fileExists(this.errorLogPath)?await e.readFileAsText(this.errorLogPath):""}logWindowError(e){this.log(`${e.message} in ${e.filename} on line ${e.lineno}:${e.colno}`,"Error")}logUnhandledRejection(e){if(!(e!=null&&e.reason))return;const t=(e==null?void 0:e.reason.stack)??e.reason;this.log(t,"Error")}addWindowErrorListener(){this.windowConnected||typeof window>"u"||(window.addEventListener("error",this.logWindowError.bind(this)),window.addEventListener("unhandledrejection",this.logUnhandledRejection.bind(this)),window.addEventListener("rejectionhandled",this.logUnhandledRejection.bind(this)),this.windowConnected=!0)}addServiceWorkerMessageListener(){navigator.serviceWorker.addEventListener("message",e=>{var t;((t=e.data)==null?void 0:t.numberOfOpenPlaygroundTabs)!==void 0&&this.addContext({numberOfOpenPlaygroundTabs:e.data.numberOfOpenPlaygroundTabs})})}addPlaygroundRequestEndListener(e){e.addEventListener("request.end",async()=>{const t=await this.getRequestPhpErrorLog(e);t.length>this.lastPHPLogLength&&(this.logRaw(t.substring(this.lastPHPLogLength)),this.lastPHPLogLength=t.length)}),e.addEventListener("request.error",t=>{t=t,t.error&&(this.log(`${t.error.message} ${t.error.stack}`,"Fatal","PHP-WASM"),this.dispatchEvent(new CustomEvent(this.fatalErrorEvent,{detail:{logs:this.getLogs(),source:t.source}})))})}formatLogDate(e){const t=new Intl.DateTimeFormat("en-GB",{year:"numeric",month:"short",day:"2-digit",timeZone:"UTC"}).format(e).replace(/ /g,"-"),r=new Intl.DateTimeFormat("en-GB",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1,timeZone:"UTC",timeZoneName:"short"}).format(e);return t+" "+r}formatMessage(e,t,r){return`[${this.formatLogDate(new Date)}] ${r} ${t}: ${e}`}log(e,t,r){t===void 0&&(t="Info");const n=this.formatMessage(e,t,r??"Playground");this.logRaw(n)}logRaw(e){this.logs.push(e),console.debug(e)}getLogs(){return[...this.logs]}addContext(e){this.context={...this.context,...e}}getContext(){return{...this.context}}}const f=new c;function h(o){o.addWindowErrorListener(),o.addServiceWorkerMessageListener()}function g(o,e){o.addPlaygroundRequestEndListener(e)}function m(o){o.addEventListener("activate",()=>{o.clients.matchAll().then(e=>{const t={numberOfOpenPlaygroundTabs:e.filter(r=>r.frameType==="top-level").length};o.clients.matchAll({includeUncontrolled:!0}).then(r=>{for(const n of r)n.postMessage(t)})})})}function w(o,e){o.addEventListener(o.fatalErrorEvent,e)}exports.Logger=c;exports.addCrashListener=w;exports.collectPhpLogs=g;exports.collectWindowErrors=h;exports.logger=f;exports.reportServiceWorkerMetrics=m;
1
+ const p = function() {
2
+ var r;
3
+ return typeof process < "u" && ((r = process.release) == null ? void 0 : r.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : (
4
+ // @ts-ignore
5
+ typeof WorkerGlobalScope < "u" && // @ts-ignore
6
+ self instanceof WorkerGlobalScope ? "WORKER" : "NODE"
7
+ );
8
+ }();
9
+ if (p === "NODE") {
10
+ let r = function(t) {
11
+ return new Promise(function(s, o) {
12
+ t.onload = t.onerror = function(n) {
13
+ t.onload = t.onerror = null, n.type === "load" ? s(t.result) : o(new Error("Failed to read the blob/file"));
14
+ };
15
+ });
16
+ }, e = function() {
17
+ const t = new Uint8Array([1, 2, 3, 4]), o = new File([t], "test").stream();
18
+ try {
19
+ return o.getReader({ mode: "byob" }), !0;
20
+ } catch {
21
+ return !1;
22
+ }
23
+ };
24
+ if (typeof File > "u") {
25
+ class t extends Blob {
26
+ constructor(o, n, i) {
27
+ super(o);
28
+ let a;
29
+ i != null && i.lastModified && (a = /* @__PURE__ */ new Date()), (!a || isNaN(a.getFullYear())) && (a = /* @__PURE__ */ new Date()), this.lastModifiedDate = a, this.lastModified = a.getMilliseconds(), this.name = n || "";
30
+ }
31
+ }
32
+ global.File = t;
33
+ }
34
+ typeof Blob.prototype.arrayBuffer > "u" && (Blob.prototype.arrayBuffer = function() {
35
+ const s = new FileReader();
36
+ return s.readAsArrayBuffer(this), r(s);
37
+ }), typeof Blob.prototype.text > "u" && (Blob.prototype.text = function() {
38
+ const s = new FileReader();
39
+ return s.readAsText(this), r(s);
40
+ }), (typeof Blob.prototype.stream > "u" || !e()) && (Blob.prototype.stream = function() {
41
+ let t = 0;
42
+ const s = this;
43
+ return new ReadableStream({
44
+ type: "bytes",
45
+ // 0.5 MB seems like a reasonable chunk size, let's adjust
46
+ // this if needed.
47
+ autoAllocateChunkSize: 512 * 1024,
48
+ async pull(o) {
49
+ const n = o.byobRequest.view, a = await s.slice(
50
+ t,
51
+ t + n.byteLength
52
+ ).arrayBuffer(), f = new Uint8Array(a);
53
+ new Uint8Array(n.buffer).set(f);
54
+ const c = f.byteLength;
55
+ o.byobRequest.respond(c), t += c, t >= s.size && o.close();
56
+ }
57
+ });
58
+ });
59
+ }
60
+ if (p === "NODE" && typeof CustomEvent > "u") {
61
+ class r extends Event {
62
+ constructor(t, s = {}) {
63
+ super(t, s), this.detail = s.detail;
64
+ }
65
+ initCustomEvent() {
66
+ }
67
+ }
68
+ globalThis.CustomEvent = r;
69
+ }
70
+ const w = (r, ...e) => {
71
+ switch (r.severity) {
72
+ case "Debug":
73
+ console.debug(r.message, ...e);
74
+ break;
75
+ case "Info":
76
+ console.info(r.message, ...e);
77
+ break;
78
+ case "Warn":
79
+ console.warn(r.message, ...e);
80
+ break;
81
+ case "Error":
82
+ console.error(r.message, ...e);
83
+ break;
84
+ case "Fatal":
85
+ console.error(r.message, ...e);
86
+ break;
87
+ default:
88
+ console.log(r.message, ...e);
89
+ }
90
+ }, E = (r, ...e) => [
91
+ typeof r == "object" ? JSON.stringify(r) : r,
92
+ ...e.map((t) => JSON.stringify(t))
93
+ ].join(" "), h = [], u = (r) => {
94
+ h.push(r);
95
+ }, b = (r) => {
96
+ if (r.raw === !0)
97
+ u(r.message);
98
+ else {
99
+ const e = L(
100
+ typeof r.message == "object" ? E(r.message) : r.message,
101
+ r.severity ?? "Info",
102
+ r.prefix ?? "JavaScript"
103
+ );
104
+ u(e);
105
+ }
106
+ };
107
+ class v extends EventTarget {
108
+ // constructor
109
+ constructor(e = []) {
110
+ super(), this.handlers = e, this.fatalErrorEvent = "playground-fatal-error";
111
+ }
112
+ /**
113
+ * Get all logs.
114
+ * @returns string[]
115
+ */
116
+ getLogs() {
117
+ return this.handlers.includes(b) ? [...h] : (this.error(`Logs aren't stored because the logToMemory handler isn't registered.
118
+ If you're using a custom logger instance, make sure to register logToMemory handler.
119
+ `), []);
120
+ }
121
+ /**
122
+ * Log message with severity.
123
+ *
124
+ * @param message any
125
+ * @param severity LogSeverity
126
+ * @param raw boolean
127
+ * @param args any
128
+ */
129
+ logMessage(e, ...t) {
130
+ for (const s of this.handlers)
131
+ s(e, ...t);
132
+ }
133
+ /**
134
+ * Log message
135
+ *
136
+ * @param message any
137
+ * @param args any
138
+ */
139
+ log(e, ...t) {
140
+ this.logMessage(
141
+ {
142
+ message: e,
143
+ severity: void 0,
144
+ prefix: "JavaScript",
145
+ raw: !1
146
+ },
147
+ ...t
148
+ );
149
+ }
150
+ /**
151
+ * Log debug message
152
+ *
153
+ * @param message any
154
+ * @param args any
155
+ */
156
+ debug(e, ...t) {
157
+ this.logMessage(
158
+ {
159
+ message: e,
160
+ severity: "Debug",
161
+ prefix: "JavaScript",
162
+ raw: !1
163
+ },
164
+ ...t
165
+ );
166
+ }
167
+ /**
168
+ * Log info message
169
+ *
170
+ * @param message any
171
+ * @param args any
172
+ */
173
+ info(e, ...t) {
174
+ this.logMessage(
175
+ {
176
+ message: e,
177
+ severity: "Info",
178
+ prefix: "JavaScript",
179
+ raw: !1
180
+ },
181
+ ...t
182
+ );
183
+ }
184
+ /**
185
+ * Log warning message
186
+ *
187
+ * @param message any
188
+ * @param args any
189
+ */
190
+ warn(e, ...t) {
191
+ this.logMessage(
192
+ {
193
+ message: e,
194
+ severity: "Warn",
195
+ prefix: "JavaScript",
196
+ raw: !1
197
+ },
198
+ ...t
199
+ );
200
+ }
201
+ /**
202
+ * Log error message
203
+ *
204
+ * @param message any
205
+ * @param args any
206
+ */
207
+ error(e, ...t) {
208
+ this.logMessage(
209
+ {
210
+ message: e,
211
+ severity: "Error",
212
+ prefix: "JavaScript",
213
+ raw: !1
214
+ },
215
+ ...t
216
+ );
217
+ }
218
+ }
219
+ const B = new v([b, w]), L = (r, e, t) => {
220
+ const s = /* @__PURE__ */ new Date(), o = new Intl.DateTimeFormat("en-GB", {
221
+ year: "numeric",
222
+ month: "short",
223
+ day: "2-digit",
224
+ timeZone: "UTC"
225
+ }).format(s).replace(/ /g, "-"), n = new Intl.DateTimeFormat("en-GB", {
226
+ hour: "2-digit",
227
+ minute: "2-digit",
228
+ second: "2-digit",
229
+ hour12: !1,
230
+ timeZone: "UTC",
231
+ timeZoneName: "short"
232
+ }).format(s);
233
+ return `[${o + " " + n}] ${t} ${e}: ${r}`;
234
+ }, O = (r, e) => {
235
+ r.addEventListener(r.fatalErrorEvent, e);
236
+ };
237
+ let l = 0;
238
+ const g = "/wordpress/wp-content/debug.log", M = async (r) => await r.fileExists(g) ? await r.readFileAsText(g) : "", P = (r, e) => {
239
+ e.addEventListener("request.end", async () => {
240
+ const t = await M(e);
241
+ if (t.length > l) {
242
+ const s = t.substring(l);
243
+ r.logMessage({
244
+ message: s,
245
+ raw: !0
246
+ }), l = t.length;
247
+ }
248
+ }), e.addEventListener("request.error", (t) => {
249
+ t = t, t.error && (r.logMessage({
250
+ message: `${t.error.message} ${t.error.stack}`,
251
+ severity: "Fatal",
252
+ prefix: t.source === "request" ? "PHP" : "WASM Crash"
253
+ }), r.dispatchEvent(
254
+ new CustomEvent(r.fatalErrorEvent, {
255
+ detail: {
256
+ logs: r.getLogs(),
257
+ source: t.source
258
+ }
259
+ })
260
+ ));
261
+ });
262
+ }, T = (r, e) => {
263
+ r.logMessage({
264
+ message: `${e.message} in ${e.filename} on line ${e.lineno}:${e.colno}`,
265
+ severity: "Error"
266
+ });
267
+ }, m = (r, e) => {
268
+ if (!(e != null && e.reason))
269
+ return;
270
+ const t = (e == null ? void 0 : e.reason.stack) ?? e.reason;
271
+ r.logMessage({
272
+ message: t,
273
+ severity: "Error"
274
+ });
275
+ };
276
+ let d = 0;
277
+ const x = (r) => {
278
+ navigator.serviceWorker.addEventListener("message", (e) => {
279
+ var t, s, o;
280
+ ((t = e.data) == null ? void 0 : t.numberOfOpenPlaygroundTabs) !== void 0 && d !== ((s = e.data) == null ? void 0 : s.numberOfOpenPlaygroundTabs) && (d = (o = e.data) == null ? void 0 : o.numberOfOpenPlaygroundTabs, r.debug(
281
+ `Number of open Playground tabs is: ${d}`
282
+ ));
283
+ });
284
+ };
285
+ let y = !1;
286
+ const S = (r) => {
287
+ y || (x(r), !(typeof window > "u") && (window.addEventListener(
288
+ "error",
289
+ (e) => T(r, e)
290
+ ), window.addEventListener(
291
+ "unhandledrejection",
292
+ (e) => m(r, e)
293
+ ), window.addEventListener(
294
+ "rejectionhandled",
295
+ (e) => m(r, e)
296
+ ), y = !0));
297
+ }, k = (r) => {
298
+ r.addEventListener("activate", () => {
299
+ r.clients.matchAll().then((e) => {
300
+ const t = {
301
+ numberOfOpenPlaygroundTabs: e.filter(
302
+ // Only count top-level frames to get the number of tabs.
303
+ (s) => s.frameType === "top-level"
304
+ ).length
305
+ };
306
+ for (const s of e)
307
+ s.postMessage(t);
308
+ });
309
+ });
310
+ };
311
+ export {
312
+ v as Logger,
313
+ O as addCrashListener,
314
+ P as collectPhpLogs,
315
+ S as collectWindowErrors,
316
+ L as formatLogEntry,
317
+ B as logger,
318
+ k as reportServiceWorkerMetrics
319
+ };
@@ -0,0 +1,8 @@
1
+ import { UniversalPHP } from '../../universal';
2
+ import { Logger } from '../logger';
3
+ /**
4
+ * Collect PHP logs from the error_log file and log them.
5
+ * @param UniversalPHP playground instance
6
+ * @param loggerInstance The logger instance
7
+ */
8
+ export declare const collectPhpLogs: (loggerInstance: Logger, playground: UniversalPHP) => void;
@@ -0,0 +1,12 @@
1
+ /// <reference lib="webworker" />
2
+ /**
3
+ * **Call this inside a service worker.**
4
+ * These errors include Playground errors like Asyncify errors. PHP errors won't trigger this event.
5
+ *
6
+ * Reports service worker metrics.
7
+ * Allows the logger to request metrics from the service worker by sending a message.
8
+ * The service worker will respond with the number of open Playground tabs.
9
+ *
10
+ * @param worker The service worker
11
+ */
12
+ export declare const reportServiceWorkerMetrics: (worker: ServiceWorkerGlobalScope) => void;
@@ -0,0 +1,6 @@
1
+ import { Logger } from '../logger';
2
+ /**
3
+ * Collect errors from JavaScript window events like error and log them.
4
+ * @param loggerInstance The logger instance
5
+ */
6
+ export declare const collectWindowErrors: (loggerInstance: Logger) => void;
@@ -0,0 +1,5 @@
1
+ import { LogHandler } from '../log-handlers';
2
+ /**
3
+ * Log message to the console.
4
+ */
5
+ export declare const logToConsole: LogHandler;
@@ -0,0 +1,7 @@
1
+ import { LogHandler } from '../log-handlers';
2
+ export declare const logs: string[];
3
+ /**
4
+ * Log to memory
5
+ */
6
+ export declare const logToMemory: LogHandler;
7
+ export declare const clearMemoryLogs: () => void;
@@ -0,0 +1,3 @@
1
+ export * from './collectors/collect-php-logs';
2
+ export * from './collectors/collect-window-errors';
3
+ export * from './collectors/collect-service-worker-metrics';
@@ -0,0 +1,6 @@
1
+ import { Log } from './logger';
2
+ export interface LogHandler {
3
+ (log: Log, ...args: any[]): void;
4
+ }
5
+ export * from './handlers/log-to-console';
6
+ export * from './handlers/log-to-memory';
package/lib/logger.d.ts CHANGED
@@ -1,5 +1,9 @@
1
- /// <reference lib="webworker" />
2
- import { UniversalPHP } from '../../../universal/src/index.ts/src/lib/universal-php';
1
+ export type Log = {
2
+ message: any;
3
+ severity?: LogSeverity;
4
+ prefix?: LogPrefix;
5
+ raw?: boolean;
6
+ };
3
7
  /**
4
8
  * Log severity levels.
5
9
  */
@@ -7,131 +11,69 @@ export type LogSeverity = 'Debug' | 'Info' | 'Warn' | 'Error' | 'Fatal';
7
11
  /**
8
12
  * Log prefix.
9
13
  */
10
- export type LogPrefix = 'Playground' | 'PHP-WASM';
14
+ export type LogPrefix = 'WASM Crash' | 'PHP' | 'JavaScript';
11
15
  /**
12
16
  * A logger for Playground.
13
17
  */
14
18
  export declare class Logger extends EventTarget {
19
+ private readonly handlers;
15
20
  readonly fatalErrorEvent = "playground-fatal-error";
21
+ constructor(handlers?: Function[]);
16
22
  /**
17
- * Log messages
18
- */
19
- private logs;
20
- /**
21
- * Whether the window events are connected.
22
- */
23
- private windowConnected;
24
- /**
25
- * The length of the last PHP log.
26
- */
27
- private lastPHPLogLength;
28
- /**
29
- * Context data
30
- */
31
- private context;
32
- /**
33
- * The path to the error log file.
23
+ * Get all logs.
24
+ * @returns string[]
34
25
  */
35
- private errorLogPath;
36
- constructor(errorLogPath?: string);
26
+ getLogs(): string[];
37
27
  /**
38
- * Read the WordPress debug.log file and return its content.
28
+ * Log message with severity.
39
29
  *
40
- * @param UniversalPHP playground instance
41
- * @returns string The content of the debug.log file
30
+ * @param message any
31
+ * @param severity LogSeverity
32
+ * @param raw boolean
33
+ * @param args any
42
34
  */
43
- private getRequestPhpErrorLog;
35
+ logMessage(log: Log, ...args: any[]): void;
44
36
  /**
45
- * Log Windows errors.
37
+ * Log message
46
38
  *
47
- * @param ErrorEvent event
39
+ * @param message any
40
+ * @param args any
48
41
  */
49
- private logWindowError;
42
+ log(message: any, ...args: any[]): void;
50
43
  /**
51
- * Log unhandled promise rejections.
44
+ * Log debug message
52
45
  *
53
- * @param PromiseRejectionEvent event
54
- */
55
- private logUnhandledRejection;
56
- /**
57
- * Register a listener for the window error events and log the data.
58
- */
59
- addWindowErrorListener(): void;
60
- /**
61
- * Register a listener for service worker messages and log the data.
62
- * The service worker will send the number of open Playground tabs.
46
+ * @param message any
47
+ * @param args any
63
48
  */
64
- addServiceWorkerMessageListener(): void;
49
+ debug(message: any, ...args: any[]): void;
65
50
  /**
66
- * Register a listener for the request.end event and log the data.
67
- * @param UniversalPHP playground instance
68
- */
69
- addPlaygroundRequestEndListener(playground: UniversalPHP): void;
70
- /**
71
- * Get UTC date in the PHP log format https://github.com/php/php-src/blob/master/main/main.c#L849
51
+ * Log info message
72
52
  *
73
- * @param date
74
- * @returns string
75
- */
76
- private formatLogDate;
77
- /**
78
- * Format log message and severity and log it.
79
- * @param string message
80
- * @param LogSeverity severity
81
- * @param string prefix
82
- */
83
- formatMessage(message: string, severity: LogSeverity, prefix: string): string;
84
- /**
85
- * Log message with severity and timestamp.
86
- * @param string message
87
- * @param LogSeverity severity
88
- * @param string prefix
89
- */
90
- log(message: string, severity?: LogSeverity, prefix?: LogPrefix): void;
91
- /**
92
- * Log message without severity and timestamp.
93
- * @param string log
94
- */
95
- logRaw(log: string): void;
96
- /**
97
- * Get all logs.
98
- * @returns string[]
53
+ * @param message any
54
+ * @param args any
99
55
  */
100
- getLogs(): string[];
56
+ info(message: any, ...args: any[]): void;
101
57
  /**
102
- * Add context data.
58
+ * Log warning message
59
+ *
60
+ * @param message any
61
+ * @param args any
103
62
  */
104
- addContext(data: Record<string, any>): void;
63
+ warn(message: any, ...args: any[]): void;
105
64
  /**
106
- * Get context data.
65
+ * Log error message
66
+ *
67
+ * @param message any
68
+ * @param args any
107
69
  */
108
- getContext(): Record<string, any>;
70
+ error(message: any, ...args: any[]): void;
109
71
  }
110
72
  /**
111
73
  * The logger instance.
112
74
  */
113
75
  export declare const logger: Logger;
114
- /**
115
- * Collect errors from JavaScript window events like error and log them.
116
- * @param loggerInstance The logger instance
117
- */
118
- export declare function collectWindowErrors(loggerInstance: Logger): void;
119
- /**
120
- * Collect PHP logs from the error_log file and log them.
121
- * @param UniversalPHP playground instance
122
- * @param loggerInstance The logger instance
123
- */
124
- export declare function collectPhpLogs(loggerInstance: Logger, playground: UniversalPHP): void;
125
- /**
126
- * **Call this inside a service worker.**
127
- *
128
- * Reports service worker metrics.
129
- * Allows the logger to request metrics from the service worker by sending a message.
130
- * The service worker will respond with the number of open Playground tabs.
131
- *
132
- * @param worker The service worker
133
- */
134
- export declare function reportServiceWorkerMetrics(worker: ServiceWorkerGlobalScope): void;
76
+ export declare const formatLogEntry: (message: string, severity: LogSeverity, prefix: string) => string;
135
77
  /**
136
78
  * Add a listener for the Playground crashes.
137
79
  * These crashes include Playground errors like Asyncify errors.
@@ -140,4 +82,4 @@ export declare function reportServiceWorkerMetrics(worker: ServiceWorkerGlobalSc
140
82
  * @param loggerInstance The logger instance
141
83
  * @param callback The callback function
142
84
  */
143
- export declare function addCrashListener(loggerInstance: Logger, callback: EventListenerOrEventListenerObject): void;
85
+ export declare const addCrashListener: (loggerInstance: Logger, callback: EventListenerOrEventListenerObject) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/logger",
3
- "version": "0.7.1",
3
+ "version": "0.7.4",
4
4
  "description": "A logger for PHP-wasm clients like Playground and WP-now.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,11 +19,12 @@
19
19
  "directory": "../../../dist/packages/php-wasm/logger"
20
20
  },
21
21
  "license": "GPL-2.0-or-later",
22
- "main": "index.cjs",
22
+ "type": "module",
23
+ "main": "index.js",
23
24
  "types": "index.d.ts",
24
25
  "engines": {
25
26
  "node": ">=18.18.0",
26
27
  "npm": ">=8.11.0"
27
28
  },
28
- "gitHead": "ed0ec39040ab4cd69dc48a8eac157436b30f9d55"
29
+ "gitHead": "0766eed33879319ed4e0658f8654f7c4270927e4"
29
30
  }
package/index.mjs DELETED
@@ -1,261 +0,0 @@
1
- const u = function() {
2
- var n;
3
- return typeof process < "u" && ((n = process.release) == null ? void 0 : n.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : (
4
- // @ts-ignore
5
- typeof WorkerGlobalScope < "u" && // @ts-ignore
6
- self instanceof WorkerGlobalScope ? "WORKER" : "NODE"
7
- );
8
- }();
9
- if (u === "NODE") {
10
- let n = function(t) {
11
- return new Promise(function(r, o) {
12
- t.onload = t.onerror = function(i) {
13
- t.onload = t.onerror = null, i.type === "load" ? r(t.result) : o(new Error("Failed to read the blob/file"));
14
- };
15
- });
16
- }, e = function() {
17
- const t = new Uint8Array([1, 2, 3, 4]), o = new File([t], "test").stream();
18
- try {
19
- return o.getReader({ mode: "byob" }), !0;
20
- } catch {
21
- return !1;
22
- }
23
- };
24
- if (typeof File > "u") {
25
- class t extends Blob {
26
- constructor(o, i, a) {
27
- super(o);
28
- let s;
29
- a != null && a.lastModified && (s = /* @__PURE__ */ new Date()), (!s || isNaN(s.getFullYear())) && (s = /* @__PURE__ */ new Date()), this.lastModifiedDate = s, this.lastModified = s.getMilliseconds(), this.name = i || "";
30
- }
31
- }
32
- global.File = t;
33
- }
34
- typeof Blob.prototype.arrayBuffer > "u" && (Blob.prototype.arrayBuffer = function() {
35
- const r = new FileReader();
36
- return r.readAsArrayBuffer(this), n(r);
37
- }), typeof Blob.prototype.text > "u" && (Blob.prototype.text = function() {
38
- const r = new FileReader();
39
- return r.readAsText(this), n(r);
40
- }), (typeof Blob.prototype.stream > "u" || !e()) && (Blob.prototype.stream = function() {
41
- let t = 0;
42
- const r = this;
43
- return new ReadableStream({
44
- type: "bytes",
45
- // 0.5 MB seems like a reasonable chunk size, let's adjust
46
- // this if needed.
47
- autoAllocateChunkSize: 512 * 1024,
48
- async pull(o) {
49
- const i = o.byobRequest.view, s = await r.slice(
50
- t,
51
- t + i.byteLength
52
- ).arrayBuffer(), d = new Uint8Array(s);
53
- new Uint8Array(i.buffer).set(d);
54
- const l = d.byteLength;
55
- o.byobRequest.respond(l), t += l, t >= r.size && o.close();
56
- }
57
- });
58
- });
59
- }
60
- if (u === "NODE" && typeof CustomEvent > "u") {
61
- class n extends Event {
62
- constructor(t, r = {}) {
63
- super(t, r), this.detail = r.detail;
64
- }
65
- initCustomEvent() {
66
- }
67
- }
68
- globalThis.CustomEvent = n;
69
- }
70
- class f extends EventTarget {
71
- constructor(e) {
72
- super(), this.fatalErrorEvent = "playground-fatal-error", this.logs = [], this.windowConnected = !1, this.lastPHPLogLength = 0, this.context = {}, this.errorLogPath = "/wordpress/wp-content/debug.log", e && (this.errorLogPath = e);
73
- }
74
- /**
75
- * Read the WordPress debug.log file and return its content.
76
- *
77
- * @param UniversalPHP playground instance
78
- * @returns string The content of the debug.log file
79
- */
80
- async getRequestPhpErrorLog(e) {
81
- return await e.fileExists(this.errorLogPath) ? await e.readFileAsText(this.errorLogPath) : "";
82
- }
83
- /**
84
- * Log Windows errors.
85
- *
86
- * @param ErrorEvent event
87
- */
88
- logWindowError(e) {
89
- this.log(
90
- `${e.message} in ${e.filename} on line ${e.lineno}:${e.colno}`,
91
- "Error"
92
- );
93
- }
94
- /**
95
- * Log unhandled promise rejections.
96
- *
97
- * @param PromiseRejectionEvent event
98
- */
99
- logUnhandledRejection(e) {
100
- if (!(e != null && e.reason))
101
- return;
102
- const t = (e == null ? void 0 : e.reason.stack) ?? e.reason;
103
- this.log(t, "Error");
104
- }
105
- /**
106
- * Register a listener for the window error events and log the data.
107
- */
108
- addWindowErrorListener() {
109
- this.windowConnected || typeof window > "u" || (window.addEventListener("error", this.logWindowError.bind(this)), window.addEventListener(
110
- "unhandledrejection",
111
- this.logUnhandledRejection.bind(this)
112
- ), window.addEventListener(
113
- "rejectionhandled",
114
- this.logUnhandledRejection.bind(this)
115
- ), this.windowConnected = !0);
116
- }
117
- /**
118
- * Register a listener for service worker messages and log the data.
119
- * The service worker will send the number of open Playground tabs.
120
- */
121
- addServiceWorkerMessageListener() {
122
- navigator.serviceWorker.addEventListener("message", (e) => {
123
- var t;
124
- ((t = e.data) == null ? void 0 : t.numberOfOpenPlaygroundTabs) !== void 0 && this.addContext({
125
- numberOfOpenPlaygroundTabs: e.data.numberOfOpenPlaygroundTabs
126
- });
127
- });
128
- }
129
- /**
130
- * Register a listener for the request.end event and log the data.
131
- * @param UniversalPHP playground instance
132
- */
133
- addPlaygroundRequestEndListener(e) {
134
- e.addEventListener("request.end", async () => {
135
- const t = await this.getRequestPhpErrorLog(e);
136
- t.length > this.lastPHPLogLength && (this.logRaw(t.substring(this.lastPHPLogLength)), this.lastPHPLogLength = t.length);
137
- }), e.addEventListener("request.error", (t) => {
138
- t = t, t.error && (this.log(
139
- `${t.error.message} ${t.error.stack}`,
140
- "Fatal",
141
- "PHP-WASM"
142
- ), this.dispatchEvent(
143
- new CustomEvent(this.fatalErrorEvent, {
144
- detail: {
145
- logs: this.getLogs(),
146
- source: t.source
147
- }
148
- })
149
- ));
150
- });
151
- }
152
- /**
153
- * Get UTC date in the PHP log format https://github.com/php/php-src/blob/master/main/main.c#L849
154
- *
155
- * @param date
156
- * @returns string
157
- */
158
- formatLogDate(e) {
159
- const t = new Intl.DateTimeFormat("en-GB", {
160
- year: "numeric",
161
- month: "short",
162
- day: "2-digit",
163
- timeZone: "UTC"
164
- }).format(e).replace(/ /g, "-"), r = new Intl.DateTimeFormat("en-GB", {
165
- hour: "2-digit",
166
- minute: "2-digit",
167
- second: "2-digit",
168
- hour12: !1,
169
- timeZone: "UTC",
170
- timeZoneName: "short"
171
- }).format(e);
172
- return t + " " + r;
173
- }
174
- /**
175
- * Format log message and severity and log it.
176
- * @param string message
177
- * @param LogSeverity severity
178
- * @param string prefix
179
- */
180
- formatMessage(e, t, r) {
181
- return `[${this.formatLogDate(/* @__PURE__ */ new Date())}] ${r} ${t}: ${e}`;
182
- }
183
- /**
184
- * Log message with severity and timestamp.
185
- * @param string message
186
- * @param LogSeverity severity
187
- * @param string prefix
188
- */
189
- log(e, t, r) {
190
- t === void 0 && (t = "Info");
191
- const o = this.formatMessage(
192
- e,
193
- t,
194
- r ?? "Playground"
195
- );
196
- this.logRaw(o);
197
- }
198
- /**
199
- * Log message without severity and timestamp.
200
- * @param string log
201
- */
202
- logRaw(e) {
203
- this.logs.push(e), console.debug(e);
204
- }
205
- /**
206
- * Get all logs.
207
- * @returns string[]
208
- */
209
- getLogs() {
210
- return [...this.logs];
211
- }
212
- /**
213
- * Add context data.
214
- */
215
- addContext(e) {
216
- this.context = { ...this.context, ...e };
217
- }
218
- /**
219
- * Get context data.
220
- */
221
- getContext() {
222
- return { ...this.context };
223
- }
224
- }
225
- const c = new f();
226
- function h(n) {
227
- n.addWindowErrorListener(), n.addServiceWorkerMessageListener();
228
- }
229
- function g(n, e) {
230
- n.addPlaygroundRequestEndListener(e);
231
- }
232
- function m(n) {
233
- n.addEventListener("activate", () => {
234
- n.clients.matchAll().then((e) => {
235
- const t = {
236
- numberOfOpenPlaygroundTabs: e.filter(
237
- // Only count top-level frames to get the number of tabs.
238
- (r) => r.frameType === "top-level"
239
- ).length
240
- };
241
- n.clients.matchAll({
242
- // We don't claim the clients, so we need to include uncontrolled clients to inform all tabs.
243
- includeUncontrolled: !0
244
- }).then((r) => {
245
- for (const o of r)
246
- o.postMessage(t);
247
- });
248
- });
249
- });
250
- }
251
- function w(n, e) {
252
- n.addEventListener(n.fatalErrorEvent, e);
253
- }
254
- export {
255
- f as Logger,
256
- w as addCrashListener,
257
- g as collectPhpLogs,
258
- h as collectWindowErrors,
259
- c as logger,
260
- m as reportServiceWorkerMetrics
261
- };