@brianbuie/node-kit 0.6.0 → 0.7.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/README.md CHANGED
@@ -4,110 +4,579 @@
4
4
 
5
5
  Basic tools for quick node.js projects
6
6
 
7
- ## Installing
7
+ # Installing
8
8
 
9
9
  ```
10
10
  npm add @brianbuie/node-kit
11
11
  ```
12
12
 
13
13
  ```js
14
- import { thing } from '@brianbuie/node-kit';
14
+ import { Fetcher, Log } from '@brianbuie/node-kit';
15
15
  ```
16
16
 
17
- ## Features
17
+ # API
18
18
 
19
- ### Fetcher
19
+ <!--#region ts2md-api-merged-here-->
20
+
21
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
22
+
23
+ # Classes
24
+
25
+ | |
26
+ | --- |
27
+ | [Cache](#class-cache) |
28
+ | [Dir](#class-dir) |
29
+ | [Fetcher](#class-fetcher) |
30
+ | [File](#class-file) |
31
+ | [FileType](#class-filetype) |
32
+ | [FileTypeCsv](#class-filetypecsv) |
33
+ | [FileTypeJson](#class-filetypejson) |
34
+ | [FileTypeNdjson](#class-filetypendjson) |
35
+ | [Jwt](#class-jwt) |
36
+ | [Log](#class-log) |
37
+ | [TempDir](#class-tempdir) |
38
+ | [TypeWriter](#class-typewriter) |
39
+
40
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
41
+
42
+ ---
43
+
44
+ ## Class: Cache
45
+
46
+ Save results of a function in a temporary file.
20
47
 
21
48
  ```ts
22
- import { Fetcher } from '@brianbuie/node-kit';
49
+ export class Cache<T> {
50
+ file;
51
+ ttl;
52
+ getValue;
53
+ constructor(key: string, ttl: number, getValue: () => T | Promise<T>)
54
+ async read()
55
+ async write()
56
+ }
57
+ ```
58
+
59
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
23
60
 
24
- // All requests will include Authorization header
25
- const api = new Fetcher({
26
- base: 'https://www.example.com',
27
- headers: {
28
- Authorization: `Bearer ${process.env.EXAMPLE_SECRET}`,
29
- },
30
- });
61
+ ---
62
+ ## Class: Dir
63
+
64
+ Reference to a specific directory with helpful methods for resolving filepaths,
65
+ sanitizing filenames, and saving files.
66
+
67
+ ```ts
68
+ export class Dir {
69
+ path;
70
+ constructor(_path: string)
71
+ create()
72
+ dir(subPath: string)
73
+ sanitize(name: string)
74
+ filepath(base: string)
75
+ file(base: string)
76
+ }
77
+ ```
31
78
 
32
- // GET https://www.example.com/route
33
- // returns [Response, Request]
34
- const [res] = await api.fetch('/route');
79
+ <details>
35
80
 
36
- // GET https://www.example.com/other-route
37
- // returns [string, Response, Request]
38
- const [text] = await api.fetchText('/other-route');
81
+ <summary>Class Dir Details</summary>
39
82
 
40
- // GET https://www.example.com/thing?page=1
41
- // returns [Thing, Response, Request]
42
- const [data] = await api.fetchJson<Thing>('/thing', { query: { page: 1 } });
83
+ ### Constructor
43
84
 
44
- // POST https://www.example.com/thing (data is sent as JSON in body)
45
- // returns [Thing, Response, Request]
46
- const [result] = await api.fetchJson<Thing>('/thing', { data: { example: 1 } });
85
+ ```ts
86
+ constructor(_path: string)
47
87
  ```
48
88
 
49
- ### Jwt
89
+ Argument Details
50
90
 
51
- Save a JSON Web Token in memory and reuse it throughout the process.
91
+ + **path**
92
+ + can be relative to workspace or absolute
52
93
 
53
- ```js
54
- import { Jwt, Fetcher } from '@brianbuie/node-kit';
94
+ ### Method dir
55
95
 
56
- const apiJwt = new Jwt({
57
- payload: {
58
- example: 'value',
59
- },
60
- options: {
61
- algorithm: 'HS256',
62
- },
63
- seconds: 60,
64
- key: process.env.JWT_KEY,
65
- });
96
+ Create a new Dir inside the current Dir
66
97
 
67
- const api = new Fetcher({
68
- base: 'https://example.com',
69
- headers: {
70
- Authorization: `Bearer ${apiJwt.token}`,
71
- },
72
- });
98
+ ```ts
99
+ dir(subPath: string)
73
100
  ```
74
101
 
75
- > TODO: expiration is not checked again when provided in a header
102
+ Argument Details
76
103
 
77
- ### Log
104
+ + **subPath**
105
+ + to create in current Dir
78
106
 
79
- Chalk output in development, structured JSON when running in gcloud
107
+ Example
80
108
 
81
- ```js
82
- import { Log } from '@brianbuie/node-kit';
109
+ ```ts
110
+ const folder = new Dir('example');
111
+ // folder.path = './example'
112
+ const child = folder.subDir('path/to/dir');
113
+ // child.path = './example/path/to/dir'
114
+ ```
115
+
116
+ ### Method filepath
117
+
118
+ ```ts
119
+ filepath(base: string)
120
+ ```
121
+
122
+ Argument Details
83
123
 
84
- Log.info('message', { other: 'details' });
124
+ + **base**
125
+ + The file name with extension
85
126
 
86
- // Print in development, or if process.env.DEBUG or --debug argument is present
87
- Log.debug('message', Response);
127
+ Example
88
128
 
89
- // Log details and throw
90
- Log.error('Something happened', details, moreDetails);
129
+ ```ts
130
+ const folder = new Dir('example');
131
+ const filepath = folder.resolve('file.json');
132
+ // 'example/file.json'
91
133
  ```
92
134
 
93
- ### snapshot
135
+ </details>
94
136
 
95
- Gets all enumerable and non-enumerable properties, so they can be included in JSON.stringify. Helpful for built-in objects, like Error, Request, Response, Headers, Map, etc.
137
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
96
138
 
97
- ```js
98
- fs.writeFileSync('result.json', JSON.stringify(snapshot(response), null, 2));
139
+ ---
140
+ ## Class: Fetcher
141
+
142
+ Fetcher provides a quick way to set up a basic API connection
143
+ with options applied to every request.
144
+ Includes basic methods for requesting and parsing responses
145
+
146
+ ```ts
147
+ export class Fetcher {
148
+ defaultOptions;
149
+ constructor(opts: FetchOptions = {})
150
+ buildUrl(route: Route, opts: FetchOptions = {}): [
151
+ URL,
152
+ string
153
+ ]
154
+ buildHeaders(route: Route, opts: FetchOptions = {})
155
+ buildRequest(route: Route, opts: FetchOptions = {}): [
156
+ Request,
157
+ FetchOptions,
158
+ string
159
+ ]
160
+ async fetch(route: Route, opts: FetchOptions = {}): Promise<[
161
+ Response,
162
+ Request
163
+ ]>
164
+ async fetchText(route: Route, opts: FetchOptions = {}): Promise<[
165
+ string,
166
+ Response,
167
+ Request
168
+ ]>
169
+ async fetchJson<T>(route: Route, opts: FetchOptions = {}): Promise<[
170
+ T,
171
+ Response,
172
+ Request
173
+ ]>
174
+ }
175
+ ```
176
+
177
+ See also: [FetchOptions](#type-fetchoptions), [Route](#type-route)
178
+
179
+ <details>
180
+
181
+ <summary>Class Fetcher Details</summary>
182
+
183
+ ### Method buildHeaders
184
+
185
+ Merges options to get headers. Useful when extending the Fetcher class to add custom auth.
186
+
187
+ ```ts
188
+ buildHeaders(route: Route, opts: FetchOptions = {})
189
+ ```
190
+ See also: [FetchOptions](#type-fetchoptions), [Route](#type-route)
191
+
192
+ ### Method buildRequest
193
+
194
+ Builds request, merging defaultOptions and provided options.
195
+ Includes Abort signal for timeout
196
+
197
+ ```ts
198
+ buildRequest(route: Route, opts: FetchOptions = {}): [
199
+ Request,
200
+ FetchOptions,
201
+ string
202
+ ]
99
203
  ```
204
+ See also: [FetchOptions](#type-fetchoptions), [Route](#type-route)
100
205
 
101
- ## Publishing changes to this package
206
+ ### Method buildUrl
102
207
 
103
- Commit all changes, then run:
208
+ Build URL with URLSearchParams if query is provided.
209
+ Also returns domain, to help with cookies
104
210
 
211
+ ```ts
212
+ buildUrl(route: Route, opts: FetchOptions = {}): [
213
+ URL,
214
+ string
215
+ ]
105
216
  ```
106
- npm version [patch|minor|major] [-m "custom commit message"]
217
+ See also: [FetchOptions](#type-fetchoptions), [Route](#type-route)
218
+
219
+ ### Method fetch
220
+
221
+ Builds and performs the request, merging provided options with defaultOptions.
222
+ If `opts.data` is provided, method is updated to POST, content-type json, data is stringified in the body.
223
+ Retries on local or network error, with increasing backoff.
224
+
225
+ ```ts
226
+ async fetch(route: Route, opts: FetchOptions = {}): Promise<[
227
+ Response,
228
+ Request
229
+ ]>
107
230
  ```
231
+ See also: [FetchOptions](#type-fetchoptions), [Route](#type-route)
232
+
233
+ </details>
234
+
235
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
236
+
237
+ ---
238
+ ## Class: File
239
+
240
+ WARNING: API will change!
241
+
242
+ ```ts
243
+ export class File {
244
+ path;
245
+ constructor(filepath: string)
246
+ get exists()
247
+ createWriteStream(options: Parameters<typeof fs.createWriteStream>[1] = {})
248
+ delete()
249
+ read()
250
+ write(contents: string)
251
+ append(lines: string | string[])
252
+ lines()
253
+ static get FileType()
254
+ json<T>(contents?: T)
255
+ static get json()
256
+ ndjson<T extends object>(lines?: T | T[])
257
+ static get ndjson()
258
+ async csv<T extends object>(rows?: T[], keys?: (keyof T)[])
259
+ static get csv()
260
+ }
261
+ ```
262
+
263
+ See also: [FileType](#class-filetype)
264
+
265
+ <details>
266
+
267
+ <summary>Class File Details</summary>
268
+
269
+ ### Method append
270
+
271
+ creates file if it doesn't exist, appends string or array of strings as new lines.
272
+ File always ends with '\n', so contents don't need to be read before appending
273
+
274
+ ```ts
275
+ append(lines: string | string[])
276
+ ```
277
+
278
+ ### Method lines
279
+
280
+ ```ts
281
+ lines()
282
+ ```
283
+
284
+ Returns
285
+
286
+ lines as strings, removes trailing '\n'
287
+
288
+ </details>
289
+
290
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
291
+
292
+ ---
293
+ ## Class: FileType
294
+
295
+ ```ts
296
+ export class FileType<T = string> {
297
+ file;
298
+ constructor(filepath: string, contents?: T)
299
+ get exists()
300
+ delete()
301
+ get path()
302
+ }
303
+ ```
304
+
305
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
306
+
307
+ ---
308
+ ## Class: FileTypeCsv
309
+
310
+ ```ts
311
+ export class FileTypeCsv<Row extends object> extends FileType {
312
+ constructor(filepath: string)
313
+ async write(rows: Row[], keys?: Key<Row>[])
314
+ async read()
315
+ }
316
+ ```
317
+
318
+ See also: [FileType](#class-filetype)
319
+
320
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
321
+
322
+ ---
323
+ ## Class: FileTypeJson
324
+
325
+ ```ts
326
+ export class FileTypeJson<T> extends FileType {
327
+ constructor(filepath: string, contents?: T)
328
+ read()
329
+ write(contents: T)
330
+ }
331
+ ```
332
+
333
+ See also: [FileType](#class-filetype)
334
+
335
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
336
+
337
+ ---
338
+ ## Class: FileTypeNdjson
339
+
340
+ ```ts
341
+ export class FileTypeNdjson<T extends object> extends FileType {
342
+ constructor(filepath: string, lines?: T | T[])
343
+ append(lines: T | T[])
344
+ lines()
345
+ }
346
+ ```
347
+
348
+ See also: [FileType](#class-filetype)
349
+
350
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
351
+
352
+ ---
353
+ ## Class: Jwt
354
+
355
+ ```ts
356
+ export class Jwt {
357
+ config;
358
+ #saved?: {
359
+ exp: number;
360
+ token: string;
361
+ };
362
+ constructor(config: JwtConfig)
363
+ get now()
364
+ #createToken()
365
+ get token()
366
+ }
367
+ ```
368
+
369
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
370
+
371
+ ---
372
+ ## Class: Log
373
+
374
+ ```ts
375
+ export class Log {
376
+ static isTest = process.env.npm_package_name === "@brianbuie/node-kit" && process.env.npm_lifecycle_event === "test";
377
+ static #toGcloud(entry: Entry)
378
+ static #toConsole(entry: Entry, color: ChalkInstance)
379
+ static #log(options: Options, ...input: unknown[])
380
+ static prepare(...input: unknown[]): {
381
+ message?: string;
382
+ details: unknown[];
383
+ }
384
+ static error(...input: unknown[])
385
+ static warn(...input: unknown[])
386
+ static notice(...input: unknown[])
387
+ static info(...input: unknown[])
388
+ static debug(...input: unknown[])
389
+ }
390
+ ```
391
+
392
+ <details>
393
+
394
+ <summary>Class Log Details</summary>
395
+
396
+ ### Method
397
+
398
+ Gcloud parses JSON in stdout
399
+
400
+ ```ts
401
+ static #toGcloud(entry: Entry)
402
+ ```
403
+
404
+ ### Method
405
+
406
+ Includes colors and better inspection for logging during dev
407
+
408
+ ```ts
409
+ static #toConsole(entry: Entry, color: ChalkInstance)
410
+ ```
411
+
412
+ ### Method error
413
+
414
+ Logs error details before throwing
415
+
416
+ ```ts
417
+ static error(...input: unknown[])
418
+ ```
419
+
420
+ ### Method prepare
421
+
422
+ Handle first argument being a string or an object with a 'message' prop
423
+ Also snapshots special objects (eg Error, Response) to keep props in later JSON.stringify output
424
+
425
+ ```ts
426
+ static prepare(...input: unknown[]): {
427
+ message?: string;
428
+ details: unknown[];
429
+ }
430
+ ```
431
+
432
+ </details>
433
+
434
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
435
+
436
+ ---
437
+ ## Class: TempDir
438
+
439
+ Extends Dir class with method to `clear()` contents
440
+
441
+ ```ts
442
+ export class TempDir extends Dir {
443
+ dir(subPath: string)
444
+ clear()
445
+ }
446
+ ```
447
+
448
+ See also: [Dir](#class-dir)
449
+
450
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
451
+
452
+ ---
453
+ ## Class: TypeWriter
454
+
455
+ ```ts
456
+ export class TypeWriter {
457
+ moduleName;
458
+ input = qt.jsonInputForTargetLanguage("typescript");
459
+ outDir;
460
+ qtSettings;
461
+ constructor(moduleName: string, settings: {
462
+ outDir?: string;
463
+ } & Partial<qt.Options> = {})
464
+ async addMember(name: string, _samples: any[])
465
+ async toString()
466
+ async toFile()
467
+ }
468
+ ```
469
+
470
+ <details>
471
+
472
+ <summary>Class TypeWriter Details</summary>
473
+
474
+ ### Method toString
475
+
476
+ function toString() { [native code] }
477
+
478
+ ```ts
479
+ async toString()
480
+ ```
481
+
482
+ </details>
483
+
484
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
485
+
486
+ ---
487
+ # Functions
488
+
489
+ | |
490
+ | --- |
491
+ | [snapshot](#function-snapshot) |
492
+ | [timeout](#function-timeout) |
493
+
494
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
495
+
496
+ ---
497
+
498
+ ## Function: snapshot
499
+
500
+ Allows special objects (Error, Headers, Set) to be included in JSON.stringify output
501
+ functions are removed
502
+
503
+ ```ts
504
+ export function snapshot(i: unknown, max = 50, depth = 0): any
505
+ ```
506
+
507
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
508
+
509
+ ---
510
+ ## Function: timeout
511
+
512
+ ```ts
513
+ export async function timeout(ms: number)
514
+ ```
515
+
516
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
517
+
518
+ ---
519
+ # Types
520
+
521
+ | |
522
+ | --- |
523
+ | [FetchOptions](#type-fetchoptions) |
524
+ | [Query](#type-query) |
525
+ | [Route](#type-route) |
526
+
527
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
528
+
529
+ ---
530
+
531
+ ## Type: FetchOptions
532
+
533
+ ```ts
534
+ export type FetchOptions = RequestInit & {
535
+ base?: string;
536
+ query?: Query;
537
+ headers?: Record<string, string>;
538
+ data?: any;
539
+ timeout?: number;
540
+ retries?: number;
541
+ retryDelay?: number;
542
+ }
543
+ ```
544
+
545
+ See also: [Query](#type-query), [timeout](#function-timeout)
546
+
547
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
548
+
549
+ ---
550
+ ## Type: Query
551
+
552
+ ```ts
553
+ export type Query = Record<string, QueryVal | QueryVal[]>
554
+ ```
555
+
556
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
557
+
558
+ ---
559
+ ## Type: Route
560
+
561
+ ```ts
562
+ export type Route = string | URL
563
+ ```
564
+
565
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
566
+
567
+ ---
568
+ # Variables
569
+
570
+ ## Variable: temp
571
+
572
+ ```ts
573
+ temp = new TempDir(".temp")
574
+ ```
575
+
576
+ See also: [TempDir](#class-tempdir)
577
+
578
+ Links: [API](#api), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
579
+
580
+ ---
108
581
 
109
- - Bumps version in `package.json`
110
- - Runs tests (`"preversion"` script in `package.json`)
111
- - Creates new commit, tagged with version
112
- - Pushes commit and tags to github (`"postversion"` script in `package.json`)
113
- - The new tag will trigger github action to publish to npm (`.github/actions/publish.yml`)
582
+ <!--#endregion ts2md-api-merged-here-->
package/dist/Cache.d.ts CHANGED
@@ -1,21 +1,17 @@
1
+ /**
2
+ * Save results of a function in a temporary file.
3
+ * @param key A unique name for the file
4
+ * @param ttl cache duration in ms
5
+ * @param getValue the function to populate the cache (eg. fetch results, generate key, etc)
6
+ */
1
7
  export declare class Cache<T> {
2
- file: {
3
- read(): {
4
- createdAt: number;
5
- value: T;
6
- } | undefined;
7
- write(contents: {
8
- createdAt: number;
9
- value: T;
10
- }): void;
11
- file: import("./File.js").File;
12
- get exists(): boolean;
13
- delete(): void;
14
- get path(): string;
15
- };
8
+ file: import("./File.js").FileTypeJson<{
9
+ createdAt: number;
10
+ value: T;
11
+ }>;
16
12
  ttl: number;
17
- refresh: () => T | Promise<T>;
18
- constructor(key: string, ttl: number, refresh: () => T | Promise<T>);
13
+ getValue: () => T | Promise<T>;
14
+ constructor(key: string, ttl: number, getValue: () => T | Promise<T>);
19
15
  read(): Promise<T>;
20
16
  write(): Promise<T>;
21
17
  }
package/dist/Cache.js CHANGED
@@ -1,13 +1,19 @@
1
1
  import { temp } from './Dir.js';
2
2
  const cacheDir = temp.dir('cache');
3
+ /**
4
+ * Save results of a function in a temporary file.
5
+ * @param key A unique name for the file
6
+ * @param ttl cache duration in ms
7
+ * @param getValue the function to populate the cache (eg. fetch results, generate key, etc)
8
+ */
3
9
  export class Cache {
4
10
  file;
5
11
  ttl;
6
- refresh;
7
- constructor(key, ttl, refresh) {
12
+ getValue;
13
+ constructor(key, ttl, getValue) {
8
14
  this.file = cacheDir.file(key).json();
9
15
  this.ttl = ttl;
10
- this.refresh = refresh;
16
+ this.getValue = getValue;
11
17
  }
12
18
  async read() {
13
19
  const { createdAt, value } = this.file.read() || {};
@@ -16,7 +22,7 @@ export class Cache {
16
22
  return this.write();
17
23
  }
18
24
  async write() {
19
- const value = await this.refresh();
25
+ const value = await this.getValue();
20
26
  this.file.write({ createdAt: Date.now(), value });
21
27
  return value;
22
28
  }
package/dist/Dir.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { File } from './File.js';
2
2
  /**
3
3
  * Reference to a specific directory with helpful methods for resolving filepaths,
4
- * sanitizing filenames, and saving files
4
+ * sanitizing filenames, and saving files.
5
5
  */
6
6
  export declare class Dir {
7
7
  path: string;
package/dist/Dir.js CHANGED
@@ -4,7 +4,7 @@ import sanitizeFilename from 'sanitize-filename';
4
4
  import { File } from './File.js';
5
5
  /**
6
6
  * Reference to a specific directory with helpful methods for resolving filepaths,
7
- * sanitizing filenames, and saving files
7
+ * sanitizing filenames, and saving files.
8
8
  */
9
9
  export class Dir {
10
10
  path;
package/dist/Fetcher.d.ts CHANGED
@@ -12,7 +12,7 @@ export type FetchOptions = RequestInit & {
12
12
  };
13
13
  /**
14
14
  * Fetcher provides a quick way to set up a basic API connection
15
- * with options applied to every request
15
+ * with options applied to every request.
16
16
  * Includes basic methods for requesting and parsing responses
17
17
  */
18
18
  export declare class Fetcher {
@@ -40,7 +40,7 @@ export declare class Fetcher {
40
40
  };
41
41
  constructor(opts?: FetchOptions);
42
42
  /**
43
- * Build URL with URLSearchParams if query is provided
43
+ * Build URL with URLSearchParams if query is provided.
44
44
  * Also returns domain, to help with cookies
45
45
  */
46
46
  buildUrl(route: Route, opts?: FetchOptions): [URL, string];
@@ -49,14 +49,14 @@ export declare class Fetcher {
49
49
  */
50
50
  buildHeaders(route: Route, opts?: FetchOptions): HeadersInit & Record<string, string>;
51
51
  /**
52
- * Builds request, merging defaultOptions and provided options
52
+ * Builds request, merging defaultOptions and provided options.
53
53
  * Includes Abort signal for timeout
54
54
  */
55
55
  buildRequest(route: Route, opts?: FetchOptions): [Request, FetchOptions, string];
56
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
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
60
  */
61
61
  fetch(route: Route, opts?: FetchOptions): Promise<[Response, Request]>;
62
62
  fetchText(route: Route, opts?: FetchOptions): Promise<[string, Response, Request]>;
package/dist/Fetcher.js CHANGED
@@ -2,7 +2,7 @@ import { merge } from 'lodash-es';
2
2
  import extractDomain from 'extract-domain';
3
3
  /**
4
4
  * Fetcher provides a quick way to set up a basic API connection
5
- * with options applied to every request
5
+ * with options applied to every request.
6
6
  * Includes basic methods for requesting and parsing responses
7
7
  */
8
8
  export class Fetcher {
@@ -16,7 +16,7 @@ export class Fetcher {
16
16
  };
17
17
  }
18
18
  /**
19
- * Build URL with URLSearchParams if query is provided
19
+ * Build URL with URLSearchParams if query is provided.
20
20
  * Also returns domain, to help with cookies
21
21
  */
22
22
  buildUrl(route, opts = {}) {
@@ -47,7 +47,7 @@ export class Fetcher {
47
47
  return headers || {};
48
48
  }
49
49
  /**
50
- * Builds request, merging defaultOptions and provided options
50
+ * Builds request, merging defaultOptions and provided options.
51
51
  * Includes Abort signal for timeout
52
52
  */
53
53
  buildRequest(route, opts = {}) {
@@ -67,9 +67,9 @@ export class Fetcher {
67
67
  return [req, mergedOptions, domain];
68
68
  }
69
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
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
73
  */
74
74
  async fetch(route, opts = {}) {
75
75
  const [_req, options] = this.buildRequest(route, opts);
package/dist/File.d.ts CHANGED
@@ -19,33 +19,33 @@ export declare class File {
19
19
  * @returns lines as strings, removes trailing '\n'
20
20
  */
21
21
  lines(): string[];
22
- static get Adaptor(): typeof Adaptor;
23
- json<T>(contents?: T): JsonFile<T>;
24
- static get json(): typeof JsonFile;
25
- ndjson<T extends object>(lines?: T | T[]): NdjsonFile<T>;
26
- static get ndjson(): typeof NdjsonFile;
27
- csv<T extends object>(rows?: T[], keys?: (keyof T)[]): Promise<CsvFile<T>>;
28
- static get csv(): typeof CsvFile;
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
29
  }
30
- declare class Adaptor<T = string> {
30
+ export declare class FileType<T = string> {
31
31
  file: File;
32
32
  constructor(filepath: string, contents?: T);
33
33
  get exists(): boolean;
34
34
  delete(): void;
35
35
  get path(): string;
36
36
  }
37
- declare class JsonFile<T> extends Adaptor {
37
+ export declare class FileTypeJson<T> extends FileType {
38
38
  constructor(filepath: string, contents?: T);
39
39
  read(): T | undefined;
40
40
  write(contents: T): void;
41
41
  }
42
- declare class NdjsonFile<T extends object> extends Adaptor {
42
+ export declare class FileTypeNdjson<T extends object> extends FileType {
43
43
  constructor(filepath: string, lines?: T | T[]);
44
44
  append(lines: T | T[]): void;
45
45
  lines(): T[];
46
46
  }
47
47
  type Key<T extends object> = keyof T;
48
- declare class CsvFile<Row extends object> extends Adaptor {
48
+ export declare class FileTypeCsv<Row extends object> extends FileType {
49
49
  constructor(filepath: string);
50
50
  write(rows: Row[], keys?: Key<Row>[]): Promise<void>;
51
51
  read(): Promise<Row[]>;
package/dist/File.js CHANGED
@@ -43,32 +43,32 @@ export class File {
43
43
  const contents = (this.read() || '').split('\n');
44
44
  return contents.slice(0, contents.length - 1);
45
45
  }
46
- static get Adaptor() {
47
- return Adaptor;
46
+ static get FileType() {
47
+ return FileType;
48
48
  }
49
49
  json(contents) {
50
- return new JsonFile(this.path, contents);
50
+ return new FileTypeJson(this.path, contents);
51
51
  }
52
52
  static get json() {
53
- return JsonFile;
53
+ return FileTypeJson;
54
54
  }
55
55
  ndjson(lines) {
56
- return new NdjsonFile(this.path, lines);
56
+ return new FileTypeNdjson(this.path, lines);
57
57
  }
58
58
  static get ndjson() {
59
- return NdjsonFile;
59
+ return FileTypeNdjson;
60
60
  }
61
61
  async csv(rows, keys) {
62
- const csvFile = new CsvFile(this.path);
62
+ const csvFile = new FileTypeCsv(this.path);
63
63
  if (rows)
64
64
  await csvFile.write(rows, keys);
65
65
  return csvFile;
66
66
  }
67
67
  static get csv() {
68
- return CsvFile;
68
+ return FileTypeCsv;
69
69
  }
70
70
  }
71
- class Adaptor {
71
+ export class FileType {
72
72
  file;
73
73
  constructor(filepath, contents) {
74
74
  this.file = new File(filepath);
@@ -89,7 +89,7 @@ class Adaptor {
89
89
  return this.file.path;
90
90
  }
91
91
  }
92
- class JsonFile extends Adaptor {
92
+ export class FileTypeJson extends FileType {
93
93
  constructor(filepath, contents) {
94
94
  super(filepath.endsWith('.json') ? filepath : filepath + '.json');
95
95
  if (contents)
@@ -103,7 +103,7 @@ class JsonFile extends Adaptor {
103
103
  this.file.write(JSON.stringify(snapshot(contents), null, 2));
104
104
  }
105
105
  }
106
- class NdjsonFile extends Adaptor {
106
+ export class FileTypeNdjson extends FileType {
107
107
  constructor(filepath, lines) {
108
108
  super(filepath.endsWith('.ndjson') ? filepath : filepath + '.ndjson');
109
109
  if (lines)
@@ -116,7 +116,7 @@ class NdjsonFile extends Adaptor {
116
116
  return this.file.lines().map((l) => JSON.parse(l));
117
117
  }
118
118
  }
119
- class CsvFile extends Adaptor {
119
+ export class FileTypeCsv extends FileType {
120
120
  constructor(filepath) {
121
121
  super(filepath.endsWith('.csv') ? filepath : filepath + '.csv');
122
122
  }
@@ -1,7 +1,7 @@
1
1
  export { Dir, TempDir, temp } from './Dir.js';
2
2
  export { Cache } from './Cache.js';
3
3
  export { Fetcher, type Route, type Query, type FetchOptions } from './Fetcher.js';
4
- export { File } from './File.js';
4
+ export { File, FileType, FileTypeJson, FileTypeNdjson, FileTypeCsv } from './File.js';
5
5
  export { Jwt } from './Jwt.js';
6
6
  export { Log } from './Log.js';
7
7
  export { snapshot } from './snapshot.js';
@@ -1,7 +1,7 @@
1
1
  export { Dir, TempDir, temp } from './Dir.js';
2
2
  export { Cache } from './Cache.js';
3
3
  export { Fetcher } from './Fetcher.js';
4
- export { File } from './File.js';
4
+ export { File, FileType, FileTypeJson, FileTypeNdjson, FileTypeCsv } from './File.js';
5
5
  export { Jwt } from './Jwt.js';
6
6
  export { Log } from './Log.js';
7
7
  export { snapshot } from './snapshot.js';
package/package.json CHANGED
@@ -1,21 +1,22 @@
1
1
  {
2
2
  "name": "@brianbuie/node-kit",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "ISC",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/brianbuie/node-kit.git"
8
8
  },
9
9
  "scripts": {
10
+ "docs": "node ./node_modules/ts2md/out/src/ts2md.js --firstHeadingLevel=1",
10
11
  "test": "tsc && node --test \"dist/**/*.test.js\" --quiet",
11
- "preversion": "npm test",
12
+ "preversion": "npm test && npm run docs",
12
13
  "postversion": "git push --follow-tags"
13
14
  },
14
15
  "type": "module",
15
16
  "exports": {
16
17
  ".": {
17
- "types": "./dist/_index.d.ts",
18
- "default": "./dist/_index.js"
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
19
20
  }
20
21
  },
21
22
  "files": [
@@ -40,6 +41,7 @@
40
41
  "@types/jsonwebtoken": "^9.0.10",
41
42
  "@types/lodash-es": "^4.17.12",
42
43
  "@types/node": "^24.9.1",
44
+ "ts2md": "^0.2.8",
43
45
  "typescript": "^5.9.3"
44
46
  }
45
47
  }
package/src/Cache.ts CHANGED
@@ -2,15 +2,21 @@ import { temp } from './Dir.js';
2
2
 
3
3
  const cacheDir = temp.dir('cache');
4
4
 
5
+ /**
6
+ * Save results of a function in a temporary file.
7
+ * @param key A unique name for the file
8
+ * @param ttl cache duration in ms
9
+ * @param getValue the function to populate the cache (eg. fetch results, generate key, etc)
10
+ */
5
11
  export class Cache<T> {
6
12
  file;
7
13
  ttl;
8
- refresh;
14
+ getValue;
9
15
 
10
- constructor(key: string, ttl: number, refresh: () => T | Promise<T>) {
16
+ constructor(key: string, ttl: number, getValue: () => T | Promise<T>) {
11
17
  this.file = cacheDir.file(key).json<{ createdAt: number; value: T }>();
12
18
  this.ttl = ttl;
13
- this.refresh = refresh;
19
+ this.getValue = getValue;
14
20
  }
15
21
 
16
22
  async read() {
@@ -20,7 +26,7 @@ export class Cache<T> {
20
26
  }
21
27
 
22
28
  async write() {
23
- const value = await this.refresh();
29
+ const value = await this.getValue();
24
30
  this.file.write({ createdAt: Date.now(), value });
25
31
  return value;
26
32
  }
package/src/Dir.ts CHANGED
@@ -5,7 +5,7 @@ import { File } from './File.js';
5
5
 
6
6
  /**
7
7
  * Reference to a specific directory with helpful methods for resolving filepaths,
8
- * sanitizing filenames, and saving files
8
+ * sanitizing filenames, and saving files.
9
9
  */
10
10
  export class Dir {
11
11
  path;
package/src/Fetcher.ts CHANGED
@@ -18,7 +18,7 @@ export type FetchOptions = RequestInit & {
18
18
 
19
19
  /**
20
20
  * Fetcher provides a quick way to set up a basic API connection
21
- * with options applied to every request
21
+ * with options applied to every request.
22
22
  * Includes basic methods for requesting and parsing responses
23
23
  */
24
24
  export class Fetcher {
@@ -34,7 +34,7 @@ export class Fetcher {
34
34
  }
35
35
 
36
36
  /**
37
- * Build URL with URLSearchParams if query is provided
37
+ * Build URL with URLSearchParams if query is provided.
38
38
  * Also returns domain, to help with cookies
39
39
  */
40
40
  buildUrl(route: Route, opts: FetchOptions = {}): [URL, string] {
@@ -65,7 +65,7 @@ export class Fetcher {
65
65
  }
66
66
 
67
67
  /**
68
- * Builds request, merging defaultOptions and provided options
68
+ * Builds request, merging defaultOptions and provided options.
69
69
  * Includes Abort signal for timeout
70
70
  */
71
71
  buildRequest(route: Route, opts: FetchOptions = {}): [Request, FetchOptions, string] {
@@ -86,9 +86,9 @@ export class Fetcher {
86
86
  }
87
87
 
88
88
  /**
89
- * Builds and performs the request, merging provided options with defaultOptions
90
- * If `opts.data` is provided, method is updated to POST, content-type json, data is stringified in the body
91
- * Retries on local or network error, with increasing backoff
89
+ * Builds and performs the request, merging provided options with defaultOptions.
90
+ * If `opts.data` is provided, method is updated to POST, content-type json, data is stringified in the body.
91
+ * Retries on local or network error, with increasing backoff.
92
92
  */
93
93
  async fetch(route: Route, opts: FetchOptions = {}): Promise<[Response, Request]> {
94
94
  const [_req, options] = this.buildRequest(route, opts);
package/src/File.test.ts CHANGED
@@ -14,9 +14,9 @@ const thing = {
14
14
  e: null,
15
15
  };
16
16
 
17
- describe('FileAdaptor', () => {
17
+ describe('FileType', () => {
18
18
  it('Creates instances', () => {
19
- const test1 = new File.Adaptor(testDir.filepath('test1.txt'));
19
+ const test1 = new File.FileType(testDir.filepath('test1.txt'));
20
20
  assert(test1.file.path.includes('test1.txt'));
21
21
  const base = 'test2';
22
22
  const eg1 = new File.json(testDir.filepath(base));
package/src/File.ts CHANGED
@@ -52,38 +52,38 @@ export class File {
52
52
  return contents.slice(0, contents.length - 1);
53
53
  }
54
54
 
55
- static get Adaptor() {
56
- return Adaptor;
55
+ static get FileType() {
56
+ return FileType;
57
57
  }
58
58
 
59
59
  json<T>(contents?: T) {
60
- return new JsonFile<T>(this.path, contents);
60
+ return new FileTypeJson<T>(this.path, contents);
61
61
  }
62
62
 
63
63
  static get json() {
64
- return JsonFile;
64
+ return FileTypeJson;
65
65
  }
66
66
 
67
67
  ndjson<T extends object>(lines?: T | T[]) {
68
- return new NdjsonFile<T>(this.path, lines);
68
+ return new FileTypeNdjson<T>(this.path, lines);
69
69
  }
70
70
 
71
71
  static get ndjson() {
72
- return NdjsonFile;
72
+ return FileTypeNdjson;
73
73
  }
74
74
 
75
75
  async csv<T extends object>(rows?: T[], keys?: (keyof T)[]) {
76
- const csvFile = new CsvFile<T>(this.path);
76
+ const csvFile = new FileTypeCsv<T>(this.path);
77
77
  if (rows) await csvFile.write(rows, keys);
78
78
  return csvFile;
79
79
  }
80
80
 
81
81
  static get csv() {
82
- return CsvFile;
82
+ return FileTypeCsv;
83
83
  }
84
84
  }
85
85
 
86
- class Adaptor<T = string> {
86
+ export class FileType<T = string> {
87
87
  file;
88
88
 
89
89
  constructor(filepath: string, contents?: T) {
@@ -109,7 +109,7 @@ class Adaptor<T = string> {
109
109
  }
110
110
  }
111
111
 
112
- class JsonFile<T> extends Adaptor {
112
+ export class FileTypeJson<T> extends FileType {
113
113
  constructor(filepath: string, contents?: T) {
114
114
  super(filepath.endsWith('.json') ? filepath : filepath + '.json');
115
115
  if (contents) this.write(contents);
@@ -125,7 +125,7 @@ class JsonFile<T> extends Adaptor {
125
125
  }
126
126
  }
127
127
 
128
- class NdjsonFile<T extends object> extends Adaptor {
128
+ export class FileTypeNdjson<T extends object> extends FileType {
129
129
  constructor(filepath: string, lines?: T | T[]) {
130
130
  super(filepath.endsWith('.ndjson') ? filepath : filepath + '.ndjson');
131
131
  if (lines) this.append(lines);
@@ -144,7 +144,7 @@ class NdjsonFile<T extends object> extends Adaptor {
144
144
 
145
145
  type Key<T extends object> = keyof T;
146
146
 
147
- class CsvFile<Row extends object> extends Adaptor {
147
+ export class FileTypeCsv<Row extends object> extends FileType {
148
148
  constructor(filepath: string) {
149
149
  super(filepath.endsWith('.csv') ? filepath : filepath + '.csv');
150
150
  }
@@ -1,7 +1,7 @@
1
1
  export { Dir, TempDir, temp } from './Dir.js';
2
2
  export { Cache } from './Cache.js';
3
3
  export { Fetcher, type Route, type Query, type FetchOptions } from './Fetcher.js';
4
- export { File } from './File.js';
4
+ export { File, FileType, FileTypeJson, FileTypeNdjson, FileTypeCsv } from './File.js';
5
5
  export { Jwt } from './Jwt.js';
6
6
  export { Log } from './Log.js';
7
7
  export { snapshot } from './snapshot.js';