@brianbuie/node-kit 0.8.0 → 0.9.1
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/LICENSE +15 -0
- package/README.md +18 -6
- package/package.json +7 -7
- package/src/Cache.ts +1 -1
- package/src/Dir.test.ts +1 -1
- package/src/Dir.ts +1 -1
- package/src/Fetcher.test.ts +1 -1
- package/src/File.test.ts +34 -30
- package/src/File.ts +56 -41
- package/src/Log.test.ts +1 -1
- package/src/Log.ts +1 -1
- package/src/TypeWriter.test.ts +1 -1
- package/src/index.ts +8 -8
- package/src/snapshot.test.ts +2 -2
- package/src/timeout.test.ts +1 -1
- package/dist/Cache.d.ts +0 -16
- package/dist/Cache.js +0 -26
- package/dist/Dir.d.ts +0 -44
- package/dist/Dir.js +0 -64
- package/dist/Fetcher.d.ts +0 -65
- package/dist/Fetcher.js +0 -111
- package/dist/File.d.ts +0 -53
- package/dist/File.js +0 -170
- package/dist/Log.d.ts +0 -43
- package/dist/Log.js +0 -80
- package/dist/TypeWriter.d.ts +0 -452
- package/dist/TypeWriter.js +0 -42
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -8
- package/dist/snapshot.d.ts +0 -5
- package/dist/snapshot.js +0 -38
- package/dist/timeout.d.ts +0 -1
- package/dist/timeout.js +0 -5
package/dist/Fetcher.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
export type Route = string | URL;
|
|
2
|
-
type QueryVal = string | number | boolean | null | undefined;
|
|
3
|
-
export type Query = Record<string, QueryVal | QueryVal[]>;
|
|
4
|
-
export type FetchOptions = RequestInit & {
|
|
5
|
-
base?: string;
|
|
6
|
-
query?: Query;
|
|
7
|
-
headers?: Record<string, string>;
|
|
8
|
-
data?: any;
|
|
9
|
-
timeout?: number;
|
|
10
|
-
retries?: number;
|
|
11
|
-
retryDelay?: number;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Fetcher provides a quick way to set up a basic API connection
|
|
15
|
-
* with options applied to every request.
|
|
16
|
-
* Includes basic methods for requesting and parsing responses
|
|
17
|
-
*/
|
|
18
|
-
export declare class Fetcher {
|
|
19
|
-
defaultOptions: {
|
|
20
|
-
body?: BodyInit | null;
|
|
21
|
-
cache?: RequestCache;
|
|
22
|
-
credentials?: RequestCredentials;
|
|
23
|
-
headers?: (HeadersInit & Record<string, string>) | undefined;
|
|
24
|
-
integrity?: string;
|
|
25
|
-
keepalive?: boolean;
|
|
26
|
-
method?: string;
|
|
27
|
-
mode?: RequestMode;
|
|
28
|
-
priority?: RequestPriority;
|
|
29
|
-
redirect?: RequestRedirect;
|
|
30
|
-
referrer?: string;
|
|
31
|
-
referrerPolicy?: ReferrerPolicy;
|
|
32
|
-
signal?: AbortSignal | null;
|
|
33
|
-
window?: null;
|
|
34
|
-
base?: string;
|
|
35
|
-
query?: Query;
|
|
36
|
-
data?: any;
|
|
37
|
-
timeout: number;
|
|
38
|
-
retries: number;
|
|
39
|
-
retryDelay: number;
|
|
40
|
-
};
|
|
41
|
-
constructor(opts?: FetchOptions);
|
|
42
|
-
/**
|
|
43
|
-
* Build URL with URLSearchParams if query is provided.
|
|
44
|
-
* Also returns domain, to help with cookies
|
|
45
|
-
*/
|
|
46
|
-
buildUrl(route: Route, opts?: FetchOptions): [URL, string];
|
|
47
|
-
/**
|
|
48
|
-
* Merges options to get headers. Useful when extending the Fetcher class to add custom auth.
|
|
49
|
-
*/
|
|
50
|
-
buildHeaders(route: Route, opts?: FetchOptions): HeadersInit & Record<string, string>;
|
|
51
|
-
/**
|
|
52
|
-
* Builds request, merging defaultOptions and provided options.
|
|
53
|
-
* Includes Abort signal for timeout
|
|
54
|
-
*/
|
|
55
|
-
buildRequest(route: Route, opts?: FetchOptions): [Request, FetchOptions, string];
|
|
56
|
-
/**
|
|
57
|
-
* Builds and performs the request, merging provided options with defaultOptions.
|
|
58
|
-
* If `opts.data` is provided, method is updated to POST, content-type json, data is stringified in the body.
|
|
59
|
-
* Retries on local or network error, with increasing backoff.
|
|
60
|
-
*/
|
|
61
|
-
fetch(route: Route, opts?: FetchOptions): Promise<[Response, Request]>;
|
|
62
|
-
fetchText(route: Route, opts?: FetchOptions): Promise<[string, Response, Request]>;
|
|
63
|
-
fetchJson<T>(route: Route, opts?: FetchOptions): Promise<[T, Response, Request]>;
|
|
64
|
-
}
|
|
65
|
-
export {};
|
package/dist/Fetcher.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { merge } from 'lodash-es';
|
|
2
|
-
import extractDomain from 'extract-domain';
|
|
3
|
-
/**
|
|
4
|
-
* Fetcher provides a quick way to set up a basic API connection
|
|
5
|
-
* with options applied to every request.
|
|
6
|
-
* Includes basic methods for requesting and parsing responses
|
|
7
|
-
*/
|
|
8
|
-
export class Fetcher {
|
|
9
|
-
defaultOptions;
|
|
10
|
-
constructor(opts = {}) {
|
|
11
|
-
this.defaultOptions = {
|
|
12
|
-
timeout: 60000,
|
|
13
|
-
retries: 0,
|
|
14
|
-
retryDelay: 3000,
|
|
15
|
-
...opts,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Build URL with URLSearchParams if query is provided.
|
|
20
|
-
* Also returns domain, to help with cookies
|
|
21
|
-
*/
|
|
22
|
-
buildUrl(route, opts = {}) {
|
|
23
|
-
const mergedOptions = merge({}, this.defaultOptions, opts);
|
|
24
|
-
const params = [];
|
|
25
|
-
Object.entries(mergedOptions.query || {}).forEach(([key, val]) => {
|
|
26
|
-
if (val === undefined)
|
|
27
|
-
return;
|
|
28
|
-
if (Array.isArray(val)) {
|
|
29
|
-
val.forEach((v) => {
|
|
30
|
-
params.push([key, `${v}`]);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
params.push([key, `${val}`]);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
const search = params.length > 0 ? '?' + new URLSearchParams(params).toString() : '';
|
|
38
|
-
const url = new URL(route + search, this.defaultOptions.base);
|
|
39
|
-
const domain = extractDomain(url.href);
|
|
40
|
-
return [url, domain];
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Merges options to get headers. Useful when extending the Fetcher class to add custom auth.
|
|
44
|
-
*/
|
|
45
|
-
buildHeaders(route, opts = {}) {
|
|
46
|
-
const { headers } = merge({}, this.defaultOptions, opts);
|
|
47
|
-
return headers || {};
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Builds request, merging defaultOptions and provided options.
|
|
51
|
-
* Includes Abort signal for timeout
|
|
52
|
-
*/
|
|
53
|
-
buildRequest(route, opts = {}) {
|
|
54
|
-
const mergedOptions = merge({}, this.defaultOptions, opts);
|
|
55
|
-
const { query, data, timeout, retries, ...init } = mergedOptions;
|
|
56
|
-
init.headers = this.buildHeaders(route, mergedOptions);
|
|
57
|
-
if (data) {
|
|
58
|
-
init.headers['content-type'] = init.headers['content-type'] || 'application/json';
|
|
59
|
-
init.method = init.method || 'POST';
|
|
60
|
-
init.body = JSON.stringify(data);
|
|
61
|
-
}
|
|
62
|
-
if (timeout) {
|
|
63
|
-
init.signal = AbortSignal.timeout(timeout);
|
|
64
|
-
}
|
|
65
|
-
const [url, domain] = this.buildUrl(route, mergedOptions);
|
|
66
|
-
const req = new Request(url, init);
|
|
67
|
-
return [req, mergedOptions, domain];
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Builds and performs the request, merging provided options with defaultOptions.
|
|
71
|
-
* If `opts.data` is provided, method is updated to POST, content-type json, data is stringified in the body.
|
|
72
|
-
* Retries on local or network error, with increasing backoff.
|
|
73
|
-
*/
|
|
74
|
-
async fetch(route, opts = {}) {
|
|
75
|
-
const [_req, options] = this.buildRequest(route, opts);
|
|
76
|
-
const maxAttempts = (options.retries || 0) + 1;
|
|
77
|
-
let attempt = 0;
|
|
78
|
-
while (attempt < maxAttempts) {
|
|
79
|
-
attempt++;
|
|
80
|
-
const [req] = this.buildRequest(route, opts);
|
|
81
|
-
const res = await fetch(req)
|
|
82
|
-
.then((r) => {
|
|
83
|
-
if (!r.ok)
|
|
84
|
-
throw new Error(r.statusText);
|
|
85
|
-
return r;
|
|
86
|
-
})
|
|
87
|
-
.catch(async (error) => {
|
|
88
|
-
if (attempt < maxAttempts) {
|
|
89
|
-
const wait = attempt * 3000;
|
|
90
|
-
console.warn(`${req.method} ${req.url} (attempt ${attempt} of ${maxAttempts})`, error);
|
|
91
|
-
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
throw new Error(error);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
if (res)
|
|
98
|
-
return [res, req];
|
|
99
|
-
}
|
|
100
|
-
throw new Error(`Failed to fetch ${_req.url}`);
|
|
101
|
-
}
|
|
102
|
-
async fetchText(route, opts = {}) {
|
|
103
|
-
return this.fetch(route, opts).then(async ([res, req]) => {
|
|
104
|
-
const text = await res.text();
|
|
105
|
-
return [text, res, req];
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
async fetchJson(route, opts = {}) {
|
|
109
|
-
return this.fetchText(route, opts).then(([txt, res, req]) => [JSON.parse(txt), res, req]);
|
|
110
|
-
}
|
|
111
|
-
}
|
package/dist/File.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Readable } from 'node:stream';
|
|
2
|
-
/**
|
|
3
|
-
* WARNING: API will change!
|
|
4
|
-
*/
|
|
5
|
-
export declare class File {
|
|
6
|
-
path: string;
|
|
7
|
-
constructor(filepath: string);
|
|
8
|
-
get exists(): boolean;
|
|
9
|
-
delete(): void;
|
|
10
|
-
read(): string | undefined;
|
|
11
|
-
write(contents: string): void;
|
|
12
|
-
streamFrom(...options: Parameters<(typeof Readable)['from']>): Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* creates file if it doesn't exist, appends string or array of strings as new lines.
|
|
15
|
-
* File always ends with '\n', so contents don't need to be read before appending
|
|
16
|
-
*/
|
|
17
|
-
append(lines: string | string[]): void;
|
|
18
|
-
/**
|
|
19
|
-
* @returns lines as strings, removes trailing '\n'
|
|
20
|
-
*/
|
|
21
|
-
lines(): string[];
|
|
22
|
-
static get FileType(): typeof FileType;
|
|
23
|
-
json<T>(contents?: T): FileTypeJson<T>;
|
|
24
|
-
static get json(): typeof FileTypeJson;
|
|
25
|
-
ndjson<T extends object>(lines?: T | T[]): FileTypeNdjson<T>;
|
|
26
|
-
static get ndjson(): typeof FileTypeNdjson;
|
|
27
|
-
csv<T extends object>(rows?: T[], keys?: (keyof T)[]): Promise<FileTypeCsv<T>>;
|
|
28
|
-
static get csv(): typeof FileTypeCsv;
|
|
29
|
-
}
|
|
30
|
-
export declare class FileType<T = string> {
|
|
31
|
-
file: File;
|
|
32
|
-
constructor(filepath: string, contents?: T);
|
|
33
|
-
get exists(): boolean;
|
|
34
|
-
delete(): void;
|
|
35
|
-
get path(): string;
|
|
36
|
-
}
|
|
37
|
-
export declare class FileTypeJson<T> extends FileType {
|
|
38
|
-
constructor(filepath: string, contents?: T);
|
|
39
|
-
read(): T | undefined;
|
|
40
|
-
write(contents: T): void;
|
|
41
|
-
}
|
|
42
|
-
export declare class FileTypeNdjson<T extends object> extends FileType {
|
|
43
|
-
constructor(filepath: string, lines?: T | T[]);
|
|
44
|
-
append(lines: T | T[]): void;
|
|
45
|
-
lines(): T[];
|
|
46
|
-
}
|
|
47
|
-
type Key<T extends object> = keyof T;
|
|
48
|
-
export declare class FileTypeCsv<Row extends object> extends FileType {
|
|
49
|
-
constructor(filepath: string);
|
|
50
|
-
write(rows: Row[], keys?: Key<Row>[]): Promise<void>;
|
|
51
|
-
read(): Promise<Row[]>;
|
|
52
|
-
}
|
|
53
|
-
export {};
|
package/dist/File.js
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import { Readable } from 'node:stream';
|
|
4
|
-
import { finished } from 'node:stream/promises';
|
|
5
|
-
import { writeToString, parseString } from 'fast-csv';
|
|
6
|
-
import { snapshot } from './snapshot.js';
|
|
7
|
-
/**
|
|
8
|
-
* WARNING: API will change!
|
|
9
|
-
*/
|
|
10
|
-
export class File {
|
|
11
|
-
path;
|
|
12
|
-
constructor(filepath) {
|
|
13
|
-
this.path = filepath;
|
|
14
|
-
}
|
|
15
|
-
get exists() {
|
|
16
|
-
return fs.existsSync(this.path);
|
|
17
|
-
}
|
|
18
|
-
delete() {
|
|
19
|
-
fs.rmSync(this.path, { force: true });
|
|
20
|
-
}
|
|
21
|
-
read() {
|
|
22
|
-
return this.exists ? fs.readFileSync(this.path, 'utf8') : undefined;
|
|
23
|
-
}
|
|
24
|
-
write(contents) {
|
|
25
|
-
fs.mkdirSync(path.parse(this.path).dir, { recursive: true });
|
|
26
|
-
fs.writeFileSync(this.path, contents);
|
|
27
|
-
}
|
|
28
|
-
async streamFrom(...options) {
|
|
29
|
-
return finished(Readable.from(...options).pipe(fs.createWriteStream(this.path)));
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* creates file if it doesn't exist, appends string or array of strings as new lines.
|
|
33
|
-
* File always ends with '\n', so contents don't need to be read before appending
|
|
34
|
-
*/
|
|
35
|
-
append(lines) {
|
|
36
|
-
if (!this.exists)
|
|
37
|
-
this.write('');
|
|
38
|
-
const contents = Array.isArray(lines) ? lines.join('\n') : lines;
|
|
39
|
-
fs.appendFileSync(this.path, contents + '\n');
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* @returns lines as strings, removes trailing '\n'
|
|
43
|
-
*/
|
|
44
|
-
lines() {
|
|
45
|
-
const contents = (this.read() || '').split('\n');
|
|
46
|
-
return contents.slice(0, contents.length - 1);
|
|
47
|
-
}
|
|
48
|
-
static get FileType() {
|
|
49
|
-
return FileType;
|
|
50
|
-
}
|
|
51
|
-
json(contents) {
|
|
52
|
-
return new FileTypeJson(this.path, contents);
|
|
53
|
-
}
|
|
54
|
-
static get json() {
|
|
55
|
-
return FileTypeJson;
|
|
56
|
-
}
|
|
57
|
-
ndjson(lines) {
|
|
58
|
-
return new FileTypeNdjson(this.path, lines);
|
|
59
|
-
}
|
|
60
|
-
static get ndjson() {
|
|
61
|
-
return FileTypeNdjson;
|
|
62
|
-
}
|
|
63
|
-
async csv(rows, keys) {
|
|
64
|
-
const csvFile = new FileTypeCsv(this.path);
|
|
65
|
-
if (rows)
|
|
66
|
-
await csvFile.write(rows, keys);
|
|
67
|
-
return csvFile;
|
|
68
|
-
}
|
|
69
|
-
static get csv() {
|
|
70
|
-
return FileTypeCsv;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
export class FileType {
|
|
74
|
-
file;
|
|
75
|
-
constructor(filepath, contents) {
|
|
76
|
-
this.file = new File(filepath);
|
|
77
|
-
if (contents) {
|
|
78
|
-
if (typeof contents !== 'string') {
|
|
79
|
-
throw new Error('File contents must be a string');
|
|
80
|
-
}
|
|
81
|
-
this.file.write(contents);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
get exists() {
|
|
85
|
-
return this.file.exists;
|
|
86
|
-
}
|
|
87
|
-
delete() {
|
|
88
|
-
this.file.delete();
|
|
89
|
-
}
|
|
90
|
-
get path() {
|
|
91
|
-
return this.file.path;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
export class FileTypeJson extends FileType {
|
|
95
|
-
constructor(filepath, contents) {
|
|
96
|
-
super(filepath.endsWith('.json') ? filepath : filepath + '.json');
|
|
97
|
-
if (contents)
|
|
98
|
-
this.write(contents);
|
|
99
|
-
}
|
|
100
|
-
read() {
|
|
101
|
-
const contents = this.file.read();
|
|
102
|
-
return contents ? JSON.parse(contents) : undefined;
|
|
103
|
-
}
|
|
104
|
-
write(contents) {
|
|
105
|
-
this.file.write(JSON.stringify(snapshot(contents), null, 2));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
export class FileTypeNdjson extends FileType {
|
|
109
|
-
constructor(filepath, lines) {
|
|
110
|
-
super(filepath.endsWith('.ndjson') ? filepath : filepath + '.ndjson');
|
|
111
|
-
if (lines)
|
|
112
|
-
this.append(lines);
|
|
113
|
-
}
|
|
114
|
-
append(lines) {
|
|
115
|
-
this.file.append(Array.isArray(lines) ? lines.map((l) => JSON.stringify(snapshot(l))) : JSON.stringify(snapshot(lines)));
|
|
116
|
-
}
|
|
117
|
-
lines() {
|
|
118
|
-
return this.file.lines().map((l) => JSON.parse(l));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
export class FileTypeCsv extends FileType {
|
|
122
|
-
constructor(filepath) {
|
|
123
|
-
super(filepath.endsWith('.csv') ? filepath : filepath + '.csv');
|
|
124
|
-
}
|
|
125
|
-
async write(rows, keys) {
|
|
126
|
-
const headerSet = new Set();
|
|
127
|
-
if (keys) {
|
|
128
|
-
for (const key of keys)
|
|
129
|
-
headerSet.add(key);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
for (const row of rows) {
|
|
133
|
-
for (const key in row)
|
|
134
|
-
headerSet.add(key);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
const headers = Array.from(headerSet);
|
|
138
|
-
const outRows = rows.map((row) => headers.map((key) => row[key]));
|
|
139
|
-
const contents = await writeToString([headers, ...outRows]);
|
|
140
|
-
this.file.write(contents);
|
|
141
|
-
}
|
|
142
|
-
async read() {
|
|
143
|
-
return new Promise((resolve, reject) => {
|
|
144
|
-
const parsed = [];
|
|
145
|
-
const content = this.file.read();
|
|
146
|
-
if (!content)
|
|
147
|
-
return resolve(parsed);
|
|
148
|
-
function parseVal(val) {
|
|
149
|
-
if (val.toLowerCase() === 'false')
|
|
150
|
-
return false;
|
|
151
|
-
if (val.toLowerCase() === 'true')
|
|
152
|
-
return true;
|
|
153
|
-
if (val.length === 0)
|
|
154
|
-
return null;
|
|
155
|
-
if (/^[\.0-9]+$/.test(val))
|
|
156
|
-
return Number(val);
|
|
157
|
-
return val;
|
|
158
|
-
}
|
|
159
|
-
parseString(content, { headers: true })
|
|
160
|
-
.on('error', (e) => reject(e))
|
|
161
|
-
.on('end', () => resolve(parsed))
|
|
162
|
-
.on('data', (raw) => {
|
|
163
|
-
parsed.push(Object.entries(raw).reduce((all, [key, val]) => ({
|
|
164
|
-
...all,
|
|
165
|
-
[key]: parseVal(val),
|
|
166
|
-
}), {}));
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
package/dist/Log.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { type ChalkInstance } from 'chalk';
|
|
2
|
-
type Severity = 'DEFAULT' | 'DEBUG' | 'INFO' | 'NOTICE' | 'WARNING' | 'ERROR' | 'CRITICAL' | 'ALERT' | 'EMERGENCY';
|
|
3
|
-
type Options = {
|
|
4
|
-
severity: Severity;
|
|
5
|
-
color: ChalkInstance;
|
|
6
|
-
};
|
|
7
|
-
export declare class Log {
|
|
8
|
-
#private;
|
|
9
|
-
static isTest: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Handle first argument being a string or an object with a 'message' prop
|
|
12
|
-
* Also snapshots special objects (eg Error, Response) to keep props in later JSON.stringify output
|
|
13
|
-
*/
|
|
14
|
-
static prepare(...input: unknown[]): {
|
|
15
|
-
message?: string;
|
|
16
|
-
details: unknown[];
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Logs error details before throwing
|
|
20
|
-
*/
|
|
21
|
-
static error(...input: unknown[]): void;
|
|
22
|
-
static warn(...input: unknown[]): {
|
|
23
|
-
message: string | undefined;
|
|
24
|
-
details: unknown[];
|
|
25
|
-
options: Options;
|
|
26
|
-
};
|
|
27
|
-
static notice(...input: unknown[]): {
|
|
28
|
-
message: string | undefined;
|
|
29
|
-
details: unknown[];
|
|
30
|
-
options: Options;
|
|
31
|
-
};
|
|
32
|
-
static info(...input: unknown[]): {
|
|
33
|
-
message: string | undefined;
|
|
34
|
-
details: unknown[];
|
|
35
|
-
options: Options;
|
|
36
|
-
};
|
|
37
|
-
static debug(...input: unknown[]): {
|
|
38
|
-
message: string | undefined;
|
|
39
|
-
details: unknown[];
|
|
40
|
-
options: Options;
|
|
41
|
-
} | undefined;
|
|
42
|
-
}
|
|
43
|
-
export {};
|
package/dist/Log.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
|
-
import { isObjectLike } from 'lodash-es';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { snapshot } from './snapshot.js';
|
|
5
|
-
export class Log {
|
|
6
|
-
// Only silence logs when THIS package is running its own tests
|
|
7
|
-
static isTest = process.env.npm_package_name === '@brianbuie/node-kit' && process.env.npm_lifecycle_event === 'test';
|
|
8
|
-
/**
|
|
9
|
-
* Gcloud parses JSON in stdout
|
|
10
|
-
*/
|
|
11
|
-
static #toGcloud(entry) {
|
|
12
|
-
if (entry.details?.length === 1) {
|
|
13
|
-
console.log(JSON.stringify({ ...entry, details: entry.details[0] }));
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
console.log(JSON.stringify(entry));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Includes colors and better inspection for logging during dev
|
|
21
|
-
*/
|
|
22
|
-
static #toConsole(entry, color) {
|
|
23
|
-
if (entry.message)
|
|
24
|
-
console.log(color(`[${entry.severity}] ${entry.message}`));
|
|
25
|
-
entry.details?.forEach((detail) => {
|
|
26
|
-
console.log(inspect(detail, { depth: 10, breakLength: 100, compact: true, colors: true }));
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
static #log(options, ...input) {
|
|
30
|
-
const { message, details } = this.prepare(...input);
|
|
31
|
-
// https://cloud.google.com/run/docs/container-contract#env-vars
|
|
32
|
-
const isGcloud = process.env.K_SERVICE !== undefined || process.env.CLOUD_RUN_JOB !== undefined;
|
|
33
|
-
if (isGcloud) {
|
|
34
|
-
this.#toGcloud({ message, severity: options.severity, details });
|
|
35
|
-
return { message, details, options };
|
|
36
|
-
}
|
|
37
|
-
// Hide output while testing this package
|
|
38
|
-
if (!this.isTest) {
|
|
39
|
-
this.#toConsole({ message, severity: options.severity, details }, options.color);
|
|
40
|
-
}
|
|
41
|
-
return { message, details, options };
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Handle first argument being a string or an object with a 'message' prop
|
|
45
|
-
* Also snapshots special objects (eg Error, Response) to keep props in later JSON.stringify output
|
|
46
|
-
*/
|
|
47
|
-
static prepare(...input) {
|
|
48
|
-
let [first, ...rest] = input.map((i) => snapshot(i));
|
|
49
|
-
if (typeof first === 'string')
|
|
50
|
-
return { message: first, details: rest };
|
|
51
|
-
// @ts-ignore
|
|
52
|
-
if (isObjectLike(first) && typeof first['message'] === 'string') {
|
|
53
|
-
const { message, ...firstDetails } = first;
|
|
54
|
-
return { message, details: [firstDetails, ...rest] };
|
|
55
|
-
}
|
|
56
|
-
return { details: input };
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Logs error details before throwing
|
|
60
|
-
*/
|
|
61
|
-
static error(...input) {
|
|
62
|
-
const { message } = this.#log({ severity: 'ERROR', color: chalk.red }, ...input);
|
|
63
|
-
throw new Error(message);
|
|
64
|
-
}
|
|
65
|
-
static warn(...input) {
|
|
66
|
-
return this.#log({ severity: 'WARNING', color: chalk.yellow }, ...input);
|
|
67
|
-
}
|
|
68
|
-
static notice(...input) {
|
|
69
|
-
return this.#log({ severity: 'NOTICE', color: chalk.cyan }, ...input);
|
|
70
|
-
}
|
|
71
|
-
static info(...input) {
|
|
72
|
-
return this.#log({ severity: 'INFO', color: chalk.white }, ...input);
|
|
73
|
-
}
|
|
74
|
-
static debug(...input) {
|
|
75
|
-
const debugging = process.argv.some((arg) => arg.includes('--debug')) || process.env.DEBUG !== undefined;
|
|
76
|
-
if (debugging || process.env.NODE_ENV !== 'production') {
|
|
77
|
-
return this.#log({ severity: 'DEBUG', color: chalk.gray }, ...input);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|