peakflow-api 0.0.0 → 0.0.1

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/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "peakflow-api",
3
- "version": "0.0.0",
3
+ "version": "0.0.1",
4
4
  "type": "module",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
7
7
  "scripts": {
8
+ "all-checks": "npm run lint && npm run typecheck && npm test",
8
9
  "build": "tsc --project tsconfig.json && node scripts/minify.mjs",
9
10
  "lint": "eslint .",
10
11
  "release:patch": "npm version patch -m \"chore: release patch\" && git push origin master --follow-tags && npm publish",
@@ -13,7 +14,7 @@
13
14
  },
14
15
  "devDependencies": {
15
16
  "@kaspernj/api-maker": "^1.0.2062",
16
- "@types/node": "^20.0.0",
17
+ "@types/node": "^20.19.27",
17
18
  "eslint": "^9.0.0",
18
19
  "eslint-plugin-jsdoc": "^48.0.0",
19
20
  "jasmine": "^5.1.0",
@@ -35,9 +35,6 @@ export default class BugReporting {
35
35
  this.collectParamsCallback = callback
36
36
  }
37
37
 
38
- /**
39
- * Initialize global error handlers.
40
- */
41
38
  /**
42
39
  * Initialize error handlers based on the runtime.
43
40
  */
@@ -241,7 +238,7 @@ export default class BugReporting {
241
238
 
242
239
  connectNodeUnhandledRejection() {
243
240
  globalThis.process.on("unhandledRejection", async (reason) => {
244
- debuggerInstance.debug(`Unhandled rejection: ${JSON.stringify(reason?.message || reason)}`)
241
+ debuggerInstance.debug(`Unhandled rejection: ${JSON.stringify(reason instanceof Error ? reason.message : reason)}`)
245
242
 
246
243
  if (!this.isHandlingError) {
247
244
  this.isHandlingError = true
@@ -252,7 +249,7 @@ export default class BugReporting {
252
249
  errorClass: "UnhandledRejection",
253
250
  file: null,
254
251
  line: null,
255
- message: reason?.message || String(reason),
252
+ message: reason instanceof Error ? reason.message : String(reason),
256
253
  url: null
257
254
  })
258
255
  } finally {
@@ -330,21 +327,15 @@ export default class BugReporting {
330
327
  debuggerInstance.debug("Resolved environment", postData.error.environment)
331
328
  }
332
329
 
333
- if (typeof XMLHttpRequest === "undefined") {
334
- debuggerInstance.debug("Skipping error report because XMLHttpRequest is unavailable")
330
+ const responseText = await this.sendErrorReport(postUrl, postData)
331
+
332
+ if (responseText == null) {
335
333
  return
336
334
  }
337
335
 
338
- const xhr = new XMLHttpRequest()
339
-
340
- xhr.open("POST", postUrl, true)
341
- xhr.setRequestHeader("Content-Type", "application/json")
342
-
343
- await this.loadXhr(xhr, JSON.stringify(postData))
336
+ debuggerInstance.debug(`Data received: ${responseText}`)
344
337
 
345
- debuggerInstance.debug(`Data received: ${xhr.responseText}`)
346
-
347
- const response = JSON.parse(digg(xhr, "responseText"))
338
+ const response = JSON.parse(digg({responseText}, "responseText"))
348
339
 
349
340
  // If the account has run out of bug reports, then this can potentially crash because 'url' wont be present.
350
341
  if (response.url) {
@@ -390,6 +381,77 @@ export default class BugReporting {
390
381
  })
391
382
  }
392
383
 
384
+ /**
385
+ * Send error report using the best available transport.
386
+ * @param {string} postUrl
387
+ * @param {object} postData
388
+ * @returns {Promise<string|null>}
389
+ */
390
+ async sendErrorReport(postUrl, postData) {
391
+ const body = JSON.stringify(postData)
392
+
393
+ if (typeof XMLHttpRequest !== "undefined") {
394
+ const xhr = new XMLHttpRequest()
395
+
396
+ xhr.open("POST", postUrl, true)
397
+ xhr.setRequestHeader("Content-Type", "application/json")
398
+
399
+ await this.loadXhr(xhr, body)
400
+ return xhr.responseText
401
+ } else if (typeof globalThis.fetch === "function") {
402
+ const response = await globalThis.fetch(postUrl, {
403
+ method: "POST",
404
+ headers: {"Content-Type": "application/json"},
405
+ body
406
+ })
407
+
408
+ return await response.text()
409
+ } else if (this.isNode()) {
410
+ return await this.sendNodeRequest(postUrl, body)
411
+ }
412
+
413
+ debuggerInstance.debug("Skipping error report because no HTTP transport is available")
414
+ return null
415
+ }
416
+
417
+ /**
418
+ * Send an HTTP request using Node's built-in modules.
419
+ * @param {string} postUrl
420
+ * @param {string} body
421
+ * @returns {Promise<string|null>}
422
+ */
423
+ async sendNodeRequest(postUrl, body) {
424
+ const {request} = await import("node:https")
425
+ const {URL} = await import("node:url")
426
+
427
+ return await new Promise((resolve) => {
428
+ const url = new URL(postUrl)
429
+
430
+ const req = request({
431
+ protocol: url.protocol,
432
+ hostname: url.hostname,
433
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
434
+ path: `${url.pathname}${url.search}`,
435
+ method: "POST",
436
+ headers: {
437
+ "Content-Type": "application/json",
438
+ "Content-Length": Buffer.byteLength(body)
439
+ }
440
+ }, (res) => {
441
+ let data = ""
442
+ res.setEncoding("utf8")
443
+ res.on("data", (chunk) => {
444
+ data += chunk
445
+ })
446
+ res.on("end", () => resolve(data))
447
+ })
448
+
449
+ req.on("error", () => resolve(null))
450
+ req.write(body)
451
+ req.end()
452
+ })
453
+ }
454
+
393
455
  /**
394
456
  * Resolve environment data for a report.
395
457
  * @param {object} args
package/tsconfig.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "inlineSourceMap": true,
14
14
  "noEmitOnError": true,
15
15
  "strict": false,
16
- "types": []
16
+ "types": ["node"]
17
17
  },
18
18
  "include": ["src/**/*.js"]
19
19
  }