@flakiness/sdk 0.95.0 → 0.96.0

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.
@@ -5,247 +5,26 @@ import fs from "fs/promises";
5
5
  import os from "os";
6
6
  import path from "path";
7
7
 
8
- // ../server/lib/common/typedHttp.js
9
- var TypedHTTP;
10
- ((TypedHTTP2) => {
11
- TypedHTTP2.StatusCodes = {
12
- Informational: {
13
- CONTINUE: 100,
14
- SWITCHING_PROTOCOLS: 101,
15
- PROCESSING: 102,
16
- EARLY_HINTS: 103
17
- },
18
- Success: {
19
- OK: 200,
20
- CREATED: 201,
21
- ACCEPTED: 202,
22
- NON_AUTHORITATIVE_INFORMATION: 203,
23
- NO_CONTENT: 204,
24
- RESET_CONTENT: 205,
25
- PARTIAL_CONTENT: 206,
26
- MULTI_STATUS: 207
27
- },
28
- Redirection: {
29
- MULTIPLE_CHOICES: 300,
30
- MOVED_PERMANENTLY: 301,
31
- MOVED_TEMPORARILY: 302,
32
- SEE_OTHER: 303,
33
- NOT_MODIFIED: 304,
34
- USE_PROXY: 305,
35
- TEMPORARY_REDIRECT: 307,
36
- PERMANENT_REDIRECT: 308
37
- },
38
- ClientErrors: {
39
- BAD_REQUEST: 400,
40
- UNAUTHORIZED: 401,
41
- PAYMENT_REQUIRED: 402,
42
- FORBIDDEN: 403,
43
- NOT_FOUND: 404,
44
- METHOD_NOT_ALLOWED: 405,
45
- NOT_ACCEPTABLE: 406,
46
- PROXY_AUTHENTICATION_REQUIRED: 407,
47
- REQUEST_TIMEOUT: 408,
48
- CONFLICT: 409,
49
- GONE: 410,
50
- LENGTH_REQUIRED: 411,
51
- PRECONDITION_FAILED: 412,
52
- REQUEST_TOO_LONG: 413,
53
- REQUEST_URI_TOO_LONG: 414,
54
- UNSUPPORTED_MEDIA_TYPE: 415,
55
- REQUESTED_RANGE_NOT_SATISFIABLE: 416,
56
- EXPECTATION_FAILED: 417,
57
- IM_A_TEAPOT: 418,
58
- INSUFFICIENT_SPACE_ON_RESOURCE: 419,
59
- METHOD_FAILURE: 420,
60
- MISDIRECTED_REQUEST: 421,
61
- UNPROCESSABLE_ENTITY: 422,
62
- LOCKED: 423,
63
- FAILED_DEPENDENCY: 424,
64
- UPGRADE_REQUIRED: 426,
65
- PRECONDITION_REQUIRED: 428,
66
- TOO_MANY_REQUESTS: 429,
67
- REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
68
- UNAVAILABLE_FOR_LEGAL_REASONS: 451
69
- },
70
- ServerErrors: {
71
- INTERNAL_SERVER_ERROR: 500,
72
- NOT_IMPLEMENTED: 501,
73
- BAD_GATEWAY: 502,
74
- SERVICE_UNAVAILABLE: 503,
75
- GATEWAY_TIMEOUT: 504,
76
- HTTP_VERSION_NOT_SUPPORTED: 505,
77
- INSUFFICIENT_STORAGE: 507,
78
- NETWORK_AUTHENTICATION_REQUIRED: 511
79
- }
80
- };
81
- const AllErrorCodes = {
82
- ...TypedHTTP2.StatusCodes.ClientErrors,
83
- ...TypedHTTP2.StatusCodes.ServerErrors
84
- };
85
- class HttpError extends Error {
86
- constructor(status, message) {
87
- super(message);
88
- this.status = status;
89
- }
90
- static withCode(code, message) {
91
- const statusCode = AllErrorCodes[code];
92
- const defaultMessage = code.split("_").map((word) => word.charAt(0) + word.slice(1).toLowerCase()).join(" ");
93
- return new HttpError(statusCode, message ?? defaultMessage);
94
- }
95
- }
96
- TypedHTTP2.HttpError = HttpError;
97
- function isInformationalResponse(response) {
98
- return response.status >= 100 && response.status < 200;
99
- }
100
- TypedHTTP2.isInformationalResponse = isInformationalResponse;
101
- function isSuccessResponse(response) {
102
- return response.status >= 200 && response.status < 300;
103
- }
104
- TypedHTTP2.isSuccessResponse = isSuccessResponse;
105
- function isRedirectResponse(response) {
106
- return response.status >= 300 && response.status < 400;
107
- }
108
- TypedHTTP2.isRedirectResponse = isRedirectResponse;
109
- function isErrorResponse(response) {
110
- return response.status >= 400 && response.status < 600;
111
- }
112
- TypedHTTP2.isErrorResponse = isErrorResponse;
113
- function info(status) {
114
- return { status };
115
- }
116
- TypedHTTP2.info = info;
117
- function ok(data, status) {
118
- return {
119
- status: status ?? TypedHTTP2.StatusCodes.Success.OK,
120
- data
121
- };
122
- }
123
- TypedHTTP2.ok = ok;
124
- function redirect(url, status = 302) {
125
- return { status, url };
126
- }
127
- TypedHTTP2.redirect = redirect;
128
- function error(message, status = TypedHTTP2.StatusCodes.ServerErrors.INTERNAL_SERVER_ERROR) {
129
- return { status, message };
130
- }
131
- TypedHTTP2.error = error;
132
- class Router {
133
- constructor(_resolveContext) {
134
- this._resolveContext = _resolveContext;
135
- }
136
- static create() {
137
- return new Router(async (e) => e.ctx);
138
- }
139
- rawMethod(method, route) {
140
- return {
141
- [method]: {
142
- method,
143
- input: route.input,
144
- etag: route.etag,
145
- resolveContext: this._resolveContext,
146
- handler: route.handler
147
- }
148
- };
149
- }
150
- get(route) {
151
- return this.rawMethod("GET", {
152
- ...route,
153
- handler: (...args) => Promise.resolve(route.handler(...args)).then((result) => TypedHTTP2.ok(result))
154
- });
155
- }
156
- post(route) {
157
- return this.rawMethod("POST", {
158
- ...route,
159
- handler: (...args) => Promise.resolve(route.handler(...args)).then((result) => TypedHTTP2.ok(result))
160
- });
161
- }
162
- use(resolveContext) {
163
- return new Router(async (options) => {
164
- const m = await this._resolveContext(options);
165
- return resolveContext({ ...options, ctx: m });
166
- });
167
- }
168
- }
169
- TypedHTTP2.Router = Router;
170
- function createClient(base, fetchCallback) {
171
- function buildUrl(path2, input, options) {
172
- const method = path2.at(-1);
173
- const url = new URL(path2.slice(0, path2.length - 1).join("/"), base);
174
- const signal = options?.signal;
175
- let body = void 0;
176
- if (method === "GET" && input)
177
- url.searchParams.set("input", JSON.stringify(input));
178
- else if (method !== "GET" && input)
179
- body = JSON.stringify(input);
180
- return {
181
- url,
182
- method,
183
- headers: body ? { "Content-Type": "application/json" } : void 0,
184
- body,
185
- signal
186
- };
187
- }
188
- function createProxy(path2 = []) {
189
- return new Proxy(() => {
190
- }, {
191
- get(target, prop) {
192
- if (typeof prop === "symbol")
193
- return void 0;
194
- if (prop === "prepare")
195
- return (input, options) => buildUrl(path2, input, options);
196
- const newPath = [...path2, prop];
197
- return createProxy(newPath);
198
- },
199
- apply(target, thisArg, args) {
200
- const options = buildUrl(path2, args[0], args[1]);
201
- return fetchCallback(options.url, {
202
- method: options.method,
203
- body: options.body,
204
- headers: options.headers,
205
- signal: options.signal
206
- }).then(async (response) => {
207
- if (response.status >= 200 && response.status < 300) {
208
- if (response.headers.get("content-type")?.includes("application/json")) {
209
- const text = await response.text();
210
- return text.length ? JSON.parse(text) : void 0;
211
- }
212
- return await response.blob();
213
- }
214
- if (response.status >= 400 && response.status < 600) {
215
- const text = await response.text();
216
- if (text)
217
- throw new Error(`HTTP request failed with status ${response.status}: ${text}`);
218
- else
219
- throw new Error(`HTTP request failed with status ${response.status}`);
220
- }
221
- });
222
- }
223
- });
224
- }
225
- return createProxy();
226
- }
227
- TypedHTTP2.createClient = createClient;
228
- })(TypedHTTP || (TypedHTTP = {}));
8
+ // src/serverapi.ts
9
+ import { TypedHTTP } from "@flakiness/shared/common/typedHttp.js";
229
10
 
