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 +2 -0
- package/README.md +9 -0
- package/build/bug-reporting/index.d.ts +24 -3
- package/build/bug-reporting/index.d.ts.map +1 -1
- package/build/bug-reporting/index.js +2 -2
- package/build/cli.d.ts +52 -0
- package/build/cli.d.ts.map +1 -0
- package/build/cli.js +3 -0
- package/package.json +8 -2
- package/spec/bug-reporting.spec.js +4 -0
- package/spec/cli.spec.js +157 -0
- package/src/bug-reporting/index.js +100 -19
- package/src/cli.js +347 -0
- package/tsconfig.json +1 -1
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":"
|
|
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
|
|
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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmcyIsInBhdGgiLCJleGVjU3luYyIsInJlYWRsaW5lIiwicGF0aFRvRmlsZVVSTCIsIkNPTkZJR19ESVJfTkFNRSIsIkNPTkZJR19GSUxFX05BTUUiLCJDbGkiLCJjb25zdHJ1Y3RvciIsImFyZ3YiLCJlbnYiLCJmZXRjaEltcGwiLCJwcm9jZXNzSW1wbCIsImNvbnNvbGVJbXBsIiwidGhpcyIsInByb2Nlc3MiLCJjb25zb2xlIiwic2xpY2UiLCJnbG9iYWxUaGlzIiwiZmV0Y2giLCJwYXJzZUFyZ3MiLCJwYXJzZWQiLCJfIiwiaSIsImxlbmd0aCIsImFyZyIsInN0YXJ0c1dpdGgiLCJrZXkiLCJpbmxpbmVWYWx1ZSIsInNwbGl0IiwidW5kZWZpbmVkIiwibmV4dCIsInB1c2giLCJydW5HaXQiLCJjb21tYW5kIiwiZW5jb2RpbmciLCJ0cmltIiwiZ2V0R2l0Um9vdCIsImdldEdpdFJlbW90ZSIsImVycm9yIiwiZ2V0R2l0QnJhbmNoIiwiYnJhbmNoIiwibm9ybWFsaXplUmVwbyIsInJlbW90ZSIsInRyaW1tZWQiLCJzc2hNYXRjaCIsIm1hdGNoIiwiaHR0cHNNYXRjaCIsInNzaFVybE1hdGNoIiwiZGlyZWN0TWF0Y2giLCJsb2FkQ29uZmlnIiwicHJvamVjdFJvb3QiLCJjb25maWdQYXRoIiwiam9pbiIsImV4aXN0c1N5bmMiLCJkYXRhIiwiSlNPTiIsInBhcnNlIiwicmVhZEZpbGVTeW5jIiwic2F2ZUNvbmZpZyIsImNvbmZpZ0RpciIsIm1rZGlyU3luYyIsInJlY3Vyc2l2ZSIsIndyaXRlRmlsZVN5bmMiLCJzdHJpbmdpZnkiLCJub3JtYWxpemVIb3N0IiwiaG9zdCIsInJlcGxhY2UiLCJwcm9tcHQiLCJxdWVzdGlvbiIsInJsIiwiY3JlYXRlSW50ZXJmYWNlIiwiaW5wdXQiLCJzdGRpbiIsIm91dHB1dCIsInN0ZG91dCIsIlByb21pc2UiLCJyZXNvbHZlIiwiYW5zd2VyIiwiY2xvc2UiLCJwYXJzZUJvb2xlYW4iLCJ2YWx1ZSIsImRlZmF1bHRWYWx1ZSIsImluY2x1ZGVzIiwidG9Mb3dlckNhc2UiLCJCb29sZWFuIiwiZW5zdXJlRmV0Y2giLCJleGl0IiwiY29kZSIsImxvZ2luQ29tbWFuZCIsIm9wdGlvbnMiLCJyZXBvIiwidXJsIiwiUEVBS0ZMT1dfQVBJX1VSTCIsImVtYWlsIiwiUEVBS0ZMT1dfQVBJX0VNQUlMIiwicGFzc3dvcmQiLCJQRUFLRkxPV19BUElfUEFTU1dPUkQiLCJyZXNwb25zZSIsIm1ldGhvZCIsImhlYWRlcnMiLCJib2R5IiwicGF5bG9hZCIsImpzb24iLCJjYXRjaCIsIm9rIiwic3VjY2VzcyIsImVycm9ycyIsInN0YXR1cyIsImF1dGhUb2tlbiIsImF1dGhfdG9rZW4iLCJwcm9qZWN0IiwibG9nIiwiYnVpbGRMb2dzQ29tbWFuZCIsImNvbmZpZyIsInBhcmFtcyIsIlVSTFNlYXJjaFBhcmFtcyIsImxhdGVzdF9idWlsZF9ncm91cCIsInRvU3RyaW5nIiwiZmFpbGluZyIsImJ1aWxkR3JvdXAiLCJidWlsZF9ncm91cCIsImJ1aWxkX2dyb3VwX25vIiwiaWQiLCJzdGF0ZSIsImJ1aWxkcyIsImJ1aWxkIiwibGFiZWwiLCJuYW1lIiwiYnVpbGRfaWRlbnRpZmllciIsImJ1aWxkX25vIiwid3JpdGUiLCJoZWxwIiwicnVuIiwiYXJncyIsImFzeW5jIiwicnVuQ2xpIiwiY2xpIiwibWVzc2FnZSIsInJlYWxwYXRoU3luYyIsImhyZWYiXSwic291cmNlcyI6WyIuLi9zcmMvY2xpLmpzIl0sIm1hcHBpbmdzIjoiO1VBQ1lBLE1BQVEsb0JBQ1JDLE1BQVUsK0JBQ2RDLE1BQWUsK0JBQ1hDLE1BQWMsd0NBQ2xCQyxNQUFvQixXQUU1QixNQUFNQyxFQUFrQixnQkFDbEJDLEVBQW1CLG1CQUl6QixNQUFNQyxFQVVKLFdBQUFDLEVBQVlDLEtBQUNBLEVBQUlDLElBQUVBLEVBQUdDLFVBQUVBLEVBQVNDLFlBQUVBLEVBQVdDLFlBQUVBLEdBQWUsSUFDN0RDLEtBQUtGLFlBQWNBLEdBQWVHLFFBQ2xDRCxLQUFLRCxZQUFjQSxHQUFlRyxRQUNsQ0YsS0FBS0wsS0FBT0EsR0FBUUssS0FBS0YsWUFBWUgsS0FBS1EsTUFBTSxHQUNoREgsS0FBS0osSUFBTUEsR0FBT0ksS0FBS0YsWUFBWUYsSUFDbkNJLEtBQUtILFVBQVlBLEdBQWFPLFdBQVdDLEtBQzNDLENBRUEsU0FBQUMsQ0FBVVgsR0FDUixNQUFNWSxFQUFTLENBQUNDLEVBQUcsSUFFbkIsSUFBSyxJQUFJQyxFQUFJLEVBQUdBLEVBQUlkLEVBQUtlLE9BQVFELEdBQUssRUFBRyxDQUN2QyxNQUFNRSxFQUFNaEIsRUFBS2MsR0FFakIsR0FBSUUsRUFBSUMsV0FBVyxNQUFPLENBQ3hCLE1BQU9DLEVBQUtDLEdBQWVILEVBQUlSLE1BQU0sR0FBR1ksTUFBTSxJQUFLLEdBRW5ELFFBQW9CQyxJQUFoQkYsRUFBMkIsQ0FDN0JQLEVBQU9NLEdBQU9DLEVBQ2QsUUFDRixDQUVBLE1BQU1HLEVBQU90QixFQUFLYyxFQUFJLEdBQ2xCUSxJQUFTQSxFQUFLTCxXQUFXLE9BQzNCTCxFQUFPTSxHQUFPSSxFQUNkUixHQUFLLEdBRUxGLEVBQU9NLElBQU8sQ0FFbEIsTUFDRU4sRUFBT0MsRUFBRVUsS0FBS1AsRUFFbEIsQ0FFQSxPQUFPSixDQUNULENBRUEsTUFBQVksQ0FBT0MsR0FDTCxPQUFPaEMsRUFBUyxPQUFPZ0MsSUFBVyxDQUFDQyxTQUFVLFNBQVNDLE1BQ3hELENBRUEsVUFBQUMsR0FDRSxPQUFPdkIsS0FBS21CLE9BQU8sNEJBQ3JCLENBRUEsWUFBQUssR0FDRSxJQUNFLE9BQU94QixLQUFLbUIsT0FBTyx3QkFDckIsQ0FBRSxNQUFPTSxHQUNQLE9BQU96QixLQUFLbUIsT0FBTyxpQ0FDckIsQ0FDRixDQUVBLFlBQUFPLEdBQ0UsTUFBTUMsRUFBUzNCLEtBQUttQixPQUFPLCtCQUMzQixNQUFrQixTQUFYUSxFQUFvQixLQUFPQSxDQUNwQyxDQUVBLGFBQUFDLENBQWNDLEdBQ1osSUFBS0EsRUFDSCxPQUFPLEtBR1QsTUFBTUMsRUFBVUQsRUFBT1AsT0FDakJTLEVBQVdELEVBQVFFLE1BQU0sNkNBQ3pCQyxFQUFhSCxFQUFRRSxNQUFNLG1EQUMzQkUsRUFBY0osRUFBUUUsTUFBTSxzREFDNUJHLEVBQWNMLEVBQVFFLE1BQU0saUNBQzVCQSxFQUFRRCxHQUFZRSxHQUFjQyxHQUFlQyxFQUV2RCxPQUFLSCxFQUlFLEdBQUdBLEVBQU0sTUFBTUEsRUFBTSxLQUhuQixJQUlYLENBRUEsVUFBQUksQ0FBV0MsR0FDVCxNQUFNQyxFQUFhbkQsRUFBS29ELEtBQUtGLEVBQWE5QyxFQUFpQkMsR0FFM0QsT0FBS04sRUFBR3NELFdBQVdGLEdBSVosQ0FDTEcsS0FBTUMsS0FBS0MsTUFBTXpELEVBQUcwRCxhQUFhTixFQUFZLFNBQzdDbkQsS0FBTW1ELEdBTEMsSUFPWCxDQUVBLFVBQUFPLENBQVdSLEVBQWFJLEdBQ3RCLE1BQU1LLEVBQVkzRCxFQUFLb0QsS0FBS0YsRUFBYTlDLEdBQ25DK0MsRUFBYW5ELEVBQUtvRCxLQUFLTyxFQUFXdEQsR0FLeEMsT0FIQU4sRUFBRzZELFVBQVVELEVBQVcsQ0FBQ0UsV0FBVyxJQUNwQzlELEVBQUcrRCxjQUFjWCxFQUFZLEdBQUdJLEtBQUtRLFVBQVVULEVBQU0sS0FBTSxPQUFRLFFBRTVESCxDQUNULENBRUEsYUFBQWEsQ0FBY0MsR0FDWixJQUFLQSxFQUNILE9BQU8sS0FHVCxNQUFNdEIsRUFBVXNCLEVBQUs5QixPQUFPK0IsUUFBUSxNQUFPLElBQzNDLE9BQU92QixFQUFRcEIsT0FBU29CLEVBQVUsSUFDcEMsQ0FFQSxNQUFBd0IsQ0FBT0MsR0FDTCxNQUFNQyxFQUFLbkUsRUFBU29FLGdCQUFnQixDQUFDQyxNQUFPMUQsS0FBS0YsWUFBWTZELE1BQU9DLE9BQVE1RCxLQUFLRixZQUFZK0QsU0FFN0YsT0FBTyxJQUFJQyxRQUFTQyxJQUNsQlAsRUFBR0QsU0FBU0EsRUFBV1MsSUFDckJSLEVBQUdTLFFBQ0hGLEVBQVFDLEVBQU8xQyxXQUdyQixDQUVBLFlBQUE0QyxDQUFhQyxFQUFPQyxHQUFlLEdBQ2pDLFlBQWNwRCxJQUFWbUQsRUFDS0MsR0FHSyxJQUFWRCxJQUE0QixJQUFWQSxFQUNiQSxFQUdZLGlCQUFWQSxHQUNELENBQUMsUUFBUyxJQUFLLEtBQU0sT0FBT0UsU0FBU0YsRUFBTUcsZUFHOUNDLFFBQVFKLEVBQ2pCLENBRUEsV0FBQUssR0FDRSxNQUE4QixtQkFBbkJ4RSxLQUFLSCxZQUNkRyxLQUFLRCxZQUFZMEIsTUFBTSx3REFDdkJ6QixLQUFLeUUsS0FBSyxJQUNILEVBSVgsQ0FFQSxJQUFBQSxDQUFLQyxHQUNIMUUsS0FBS0YsWUFBWTJFLEtBQUtDLEVBQ3hCLENBRUEsa0JBQU1DLENBQWFDLEdBQ2pCLElBQUs1RSxLQUFLd0UsY0FDUixPQUdGLElBQUluQyxFQUNKLElBQ0VBLEVBQWNyQyxLQUFLdUIsWUFDckIsQ0FBRSxNQUFPRSxHQUdQLE9BRkF6QixLQUFLRCxZQUFZMEIsTUFBTSw4RUFDdkJ6QixLQUFLeUUsS0FBSyxFQUVaLENBRUEsTUFBTUksRUFBT0QsRUFBUUMsTUFBUTdFLEtBQUs0QixjQUFjNUIsS0FBS3dCLGdCQUNyRCxJQUFLcUQsRUFHSCxPQUZBN0UsS0FBS0QsWUFBWTBCLE1BQU0sNEVBQ3ZCekIsS0FBS3lFLEtBQUssR0FJWixJQUFJckIsRUFBT3BELEtBQUttRCxjQUFjeUIsRUFBUXhCLE1BQVF3QixFQUFRRSxLQUFPOUUsS0FBS0osSUFBSW1GLGtCQUNqRTNCLElBQ0hBLEVBQU9wRCxLQUFLbUQsb0JBQW9CbkQsS0FBS3NELE9BQU8sMkJBRzlDLE1BQU0wQixFQUFRSixFQUFRSSxPQUFTaEYsS0FBS0osSUFBSXFGLDBCQUE0QmpGLEtBQUtzRCxPQUFPLFdBQzFFNEIsRUFBV04sRUFBUU0sVUFBWWxGLEtBQUtKLElBQUl1Riw2QkFBK0JuRixLQUFLc0QsT0FBTyxjQUV6RixJQUFLRixJQUFTNEIsSUFBVUUsRUFHdEIsT0FGQWxGLEtBQUtELFlBQVkwQixNQUFNLGdEQUN2QnpCLEtBQUt5RSxLQUFLLEdBSVosTUFBTVcsUUFBaUJwRixLQUFLSCxVQUFVLEdBQUd1RCxrQkFBNkIsQ0FDcEVpQyxPQUFRLE9BQ1JDLFFBQVMsQ0FBQyxlQUFnQixvQkFDMUJDLEtBQU03QyxLQUFLUSxVQUFVLENBQUM4QixRQUFPRSxXQUFVTCxXQUduQ1csUUFBZ0JKLEVBQVNLLE9BQU9DLE1BQU0sSUFBTSxNQUVsRCxJQUFLTixFQUFTTyxLQUFPSCxJQUErQixJQUFwQkEsRUFBUUksUUFBbUIsQ0FDekQsTUFBTUMsRUFBU0wsR0FBU0ssUUFBVSxDQUFDLDhCQUE4QlQsRUFBU1UsV0FHMUUsT0FGQTlGLEtBQUtELFlBQVkwQixNQUFNb0UsRUFBT3RELEtBQUssWUFDbkN2QyxLQUFLeUUsS0FBSyxFQUVaLENBRUEsTUFBTW5DLEVBQWF0QyxLQUFLNkMsV0FBV1IsRUFBYSxDQUM5Q2UsT0FDQTJDLFVBQVdQLEVBQVFRLFdBQ25CbkIsS0FBTVcsRUFBUVMsU0FBU3BCLE1BQVFBLElBR2pDN0UsS0FBS0QsWUFBWW1HLElBQUksd0JBQXdCNUQsSUFDL0MsQ0FFQSxzQkFBTTZELENBQWlCdkIsR0FDckIsSUFBSzVFLEtBQUt3RSxjQUNSLE9BR0YsSUFBSW5DLEVBQ0osSUFDRUEsRUFBY3JDLEtBQUt1QixZQUNyQixDQUFFLE1BQU9FLEdBR1AsT0FGQXpCLEtBQUtELFlBQVkwQixNQUFNLDhFQUN2QnpCLEtBQUt5RSxLQUFLLEVBRVosQ0FFQSxNQUFNMkIsRUFBU3BHLEtBQUtvQyxXQUFXQyxHQUMvQixJQUFLK0QsRUFHSCxPQUZBcEcsS0FBS0QsWUFBWTBCLE1BQU0sb0ZBQ3ZCekIsS0FBS3lFLEtBQUssR0FJWixNQUFNOUMsRUFBU2lELEVBQVFqRCxRQUFVM0IsS0FBSzBCLGVBQ3RDLElBQUtDLEVBR0gsT0FGQTNCLEtBQUtELFlBQVkwQixNQUFNLHFFQUN2QnpCLEtBQUt5RSxLQUFLLEdBSVosTUFBTTRCLEVBQVMsSUFBSUMsZ0JBQWdCLENBQ2pDTixXQUFZSSxFQUFPM0QsS0FBS3NELFVBQ3hCcEUsU0FDQTRFLG1CQUFvQnZHLEtBQUtrRSxhQUFhVSxFQUFRLHVCQUF1QixHQUFNNEIsV0FDM0VDLFFBQVN6RyxLQUFLa0UsYUFBYVUsRUFBUTZCLFNBQVNELGFBR3hDcEIsUUFBaUJwRixLQUFLSCxVQUFVLEdBQUd1RyxFQUFPM0QsS0FBS1csMkJBQWtDaUQsRUFBT0csY0FDeEZoQixRQUFnQkosRUFBU0ssT0FBT0MsTUFBTSxJQUFNLE1BRWxELElBQUtOLEVBQVNPLEtBQU9ILElBQStCLElBQXBCQSxFQUFRSSxRQUFtQixDQUN6RCxNQUFNQyxFQUFTTCxHQUFTSyxRQUFVLENBQUMsOEJBQThCVCxFQUFTVSxXQUcxRSxPQUZBOUYsS0FBS0QsWUFBWTBCLE1BQU1vRSxFQUFPdEQsS0FBSyxZQUNuQ3ZDLEtBQUt5RSxLQUFLLEVBRVosQ0FFQSxNQUFNaUMsRUFBYWxCLEVBQVFtQixZQUszQixHQUpJRCxHQUNGMUcsS0FBS0QsWUFBWW1HLElBQUksZ0JBQWdCUSxFQUFXRSxnQkFBa0JGLEVBQVdHLE9BQU9ILEVBQVdJLFVBRzVGdEIsRUFBUXVCLFFBQW9DLElBQTFCdkIsRUFBUXVCLE9BQU9yRyxPQUt0QyxJQUFLLE1BQU1zRyxLQUFTeEIsRUFBUXVCLE9BQVEsQ0FDbEMsTUFBTUUsRUFBUUQsRUFBTUUsTUFBUUYsRUFBTUcsa0JBQW9CLFNBQVNILEVBQU1JLFVBQVlKLEVBQU1ILEtBQ3ZGN0csS0FBS0QsWUFBWW1HLElBQUksUUFBUWUsTUFBVUQsRUFBTUYsYUFDekNFLEVBQU1kLEtBQU9jLEVBQU1kLElBQUl4RixPQUFTLEVBQ2xDVixLQUFLRixZQUFZK0QsT0FBT3dELE1BQU0sR0FBR0wsRUFBTWQsU0FFdkNsRyxLQUFLRCxZQUFZbUcsSUFBSSxZQUV6QixNQVpFbEcsS0FBS0QsWUFBWW1HLElBQUksMkNBYXpCLENBRUEsSUFBQW9CLEdBQ0V0SCxLQUFLRCxZQUFZbUcsSUFBSSxtVUFDdkIsQ0FFQSxTQUFNcUIsR0FDSixNQUFNQyxFQUFPeEgsS0FBS00sVUFBVU4sS0FBS0wsTUFDM0J5QixFQUFVb0csRUFBS2hILEVBQUUsR0FFbEJZLEdBQXVCLE9BQVpBLEdBQWdDLFdBQVpBLEVBS3BCLFVBQVpBLEVBS1ksZUFBWkEsR0FLSnBCLEtBQUtELFlBQVkwQixNQUFNLG9CQUFvQkwsS0FDM0NwQixLQUFLc0gsT0FDTHRILEtBQUt5RSxLQUFLLFVBTkZ6RSxLQUFLbUcsaUJBQWlCcUIsU0FMdEJ4SCxLQUFLMkUsYUFBYTZDLEdBTHhCeEgsS0FBS3NILE1BaUJULFNBT0tHLGVBQWVDLE9BQU9DLEdBQzNCLFVBQ1FBLEVBQUlKLEtBQ1osQ0FBRSxNQUFPOUYsR0FDUGtHLEVBQUk1SCxZQUFZMEIsTUFBTUEsR0FBT21HLFNBQVduRyxHQUN4Q2tHLEVBQUk3SCxZQUFZMkUsS0FBSyxFQUN2QixDQUNGLFFBRVFoRixVQUVSLEdBQUlRLFFBQVFOLEtBQUssR0FBSSxDQUVmTCxFQURjSixFQUFHMkksYUFBYTVILFFBQVFOLEtBQUssS0FDbEJtSSxtQkFBcUJoRCxLQUNoRDRDLE9BQU8sSUFBSWpJLEVBRWYiLCJpZ25vcmVMaXN0IjpbXX0=
|
package/package.json
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peakflow-api",
|
|
3
|
-
"version": "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.
|
|
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
|
package/spec/cli.spec.js
ADDED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
334
|
-
|
|
349
|
+
const responseText = await this.sendErrorReport(postUrl, postData)
|
|
350
|
+
|
|
351
|
+
if (responseText == null) {
|
|
335
352
|
return
|
|
336
353
|
}
|
|
337
354
|
|
|
338
|
-
|
|
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(
|
|
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
|
+
}
|