@flareapp/js 2.0.0-rc.1 → 2.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flareapp/js",
3
- "version": "2.0.0-rc.1",
3
+ "version": "2.0.0",
4
4
  "description": "JavaScript client for flareapp.io",
5
5
  "homepage": "https://flareapp.io",
6
6
  "bugs": {
@@ -11,29 +11,47 @@
11
11
  "url": "git+https://github.com/spatie/flare-client-js.git"
12
12
  },
13
13
  "license": "MIT",
14
- "author": "adriaan@spatie.be",
15
- "main": "./dist/index.js",
14
+ "author": {
15
+ "name": "Spatie",
16
+ "email": "info@spatie.be"
17
+ },
18
+ "contributors": [
19
+ "Adriaan Marain <adriaan@spatie.be>",
20
+ "Alex Vanderbist <alex@spatie.be>",
21
+ "Dries Heyninck <dries@spatie.be>",
22
+ "Freek Van der Herten <freek@spatie.be>",
23
+ "Sebastian De Deyne <sebastian@spatie.be>",
24
+ "Sébastien Henau <seba@spatie.be>"
25
+ ],
26
+ "main": "./dist/index.cjs",
16
27
  "module": "./dist/index.mjs",
17
- "types": "./dist/index.d.ts",
28
+ "types": "./dist/index.d.cts",
18
29
  "exports": {
19
30
  ".": {
20
- "require": "./dist/index.js",
21
- "import": "./dist/index.mjs"
31
+ "import": {
32
+ "types": "./dist/index.d.mts",
33
+ "default": "./dist/index.mjs"
34
+ },
35
+ "require": {
36
+ "types": "./dist/index.d.cts",
37
+ "default": "./dist/index.cjs"
38
+ }
22
39
  }
23
40
  },
24
41
  "scripts": {
25
42
  "prepublishOnly": "npm run build",
26
- "build": "tsup src/index.ts --format cjs,esm --dts --env.FLARE_JS_CLIENT_VERSION=\\\"$(node -p \"require('./package.json').version\")\\\" --clean",
43
+ "build": "tsdown src/index.ts --format cjs,esm --dts --env.FLARE_JS_CLIENT_VERSION=$(node -p \"require('./package.json').version\") --clean",
27
44
  "test": "vitest run",
28
- "typescript": "tsc"
45
+ "typescript": "tsc --noEmit",
46
+ "release": "release-it"
29
47
  },
30
48
  "dependencies": {
31
49
  "error-stack-parser": "^2.0.2"
32
50
  },
33
51
  "devDependencies": {
34
- "tsup": "^8.0.1",
35
- "typescript": "^5.3.3",
36
- "vitest": "^1.0.4"
52
+ "tsdown": "^0.20.3",
53
+ "typescript": "^5.7.0",
54
+ "vitest": "^4.0.18"
37
55
  },
