peakflow-api 0.0.0 → 0.0.5

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/AGENTS.md CHANGED
@@ -23,5 +23,7 @@ This repo hosts the Peakflow JavaScript client for error reporting across browse
23
23
  ## Notes for Agents
24
24
  - Avoid adding global browser dependencies unless guarded by runtime checks.
25
25
  - When changing API exports, update `README.md` examples.
26
+ - `.js` files should always have JSDoc comments to keep TypeScript checks happy.
27
+ - Use `gh` to open pull requests when requested.
26
28
  - Keep JSDoc accurate; TypeScript checks JS via `checkJs`.
27
29
  - Ensure new browser-only logic is opt-in and documented.
package/README.md CHANGED
@@ -51,3 +51,12 @@ const bugReporting = new BugReporting({authToken: "your-token"})
51
51
 
52
52
  bugReporting.connectExpoErrorHandlers()
53
53
  ```
54
+
55
+ ## CLI
56
+
57
+ ```sh
58
+ npx peakflow-api login
59
+ npx peakflow-api build-logs --latest-build-group --failing
60
+ ```
61
+
62
+ The CLI stores credentials in `.peakflow-api/credentials.json` at the git root and uses the current branch by default.
@@ -13,6 +13,7 @@ export default class BugReporting {
13
13
  collectEnvironmentCallback: (args: object) => Promise<object> | object;
14
14
  collectParamsCallback: (args: object) => Promise<object> | object;
15
15
  sourceMapsLoader: SourceMapsLoader;
16
+ envSenseResult: import("env-sense/build/types.js").EnvSenseResult;
16
17
  /**
17
18
  * Register a callback to resolve environment metadata.
18
19
  * @param {(args: object) => Promise<object>|object} callback
@@ -23,14 +24,20 @@ export default class BugReporting {
23
24
  * @param {(args: object) => Promise<object>|object} callback
24
25
  */
25
26
  collectParams(callback: (args: object) => Promise<object> | object): void;
26
- /**
27
- * Initialize global error handlers.
28
- */
29
27
  /**
30
28
  * Initialize error handlers based on the runtime.
31
29
  */
32
30
  connect(): void;
33
31
  isHandlingError: boolean;
32
+ /**
33
+ * Resolve environment flags using env-sense.
34
+ * @returns {{isBrowser: boolean, isNative: boolean, isServer: boolean}}
35
+ */
36
+ getEnvSense(): {
37
+ isBrowser: boolean;
38
+ isNative: boolean;
39
+ isServer: boolean;
40
+ };
34
41
  /**
35
42
  * Check if the runtime looks like a browser environment.
36
43
  * @returns {boolean}
@@ -110,6 +117,20 @@ export default class BugReporting {
110
117
  * @returns {Promise<void>}
111
118
  */
112
119
  loadXhr(xhr: XMLHttpRequest, postData: string): Promise<void>;
120
+ /**
121
+ * Send error report using the best available transport.
122
+ * @param {string} postUrl
123
+ * @param {object} postData
124
+ * @returns {Promise<string|null>}
125
+ */
126
+ sendErrorReport(postUrl: string, postData: object): Promise<string | null>;
127
+ /**
128
+ * Send an HTTP request using Node's built-in modules.
129
+ * @param {string} postUrl
130
+ * @param {string} body
131
+ * @returns {Promise<string|null>}
132
+ */
133
+ sendNodeRequest(postUrl: string, body: string): Promise<string | null>;
113
134
  /**
114
135
  * Resolve environment data for a report.
115
136
  * @param {object} args
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bug-reporting/index.js"],"names":[],"mappings":"AAMA;;GAEG;AACH;IACE;;OAEG;IACH,kBAFW;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,EAQ7B;IALC,kBAA+B;IAC/B,iBAAoB;IACpB,mCAOgB,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,CAPN;IAC3C,8BAcgB,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,CAdX;IACtC,mCAA4B;IAG9B;;;OAGG;IACH,6BAFW,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,QAIlD;IAED;;;OAGG;IACH,wBAFW,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,QAIlD;IAED;;OAEG;IACH;;OAEG;IACH,gBAmBC;IAjBC,yBAA4B;IAmB9B;;;OAGG;IACH,aAFa,OAAO,CAInB;IAED;;;OAGG;IACH,UAFa,OAAO,CAInB;IAED;;;OAGG;IACH,UAFa,OAAO,CAInB;IAED;;;OAGG;IACH,0BAFa,OAAO,CA0BnB;IAED;;OAEG;IACH,uBAyBC;IAED;;OAEG;IACH,kCAqBC;IAED;;;OAGG;IACH,4BAFa,OAAO,CAqCnB;IAED;;OAEG;IACH,qCAqBC;IAED,sCAqBC;IAED;;;;;;;;;;OAUG;IACH,kBAPG;QAA6B,KAAK;iCAFM,MAAM;kCAAwB,MAAM;;QAGtD,UAAU,GAAxB,MAAM;QACa,IAAI,GAAvB,MAAM,GAAC,IAAI;QACQ,IAAI,GAAvB,MAAM,GAAC,IAAI;QACE,OAAO,EAApB,MAAM;QACY,GAAG,EAArB,MAAM,GAAC,IAAI;KACrB,iBA8EA;IAED;;;OAGG;IACH,qCAFW,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,QAIjE;IADC,6CAHkB,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAGd;IAGpD;;;;OAIG;IACH,aAHW,MAAM,GACJ,iBAAiB,GAAC,IAAI,CAYlC;IAED;;;;;OAKG;IACH,aAJW,cAAc,YACd,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAOzB;IAED;;;;OAIG;IACH,yBAHW,MAAM,GACJ,OAAO,CAAC,MAAM,GAAC,SAAS,CAAC,CAMrC;IAED;;;;OAIG;IACH,oBAHW,MAAM,GACJ,OAAO,CAAC,MAAM,GAAC,SAAS,CAAC,CASrC;IAED;;;OAGG;IACH,kBAFW,OAAO,QAIjB;CACF;6BApa4B,iDAAiD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bug-reporting/index.js"],"names":[],"mappings":"AAOA;;GAEG;AACH;IACE;;OAEG;IACH,kBAFW;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,EAS7B;IANC,kBAA+B;IAC/B,iBAAoB;IACpB,mCAQgB,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,CARN;IAC3C,8BAegB,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,CAfX;IACtC,mCAA4B;IAC5B,kEAA0B;IAG5B;;;OAGG;IACH,6BAFW,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,QAIlD;IAED;;;OAGG;IACH,wBAFW,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAC,MAAM,QAIlD;IAED;;OAEG;IACH,gBAmBC;IAjBC,yBAA4B;IAmB9B;;;OAGG;IACH,eAFa;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAC,CAQtE;IAED;;;OAGG;IACH,aAFa,OAAO,CAInB;IAED;;;OAGG;IACH,UAFa,OAAO,CAInB;IAED;;;OAGG;IACH,UAFa,OAAO,CAInB;IAED;;;OAGG;IACH,0BAFa,OAAO,CA0BnB;IAED;;OAEG;IACH,uBAyBC;IAED;;OAEG;IACH,kCAqBC;IAED;;;OAGG;IACH,4BAFa,OAAO,CA0CnB;IAED;;OAEG;IACH,qCAqBC;IAED,sCAqBC;IAED;;;;;;;;;;OAUG;IACH,kBAPG;QAA6B,KAAK;iCAFM,MAAM;kCAAwB,MAAM;;QAGtD,UAAU,GAAxB,MAAM;QACa,IAAI,GAAvB,MAAM,GAAC,IAAI;QACQ,IAAI,GAAvB,MAAM,GAAC,IAAI;QACE,OAAO,EAApB,MAAM;QACY,GAAG,EAArB,MAAM,GAAC,IAAI;KACrB,iBAwEA;IAED;;;OAGG;IACH,qCAFW,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,QAIjE;IADC,6CAHkB,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAGd;IAGpD;;;;OAIG;IACH,aAHW,MAAM,GACJ,iBAAiB,GAAC,IAAI,CAYlC;IAED;;;;;OAKG;IACH,aAJW,cAAc,YACd,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAOzB;IAED;;;;;OAKG;IACH,yBAJW,MAAM,YACN,MAAM,GACJ,OAAO,CAAC,MAAM,GAAC,IAAI,CAAC,CA2BhC;IAED;;;;;OAKG;IACH,yBAJW,MAAM,QACN,MAAM,GACJ,OAAO,CAAC,MAAM,GAAC,IAAI,CAAC,CAgChC;IAED;;;;OAIG;IACH,yBAHW,MAAM,GACJ,OAAO,CAAC,MAAM,GAAC,SAAS,CAAC,CAMrC;IAED;;;;OAIG;IACH,oBAHW,MAAM,GACJ,OAAO,CAAC,MAAM,GAAC,SAAS,CAAC,CASrC;IAED;;;OAGG;IACH,kBAFW,OAAO,QAIjB;CACF;6BApf4B,iDAAiD"}
@@ -1,2 +1,2 @@
1
- import{digg as r}from"diggerize";import e from"qs";import o from"./variables.js";import{debuggerInstance as n}from"../debugger.js";import s from"@kaspernj/api-maker/build/source-maps-loader.js";export default class a{constructor(r){this.authToken=r.authToken,this.testing=!1,this.collectEnvironmentCallback=void 0,this.collectParamsCallback=void 0,this.sourceMapsLoader=null}collectEnvironment(r){this.collectEnvironmentCallback=r}collectParams(r){this.collectParamsCallback=r}connect(){n.debug("Connecting handler"),this.isHandlingError=!1,this.isBrowser()?(this.connectOnError(),this.connectUnhandledRejection()):n.debug("Skipping browser error handlers outside the browser"),this.isExpo()&&this.connectExpoErrorHandlers(),this.isNode()&&(this.connectNodeUncaughtException(),this.connectNodeUnhandledRejection())}isBrowser(){return void 0!==globalThis.document&&"function"==typeof globalThis.addEventListener}isExpo(){return"function"==typeof globalThis.ErrorUtils?.setGlobalHandler}isNode(){return void 0!==globalThis.process&&"function"==typeof globalThis.process.on}enableSourceMapsLoader(){return"undefined"!=typeof window&&"undefined"!=typeof document&&(this.sourceMapsLoader||(this.sourceMapsLoader=new s),this.sourceMapsLoader.loadSourceMapsForScriptTags(r=>{const e=r.getAttribute("src"),o=r.getAttribute("type");if(this.loadSourceMapForScriptTagsCallback&&e&&("text/javascript"==o||!o)){n.debug(`Loading source map for ${e}`);const o=this.loadSourceMapForScriptTagsCallback(r);if(o)return o}}),!0)}connectOnError(){globalThis.addEventListener("error",async r=>{if(n.debug(`Error cought with message: ${r.message}`),n.debug(`Message: ${r.message}`),n.debug(`File: ${r.filename}`),n.debug(`Line: ${r.lineno}`),n.debug(`Error: ${r.error}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:r.error,errorClass:r.error?.name,file:r.filename,line:r.lineno,message:r.message||"Unknown error",url:globalThis.location?.href})}finally{this.isHandlingError=!1}}})}connectUnhandledRejection(){globalThis.addEventListener("unhandledrejection",async r=>{if(n.debug(`Unhandled rejection: ${JSON.stringify(r.reason.message||r.reason)}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:r.reason,errorClass:"UnhandledRejection",file:null,line:null,message:r.reason.message||r.reason||"Unhandled promise rejection",url:globalThis.location?.href})}finally{this.isHandlingError=!1}}})}connectExpoErrorHandlers(){if(!this.isExpo())return!1;const r="function"==typeof globalThis.ErrorUtils.getGlobalHandler?globalThis.ErrorUtils.getGlobalHandler():null;return globalThis.ErrorUtils.setGlobalHandler((e,o)=>{n.debug(`Expo error: ${e?.message||e}`),this.isHandlingError||(this.isHandlingError=!0,Promise.resolve(this.handleError({error:e,errorClass:e?.name||(o?"FatalError":"ExpoError"),file:null,line:null,message:e?.message||String(e),url:null})).finally(()=>{this.isHandlingError=!1})),r&&r(e,o)}),!0}connectNodeUncaughtException(){globalThis.process.on("uncaughtException",async r=>{if(n.debug(`Uncaught exception: ${r?.message||r}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:r,errorClass:r?.name||"UncaughtException",file:null,line:null,message:r?.message||String(r),url:null})}finally{this.isHandlingError=!1}}})}connectNodeUnhandledRejection(){globalThis.process.on("unhandledRejection",async r=>{if(n.debug(`Unhandled rejection: ${JSON.stringify(r?.message||r)}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:r instanceof Error?r:void 0,errorClass:"UnhandledRejection",file:null,line:null,message:r?.message||String(r),url:null})}finally{this.isHandlingError=!1}}})}async handleError(e){let s,a;n.debug(`Handle error: ${JSON.stringify(e)}`),e.error&&e.error.stack&&this.sourceMapsLoader?(n.debug("Parse stacktrace"),await this.sourceMapsLoader.loadSourceMaps(e.error),s=this.sourceMapsLoader.parseStackTrace(e.error.stack)):e.error&&e.error.stack?s=[e.error.stack]:e.file&&(n.debug("No stacktrace was present on the error so cant parse it"),s=[`${e.file}:${e.line}`]),n.debug(`AuthToken: ${this.authToken}`),n.debug(`Backtrace: ${s}`);const t=e.errorClass||"UnknownError",i={auth_token:this.authToken,error:{backtrace:s,error_class:t,message:e.message,url:e.url,user_agent:void 0!==globalThis.navigator&&globalThis.navigator?globalThis.navigator.userAgent:null}};if(a=this.testing?o.bugReportsPath:o.bugReportsUrl,n.debug(`Sending error report to: ${a}`),e.error?.peakflowParameters?i.error.parameters=e.error.peakflowParameters:(n.debug("Resolving params"),i.error.parameters=await this.resolveParams(e),n.debug("Resolved params",i.error.parameters)),e.error?.peakflowEnvironment?i.error.environment=e.error.peakflowEnvironment:(n.debug("Resolving environment"),i.error.environment=await this.resolveEnvironment(e),n.debug("Resolved environment",i.error.environment)),"undefined"==typeof XMLHttpRequest)return void n.debug("Skipping error report because XMLHttpRequest is unavailable");const l=new XMLHttpRequest;l.open("POST",a,!0),l.setRequestHeader("Content-Type","application/json"),await this.loadXhr(l,JSON.stringify(i)),n.debug(`Data received: ${l.responseText}`);const c=JSON.parse(r(l,"responseText"));c.url&&console.log(`Peakflow: Error was reported: ${r(c,"url")}`)}loadSourceMapForScriptTags(r){this.loadSourceMapForScriptTagsCallback=r}loadUrl(r){if(!this.isBrowser())return null;const e=globalThis.document.createElement("a");return e.href=r,e}loadXhr(r,e){return new Promise(o=>{r.onload=()=>o(),r.send(e)})}async resolveEnvironment(r){if(this.collectEnvironmentCallback)return await this.collectEnvironmentCallback(r)}async resolveParams(r){if(this.collectParamsCallback)return await this.collectParamsCallback(r);if("object"==typeof globalThis.location&&globalThis.location){const r="string"==typeof globalThis.location.search?globalThis.location.search:"";return e.parse(r.substr(1))}}setTesting(r){this.testing=r}}
2
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJkaWdnIiwicXMiLCJSYWlsc1ZhcmlhYmxlcyIsImRlYnVnZ2VySW5zdGFuY2UiLCJTb3VyY2VNYXBzTG9hZGVyIiwiQnVnUmVwb3J0aW5nIiwiY29uc3RydWN0b3IiLCJkYXRhIiwidGhpcyIsImF1dGhUb2tlbiIsInRlc3RpbmciLCJjb2xsZWN0RW52aXJvbm1lbnRDYWxsYmFjayIsInVuZGVmaW5lZCIsImNvbGxlY3RQYXJhbXNDYWxsYmFjayIsInNvdXJjZU1hcHNMb2FkZXIiLCJjb2xsZWN0RW52aXJvbm1lbnQiLCJjYWxsYmFjayIsImNvbGxlY3RQYXJhbXMiLCJjb25uZWN0IiwiZGVidWciLCJpc0hhbmRsaW5nRXJyb3IiLCJpc0Jyb3dzZXIiLCJjb25uZWN0T25FcnJvciIsImNvbm5lY3RVbmhhbmRsZWRSZWplY3Rpb24iLCJpc0V4cG8iLCJjb25uZWN0RXhwb0Vycm9ySGFuZGxlcnMiLCJpc05vZGUiLCJjb25uZWN0Tm9kZVVuY2F1Z2h0RXhjZXB0aW9uIiwiY29ubmVjdE5vZGVVbmhhbmRsZWRSZWplY3Rpb24iLCJnbG9iYWxUaGlzIiwiZG9jdW1lbnQiLCJhZGRFdmVudExpc3RlbmVyIiwiRXJyb3JVdGlscyIsInNldEdsb2JhbEhhbmRsZXIiLCJwcm9jZXNzIiwib24iLCJlbmFibGVTb3VyY2VNYXBzTG9hZGVyIiwid2luZG93IiwibG9hZFNvdXJjZU1hcHNGb3JTY3JpcHRUYWdzIiwic2NyaXB0Iiwic3JjIiwiZ2V0QXR0cmlidXRlIiwidHlwZSIsImxvYWRTb3VyY2VNYXBGb3JTY3JpcHRUYWdzQ2FsbGJhY2siLCJyZXN1bHQiLCJhc3luYyIsImV2ZW50IiwibWVzc2FnZSIsImZpbGVuYW1lIiwibGluZW5vIiwiZXJyb3IiLCJoYW5kbGVFcnJvciIsImVycm9yQ2xhc3MiLCJuYW1lIiwiZmlsZSIsImxpbmUiLCJ1cmwiLCJsb2NhdGlvbiIsImhyZWYiLCJKU09OIiwic3RyaW5naWZ5IiwicmVhc29uIiwicHJldmlvdXNIYW5kbGVyIiwiZ2V0R2xvYmFsSGFuZGxlciIsImlzRmF0YWwiLCJQcm9taXNlIiwicmVzb2x2ZSIsIlN0cmluZyIsImZpbmFsbHkiLCJFcnJvciIsImJhY2t0cmFjZSIsInBvc3RVcmwiLCJzdGFjayIsImxvYWRTb3VyY2VNYXBzIiwicGFyc2VTdGFja1RyYWNlIiwicG9zdERhdGEiLCJhdXRoX3Rva2VuIiwiZXJyb3JfY2xhc3MiLCJ1c2VyX2FnZW50IiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiYnVnUmVwb3J0c1BhdGgiLCJidWdSZXBvcnRzVXJsIiwicGVha2Zsb3dQYXJhbWV0ZXJzIiwicGFyYW1ldGVycyIsInJlc29sdmVQYXJhbXMiLCJwZWFrZmxvd0Vudmlyb25tZW50IiwiZW52aXJvbm1lbnQiLCJyZXNvbHZlRW52aXJvbm1lbnQiLCJYTUxIdHRwUmVxdWVzdCIsInhociIsIm9wZW4iLCJzZXRSZXF1ZXN0SGVhZGVyIiwibG9hZFhociIsInJlc3BvbnNlVGV4dCIsInJlc3BvbnNlIiwicGFyc2UiLCJjb25zb2xlIiwibG9nIiwibG9hZFNvdXJjZU1hcEZvclNjcmlwdFRhZ3MiLCJsb2FkVXJsIiwicGFyc2VyIiwiY3JlYXRlRWxlbWVudCIsIm9ubG9hZCIsInNlbmQiLCJhcmdzIiwic2VhcmNoIiwic3Vic3RyIiwic2V0VGVzdGluZyIsInZhbHVlIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2J1Zy1yZXBvcnRpbmcvaW5kZXguanMiXSwibWFwcGluZ3MiOiJlQUFRQSxNQUFXLG1CQUNaQyxNQUFRLFlBQ1JDLE1BQW9CLDRDQUNuQkMsTUFBdUIsd0JBQ3hCQyxNQUFzQixpRUFLZixNQUFPQyxFQUluQixXQUFBQyxDQUFZQyxHQUNWQyxLQUFLQyxVQUFZRixFQUFLRSxVQUN0QkQsS0FBS0UsU0FBVSxFQUNmRixLQUFLRyxnQ0FBNkJDLEVBQ2xDSixLQUFLSywyQkFBd0JELEVBQzdCSixLQUFLTSxpQkFBbUIsSUFDMUIsQ0FNQSxrQkFBQUMsQ0FBbUJDLEdBQ2pCUixLQUFLRywyQkFBNkJLLENBQ3BDLENBTUEs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
1
+ import{digg as e}from"diggerize";import r from"qs";import n from"env-sense";import o from"./variables.js";import{debuggerInstance as t}from"../debugger.js";import s from"@kaspernj/api-maker/build/source-maps-loader.js";export default class a{constructor(e){this.authToken=e.authToken,this.testing=!1,this.collectEnvironmentCallback=void 0,this.collectParamsCallback=void 0,this.sourceMapsLoader=null,this.envSenseResult=null}collectEnvironment(e){this.collectEnvironmentCallback=e}collectParams(e){this.collectParamsCallback=e}connect(){t.debug("Connecting handler"),this.isHandlingError=!1,this.isBrowser()?(this.connectOnError(),this.connectUnhandledRejection()):t.debug("Skipping browser error handlers outside the browser"),this.isExpo()&&this.connectExpoErrorHandlers(),this.isNode()&&(this.connectNodeUncaughtException(),this.connectNodeUnhandledRejection())}getEnvSense(){return this.envSenseResult||(this.envSenseResult=n()),this.envSenseResult}isBrowser(){return this.getEnvSense().isBrowser&&"function"==typeof globalThis.addEventListener}isExpo(){return this.getEnvSense().isNative}isNode(){return this.getEnvSense().isServer&&"function"==typeof globalThis.process?.on}enableSourceMapsLoader(){return"undefined"!=typeof window&&"undefined"!=typeof document&&(this.sourceMapsLoader||(this.sourceMapsLoader=new s),this.sourceMapsLoader.loadSourceMapsForScriptTags(e=>{const r=e.getAttribute("src"),n=e.getAttribute("type");if(this.loadSourceMapForScriptTagsCallback&&r&&("text/javascript"==n||!n)){t.debug(`Loading source map for ${r}`);const n=this.loadSourceMapForScriptTagsCallback(e);if(n)return n}}),!0)}connectOnError(){globalThis.addEventListener("error",async e=>{if(t.debug(`Error cought with message: ${e.message}`),t.debug(`Message: ${e.message}`),t.debug(`File: ${e.filename}`),t.debug(`Line: ${e.lineno}`),t.debug(`Error: ${e.error}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:e.error,errorClass:e.error?.name,file:e.filename,line:e.lineno,message:e.message||"Unknown error",url:globalThis.location?.href})}finally{this.isHandlingError=!1}}})}connectUnhandledRejection(){globalThis.addEventListener("unhandledrejection",async e=>{if(t.debug(`Unhandled rejection: ${JSON.stringify(e.reason.message||e.reason)}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:e.reason,errorClass:"UnhandledRejection",file:null,line:null,message:e.reason.message||e.reason||"Unhandled promise rejection",url:globalThis.location?.href})}finally{this.isHandlingError=!1}}})}connectExpoErrorHandlers(){if(!this.isExpo())return!1;if("function"!=typeof globalThis.ErrorUtils?.setGlobalHandler)return t.debug("Expo error handlers are unavailable: ErrorUtils.setGlobalHandler missing"),!1;const e="function"==typeof globalThis.ErrorUtils.getGlobalHandler?globalThis.ErrorUtils.getGlobalHandler():null;return globalThis.ErrorUtils.setGlobalHandler((r,n)=>{t.debug(`Expo error: ${r?.message||r}`),this.isHandlingError||(this.isHandlingError=!0,Promise.resolve(this.handleError({error:r,errorClass:r?.name||(n?"FatalError":"ExpoError"),file:null,line:null,message:r?.message||String(r),url:null})).finally(()=>{this.isHandlingError=!1})),e&&e(r,n)}),!0}connectNodeUncaughtException(){globalThis.process.on("uncaughtException",async e=>{if(t.debug(`Uncaught exception: ${e?.message||e}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:e,errorClass:e?.name||"UncaughtException",file:null,line:null,message:e?.message||String(e),url:null})}finally{this.isHandlingError=!1}}})}connectNodeUnhandledRejection(){globalThis.process.on("unhandledRejection",async e=>{if(t.debug(`Unhandled rejection: ${JSON.stringify(e instanceof Error?e.message:e)}`),!this.isHandlingError){this.isHandlingError=!0;try{await this.handleError({error:e instanceof Error?e:void 0,errorClass:"UnhandledRejection",file:null,line:null,message:e instanceof Error?e.message:String(e),url:null})}finally{this.isHandlingError=!1}}})}async handleError(r){let n,s;t.debug(`Handle error: ${JSON.stringify(r)}`),r.error&&r.error.stack&&this.sourceMapsLoader?(t.debug("Parse stacktrace"),await this.sourceMapsLoader.loadSourceMaps(r.error),n=this.sourceMapsLoader.parseStackTrace(r.error.stack)):r.error&&r.error.stack?n=[r.error.stack]:r.file&&(t.debug("No stacktrace was present on the error so cant parse it"),n=[`${r.file}:${r.line}`]),t.debug(`AuthToken: ${this.authToken}`),t.debug(`Backtrace: ${n}`);const a=r.errorClass||"UnknownError",i={auth_token:this.authToken,error:{backtrace:n,error_class:a,message:r.message,url:r.url,user_agent:void 0!==globalThis.navigator&&globalThis.navigator?globalThis.navigator.userAgent:null}};s=this.testing?o.bugReportsPath:o.bugReportsUrl,t.debug(`Sending error report to: ${s}`),r.error?.peakflowParameters?i.error.parameters=r.error.peakflowParameters:(t.debug("Resolving params"),i.error.parameters=await this.resolveParams(r),t.debug("Resolved params",i.error.parameters)),r.error?.peakflowEnvironment?i.error.environment=r.error.peakflowEnvironment:(t.debug("Resolving environment"),i.error.environment=await this.resolveEnvironment(r),t.debug("Resolved environment",i.error.environment));const l=await this.sendErrorReport(s,i);if(null==l)return;t.debug(`Data received: ${l}`);const c=JSON.parse(e({responseText:l},"responseText"));c.url&&console.log(`Peakflow: Error was reported: ${e(c,"url")}`)}loadSourceMapForScriptTags(e){this.loadSourceMapForScriptTagsCallback=e}loadUrl(e){if(!this.isBrowser())return null;const r=globalThis.document.createElement("a");return r.href=e,r}loadXhr(e,r){return new Promise(n=>{e.onload=()=>n(),e.send(r)})}async sendErrorReport(e,r){const n=JSON.stringify(r);if("undefined"!=typeof XMLHttpRequest){const r=new XMLHttpRequest;return r.open("POST",e,!0),r.setRequestHeader("Content-Type","application/json"),await this.loadXhr(r,n),r.responseText}if("function"==typeof globalThis.fetch){const r=await globalThis.fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:n});return await r.text()}return this.isNode()?await this.sendNodeRequest(e,n):(t.debug("Skipping error report because no HTTP transport is available"),null)}async sendNodeRequest(e,r){const{request:n}=await import("node:https"),{URL:o}=await import("node:url");return await new Promise(t=>{const s=new o(e),a=n({protocol:s.protocol,hostname:s.hostname,port:s.port||("https:"===s.protocol?443:80),path:`${s.pathname}${s.search}`,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r)}},e=>{let r="";e.setEncoding("utf8"),e.on("data",e=>{r+=e}),e.on("end",()=>t(r))});a.on("error",()=>t(null)),a.write(r),a.end()})}async resolveEnvironment(e){if(this.collectEnvironmentCallback)return await this.collectEnvironmentCallback(e)}async resolveParams(e){if(this.collectParamsCallback)return await this.collectParamsCallback(e);if("object"==typeof globalThis.location&&globalThis.location){const e="string"==typeof globalThis.location.search?globalThis.location.search:"";return r.parse(e.substr(1))}}setTesting(e){this.testing=e}}
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJkaWdnIiwicXMiLCJlbnZTZW5zZSIsIlJhaWxzVmFyaWFibGVzIiwiZGVidWdnZXJJbnN0YW5jZSIsIlNvdXJjZU1hcHNMb2FkZXIiLCJCdWdSZXBvcnRpbmciLCJjb25zdHJ1Y3RvciIsImRhdGEiLCJ0aGlzIiwiYXV0aFRva2VuIiwidGVzdGluZyIsImNvbGxlY3RFbnZpcm9ubWVudENhbGxiYWNrIiwidW5kZWZpbmVkIiwiY29sbGVjdFBhcmFtc0NhbGxiYWNrIiwic291cmNlTWFwc0xvYWRlciIsImVudlNlbnNlUmVzdWx0IiwiY29sbGVjdEVudmlyb25tZW50IiwiY2FsbGJhY2siLCJjb2xsZWN0UGFyYW1zIiwiY29ubmVjdCIsImRlYnVnIiwiaXNIYW5kbGluZ0Vycm9yIiwiaXNCcm93c2VyIiwiY29ubmVjdE9uRXJyb3IiLCJjb25uZWN0VW5oYW5kbGVkUmVqZWN0aW9uIiwiaXNFeHBvIiwiY29ubmVjdEV4cG9FcnJvckhhbmRsZXJzIiwiaXNOb2RlIiwiY29ubmVjdE5vZGVVbmNhdWdodEV4Y2VwdGlvbiIsImNvbm5lY3ROb2RlVW5oYW5kbGVkUmVqZWN0aW9uIiwiZ2V0RW52U2Vuc2UiLCJnbG9iYWxUaGlzIiwiYWRkRXZlbnRMaXN0ZW5lciIsImlzTmF0aXZlIiwiaXNTZXJ2ZXIiLCJwcm9jZXNzIiwib24iLCJlbmFibGVTb3VyY2VNYXBzTG9hZGVyIiwid2luZG93IiwiZG9jdW1lbnQiLCJsb2FkU291cmNlTWFwc0ZvclNjcmlwdFRhZ3MiLCJzY3JpcHQiLCJzcmMiLCJnZXRBdHRyaWJ1dGUiLCJ0eXBlIiwibG9hZFNvdXJjZU1hcEZvclNjcmlwdFRhZ3NDYWxsYmFjayIsInJlc3VsdCIsImFzeW5jIiwiZXZlbnQiLCJtZXNzYWdlIiwiZmlsZW5hbWUiLCJsaW5lbm8iLCJlcnJvciIsImhhbmRsZUVycm9yIiwiZXJyb3JDbGFzcyIsIm5hbWUiLCJmaWxlIiwibGluZSIsInVybCIsImxvY2F0aW9uIiwiaHJlZiIsIkpTT04iLCJzdHJpbmdpZnkiLCJyZWFzb24iLCJFcnJvclV0aWxzIiwic2V0R2xvYmFsSGFuZGxlciIsInByZXZpb3VzSGFuZGxlciIsImdldEdsb2JhbEhhbmRsZXIiLCJpc0ZhdGFsIiwiUHJvbWlzZSIsInJlc29sdmUiLCJTdHJpbmciLCJmaW5hbGx5IiwiRXJyb3IiLCJiYWNrdHJhY2UiLCJwb3N0VXJsIiwic3RhY2siLCJsb2FkU291cmNlTWFwcyIsInBhcnNlU3RhY2tUcmFjZSIsInBvc3REYXRhIiwiYXV0aF90b2tlbiIsImVycm9yX2NsYXNzIiwidXNlcl9hZ2VudCIsIm5hdmlnYXRvciIsInVzZXJBZ2VudCIsImJ1Z1JlcG9ydHNQYXRoIiwiYnVnUmVwb3J0c1VybCIsInBlYWtmbG93UGFyYW1ldGVycyIsInBhcmFtZXRlcnMiLCJyZXNvbHZlUGFyYW1zIiwicGVha2Zsb3dFbnZpcm9ubWVudCIsImVudmlyb25tZW50IiwicmVzb2x2ZUVudmlyb25tZW50IiwicmVzcG9uc2VUZXh0Iiwic2VuZEVycm9yUmVwb3J0IiwicmVzcG9uc2UiLCJwYXJzZSIsImNvbnNvbGUiLCJsb2ciLCJsb2FkU291cmNlTWFwRm9yU2NyaXB0VGFncyIsImxvYWRVcmwiLCJwYXJzZXIiLCJjcmVhdGVFbGVtZW50IiwibG9hZFhociIsInhociIsIm9ubG9hZCIsInNlbmQiLCJib2R5IiwiWE1MSHR0cFJlcXVlc3QiLCJvcGVuIiwic2V0UmVxdWVzdEhlYWRlciIsImZldGNoIiwibWV0aG9kIiwiaGVhZGVycyIsInRleHQiLCJzZW5kTm9kZVJlcXVlc3QiLCJyZXF1ZXN0IiwiaW1wb3J0IiwiVVJMIiwicmVxIiwicHJvdG9jb2wiLCJob3N0bmFtZSIsInBvcnQiLCJwYXRoIiwicGF0aG5hbWUiLCJzZWFyY2giLCJCdWZmZXIiLCJieXRlTGVuZ3RoIiwicmVzIiwic2V0RW5jb2RpbmciLCJjaHVuayIsIndyaXRlIiwiZW5kIiwiYXJncyIsInN1YnN0ciIsInNldFRlc3RpbmciLCJ2YWx1ZSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9idWctcmVw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
package/build/cli.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @param {Cli} cli
4
+ * @returns {Promise<void>}
5
+ */
6
+ export function runCli(cli: Cli): Promise<void>;
7
+ export class Cli {
8
+ /**
9
+ * @param {{
10
+ * argv?: string[],
11
+ * env?: NodeJS.ProcessEnv,
12
+ * fetchImpl?: typeof fetch,
13
+ * processImpl?: NodeJS.Process,
14
+ * consoleImpl?: Console
15
+ * }} [options]
16
+ */
17
+ constructor({ argv, env, fetchImpl, processImpl, consoleImpl }?: {
18
+ argv?: string[];
19
+ env?: NodeJS.ProcessEnv;
20
+ fetchImpl?: typeof fetch;
21
+ processImpl?: NodeJS.Process;
22
+ consoleImpl?: Console;
23
+ });
24
+ processImpl: NodeJS.Process;
25
+ consoleImpl: Console;
26
+ argv: string[];
27
+ env: NodeJS.ProcessEnv;
28
+ fetchImpl: typeof fetch;
29
+ parseArgs(argv: any): {
30
+ _: any[];
31
+ };
32
+ runGit(command: any): string;
33
+ getGitRoot(): string;
34
+ getGitRemote(): string;
35
+ getGitBranch(): string;
36
+ normalizeRepo(remote: any): string;
37
+ loadConfig(projectRoot: any): {
38
+ data: any;
39
+ path: string;
40
+ };
41
+ saveConfig(projectRoot: any, data: any): string;
42
+ normalizeHost(host: any): any;
43
+ prompt(question: any): Promise<any>;
44
+ parseBoolean(value: any, defaultValue?: boolean): any;
45
+ ensureFetch(): boolean;
46
+ exit(code: any): void;
47
+ loginCommand(options: any): Promise<void>;
48
+ buildLogsCommand(options: any): Promise<void>;
49
+ help(): void;
50
+ run(): Promise<void>;
51
+ }
52
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.js"],"names":[],"mappings":";AAsUA;;;GAGG;AACH,4BAHW,GAAG,GACD,OAAO,CAAC,IAAI,CAAC,CASzB;AArUD;IACE;;;;;;;;OAQG;IACH,iEARW;QACN,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;QACxB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;QAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;KACtB,EAQH;IALC,4BAAyC;IACzC,qBAAyC;IACzC,eAAkD;IAClD,uBAAsC;IACtC,wBAA8C;IAGhD;;MA2BC;IAED,6BAEC;IAED,qBAEC;IAED,uBAMC;IAED,uBAGC;IAED,mCAiBC;IAED;;;MAWC;IAED,gDAQC;IAED,8BAOC;IAED,oCASC;IAED,sDAcC;IAED,uBAQC;IAED,sBAEC;IAED,0CAyDC;IAED,8CAgEC;IAED,aAEC;IAED,qBAsBC;CACF"}
package/build/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import*as t from"node:fs";import*as e from"node:path";import{execSync as o}from"node:child_process";import*as i from"node:readline";import{pathToFileURL as s}from"node:url";const r=".peakflow-api",n="credentials.json";class l{constructor({argv:t,env:e,fetchImpl:o,processImpl:i,consoleImpl:s}={}){this.processImpl=i||process,this.consoleImpl=s||console,this.argv=t||this.processImpl.argv.slice(2),this.env=e||this.processImpl.env,this.fetchImpl=o||globalThis.fetch}parseArgs(t){const e={_:[]};for(let o=0;o<t.length;o+=1){const i=t[o];if(i.startsWith("--")){const[s,r]=i.slice(2).split("=",2);if(void 0!==r){e[s]=r;continue}const n=t[o+1];n&&!n.startsWith("--")?(e[s]=n,o+=1):e[s]=!0}else e._.push(i)}return e}runGit(t){return o(`git ${t}`,{encoding:"utf8"}).trim()}getGitRoot(){return this.runGit("rev-parse --show-toplevel")}getGitRemote(){try{return this.runGit("remote get-url origin")}catch(t){return this.runGit("config --get remote.origin.url")}}getGitBranch(){const t=this.runGit("rev-parse --abbrev-ref HEAD");return"HEAD"===t?null:t}normalizeRepo(t){if(!t)return null;const e=t.trim(),o=e.match(/^[^@]+@[^:]+:([^/]+)\/([^/]+?)(?:\.git)?$/),i=e.match(/^https?:\/\/[^/]+\/([^/]+)\/([^/]+?)(?:\.git)?$/),s=e.match(/^ssh:\/\/[^@]+@[^/]+\/([^/]+)\/([^/]+?)(?:\.git)?$/),r=e.match(/^([^/]+)\/([^/]+?)(?:\.git)?$/),n=o||i||s||r;return n?`${n[1]}/${n[2]}`:null}loadConfig(o){const i=e.join(o,r,n);return t.existsSync(i)?{data:JSON.parse(t.readFileSync(i,"utf8")),path:i}:null}saveConfig(o,i){const s=e.join(o,r),l=e.join(s,n);return t.mkdirSync(s,{recursive:!0}),t.writeFileSync(l,`${JSON.stringify(i,null,2)}\n`,"utf8"),l}normalizeHost(t){if(!t)return null;const e=t.trim().replace(/\/$/,"");return e.length?e:null}prompt(t){const e=i.createInterface({input:this.processImpl.stdin,output:this.processImpl.stdout});return new Promise(o=>{e.question(t,t=>{e.close(),o(t.trim())})})}parseBoolean(t,e=!1){return void 0===t?e:!0===t||!1===t?t:"string"==typeof t?!["false","0","no","off"].includes(t.toLowerCase()):Boolean(t)}ensureFetch(){return"function"==typeof this.fetchImpl||(this.consoleImpl.error("peakflow-api requires Node.js 18+ for fetch support."),this.exit(1),!1)}exit(t){this.processImpl.exit(t)}async loginCommand(t){if(!this.ensureFetch())return;let e;try{e=this.getGitRoot()}catch(t){return this.consoleImpl.error("Unable to locate a git repository. Run this from a project directory."),void this.exit(1)}const o=t.repo||this.normalizeRepo(this.getGitRemote());if(!o)return this.consoleImpl.error("Unable to resolve a GitHub repo from origin. Use --repo owner/name."),void this.exit(1);let i=this.normalizeHost(t.host||t.url||this.env.PEAKFLOW_API_URL);i||(i=this.normalizeHost(await this.prompt("Peakflow server URL: ")));const s=t.email||this.env.PEAKFLOW_API_EMAIL||await this.prompt("Email: "),r=t.password||this.env.PEAKFLOW_API_PASSWORD||await this.prompt("Password: ");if(!i||!s||!r)return this.consoleImpl.error("Host, email, and password are required."),void this.exit(1);const n=await this.fetchImpl(`${i}/api/cli/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:s,password:r,repo:o})}),l=await n.json().catch(()=>null);if(!n.ok||!l||!1===l.success){const t=l?.errors||[`Request failed with status ${n.status}.`];return this.consoleImpl.error(t.join("\n")),void this.exit(1)}const a=this.saveConfig(e,{host:i,authToken:l.auth_token,repo:l.project?.repo||o});this.consoleImpl.log(`Saved credentials to ${a}`)}async buildLogsCommand(t){if(!this.ensureFetch())return;let e;try{e=this.getGitRoot()}catch(t){return this.consoleImpl.error("Unable to locate a git repository. Run this from a project directory."),void this.exit(1)}const o=this.loadConfig(e);if(!o)return this.consoleImpl.error("Missing .peakflow-api/credentials.json. Run `npx peakflow-api login` first."),void this.exit(1);const i=t.branch||this.getGitBranch();if(!i)return this.consoleImpl.error("Unable to determine git branch. Use --branch to specify one."),void this.exit(1);const s=new URLSearchParams({auth_token:o.data.authToken,branch:i,latest_build_group:this.parseBoolean(t["latest-build-group"],!0).toString(),failing:this.parseBoolean(t.failing).toString()}),r=await this.fetchImpl(`${o.data.host}/api/cli/build_logs?${s.toString()}`),n=await r.json().catch(()=>null);if(!r.ok||!n||!1===n.success){const t=n?.errors||[`Request failed with status ${r.status}.`];return this.consoleImpl.error(t.join("\n")),void this.exit(1)}const l=n.build_group;if(l&&this.consoleImpl.log(`Build group #${l.build_group_no||l.id} (${l.state})`),n.builds&&0!==n.builds.length)for(const t of n.builds){const e=t.name||t.build_identifier||`Build ${t.build_no||t.id}`;this.consoleImpl.log(`\n== ${e} (${t.state}) ==`),t.log&&t.log.length>0?this.processImpl.stdout.write(`${t.log}\n`):this.consoleImpl.log("(no logs)")}else this.consoleImpl.log("No builds matched the requested filters.")}help(){this.consoleImpl.log("peakflow-api CLI\n\nCommands:\n login Authenticate and store credentials\n build-logs --latest-build-group --failing Fetch logs for failing builds\n\nOptions:\n --host/--url, --email, --password, --repo Login parameters\n --branch, --latest-build-group, --failing build-logs filters\n")}async run(){const t=this.parseArgs(this.argv),e=t._[0];e&&"-h"!==e&&"--help"!==e?"login"!==e?"build-logs"!==e?(this.consoleImpl.error(`Unknown command: ${e}`),this.help(),this.exit(1)):await this.buildLogsCommand(t):await this.loginCommand(t):this.help()}}export async function runCli(t){try{await t.run()}catch(e){t.consoleImpl.error(e?.message||e),t.processImpl.exit(1)}}export{l as Cli};if(process.argv[1]){s(t.realpathSync(process.argv[1])).href===import.meta.url&&runCli(new l)}
3
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmcyIsInBhdGgiLCJleGVjU3luYyIsInJlYWRsaW5lIiwicGF0aFRvRmlsZVVSTCIsIkNPTkZJR19ESVJfTkFNRSIsIkNPTkZJR19GSUxFX05BTUUiLCJDbGkiLCJjb25zdHJ1Y3RvciIsImFyZ3YiLCJlbnYiLCJmZXRjaEltcGwiLCJwcm9jZXNzSW1wbCIsImNvbnNvbGVJbXBsIiwidGhpcyIsInByb2Nlc3MiLCJjb25zb2xlIiwic2xpY2UiLCJnbG9iYWxUaGlzIiwiZmV0Y2giLCJwYXJzZUFyZ3MiLCJwYXJzZWQiLCJfIiwiaSIsImxlbmd0aCIsImFyZyIsInN0YXJ0c1dpdGgiLCJrZXkiLCJpbmxpbmVWYWx1ZSIsInNwbGl0IiwidW5kZWZpbmVkIiwibmV4dCIsInB1c2giLCJydW5HaXQiLCJjb21tYW5kIiwiZW5jb2RpbmciLCJ0cmltIiwiZ2V0R2l0Um9vdCIsImdldEdpdFJlbW90ZSIsImVycm9yIiwiZ2V0R2l0QnJhbmNoIiwiYnJhbmNoIiwibm9ybWFsaXplUmVwbyIsInJlbW90ZSIsInRyaW1tZWQiLCJzc2hNYXRjaCIsIm1hdGNoIiwiaHR0cHNNYXRjaCIsInNzaFVybE1hdGNoIiwiZGlyZWN0TWF0Y2giLCJsb2FkQ29uZmlnIiwicHJvamVjdFJvb3QiLCJjb25maWdQYXRoIiwiam9pbiIsImV4aXN0c1N5bmMiLCJkYXRhIiwiSlNPTiIsInBhcnNlIiwicmVhZEZpbGVTeW5jIiwic2F2ZUNvbmZpZyIsImNvbmZpZ0RpciIsIm1rZGlyU3luYyIsInJlY3Vyc2l2ZSIsIndyaXRlRmlsZVN5bmMiLCJzdHJpbmdpZnkiLCJub3JtYWxpemVIb3N0IiwiaG9zdCIsInJlcGxhY2UiLCJwcm9tcHQiLCJxdWVzdGlvbiIsInJsIiwiY3JlYXRlSW50ZXJmYWNlIiwiaW5wdXQiLCJzdGRpbiIsIm91dHB1dCIsInN0ZG91dCIsIlByb21pc2UiLCJyZXNvbHZlIiwiYW5zd2VyIiwiY2xvc2UiLCJwYXJzZUJvb2xlYW4iLCJ2YWx1ZSIsImRlZmF1bHRWYWx1ZSIsImluY2x1ZGVzIiwidG9Mb3dlckNhc2UiLCJCb29sZWFuIiwiZW5zdXJlRmV0Y2giLCJleGl0IiwiY29kZSIsImxvZ2luQ29tbWFuZCIsIm9wdGlvbnMiLCJyZXBvIiwidXJsIiwiUEVBS0ZMT1dfQVBJX1VSTCIsImVtYWlsIiwiUEVBS0ZMT1dfQVBJX0VNQUlMIiwicGFzc3dvcmQiLCJQRUFLRkxPV19BUElfUEFTU1dPUkQiLCJyZXNwb25zZSIsIm1ldGhvZCIsImhlYWRlcnMiLCJib2R5IiwicGF5bG9hZCIsImpzb24iLCJjYXRjaCIsIm9rIiwic3VjY2VzcyIsImVycm9ycyIsInN0YXR1cyIsImF1dGhUb2tlbiIsImF1dGhfdG9rZW4iLCJwcm9qZWN0IiwibG9nIiwiYnVpbGRMb2dzQ29tbWFuZCIsImNvbmZpZyIsInBhcmFtcyIsIlVSTFNlYXJjaFBhcmFtcyIsImxhdGVzdF9idWlsZF9ncm91cCIsInRvU3RyaW5nIiwiZmFpbGluZyIsImJ1aWxkR3JvdXAiLCJidWlsZF9ncm91cCIsImJ1aWxkX2dyb3VwX25vIiwiaWQiLCJzdGF0ZSIsImJ1aWxkcyIsImJ1aWxkIiwibGFiZWwiLCJuYW1lIiwiYnVpbGRfaWRlbnRpZmllciIsImJ1aWxkX25vIiwid3JpdGUiLCJoZWxwIiwicnVuIiwiYXJncyIsImFzeW5jIiwicnVuQ2xpIiwiY2xpIiwibWVzc2FnZSIsInJlYWxwYXRoU3luYyIsImhyZWYiXSwic291cmNlcyI6WyIuLi9zcmMvY2xpLmpzIl0sIm1hcHBpbmdzIjoiO1VBQ1lBLE1BQVEsb0JBQ1JDLE1BQVUsK0JBQ2RDLE1BQWUsK0JBQ1hDLE1BQWMsd0NBQ2xCQyxNQUFvQixXQUU1QixNQUFNQyxFQUFrQixnQkFDbEJDLEVBQW1CLG1CQUl6QixNQUFNQyxFQVVKLFdBQUFDLEVBQVlDLEtBQUNBLEVBQUlDLElBQUVBLEVBQUdDLFVBQUVBLEVBQVNDLFlBQUVBLEVBQVdDLFlBQUVBLEdBQWUsSUFDN0RDLEtBQUtGLFlBQWNBLEdBQWVHLFFBQ2xDRCxLQUFLRCxZQUFjQSxHQUFlRyxRQUNsQ0Ys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
package/package.json CHANGED
@@ -1,19 +1,24 @@
1
1
  {
2
2
  "name": "peakflow-api",
3
- "version": "0.0.0",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
7
+ "bin": {
8
+ "peakflow-api": "build/cli.js"
9
+ },
7
10
  "scripts": {
11
+ "all-checks": "npm run lint && npm run typecheck && npm test",
8
12
  "build": "tsc --project tsconfig.json && node scripts/minify.mjs",
9
13
  "lint": "eslint .",
10
14
  "release:patch": "npm version patch -m \"chore: release patch\" && git push origin master --follow-tags && npm publish",
15
+ "release:patch:publish": "npm run build && npm version patch -m \"chore: release patch\" && git push origin master --follow-tags && npm publish",
11
16
  "typecheck": "tsc --project tsconfig.json --noEmit",
12
17
  "test": "jasmine"
13
18
  },
14
19
  "devDependencies": {
15
20
  "@kaspernj/api-maker": "^1.0.2062",
16
- "@types/node": "^20.0.0",
21
+ "@types/node": "^20.19.27",
17
22
  "eslint": "^9.0.0",
18
23
  "eslint-plugin-jsdoc": "^48.0.0",
19
24
  "jasmine": "^5.1.0",
@@ -25,6 +30,7 @@
25
30
  },
26
31
  "dependencies": {
27
32
  "diggerize": "^1.0.10",
33
+ "env-sense": "^1.0.2",
28
34
  "qs": "^6.14.0"
29
35
  }
30
36
  }
@@ -136,6 +136,10 @@ describe("BugReporting", () => {
136
136
  let previousHandlerCalled = false
137
137
  let globalHandler = null
138
138
 
139
+ Object.defineProperty(globalThis, "navigator", {
140
+ configurable: true,
141
+ value: {userAgent: "test-agent", product: "ReactNative"}
142
+ })
139
143
  globalThis.ErrorUtils = {
140
144
  getGlobalHandler: () => (error, isFatal) => {
141
145
  previousHandlerCalled = true
@@ -0,0 +1,157 @@
1
+ import fs from "node:fs"
2
+ import os from "node:os"
3
+ import path from "node:path"
4
+ import {Cli, runCli} from "../src/cli.js"
5
+
6
+ describe("Cli", () => {
7
+ /**
8
+ * @returns {string}
9
+ */
10
+ const createTempDir = () => fs.mkdtempSync(path.join(os.tmpdir(), "peakflow-cli-"))
11
+
12
+ /**
13
+ * @returns {{
14
+ * logs: string[],
15
+ * errors: string[],
16
+ * consoleImpl: {log: (...args: string[]) => void, error: (...args: string[]) => void}
17
+ * }}
18
+ */
19
+ const createConsole = () => {
20
+ const logs = []
21
+ const errors = []
22
+
23
+ return {
24
+ logs,
25
+ errors,
26
+ consoleImpl: {
27
+ log: (...args) => logs.push(args.join(" ")),
28
+ error: (...args) => errors.push(args.join(" "))
29
+ }
30
+ }
31
+ }
32
+
33
+ /**
34
+ * @returns {{
35
+ * writes: string[],
36
+ * processImpl: {
37
+ * stdout: {write: (text: string) => void},
38
+ * stdin: object,
39
+ * env: object,
40
+ * argv: string[],
41
+ * exit: (code: number) => void
42
+ * }
43
+ * }}
44
+ */
45
+ const createProcess = () => {
46
+ const writes = []
47
+
48
+ return {
49
+ writes,
50
+ processImpl: {
51
+ stdout: {write: (text) => writes.push(text)},
52
+ stdin: {},
53
+ env: {},
54
+ argv: [],
55
+ exit: (code) => {
56
+ const error = new Error("process.exit")
57
+ error.exitCode = code
58
+ throw error
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ it("logs in and saves credentials", async () => {
65
+ const tempDir = createTempDir()
66
+ const {logs, errors, consoleImpl} = createConsole()
67
+ const {processImpl} = createProcess()
68
+ let fetchUrl = null
69
+
70
+ const cli = new Cli({
71
+ argv: [
72
+ "login",
73
+ "--repo",
74
+ "acme/rocket",
75
+ "--host",
76
+ "https://peakflow.test",
77
+ "--email",
78
+ "user@test.peakflow.io",
79
+ "--password",
80
+ "password"
81
+ ],
82
+ env: {},
83
+ fetchImpl: async (url) => {
84
+ fetchUrl = url
85
+ return {
86
+ ok: true,
87
+ json: async () => ({success: true, auth_token: "token", project: {repo: "acme/rocket"}})
88
+ }
89
+ },
90
+ processImpl,
91
+ consoleImpl
92
+ })
93
+
94
+ cli.getGitRoot = () => tempDir
95
+
96
+ await runCli(cli)
97
+
98
+ const configPath = path.join(tempDir, ".peakflow-api", "credentials.json")
99
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"))
100
+
101
+ expect(fetchUrl).toBe("https://peakflow.test/api/cli/login")
102
+ expect(errors.length).toBe(0)
103
+ expect(logs[0]).toContain(configPath)
104
+ expect(config).toEqual({
105
+ host: "https://peakflow.test",
106
+ authToken: "token",
107
+ repo: "acme/rocket"
108
+ })
109
+ })
110
+
111
+ it("prints build logs for the latest build group", async () => {
112
+ const tempDir = createTempDir()
113
+ const {logs, errors, consoleImpl} = createConsole()
114
+ const {processImpl, writes} = createProcess()
115
+ let fetchUrl = null
116
+
117
+ fs.mkdirSync(path.join(tempDir, ".peakflow-api"), {recursive: true})
118
+ fs.writeFileSync(
119
+ path.join(tempDir, ".peakflow-api", "credentials.json"),
120
+ JSON.stringify({host: "https://peakflow.test", authToken: "token", repo: "acme/rocket"}),
121
+ "utf8"
122
+ )
123
+
124
+ const cli = new Cli({
125
+ argv: ["build-logs", "--branch", "main", "--failing"],
126
+ env: {},
127
+ fetchImpl: async (url) => {
128
+ fetchUrl = url
129
+ return {
130
+ ok: true,
131
+ json: async () => ({
132
+ success: true,
133
+ build_group: {id: "bg1", state: "failed"},
134
+ builds: [
135
+ {id: "build1", state: "failed", log: "boom", build_no: 1}
136
+ ]
137
+ })
138
+ }
139
+ },
140
+ processImpl,
141
+ consoleImpl
142
+ })
143
+
144
+ cli.getGitRoot = () => tempDir
145
+
146
+ await runCli(cli)
147
+
148
+ expect(errors.length).toBe(0)
149
+ expect(fetchUrl).toContain("https://peakflow.test/api/cli/build_logs")
150
+ expect(fetchUrl).toContain("auth_token=token")
151
+ expect(fetchUrl).toContain("branch=main")
152
+ expect(fetchUrl).toContain("latest_build_group=true")
153
+ expect(fetchUrl).toContain("failing=true")
154
+ expect(logs[0]).toContain("Build group")
155
+ expect(writes.join("")).toContain("boom")
156
+ })
157
+ })
@@ -1,5 +1,6 @@
1
1
  import {digg} from "diggerize"
2
2
  import qs from "qs"
3
+ import envSense from "env-sense"
3
4
  import RailsVariables from "./variables.js"
4
5
  import {debuggerInstance} from "../debugger.js"
5
6
  import SourceMapsLoader from "@kaspernj/api-maker/build/source-maps-loader.js"
@@ -17,6 +18,7 @@ export default class BugReporting {
17
18
  this.collectEnvironmentCallback = undefined
18
19
  this.collectParamsCallback = undefined
19
20
  this.sourceMapsLoader = null
21
+ this.envSenseResult = null
20
22
  }
21
23
 
22
24
  /**
@@ -35,9 +37,6 @@ export default class BugReporting {
35
37
  this.collectParamsCallback = callback
36
38
  }
37
39
 
38
- /**
39
- * Initialize global error handlers.
40
- */
41
40
  /**
42
41
  * Initialize error handlers based on the runtime.
43
42
  */
@@ -62,12 +61,24 @@ export default class BugReporting {
62
61
  }
63
62
  }
64
63
 
64
+ /**
65
+ * Resolve environment flags using env-sense.
66
+ * @returns {{isBrowser: boolean, isNative: boolean, isServer: boolean}}
67
+ */
68
+ getEnvSense() {
69
+ if (!this.envSenseResult) {
70
+ this.envSenseResult = envSense()
71
+ }
72
+
73
+ return this.envSenseResult
74
+ }
75
+
65
76
  /**
66
77
  * Check if the runtime looks like a browser environment.
67
78
  * @returns {boolean}
68
79
  */
69
80
  isBrowser() {
70
- return typeof globalThis.document !== "undefined" && typeof globalThis.addEventListener === "function"
81
+ return this.getEnvSense().isBrowser && typeof globalThis.addEventListener === "function"
71
82
  }
72
83
 
73
84
  /**
@@ -75,7 +86,7 @@ export default class BugReporting {
75
86
  * @returns {boolean}
76
87
  */
77
88
  isExpo() {
78
- return typeof globalThis.ErrorUtils?.setGlobalHandler === "function"
89
+ return this.getEnvSense().isNative
79
90
  }
80
91
 
81
92
  /**
@@ -83,7 +94,7 @@ export default class BugReporting {
83
94
  * @returns {boolean}
84
95
  */
85
96
  isNode() {
86
- return typeof globalThis.process !== "undefined" && typeof globalThis.process.on === "function"
97
+ return this.getEnvSense().isServer && typeof globalThis.process?.on === "function"
87
98
  }
88
99
 
89
100
  /**
@@ -181,6 +192,11 @@ export default class BugReporting {
181
192
  return false
182
193
  }
183
194
 
195
+ if (typeof globalThis.ErrorUtils?.setGlobalHandler !== "function") {
196
+ debuggerInstance.debug("Expo error handlers are unavailable: ErrorUtils.setGlobalHandler missing")
197
+ return false
198
+ }
199
+
184
200
  const previousHandler = typeof globalThis.ErrorUtils.getGlobalHandler === "function"
185
201
  ? globalThis.ErrorUtils.getGlobalHandler()
186
202
  : null
@@ -241,7 +257,7 @@ export default class BugReporting {
241
257
 
242
258
  connectNodeUnhandledRejection() {
243
259
  globalThis.process.on("unhandledRejection", async (reason) => {
244
- debuggerInstance.debug(`Unhandled rejection: ${JSON.stringify(reason?.message || reason)}`)
260
+ debuggerInstance.debug(`Unhandled rejection: ${JSON.stringify(reason instanceof Error ? reason.message : reason)}`)
245
261
 
246
262
  if (!this.isHandlingError) {
247
263
  this.isHandlingError = true
@@ -252,7 +268,7 @@ export default class BugReporting {
252
268
  errorClass: "UnhandledRejection",
253
269
  file: null,
254
270
  line: null,
255
- message: reason?.message || String(reason),
271
+ message: reason instanceof Error ? reason.message : String(reason),
256
272
  url: null
257
273
  })
258
274
  } finally {
@@ -330,21 +346,15 @@ export default class BugReporting {
330
346
  debuggerInstance.debug("Resolved environment", postData.error.environment)
331
347
  }
332
348
 
333
- if (typeof XMLHttpRequest === "undefined") {
334
- debuggerInstance.debug("Skipping error report because XMLHttpRequest is unavailable")
349
+ const responseText = await this.sendErrorReport(postUrl, postData)
350
+
351
+ if (responseText == null) {
335
352
  return
336
353
  }
337
354
 
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))
344
-
345
- debuggerInstance.debug(`Data received: ${xhr.responseText}`)
355
+ debuggerInstance.debug(`Data received: ${responseText}`)
346
356
 
347
- const response = JSON.parse(digg(xhr, "responseText"))
357
+ const response = JSON.parse(digg({responseText}, "responseText"))
348
358
 
349
359
  // If the account has run out of bug reports, then this can potentially crash because 'url' wont be present.
350
360
  if (response.url) {
@@ -390,6 +400,77 @@ export default class BugReporting {
390
400
  })
391
401
  }
392
402
 
403
+ /**
404
+ * Send error report using the best available transport.
405
+ * @param {string} postUrl
406
+ * @param {object} postData
407
+ * @returns {Promise<string|null>}
408
+ */
409
+ async sendErrorReport(postUrl, postData) {
410
+ const body = JSON.stringify(postData)
411
+
412
+ if (typeof XMLHttpRequest !== "undefined") {
413
+ const xhr = new XMLHttpRequest()
414
+
415
+ xhr.open("POST", postUrl, true)
416
+ xhr.setRequestHeader("Content-Type", "application/json")
417
+
418
+ await this.loadXhr(xhr, body)
419
+ return xhr.responseText
420
+ } else if (typeof globalThis.fetch === "function") {
421
+ const response = await globalThis.fetch(postUrl, {
422
+ method: "POST",
423
+ headers: {"Content-Type": "application/json"},
424
+ body
425
+ })
426
+
427
+ return await response.text()
428
+ } else if (this.isNode()) {
429
+ return await this.sendNodeRequest(postUrl, body)
430
+ }
431
+
432
+ debuggerInstance.debug("Skipping error report because no HTTP transport is available")
433
+ return null
434
+ }
435
+
436
+ /**
437
+ * Send an HTTP request using Node's built-in modules.
438
+ * @param {string} postUrl
439
+ * @param {string} body
440
+ * @returns {Promise<string|null>}
441
+ */
442
+ async sendNodeRequest(postUrl, body) {
443
+ const {request} = await import("node:https")
444
+ const {URL} = await import("node:url")
445
+
446
+ return await new Promise((resolve) => {
447
+ const url = new URL(postUrl)
448
+
449
+ const req = request({
450
+ protocol: url.protocol,
451
+ hostname: url.hostname,
452
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
453
+ path: `${url.pathname}${url.search}`,
454
+ method: "POST",
455
+ headers: {
456
+ "Content-Type": "application/json",
457
+ "Content-Length": Buffer.byteLength(body)
458
+ }
459
+ }, (res) => {
460
+ let data = ""
461
+ res.setEncoding("utf8")
462
+ res.on("data", (chunk) => {
463
+ data += chunk
464
+ })
465
+ res.on("end", () => resolve(data))
466
+ })
467
+
468
+ req.on("error", () => resolve(null))
469
+ req.write(body)
470
+ req.end()
471
+ })
472
+ }
473
+
393
474
  /**
394
475
  * Resolve environment data for a report.
395
476
  * @param {object} args
package/src/cli.js ADDED
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env node
2
+ import * as fs from "node:fs"
3
+ import * as path from "node:path"
4
+ import {execSync} from "node:child_process"
5
+ import * as readline from "node:readline"
6
+ import {pathToFileURL} from "node:url"
7
+
8
+ const CONFIG_DIR_NAME = ".peakflow-api"
9
+ const CONFIG_FILE_NAME = "credentials.json"
10
+ const DEFAULT_LOGIN_PATH = "/api/cli/login"
11
+ const DEFAULT_BUILD_LOGS_PATH = "/api/cli/build_logs"
12
+
13
+ class Cli {
14
+ /**
15
+ * @param {{
16
+ * argv?: string[],
17
+ * env?: NodeJS.ProcessEnv,
18
+ * fetchImpl?: typeof fetch,
19
+ * processImpl?: NodeJS.Process,
20
+ * consoleImpl?: Console
21
+ * }} [options]
22
+ */
23
+ constructor({argv, env, fetchImpl, processImpl, consoleImpl} = {}) {
24
+ this.processImpl = processImpl || process
25
+ this.consoleImpl = consoleImpl || console
26
+ this.argv = argv || this.processImpl.argv.slice(2)
27
+ this.env = env || this.processImpl.env
28
+ this.fetchImpl = fetchImpl || globalThis.fetch
29
+ }
30
+
31
+ parseArgs(argv) {
32
+ const parsed = {_: []}
33
+
34
+ for (let i = 0; i < argv.length; i += 1) {
35
+ const arg = argv[i]
36
+
37
+ if (arg.startsWith("--")) {
38
+ const [key, inlineValue] = arg.slice(2).split("=", 2)
39
+
40
+ if (inlineValue !== undefined) {
41
+ parsed[key] = inlineValue
42
+ continue
43
+ }
44
+
45
+ const next = argv[i + 1]
46
+ if (next && !next.startsWith("--")) {
47
+ parsed[key] = next
48
+ i += 1
49
+ } else {
50
+ parsed[key] = true
51
+ }
52
+ } else {
53
+ parsed._.push(arg)
54
+ }
55
+ }
56
+
57
+ return parsed
58
+ }
59
+
60
+ runGit(command) {
61
+ return execSync(`git ${command}`, {encoding: "utf8"}).trim()
62
+ }
63
+
64
+ getGitRoot() {
65
+ return this.runGit("rev-parse --show-toplevel")
66
+ }
67
+
68
+ getGitRemote() {
69
+ try {
70
+ return this.runGit("remote get-url origin")
71
+ } catch (error) {
72
+ return this.runGit("config --get remote.origin.url")
73
+ }
74
+ }
75
+
76
+ getGitBranch() {
77
+ const branch = this.runGit("rev-parse --abbrev-ref HEAD")
78
+ return branch === "HEAD" ? null : branch
79
+ }
80
+
81
+ normalizeRepo(remote) {
82
+ if (!remote) {
83
+ return null
84
+ }
85
+
86
+ const trimmed = remote.trim()
87
+ const sshMatch = trimmed.match(/^[^@]+@[^:]+:([^/]+)\/([^/]+?)(?:\.git)?$/)
88
+ const httpsMatch = trimmed.match(/^https?:\/\/[^/]+\/([^/]+)\/([^/]+?)(?:\.git)?$/)
89
+ const sshUrlMatch = trimmed.match(/^ssh:\/\/[^@]+@[^/]+\/([^/]+)\/([^/]+?)(?:\.git)?$/)
90
+ const directMatch = trimmed.match(/^([^/]+)\/([^/]+?)(?:\.git)?$/)
91
+ const match = sshMatch || httpsMatch || sshUrlMatch || directMatch
92
+
93
+ if (!match) {
94
+ return null
95
+ }
96
+
97
+ return `${match[1]}/${match[2]}`
98
+ }
99
+
100
+ loadConfig(projectRoot) {
101
+ const configPath = path.join(projectRoot, CONFIG_DIR_NAME, CONFIG_FILE_NAME)
102
+
103
+ if (!fs.existsSync(configPath)) {
104
+ return null
105
+ }
106
+
107
+ return {
108
+ data: JSON.parse(fs.readFileSync(configPath, "utf8")),
109
+ path: configPath
110
+ }
111
+ }
112
+
113
+ saveConfig(projectRoot, data) {
114
+ const configDir = path.join(projectRoot, CONFIG_DIR_NAME)
115
+ const configPath = path.join(configDir, CONFIG_FILE_NAME)
116
+
117
+ fs.mkdirSync(configDir, {recursive: true})
118
+ fs.writeFileSync(configPath, `${JSON.stringify(data, null, 2)}\n`, "utf8")
119
+
120
+ return configPath
121
+ }
122
+
123
+ normalizeHost(host) {
124
+ if (!host) {
125
+ return null
126
+ }
127
+
128
+ const trimmed = host.trim().replace(/\/$/, "")
129
+ return trimmed.length ? trimmed : null
130
+ }
131
+
132
+ prompt(question) {
133
+ const rl = readline.createInterface({input: this.processImpl.stdin, output: this.processImpl.stdout})
134
+
135
+ return new Promise((resolve) => {
136
+ rl.question(question, (answer) => {
137
+ rl.close()
138
+ resolve(answer.trim())
139
+ })
140
+ })
141
+ }
142
+
143
+ parseBoolean(value, defaultValue = false) {
144
+ if (value === undefined) {
145
+ return defaultValue
146
+ }
147
+
148
+ if (value === true || value === false) {
149
+ return value
150
+ }
151
+
152
+ if (typeof value === "string") {
153
+ return !["false", "0", "no", "off"].includes(value.toLowerCase())
154
+ }
155
+
156
+ return Boolean(value)
157
+ }
158
+
159
+ ensureFetch() {
160
+ if (typeof this.fetchImpl !== "function") {
161
+ this.consoleImpl.error("peakflow-api requires Node.js 18+ for fetch support.")
162
+ this.exit(1)
163
+ return false
164
+ }
165
+
166
+ return true
167
+ }
168
+
169
+ exit(code) {
170
+ this.processImpl.exit(code)
171
+ }
172
+
173
+ async loginCommand(options) {
174
+ if (!this.ensureFetch()) {
175
+ return
176
+ }
177
+
178
+ let projectRoot
179
+ try {
180
+ projectRoot = this.getGitRoot()
181
+ } catch (error) {
182
+ this.consoleImpl.error("Unable to locate a git repository. Run this from a project directory.")
183
+ this.exit(1)
184
+ return
185
+ }
186
+
187
+ const repo = options.repo || this.normalizeRepo(this.getGitRemote())
188
+ if (!repo) {
189
+ this.consoleImpl.error("Unable to resolve a GitHub repo from origin. Use --repo owner/name.")
190
+ this.exit(1)
191
+ return
192
+ }
193
+
194
+ let host = this.normalizeHost(options.host || options.url || this.env.PEAKFLOW_API_URL)
195
+ if (!host) {
196
+ host = this.normalizeHost(await this.prompt("Peakflow server URL: "))
197
+ }
198
+
199
+ const email = options.email || this.env.PEAKFLOW_API_EMAIL || await this.prompt("Email: ")
200
+ const password = options.password || this.env.PEAKFLOW_API_PASSWORD || await this.prompt("Password: ")
201
+
202
+ if (!host || !email || !password) {
203
+ this.consoleImpl.error("Host, email, and password are required.")
204
+ this.exit(1)
205
+ return
206
+ }
207
+
208
+ const response = await this.fetchImpl(`${host}${DEFAULT_LOGIN_PATH}`, {
209
+ method: "POST",
210
+ headers: {"Content-Type": "application/json"},
211
+ body: JSON.stringify({email, password, repo})
212
+ })
213
+
214
+ const payload = await response.json().catch(() => null)
215
+
216
+ if (!response.ok || !payload || payload.success === false) {
217
+ const errors = payload?.errors || [`Request failed with status ${response.status}.`]
218
+ this.consoleImpl.error(errors.join("\n"))
219
+ this.exit(1)
220
+ return
221
+ }
222
+
223
+ const configPath = this.saveConfig(projectRoot, {
224
+ host,
225
+ authToken: payload.auth_token,
226
+ repo: payload.project?.repo || repo
227
+ })
228
+
229
+ this.consoleImpl.log(`Saved credentials to ${configPath}`)
230
+ }
231
+
232
+ async buildLogsCommand(options) {
233
+ if (!this.ensureFetch()) {
234
+ return
235
+ }
236
+
237
+ let projectRoot
238
+ try {
239
+ projectRoot = this.getGitRoot()
240
+ } catch (error) {
241
+ this.consoleImpl.error("Unable to locate a git repository. Run this from a project directory.")
242
+ this.exit(1)
243
+ return
244
+ }
245
+
246
+ const config = this.loadConfig(projectRoot)
247
+ if (!config) {
248
+ this.consoleImpl.error("Missing .peakflow-api/credentials.json. Run `npx peakflow-api login` first.")
249
+ this.exit(1)
250
+ return
251
+ }
252
+
253
+ const branch = options.branch || this.getGitBranch()
254
+ if (!branch) {
255
+ this.consoleImpl.error("Unable to determine git branch. Use --branch to specify one.")
256
+ this.exit(1)
257
+ return
258
+ }
259
+
260
+ const params = new URLSearchParams({
261
+ auth_token: config.data.authToken,
262
+ branch,
263
+ latest_build_group: this.parseBoolean(options["latest-build-group"], true).toString(),
264
+ failing: this.parseBoolean(options.failing).toString()
265
+ })
266
+
267
+ const response = await this.fetchImpl(`${config.data.host}${DEFAULT_BUILD_LOGS_PATH}?${params.toString()}`)
268
+ const payload = await response.json().catch(() => null)
269
+
270
+ if (!response.ok || !payload || payload.success === false) {
271
+ const errors = payload?.errors || [`Request failed with status ${response.status}.`]
272
+ this.consoleImpl.error(errors.join("\n"))
273
+ this.exit(1)
274
+ return
275
+ }
276
+
277
+ const buildGroup = payload.build_group
278
+ if (buildGroup) {
279
+ this.consoleImpl.log(`Build group #${buildGroup.build_group_no || buildGroup.id} (${buildGroup.state})`)
280
+ }
281
+
282
+ if (!payload.builds || payload.builds.length === 0) {
283
+ this.consoleImpl.log("No builds matched the requested filters.")
284
+ return
285
+ }
286
+
287
+ for (const build of payload.builds) {
288
+ const label = build.name || build.build_identifier || `Build ${build.build_no || build.id}`
289
+ this.consoleImpl.log(`\n== ${label} (${build.state}) ==`)
290
+ if (build.log && build.log.length > 0) {
291
+ this.processImpl.stdout.write(`${build.log}\n`)
292
+ } else {
293
+ this.consoleImpl.log("(no logs)")
294
+ }
295
+ }
296
+ }
297
+
298
+ help() {
299
+ this.consoleImpl.log("peakflow-api CLI\n\nCommands:\n login Authenticate and store credentials\n build-logs --latest-build-group --failing Fetch logs for failing builds\n\nOptions:\n --host/--url, --email, --password, --repo Login parameters\n --branch, --latest-build-group, --failing build-logs filters\n")
300
+ }
301
+
302
+ async run() {
303
+ const args = this.parseArgs(this.argv)
304
+ const command = args._[0]
305
+
306
+ if (!command || command === "-h" || command === "--help") {
307
+ this.help()
308
+ return
309
+ }
310
+
311
+ if (command === "login") {
312
+ await this.loginCommand(args)
313
+ return
314
+ }
315
+
316
+ if (command === "build-logs") {
317
+ await this.buildLogsCommand(args)
318
+ return
319
+ }
320
+
321
+ this.consoleImpl.error(`Unknown command: ${command}`)
322
+ this.help()
323
+ this.exit(1)
324
+ }
325
+ }
326
+
327
+ /**
328
+ * @param {Cli} cli
329
+ * @returns {Promise<void>}
330
+ */
331
+ export async function runCli(cli) {
332
+ try {
333
+ await cli.run()
334
+ } catch (error) {
335
+ cli.consoleImpl.error(error?.message || error)
336
+ cli.processImpl.exit(1)
337
+ }
338
+ }
339
+
340
+ export {Cli}
341
+
342
+ if (process.argv[1]) {
343
+ const entryPath = fs.realpathSync(process.argv[1])
344
+ if (pathToFileURL(entryPath).href === import.meta.url) {
345
+ runCli(new Cli())
346
+ }
347
+ }
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
  }