230
11
  // src/utils.ts
12
+ import { FlakinessReport } from "@flakiness/report";
231
13
  import http from "http";
232
14
  import https from "https";
233
- import util from "util";
234
- import zlib from "zlib";
235
- var gzipAsync = util.promisify(zlib.gzip);
236
- var gunzipAsync = util.promisify(zlib.gunzip);
237
- var gunzipSync = zlib.gunzipSync;
238
- var brotliCompressAsync = util.promisify(zlib.brotliCompress);
239
- var brotliCompressSync = zlib.brotliCompressSync;
15
+ var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
16
+ function errorText(error) {
17
+ return FLAKINESS_DBG ? error.stack : error.message;
18
+ }
240
19
  async function retryWithBackoff(job, backoff = []) {
241
20
  for (const timeout of backoff) {
242
21
  try {
243
22
  return await job();
244
23
  } catch (e) {
245
24
  if (e instanceof AggregateError)
246
- console.error(`[flakiness.io err]`, e.errors[0].message);
25
+ console.error(`[flakiness.io err]`, errorText(e.errors[0]));
247
26
  else if (e instanceof Error)
248
- console.error(`[flakiness.io err]`, e.message);
27
+ console.error(`[flakiness.io err]`, errorText(e));
249
28
  else
250
29
  console.error(`[flakiness.io err]`, e);
251
30
  await new Promise((x) => setTimeout(x, timeout));
@@ -263,6 +42,7 @@ var httpUtils;
263
42
  reject = b;
264
43
  });
265
44
  const protocol = url.startsWith("https") ? https : http;
45
+ headers = Object.fromEntries(Object.entries(headers).filter(([key, value]) => value !== void 0));
266
46
  const request = protocol.request(url, { method, headers }, (res) => {
267
47
  const chunks = [];
268
48
  res.on("data", (chunk) => chunks.push(chunk));
@@ -344,6 +124,12 @@ var FlakinessSession = class _FlakinessSession {
344
124
  this._config = _config;
345
125
  this.api = createServerAPI(this._config.endpoint, { auth: this._config.token });
346
126
  }
127
+ static async loadOrDie() {
128
+ const session = await _FlakinessSession.load();
129
+ if (!session)
130
+ throw new Error(`Please login first with 'npx flakiness login'`);
131
+ return session;
132
+ }
347
133
  static async load() {
348
134
  const data = await fs.readFile(CONFIG_PATH, "utf-8").catch((e) => void 0);
349
135
  if (!data)
@@ -1,29 +1,27 @@
1
- // src/flakinessLink.ts
2
- import fs from "fs/promises";
3
- import path from "path";
1
+ // src/flakinessConfig.ts
2
+ import fs from "fs";
3
+ import path2 from "path";
4
4
 
5
5
  // src/utils.ts
6
+ import { FlakinessReport } from "@flakiness/report";
6
7
  import assert from "assert";
7
8
  import { spawnSync } from "child_process";
8
9
  import http from "http";
9
10
  import https from "https";
10
- import { posix as posixPath, win32 as win32Path } from "path";
11
- import util from "util";
12
- import zlib from "zlib";
13
- var gzipAsync = util.promisify(zlib.gzip);
14
- var gunzipAsync = util.promisify(zlib.gunzip);
15
- var gunzipSync = zlib.gunzipSync;
16
- var brotliCompressAsync = util.promisify(zlib.brotliCompress);
17
- var brotliCompressSync = zlib.brotliCompressSync;
11
+ import path, { posix as posixPath, win32 as win32Path } from "path";
12
+ var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
13
+ function errorText(error) {
14
+ return FLAKINESS_DBG ? error.stack : error.message;
15
+ }
18
16
  async function retryWithBackoff(job, backoff = []) {
19
17
  for (const timeout of backoff) {
20
18
  try {
21
19
  return await job();
22
20
  } catch (e) {
23
21
  if (e instanceof AggregateError)
24
- console.error(`[flakiness.io err]`, e.errors[0].message);
22
+ console.error(`[flakiness.io err]`, errorText(e.errors[0]));
25
23
  else if (e instanceof Error)
26
- console.error(`[flakiness.io err]`, e.message);
24
+ console.error(`[flakiness.io err]`, errorText(e));
27
25
  else
28
26
  console.error(`[flakiness.io err]`, e);
29
27
  await new Promise((x) => setTimeout(x, timeout));
@@ -41,6 +39,7 @@ var httpUtils;
41
39
  reject = b;
42
40
  });
43
41
  const protocol = url.startsWith("https") ? https : http;
42
+ headers = Object.fromEntries(Object.entries(headers).filter(([key, value]) => value !== void 0));
44
43
  const request = protocol.request(url, { method, headers }, (res) => {
45
44
  const chunks = [];
46
45
  res.on("data", (chunk) => chunks.push(chunk));
@@ -126,36 +125,68 @@ function normalizePath(aPath) {
126
125
  return aPath;
127
126
  }
128
127
 
129
- // src/flakinessLink.ts
130
- var GIT_ROOT = computeGitRoot(process.cwd());
131
- var CONFIG_DIR = path.join(GIT_ROOT, ".flakiness");
132
- var CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
133
- var FlakinessLink = class _FlakinessLink {
134
- constructor(_config) {
128
+ // src/flakinessConfig.ts
129
+ function createConfigPath(dir) {
130
+ return path2.join(dir, ".flakiness", "config.json");
131
+ }
132
+ var gConfigPath;
133
+ function ensureConfigPath() {
134
+ if (!gConfigPath)
135
+ gConfigPath = computeConfigPath();
136
+ return gConfigPath;
137
+ }
138
+ function computeConfigPath() {
139
+ for (let p = process.cwd(); p !== path2.resolve(p, ".."); p = path2.resolve(p, "..")) {
140
+ const configPath = createConfigPath(p);
141
+ if (fs.existsSync(configPath))
142
+ return configPath;
143
+ }
144
+ try {
145
+ const gitRoot = computeGitRoot(process.cwd());
146
+ return createConfigPath(gitRoot);
147
+ } catch (e) {
148
+ return createConfigPath(process.cwd());
149
+ }
150
+ }
151
+ var FlakinessConfig = class _FlakinessConfig {
152
+ constructor(_configPath, _config) {
153
+ this._configPath = _configPath;
135
154
  this._config = _config;
136
155
  }
137
156
  static async load() {
138
- const data = await fs.readFile(CONFIG_PATH, "utf-8").catch((e) => void 0);
139
- if (!data)
140
- return void 0;
141
- const json = JSON.parse(data);
142
- return new _FlakinessLink(json);
157
+ const configPath = ensureConfigPath();
158
+ const data = await fs.promises.readFile(configPath, "utf-8").catch((e) => void 0);
159
+ const json = data ? JSON.parse(data) : {};
160
+ return new _FlakinessConfig(configPath, json);
143
161
  }
144
- static async remove() {
145
- await fs.unlink(CONFIG_PATH).catch((e) => void 0);
162
+ static async projectOrDie(session) {
163
+ const config = await _FlakinessConfig.load();
164
+ const projectPublicId = config.projectPublicId();
165
+ if (!projectPublicId)
166
+ throw new Error(`Please link to flakiness project with 'npx flakiness link'`);
167
+ const project = await session.api.project.getProject.GET({ projectPublicId }).catch((e) => void 0);
168
+ if (!project)
169
+ throw new Error(`Failed to fetch linked project; please re-link with 'npx flakiness link'`);
170
+ return project;
171
+ }
172
+ static createEmpty() {
173
+ return new _FlakinessConfig(ensureConfigPath(), {});
146
174
  }
147
175
  path() {
148
- return CONFIG_PATH;
176
+ return this._configPath;
177
+ }
178
+ projectPublicId() {
179
+ return this._config.projectPublicId;
149
180
  }
150
- projectId() {
151
- return this._config.projectId;
181
+ setProjectPublicId(projectId) {
182
+ this._config.projectPublicId = projectId;
152
183
  }
153
184
  async save() {
154
- await fs.mkdir(CONFIG_DIR, { recursive: true });
155
- await fs.writeFile(CONFIG_PATH, JSON.stringify(this._config, null, 2));
185
+ await fs.promises.mkdir(path2.dirname(this._configPath), { recursive: true });
186
+ await fs.promises.writeFile(this._configPath, JSON.stringify(this._config, null, 2));
156
187
  }
157
188
  };
158
189
  export {
159
- FlakinessLink
190
+ FlakinessConfig
160
191
  };
161
- //# sourceMappingURL=flakinessLink.js.map
192
+ //# sourceMappingURL=flakinessConfig.js.map
@@ -3,247 +3,26 @@ import fs from "fs/promises";
3
3
  import os from "os";
4
4
  import path from "path";
5
5
 
6
- // ../server/lib/common/typedHttp.js
7
- var TypedHTTP;
8
- ((TypedHTTP2) => {
9
- TypedHTTP2.StatusCodes = {
10
- Informational: {
11
- CONTINUE: 100,
12
- SWITCHING_PROTOCOLS: 101,
13
- PROCESSING: 102,
14
- EARLY_HINTS: 103
15
- },
16
- Success: {
17
- OK: 200,
18
- CREATED: 201,
19
- ACCEPTED: 202,
20
- NON_AUTHORITATIVE_INFORMATION: 203,
21
- NO_CONTENT: 204,
22
- RESET_CONTENT: 205,
23
- PARTIAL_CONTENT: 206,
24
- MULTI_STATUS: 207
25
- },
26
- Redirection: {
27
- MULTIPLE_CHOICES: 300,
28
- MOVED_PERMANENTLY: 301,
29
- MOVED_TEMPORARILY: 302,
30
- SEE_OTHER: 303,
31
- NOT_MODIFIED: 304,
32
- USE_PROXY: 305,
33
- TEMPORARY_REDIRECT: 307,
34
- PERMANENT_REDIRECT: 308
35
- },
36
- ClientErrors: {
37
- BAD_REQUEST: 400,
38
- UNAUTHORIZED: 401,
39
- PAYMENT_REQUIRED: 402,
40
- FORBIDDEN: 403,
41
- NOT_FOUND: 404,
42
- METHOD_NOT_ALLOWED: 405,
43
- NOT_ACCEPTABLE: 406,
44
- PROXY_AUTHENTICATION_REQUIRED: 407,
45
- REQUEST_TIMEOUT: 408,
46
- CONFLICT: 409,
47
- GONE: 410,
48
- LENGTH_REQUIRED: 411,
49
- PRECONDITION_FAILED: 412,
50
- REQUEST_TOO_LONG: 413,
51
- REQUEST_URI_TOO_LONG: 414,
52
- UNSUPPORTED_MEDIA_TYPE: 415,
53
- REQUESTED_RANGE_NOT_SATISFIABLE: 416,
54
- EXPECTATION_FAILED: 417,
55
- IM_A_TEAPOT: 418,
56
- INSUFFICIENT_SPACE_ON_RESOURCE: 419,
57
- METHOD_FAILURE: 420,
58
- MISDIRECTED_REQUEST: 421,
59
- UNPROCESSABLE_ENTITY: 422,
60
- LOCKED: 423,
61
- FAILED_DEPENDENCY: 424,
62
- UPGRADE_REQUIRED: 426,
63
- PRECONDITION_REQUIRED: 428,
64
- TOO_MANY_REQUESTS: 429,
65
- REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
66
- UNAVAILABLE_FOR_LEGAL_REASONS: 451
67
- },
68
- ServerErrors: {
69
- INTERNAL_SERVER_ERROR: 500,
70
- NOT_IMPLEMENTED: 501,
71
- BAD_GATEWAY: 502,
72
- SERVICE_UNAVAILABLE: 503,
73
- GATEWAY_TIMEOUT: 504,
74
- HTTP_VERSION_NOT_SUPPORTED: 505,
75
- INSUFFICIENT_STORAGE: 507,
76
- NETWORK_AUTHENTICATION_REQUIRED: 511
77
- }
78
- };
79
- const AllErrorCodes = {
80
- ...TypedHTTP2.StatusCodes.ClientErrors,
81
- ...TypedHTTP2.StatusCodes.ServerErrors
82
- };
83
- class HttpError extends Error {
84
- constructor(status, message) {
85
- super(message);
86
- this.status = status;
87
- }
88
- static withCode(code, message) {
89
- const statusCode = AllErrorCodes[code];
90
- const defaultMessage = code.split("_").map((word) => word.charAt(0) + word.slice(1).toLowerCase()).join(" ");
91
- return new HttpError(statusCode, message ?? defaultMessage);
92
- }
93
- }
94
- TypedHTTP2.HttpError = HttpError;
95
- function isInformationalResponse(response) {
96
- return response.status >= 100 && response.status < 200;
97
- }
98
- TypedHTTP2.isInformationalResponse = isInformationalResponse;
99
- function isSuccessResponse(response) {
100
- return response.status >= 200 && response.status < 300;
101
- }
102
- TypedHTTP2.isSuccessResponse = isSuccessResponse;
103
- function isRedirectResponse(response) {
104
- return response.status >= 300 && response.status < 400;
105
- }
106
- TypedHTTP2.isRedirectResponse = isRedirectResponse;
107
- function isErrorResponse(response) {
108
- return response.status >= 400 && response.status < 600;
109
- }
110
- TypedHTTP2.isErrorResponse = isErrorResponse;
111
- function info(status) {
112
- return { status };
113
- }
114
- TypedHTTP2.info = info;
115
- function ok(data, status) {
116
- return {
117
- status: status ?? TypedHTTP2.StatusCodes.Success.OK,
118
- data
119
- };
120
- }
121
- TypedHTTP2.ok = ok;
122
- function redirect(url, status = 302) {
123
- return { status, url };
124
- }
125
- TypedHTTP2.redirect = redirect;
126
- function error(message, status = TypedHTTP2.StatusCodes.ServerErrors.INTERNAL_SERVER_ERROR) {
127
- return { status, message };
128
- }
129
- TypedHTTP2.error = error;
130
- class Router {
131
- constructor(_resolveContext) {
132
- this._resolveContext = _resolveContext;
133
- }
134
- static create() {
135
- return new Router(async (e) => e.ctx);
136
- }
137
- rawMethod(method, route) {
138
- return {
139
- [method]: {
140
- method,
141
- input: route.input,
142
- etag: route.etag,
143
- resolveContext: this._resolveContext,
144
- handler: route.handler
145
- }
146
- };
147
- }
148
- get(route) {
149
- return this.rawMethod("GET", {
150
- ...route,
151
- handler: (...args) => Promise.resolve(route.handler(...args)).then((result) => TypedHTTP2.ok(result))
152
- });
153
- }
154
- post(route) {
155
- return this.rawMethod("POST", {
156
- ...route,
157
- handler: (...args) => Promise.resolve(route.handler(...args)).then((result) => TypedHTTP2.ok(result))
158
- });
159
- }
160
- use(resolveContext) {
161
- return new Router(async (options) => {
162
- const m = await this._resolveContext(options);
163
- return resolveContext({ ...options, ctx: m });
164
- });
165
- }
166
- }
167
- TypedHTTP2.Router = Router;
168
- function createClient(base, fetchCallback) {
169
- function buildUrl(path2, input, options) {
170
- const method = path2.at(-1);
171
- const url = new URL(path2.slice(0, path2.length - 1).join("/"), base);
172
- const signal = options?.signal;
173
- let body = void 0;
174
- if (method === "GET" && input)
175
- url.searchParams.set("input", JSON.stringify(input));
176
- else if (method !== "GET" && input)
177
- body = JSON.stringify(input);
178
- return {
179
- url,
180
- method,
181
- headers: body ? { "Content-Type": "application/json" } : void 0,
182
- body,
183
- signal
184
- };
185
- }
186
- function createProxy(path2 = []) {
187
- return new Proxy(() => {
188
- }, {
189
- get(target, prop) {
190
- if (typeof prop === "symbol")
191
- return void 0;
192
- if (prop === "prepare")
193
- return (input, options) => buildUrl(path2, input, options);
194
- const newPath = [...path2, prop];
195
- return createProxy(newPath);
196
- },
197
- apply(target, thisArg, args) {
198
- const options = buildUrl(path2, args[0], args[1]);
199
- return fetchCallback(options.url, {
200
- method: options.method,
201
- body: options.body,
202
- headers: options.headers,
203
- signal: options.signal
204
- }).then(async (response) => {
205
- if (response.status >= 200 && response.status < 300) {
206
- if (response.headers.get("content-type")?.includes("application/json")) {
207
- const text = await response.text();
208
- return text.length ? JSON.parse(text) : void 0;
209
- }
210
- return await response.blob();
211
- }
212
- if (response.status >= 400 && response.status < 600) {
213
- const text = await response.text();
214
- if (text)
215
- throw new Error(`HTTP request failed with status ${response.status}: ${text}`);
216
- else
217
- throw new Error(`HTTP request failed with status ${response.status}`);
218
- }
219
- });
220
- }
221
- });
222
- }
223
- return createProxy();
224
- }
225
- TypedHTTP2.createClient = createClient;
226
- })(TypedHTTP || (TypedHTTP = {}));
6
+ // src/serverapi.ts
7
+ import { TypedHTTP } from "@flakiness/shared/common/typedHttp.js";
227
8
 
228
9
  // src/utils.ts
10
+ import { FlakinessReport } from "@flakiness/report";
229
11
  import http from "http";
230
12
  import https from "https";
231
- import util from "util";
232
- import zlib from "zlib";
233
- var gzipAsync = util.promisify(zlib.gzip);
234
- var gunzipAsync = util.promisify(zlib.gunzip);
235
- var gunzipSync = zlib.gunzipSync;
236
- var brotliCompressAsync = util.promisify(zlib.brotliCompress);
237
- var brotliCompressSync = zlib.brotliCompressSync;
13
+ var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
14
+ function errorText(error) {
15
+ return FLAKINESS_DBG ? error.stack : error.message;
16
+ }
238
17
  async function retryWithBackoff(job, backoff = []) {
239
18
  for (const timeout of backoff) {
240
19
  try {
241
20
  return await job();
242
21
  } catch (e) {
243
22
  if (e instanceof AggregateError)
244
- console.error(`[flakiness.io err]`, e.errors[0].message);
23
+ console.error(`[flakiness.io err]`, errorText(e.errors[0]));
245
24
  else if (e instanceof Error)
246
- console.error(`[flakiness.io err]`, e.message);
25
+ console.error(`[flakiness.io err]`, errorText(e));
247
26
  else
248
27
  console.error(`[flakiness.io err]`, e);
249
28
  await new Promise((x) => setTimeout(x, timeout));
@@ -261,6 +40,7 @@ var httpUtils;
261
40
  reject = b;
262
41
  });
263
42
  const protocol = url.startsWith("https") ? https : http;
43
+ headers = Object.fromEntries(Object.entries(headers).filter(([key, value]) => value !== void 0));
264
44
  const request = protocol.request(url, { method, headers }, (res) => {
265
45
  const chunks = [];
266
46
  res.on("data", (chunk) => chunks.push(chunk));
@@ -342,6 +122,12 @@ var FlakinessSession = class _FlakinessSession {
342
122
  this._config = _config;
343
123
  this.api = createServerAPI(this._config.endpoint, { auth: this._config.token });
344
124
  }
125
+ static async loadOrDie() {
126
+ const session = await _FlakinessSession.load();
127
+ if (!session)
128
+ throw new Error(`Please login first with 'npx flakiness login'`);
129
+ return session;
130
+ }
345
131
  static async load() {
346
132
  const data = await fs.readFile(CONFIG_PATH, "utf-8").catch((e) => void 0);
347
133
  if (!data)