peakflow-api 0.0.1 → 0.0.6

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,8 @@ 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
+ - Keep single-line JSDoc comments on a single line.
28
+ - Use `gh` to open pull requests when requested.
26
29
  - Keep JSDoc accurate; TypeScript checks JS via `checkJs`.
27
30
  - Ensure new browser-only logic is opt-in and documented.
package/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # Changelog
2
+ - Fix: avoid bundlers resolving Node-only modules in bug-reporting node transport by using runtime-only imports.
3
+ - Chore: keep single-line JSDoc comments on a single line and document the convention.
4
+ - Fix: defer runtime import helper creation to avoid CSP unsafe-eval during browser module load.
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,14 +1,18 @@
1
1
  {
2
2
  "name": "peakflow-api",
3
- "version": "0.0.1",
3
+ "version": "0.0.6",
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": {
8
11
  "all-checks": "npm run lint && npm run typecheck && npm test",
9
12
  "build": "tsc --project tsconfig.json && node scripts/minify.mjs",
10
13
  "lint": "eslint .",
11
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",
12
16
  "typecheck": "tsc --project tsconfig.json --noEmit",
13
17
  "test": "jasmine"
14
18
  },
@@ -26,6 +30,7 @@
26
30
  },
27
31
  "dependencies": {
28
32
  "diggerize": "^1.0.10",
33
+ "env-sense": "^1.0.2",
29
34
  "qs": "^6.14.0"
30
35
  }
31
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
  /**
@@ -59,12 +61,24 @@ export default class BugReporting {
59
61
  }
60
62
  }
61
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
+
62
76
  /**
63
77
  * Check if the runtime looks like a browser environment.
64
78
  * @returns {boolean}
65
79
  */
66
80
  isBrowser() {
67
- return typeof globalThis.document !== "undefined" && typeof globalThis.addEventListener === "function"
81
+ return this.getEnvSense().isBrowser && typeof globalThis.addEventListener === "function"
68
82
  }
69
83
 
70
84
  /**
@@ -72,7 +86,7 @@ export default class BugReporting {
72
86
  * @returns {boolean}
73
87
  */
74
88
  isExpo() {
75
- return typeof globalThis.ErrorUtils?.setGlobalHandler === "function"
89
+ return this.getEnvSense().isNative
76
90
  }
77
91
 
78
92
  /**
@@ -80,7 +94,7 @@ export default class BugReporting {
80
94
  * @returns {boolean}
81
95
  */
82
96
  isNode() {
83
- return typeof globalThis.process !== "undefined" && typeof globalThis.process.on === "function"
97
+ return this.getEnvSense().isServer && typeof globalThis.process?.on === "function"
84
98
  }
85
99
 
86
100
  /**
@@ -178,6 +192,11 @@ export default class BugReporting {
178
192
  return false
179
193
  }
180
194
 
195
+ if (typeof globalThis.ErrorUtils?.setGlobalHandler !== "function") {
196
+ debuggerInstance.debug("Expo error handlers are unavailable: ErrorUtils.setGlobalHandler missing")
197
+ return false
198
+ }
199
+
181
200
  const previousHandler = typeof globalThis.ErrorUtils.getGlobalHandler === "function"
182
201
  ? globalThis.ErrorUtils.getGlobalHandler()
183
202
  : null
@@ -210,9 +229,7 @@ export default class BugReporting {
210
229
  return true
211
230
  }
212
231
 
213
- /**
214
- * Wire Node.js uncaught error handlers.
215
- */
232
+ /** Wire Node.js uncaught error handlers. */
216
233
  connectNodeUncaughtException() {
217
234
  globalThis.process.on("uncaughtException", async (error) => {
218
235
  debuggerInstance.debug(`Uncaught exception: ${error?.message || error}`)
@@ -421,8 +438,18 @@ export default class BugReporting {
421
438
  * @returns {Promise<string|null>}
422
439
  */
423
440
  async sendNodeRequest(postUrl, body) {
424
- const {request} = await import("node:https")
425
- const {URL} = await import("node:url")
441
+ /** @type {(specifier: string) => Promise<unknown>} */
442
+ const runtimeImport = (specifier) => {
443
+ const loader = new Function("specifier", "return import(specifier)")
444
+ return loader(specifier)
445
+ }
446
+
447
+ const {request} = /** @type {{request: typeof import("node:https").request}} */ (
448
+ await runtimeImport("node:https")
449
+ )
450
+ const {URL} = /** @type {{URL: typeof import("node:url").URL}} */ (
451
+ await runtimeImport("node:url")
452
+ )
426
453
 
427
454
  return await new Promise((resolve) => {
428
455
  const url = new URL(postUrl)
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
+ }