38
56
  "publishConfig": {
39
57
  "access": "public"
package/dist/index.d.ts DELETED
@@ -1,109 +0,0 @@
1
- type Config = {
2
- key: string;
3
- version: string;
4
- sourcemapVersion: string;
5
- stage: string;
6
- maxGlowsPerReport: number;
7
- reportBrowserExtensionErrors: boolean;
8
- reportingUrl: string;
9
- debug: boolean;
10
- beforeEvaluate: (error: Error) => Error | false | null | Promise<Error | false | null>;
11
- beforeSubmit: (report: Report) => Report | false | null | Promise<Report | false | null>;
12
- };
13
- type Report = {
14
- notifier: string;
15
- exception_class: string;
16
- seen_at: number;
17
- message: string;
18
- language: 'javascript';
19
- glows: Glow[];
20
- context: Context;
21
- stacktrace: StackFrame[];
22
- sourcemap_version_id: string;
23
- solutions: Solution[];
24
- stage?: string;
25
- };
26
- interface SolutionProviderExtraParameters {
27
- }
28
- type SolutionProvider = {
29
- canSolve: (error: Error, extraParameters?: SolutionProviderExtraParameters) => boolean | Promise<boolean>;
30
- getSolutions: (error: Error, extraParameters?: SolutionProviderExtraParameters) => Solution[] | Promise<Solution[]>;
31
- };
32
- type Solution = {
33
- class: string;
34
- title: string;
35
- description: string;
36
- links: {
37
- [label: string]: string;
38
- };
39
- action_description?: string;
40
- is_runnable?: boolean;
41
- };
42
- type Context = {
43
- request?: {
44
- url?: String;
45
- useragent?: String;
46
- referrer?: String;
47
- readyState?: String;
48
- };
49
- request_data?: {
50
- queryString: {
51
- [key: string]: string;
52
- };
53
- };
54
- cookies?: {
55
- [key: string]: string;
56
- };
57
- [key: string]: any;
58
- };
59
- type StackFrame = {
60
- line_number: number;
61
- column_number: number;
62
- method: string;
63
- file: string;
64
- code_snippet: {
65
- [key: number]: string;
66
- };
67
- trimmed_column_number: number | null;
68
- class: string;
69
- };
70
- type Glow = {
71
- time: number;
72
- microtime: number;
73
- name: String;
74
- message_level: MessageLevel;
75
- meta_data: object | object[];
76
- };
77
- type MessageLevel = 'info' | 'debug' | 'warning' | 'error' | 'critical';
78
-
79
- declare class Api {
80
- report(report: Report, url: string, key: string, reportBrowserExtensionErrors: boolean): Promise<void>;
81
- }
82
-
83
- declare class Flare {
84
- http: Api;
85
- config: Config;
86
- glows: Glow[];
87
- context: Context;
88
- solutionProviders: SolutionProvider[];
89
- constructor(http?: Api);
90
- light(key?: string, debug?: boolean): Flare;
91
- configure(config: Partial<Config>): Flare;
92
- test(): Promise<void>;
93
- glow(name: string, level?: MessageLevel, data?: object | object[]): Flare;
94
- clearGlows(): Flare;
95
- addContext(name: string, value: any): Flare;
96
- addContextGroup(groupName: string, value: object): Flare;
97
- registerSolutionProvider(solutionProvider: SolutionProvider): Flare;
98
- report(error: Error, context?: Context, extraSolutionParameters?: SolutionProviderExtraParameters): Promise<void>;
99
- reportMessage(message: string, context?: Context, exceptionClass?: string): Promise<void>;
100
- createReportFromError(error: Error, context?: Context, extraSolutionParameters?: SolutionProviderExtraParameters): Promise<Report | false>;
101
- sendReport(report: Report): Promise<void>;
102
- set beforeEvaluate(beforeEvaluate: Config['beforeEvaluate']);
103
- set beforeSubmit(beforeSubmit: Config['beforeSubmit']);
104
- set stage(stage: string | undefined);
105
- }
106
-
107
- declare const flare: Flare;
108
-
109
- export { Flare, flare };
package/dist/index.js DELETED
@@ -1,504 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
33
- Flare: () => Flare,
34
- flare: () => flare
35
- });
36
- module.exports = __toCommonJS(src_exports);
37
-
38
- // src/env/index.ts
39
- var CLIENT_VERSION = false ? "?" : '"2.0.0-rc.1"';
40
- var KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
41
- var SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
42
-
43
- // src/util/assert.ts
44
- function assert(value, message, debug) {
45
- if (debug && !value) {
46
- console.error(`Flare JavaScript client v${CLIENT_VERSION}: ${message}`);
47
- }
48
- return !!value;
49
- }
50
-
51
- // src/util/assertKey.ts
52
- function assertKey(key, debug) {
53
- return assert(
54
- key,
55
- "The client was not yet initialised with an API key. Run client.light('<flare-project-key>') when you initialise your app. If you are running in dev mode and didn't run the light command on purpose, you can ignore this error.",
56
- debug
57
- );
58
- }
59
-
60
- // src/util/assertSolutionProvider.ts
61
- function assertSolutionProvider(solutionProvider, debug) {
62
- return assert("canSolve" in solutionProvider, "A solution provider without a [canSolve] property was added.", debug) && assert(
63
- "getSolutions" in solutionProvider,
64
- "A solution provider without a [getSolutions] property was added.",
65
- debug
66
- );
67
- }
68
-
69
- // src/util/flatJsonStringify.ts
70
- function flatJsonStringify(json) {
71
- let cache = [];
72
- const flattenedStringifiedJson = JSON.stringify(json, function(_, value) {
73
- if (typeof value === "object" && value !== null) {
74
- if (cache.indexOf(value) !== -1) {
75
- try {
76
- return JSON.parse(JSON.stringify(value));
77
- } catch (error) {
78
- return;
79
- }
80
- }
81
- cache.push(value);
82
- }
83
- return value;
84
- });
85
- cache = null;
86
- return flattenedStringifiedJson;
87
- }
88
-
89
- // src/util/flattenOnce.ts
90
- function flattenOnce(array) {
91
- return array.reduce((flat, toFlatten) => {
92
- return flat.concat(toFlatten);
93
- }, []);
94
- }
95
-
96
- // src/util/now.ts
97
- function now() {
98
- return Math.round(Date.now() / 1e3);
99
- }
100
-
101
- // src/api/Api.ts
102
- var Api = class {
103
- report(report, url, key, reportBrowserExtensionErrors) {
104
- return fetch(url, {
105
- method: "POST",
106
- headers: {
107
- "Content-Type": "application/json",
108
- "X-Api-Token": key,
109
- "X-Requested-With": "XMLHttpRequest",
110
- "X-Report-Browser-Extension-Errors": JSON.stringify(reportBrowserExtensionErrors)
111
- },
112
- body: flatJsonStringify({
113
- ...report,
114
- key
115
- })
116
- }).then(
117
- (response) => {
118
- if (response.status !== 204) {
119
- console.error(`Received response with status ${response.status} from Flare`);
120
- }
121
- },
122
- (error) => console.error(error)
123
- );
124
- }
125
- };
126
-
127
- // src/context/cookie.ts
128
- function cookie() {
129
- if (!window.document.cookie) {
130
- return {};
131
- }
132
- return {
133
- cookies: window.document.cookie.split("; ").reduce(
134
- (cookies, cookie2) => {
135
- const [cookieName, cookieValue] = cookie2.split(/=/);
136
- cookies[cookieName] = cookieValue;
137
- return cookies;
138
- },
139
- {}
140
- )
141
- };
142
- }
143
-
144
- // src/context/request.ts
145
- function request() {
146
- return {
147
- request: {
148
- url: window.document.location.href,
149
- useragent: window.navigator.userAgent,
150
- referrer: window.document.referrer,
151
- readyState: window.document.readyState
152
- }
153
- };
154
- }
155
-
156
- // src/context/requestData.ts
157
- function requestData() {
158
- if (!window.location.search) {
159
- return {};
160
- }
161
- const queryString = {};
162
- new URLSearchParams(window.location.search).forEach((value, key) => {
163
- queryString[key] = value;
164
- });
165
- return { request_data: { queryString } };
166
- }
167
-
168
- // src/context/collectContext.ts
169
- function collectContext(additionalContext) {
170
- if (typeof window === "undefined") {
171
- return additionalContext;
172
- }
173
- return {
174
- ...cookie(),
175
- ...request(),
176
- ...requestData(),
177
- ...additionalContext
178
- };
179
- }
180
-
181
- // src/solutions/getSolutions.ts
182
- function getSolutions(solutionProviders, error, extraSolutionParameters = {}) {
183
- return new Promise((resolve) => {
184
- const canSolves = solutionProviders.reduce(
185
- (canSolves2, provider) => {
186
- canSolves2.push(Promise.resolve(provider.canSolve(error, extraSolutionParameters)));
187
- return canSolves2;
188
- },
189
- []
190
- );
191
- Promise.all(canSolves).then((resolvedCanSolves) => {
192
- const solutionPromises = [];
193
- resolvedCanSolves.forEach((canSolve, i) => {
194
- if (canSolve) {
195
- solutionPromises.push(
196
- Promise.resolve(solutionProviders[i].getSolutions(error, extraSolutionParameters))
197
- );
198
- }
199
- });
200
- Promise.all(solutionPromises).then((solutions) => {
201
- resolve(flattenOnce(solutions));
202
- });
203
- });
204
- });
205
- }
206
-
207
- // src/stacktrace/createStackTrace.ts
208
- var import_error_stack_parser = __toESM(require("error-stack-parser"));
209
-
210
- // src/stacktrace/fileReader.ts
211
- var cachedFiles = {};
212
- function getCodeSnippet(url, lineNumber, columnNumber) {
213
- return new Promise((resolve) => {
214
- if (!url || !lineNumber) {
215
- return resolve({
216
- codeSnippet: {
217
- 0: `Could not read from file: missing file URL or line number. URL: ${url} lineNumber: ${lineNumber}`
218
- },
219
- trimmedColumnNumber: null
220
- });
221
- }
222
- readFile(url).then((fileText) => {
223
- if (!fileText) {
224
- return resolve({
225
- codeSnippet: {
226
- 0: `Could not read from file: Error while opening file at URL ${url}`
227
- },
228
- trimmedColumnNumber: null
229
- });
230
- }
231
- return resolve(readLinesFromFile(fileText, lineNumber, columnNumber));
232
- });
233
- });
234
- }
235
- function readFile(url) {
236
- if (cachedFiles[url]) {
237
- return Promise.resolve(cachedFiles[url]);
238
- }
239
- return fetch(url).then((response) => {
240
- if (response.status !== 200) {
241
- return null;
242
- }
243
- return response.text();
244
- }).catch(() => null);
245
- }
246
- function readLinesFromFile(fileText, lineNumber, columnNumber, maxSnippetLineLength = 1e3, maxSnippetLines = 40) {
247
- const codeSnippet = {};
248
- let trimmedColumnNumber = null;
249
- const lines = fileText.split("\n");
250
- for (let i = -maxSnippetLines / 2; i <= maxSnippetLines / 2; i++) {
251
- const currentLineIndex = lineNumber + i;
252
- if (currentLineIndex >= 0 && lines[currentLineIndex]) {
253
- const displayLine = currentLineIndex + 1;
254
- if (lines[currentLineIndex].length > maxSnippetLineLength) {
255
- if (columnNumber && columnNumber + maxSnippetLineLength / 2 > maxSnippetLineLength) {
256
- codeSnippet[displayLine] = lines[currentLineIndex].substr(
257
- columnNumber - Math.round(maxSnippetLineLength / 2),
258
- maxSnippetLineLength
259
- );
260
- if (displayLine === lineNumber) {
261
- trimmedColumnNumber = Math.round(maxSnippetLineLength / 2);
262
- }
263
- continue;
264
- }
265
- codeSnippet[displayLine] = lines[currentLineIndex].substr(0, maxSnippetLineLength) + "\u2026";
266
- continue;
267
- }
268
- codeSnippet[displayLine] = lines[currentLineIndex];
269
- }
270
- }
271
- return { codeSnippet, trimmedColumnNumber };
272
- }
273
-
274
- // src/stacktrace/createStackTrace.ts
275
- function createStackTrace(error, debug) {
276
- return new Promise((resolve) => {
277
- if (!hasStack(error)) {
278
- assert(false, "Couldn't generate stacktrace of below error:", debug);
279
- if (debug) {
280
- console.error(error);
281
- }
282
- return resolve([
283
- {
284
- line_number: 0,
285
- column_number: 0,
286
- method: "unknown",
287
- file: "unknown",
288
- code_snippet: {
289
- 0: "Could not read from file: stacktrace missing"
290
- },
291
- trimmed_column_number: null,
292
- class: "unknown"
293
- }
294
- ]);
295
- }
296
- Promise.all(
297
- import_error_stack_parser.default.parse(error).map((frame) => {
298
- return new Promise((resolve2) => {
299
- getCodeSnippet(frame.fileName, frame.lineNumber, frame.columnNumber).then((snippet) => {
300
- resolve2({
301
- line_number: frame.lineNumber || 1,
302
- column_number: frame.columnNumber || 1,
303
- method: frame.functionName || "Anonymous or unknown function",
304
- file: frame.fileName || "Unknown file",
305
- code_snippet: snippet.codeSnippet,
306
- trimmed_column_number: snippet.trimmedColumnNumber,
307
- class: ""
308
- });
309
- });
310
- });
311
- })
312
- ).then(resolve);
313
- });
314
- }
315
- function hasStack(err) {
316
- return !!err && (!!err.stack || !!err.stacktrace || !!err["opera#sourceloc"]) && typeof (err.stack || err.stacktrace || err["opera#sourceloc"]) === "string" && err.stack !== `${err.name}: ${err.message}`;
317
- }
318
-
319
- // src/Flare.ts
320
- var Flare = class {
321
- constructor(http = new Api()) {
322
- this.http = http;
323
- this.config = {
324
- key: KEY,
325
- version: CLIENT_VERSION,
326
- sourcemapVersion: SOURCEMAP_VERSION,
327
- stage: "",
328
- maxGlowsPerReport: 30,
329
- reportingUrl: "https://reporting.flareapp.io/api/reports",
330
- reportBrowserExtensionErrors: false,
331
- debug: false,
332
- beforeEvaluate: (error) => error,
333
- beforeSubmit: (report) => report
334
- };
335
- this.glows = [];
336
- this.context = { context: {} };
337
- this.solutionProviders = [];
338
- }
339
- light(key = KEY, debug = false) {
340
- this.config.key = key;
341
- this.config.debug = debug;
342
- return this;
343
- }
344
- configure(config) {
345
- this.config = { ...this.config, ...config };
346
- return this;
347
- }
348
- test() {
349
- return this.report(new Error("The Flare client is set up correctly!"));
350
- }
351
- glow(name, level = "info", data = []) {
352
- const time = now();
353
- this.glows.push({
354
- name,
355
- message_level: level,
356
- meta_data: data,
357
- time,
358
- microtime: time
359
- });
360
- if (this.glows.length > this.config.maxGlowsPerReport) {
361
- this.glows = this.glows.slice(this.glows.length - this.config.maxGlowsPerReport);
362
- }
363
- return this;
364
- }
365
- clearGlows() {
366
- this.glows = [];
367
- return this;
368
- }
369
- addContext(name, value) {
370
- this.context.context[name] = value;
371
- return this;
372
- }
373
- addContextGroup(groupName, value) {
374
- this.context[groupName] = value;
375
- return this;
376
- }
377
- registerSolutionProvider(solutionProvider) {
378
- if (!assertSolutionProvider(solutionProvider, this.config.debug)) {
379
- return this;
380
- }
381
- this.solutionProviders.push(solutionProvider);
382
- return this;
383
- }
384
- async report(error, context = {}, extraSolutionParameters = {}) {
385
- const errorToReport = await this.config.beforeEvaluate(error);
386
- if (!errorToReport) {
387
- return;
388
- }
389
- const report = await this.createReportFromError(error, context, extraSolutionParameters);
390
- if (!report) {
391
- return;
392
- }
393
- return this.sendReport(report);
394
- }
395
- async reportMessage(message, context = {}, exceptionClass = "Log") {
396
- const stackTrace = await createStackTrace(Error(), this.config.debug);
397
- stackTrace.shift();
398
- this.sendReport({
399
- notifier: `Flare JavaScript client v${CLIENT_VERSION}`,
400
- exception_class: exceptionClass,
401
- seen_at: now(),
402
- message,
403
- language: "javascript",
404
- glows: this.glows,
405
- context: collectContext({ ...context, ...this.context }),
406
- stacktrace: stackTrace,
407
- sourcemap_version_id: this.config.sourcemapVersion,
408
- solutions: [],
409
- stage: this.config.stage
410
- });
411
- }
412
- createReportFromError(error, context = {}, extraSolutionParameters = {}) {
413
- if (!assert(error, "No error provided.", this.config.debug)) {
414
- return Promise.resolve(false);
415
- }
416
- const seenAt = now();
417
- return Promise.all([
418
- getSolutions(this.solutionProviders, error, extraSolutionParameters),
419
- createStackTrace(error, this.config.debug)
420
- ]).then((result) => {
421
- const [solutions, stacktrace] = result;
422
- assert(stacktrace.length, "Couldn't generate stacktrace of this error: " + error, this.config.debug);
423
- return {
424
- notifier: `Flare JavaScript client v${CLIENT_VERSION}`,
425
- exception_class: error.constructor && error.constructor.name ? error.constructor.name : "undefined",
426
- seen_at: seenAt,
427
- message: error.message,
428
- language: "javascript",
429
- glows: this.glows,
430
- context: collectContext({ ...context, ...this.context }),
431
- stacktrace,
432
- sourcemap_version_id: this.config.sourcemapVersion,
433
- solutions,
434
- stage: this.config.stage
435
- };
436
- });
437
- }
438
- async sendReport(report) {
439
- if (!assertKey(this.config.key, this.config.debug)) {
440
- return;
441
- }
442
- const reportToSubmit = await this.config.beforeSubmit(report);
443
- if (!reportToSubmit) {
444
- return;
445
- }
446
- return this.http.report(
447
- reportToSubmit,
448
- this.config.reportingUrl,
449
- this.config.key,
450
- this.config.reportBrowserExtensionErrors
451
- );
452
- }
453
- // Deprecated, the following methods exist for backwards compatibility.
454
- set beforeEvaluate(beforeEvaluate) {
455
- this.config.beforeEvaluate = beforeEvaluate ?? "";
456
- }
457
- set beforeSubmit(beforeSubmit) {
458
- this.config.beforeSubmit = beforeSubmit ?? "";
459
- }
460
- set stage(stage) {
461
- this.config.stage = stage ?? "";
462
- }
463
- };
464
-
465
- // src/browser/catchWindowErrors.ts
466
- function catchWindowErrors() {
467
- if (typeof window === "undefined") {
468
- return;
469
- }
470
- const flare2 = window.flare;
471
- if (!window || !flare2) {
472
- return;
473
- }
474
- const originalOnerrorHandler = window.onerror;
475
- const originalOnunhandledrejectionHandler = window.onunhandledrejection;
476
- window.onerror = (_1, _2, _3, _4, error) => {
477
- if (error) {
478
- flare2.report(error);
479
- }
480
- if (typeof originalOnerrorHandler === "function") {
481
- originalOnerrorHandler(_1, _2, _3, _4, error);
482
- }
483
- };
484
- window.onunhandledrejection = (error) => {
485
- if (error.reason instanceof Error) {
486
- flare2.report(error.reason);
487
- }
488
- if (typeof originalOnunhandledrejectionHandler === "function") {
489
- originalOnunhandledrejectionHandler(error);
490
- }
491
- };
492
- }
493
-
494
- // src/index.ts
495
- var flare = new Flare();
496
- if (typeof window !== "undefined" && window) {
497
- window.flare = flare;
498
- catchWindowErrors();
499
- }
500
- // Annotate the CommonJS export names for ESM import in node:
501
- 0 && (module.exports = {
502
- Flare,
503
- flare
504
- });