backlib 0.5.0-SNAPSHOT.1 → 0.5.2-SNAPSHOT.2

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.
@@ -1,6 +1,7 @@
1
1
  import { LogWriter } from './index.js';
2
- export declare type OnFileCompleted = (file: string) => Promise<void>;
3
2
  export declare type FileNameProvider = (rev: number) => string;
3
+ export declare type FileHeaderProvider = () => string | null;
4
+ export declare type OnFileCompleted = (file: string) => Promise<void>;
4
5
  /** Record serializer to string, which will be appended to the file. If null, record will be skipped */
5
6
  export declare type RecordSerializer<R> = (rec: R) => string | null;
6
7
  export interface FileWriterOptions<R> {
@@ -12,15 +13,19 @@ export interface FileWriterOptions<R> {
12
13
  maxTime: number;
13
14
  /** Optional fileName generator for the new log file name (MUST BE UNIQUE for this dir) */
14
15
  fileNameProvider?: FileNameProvider;
16
+ /** Called when the log file is first created (useful to create the csv header for csv format) */
17
+ fileHeaderProvider?: FileHeaderProvider;
18
+ /** Optional recordSerializer to file. By default, JSON.serializer() (new line json) */
15
19
  recordSerializer?: RecordSerializer<R>;
20
+ /** Called when a log file is completed (i.e., new entries will go to another file) */
16
21
  onFileCompleted?: OnFileCompleted;
17
22
  }
18
23
  export declare class FileWriter<R> implements LogWriter<R> {
19
- readonly name = "to-deprecate";
20
24
  private dir;
21
25
  private maxCount;
22
26
  private maxTime;
23
27
  private fileNameProvider;
28
+ private fileHeaderProvider;
24
29
  private recordSerializer;
25
30
  private onFileCompleted?;
26
31
  private _init;
@@ -28,10 +33,11 @@ export declare class FileWriter<R> implements LogWriter<R> {
28
33
  private count;
29
34
  private nextUpload;
30
35
  private lastUpload?;
31
- private file?;
36
+ private filePath?;
37
+ private fileHandle?;
32
38
  constructor(opts: FileWriterOptions<R>);
33
39
  private init;
34
- /** Update the revision file */
40
+ /** Update the revision file and create the new file and call onFileStart */
35
41
  private rev;
36
42
  /** IMPLEMENTATION of the FileWriter interface */
37
43
  writeRec(rec: R): Promise<void>;
@@ -1,10 +1,10 @@
1
+ import { appendFileSync, openSync } from 'fs';
1
2
  import { pathExists } from 'fs-aux';
2
- import { appendFile, mkdir, rename } from 'fs/promises';
3
+ import { appendFile, mkdir, open, rename } from 'fs/promises';
3
4
  import * as Path from "path";
4
5
  import { isString } from 'utils-min';
5
6
  export class FileWriter {
6
7
  constructor(opts) {
7
- this.name = 'to-deprecate'; // TODO: to deprecate
8
8
  this._init = false;
9
9
  this._rev = 0;
10
10
  this.count = 0;
@@ -13,6 +13,7 @@ export class FileWriter {
13
13
  this.maxTime = opts.maxTime;
14
14
  this.dir = opts.dir;
15
15
  this.fileNameProvider = opts.fileNameProvider ?? defaultFileNameProvider;
16
+ this.fileHeaderProvider = opts.fileHeaderProvider ?? defaultFileHeaderProvider;
16
17
  this.onFileCompleted = opts.onFileCompleted;
17
18
  this.recordSerializer = opts.recordSerializer ?? defaultSerializer;
18
19
  }
@@ -23,12 +24,28 @@ export class FileWriter {
23
24
  this._init = true;
24
25
  }
25
26
  }
26
- /** Update the revision file */
27
- rev() {
27
+ /** Update the revision file and create the new file and call onFileStart */
28
+ async rev() {
28
29
  this.count = 0;
29
30
  this._rev = this._rev + 1;
31
+ // make sure to reset the file info
32
+ this.filePath = undefined;
33
+ this.fileHandle = undefined;
34
+ // -- CREATE the new file
30
35
  const fileName = this.fileNameProvider(this._rev);
31
- this.file = Path.join(this.dir, fileName);
36
+ this.filePath = Path.join(this.dir, fileName);
37
+ // create and add the content Sync to make sure header is always first
38
+ let fd = openSync(this.filePath, 'a');
39
+ let fileHeader = this.fileHeaderProvider();
40
+ if (fileHeader != null) {
41
+ appendFileSync(fd, fileHeader);
42
+ }
43
+ else {
44
+ // make sure it is created (might not be needed)
45
+ appendFileSync(fd, '');
46
+ }
47
+ // -- CREATE the file handler
48
+ this.fileHandle = await open(this.filePath, 'a');
32
49
  }
33
50
  /** IMPLEMENTATION of the FileWriter interface */
34
51
  async writeRec(rec) {
@@ -38,13 +55,12 @@ export class FileWriter {
38
55
  const str = this.recordSerializer(rec);
39
56
  if (str != null) {
40
57
  const strWithNl = str + '\n'; // add the new line
41
- await appendFile(this.file, strWithNl);
58
+ await appendFile(this.fileHandle, strWithNl);
42
59
  }
43
60
  // add count
44
61
  this.count = this.count + 1;
45
62
  // if we are above the count, we upload
46
63
  if (this.count > this.maxCount) {
47
- console.log(`->> rev ${this.name} because count ${this.count} > maxCount ${this.maxCount}`);
48
64
  await this.endFile();
49
65
  }
50
66
  // if still below the count, but do not have this.nextUpload, schedule one
@@ -55,22 +71,23 @@ export class FileWriter {
55
71
  setTimeout(async () => {
56
72
  // perform only if this.nextUpload match the scheduled nextUpload (otherwise, was already processed and this schedule is outdated)
57
73
  if (this.nextUpload === nextUpload) {
58
- console.log(`->> rev ${this.name} because maxTimeMs ${maxTimeMs}`);
59
74
  await this.endFile();
60
75
  }
61
76
  }, maxTimeMs);
62
77
  }
63
78
  }
64
79
  async endFile() {
65
- const file = this.file;
80
+ const file = this.filePath;
81
+ const fileHandle = this.fileHandle;
66
82
  // we rev just before to make sure other logs will happen on new files
67
- this.rev();
83
+ await this.rev();
84
+ // process old file
68
85
  try {
69
86
  const exists = await pathExists(file);
70
87
  if (exists) {
88
+ await fileHandle?.close();
71
89
  if (this.onFileCompleted) {
72
90
  try {
73
- console.log(`->> endFile processing ${this.name} `);
74
91
  await this.onFileCompleted(file);
75
92
  }
76
93
  catch (ex) {
@@ -96,6 +113,11 @@ export class FileWriter {
96
113
  function defaultSerializer(rec) {
97
114
  return isString(rec) ? rec : JSON.stringify(rec);
98
115
  }
116
+ function defaultFileHeaderProvider() {
117
+ // Return null, meaning, no header
118
+ return null;
119
+ // For CSV, custom onFileStart will need to set the header
120
+ }
99
121
  function defaultFileNameProvider(rev) {
100
122
  const date = new Date().toISOString().replace(/[T:.]/g, "-").slice(0, -1);
101
123
  const revStr = `${rev}`.padStart(5, '0');
@@ -1 +1 @@
1
- {"version":3,"file":"log-file-writer.js","sourceRoot":"","sources":["../src/log-file-writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"log-file-writer.js","sourceRoot":"","sources":["../src/log-file-writer.ts"],"names":[],"mappings":"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"}
package/dist/log.d.ts CHANGED
@@ -2,10 +2,10 @@ export interface LogOptions<R> {
2
2
  writers: LogWriter<R>[];
3
3
  }
4
4
  /**
5
- * Base Log class that handle the base log management logic.
5
+ * Base Log class that handle the log management logic and call `writer.writeRec` on the registered logWriters
6
6
  */
7
7
  export declare class BaseLog<R> {
8
- private logWriters;
8
+ #private;
9
9
  constructor(opts: LogOptions<R>);
10
10
  log(rec: R): Promise<void>;
11
11
  }
package/dist/log.js CHANGED
@@ -1,25 +1,37 @@
1
1
  // const { pathExists, mkdirs, appendFile, rename } = (await import('fs-extra')).default;
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _BaseLog_logWriters;
2
14
  /**
3
- * Base Log class that handle the base log management logic.
15
+ * Base Log class that handle the log management logic and call `writer.writeRec` on the registered logWriters
4
16
  */
5
17
  export class BaseLog {
6
18
  constructor(opts) {
7
- this.logWriters = [];
8
- this.logWriters = [...opts.writers];
19
+ _BaseLog_logWriters.set(this, []);
20
+ __classPrivateFieldSet(this, _BaseLog_logWriters, [...opts.writers], "f");
9
21
  }
10
22
  async log(rec) {
11
- //
12
- for (const writer of this.logWriters) {
23
+ for (const writer of __classPrivateFieldGet(this, _BaseLog_logWriters, "f")) {
13
24
  if (writer.writeRec) {
14
25
  try {
15
26
  await writer.writeRec(rec);
16
27
  }
17
28
  catch (ex) {
18
29
  // here log console.log, no choise
19
- console.log(`ERROR - BACKLIB - Log exception when writeRec on logWriter ${writer}. ${ex}`);
30
+ console.log(`ERROR - BACKLIB - Log exception when calling writeRec on logWriter ${writer}. ${ex}`);
20
31
  }
21
32
  }
22
33
  }
23
34
  }
24
35
  }
36
+ _BaseLog_logWriters = new WeakMap();
25
37
  //# sourceMappingURL=log.js.map
package/dist/log.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AACA,yFAAyF;AAQzF;;GAEG;AACH,MAAM,OAAO,OAAO;IAGnB,YAAY,IAAmB;QAFvB,eAAU,GAAmB,EAAE,CAAC;QAGvC,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAM;QAEf,GAAG;QACH,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE;YACrC,IAAI,MAAM,CAAC,QAAQ,EAAE;gBACpB,IAAI;oBACH,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;iBAC3B;gBAAC,OAAO,EAAE,EAAE;oBACZ,kCAAkC;oBAClC,OAAO,CAAC,GAAG,CAAC,8DAA8D,MAAM,KAAK,EAAE,EAAE,CAAC,CAAC;iBAC3F;aACD;SACD;IAEF,CAAC;CAED"}
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AACA,yFAAyF;;;;;;;;;;;;;AAQzF;;GAEG;AACH,MAAM,OAAO,OAAO;IAGnB,YAAY,IAAmB;QAF/B,8BAA8B,EAAE,EAAC;QAGhC,uBAAA,IAAI,uBAAe,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAA,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAM;QAEf,KAAK,MAAM,MAAM,IAAI,uBAAA,IAAI,2BAAY,EAAE;YACtC,IAAI,MAAM,CAAC,QAAQ,EAAE;gBACpB,IAAI;oBACH,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;iBAC3B;gBAAC,OAAO,EAAE,EAAE;oBACZ,kCAAkC;oBAClC,OAAO,CAAC,GAAG,CAAC,sEAAsE,MAAM,KAAK,EAAE,EAAE,CAAC,CAAC;iBACnG;aACD;SACD;IAEF,CAAC;CAED"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "backlib",
3
3
  "type": "module",
4
- "version": "0.5.0-SNAPSHOT.1",
4
+ "version": "0.5.2-SNAPSHOT.2",
5
5
  "description": "Minimalist library for backend services",
6
6
  "main": "dist/index.js",
7
7
  "engines": {
@@ -1,11 +1,13 @@
1
+ import { appendFileSync, openSync } from 'fs';
1
2
  import { pathExists } from 'fs-aux';
2
- import { appendFile, mkdir, rename } from 'fs/promises';
3
+ import { appendFile, FileHandle, mkdir, open, rename } from 'fs/promises';
3
4
  import * as Path from "path";
4
5
  import { isString } from 'utils-min';
5
6
  import { LogWriter } from './index.js';
6
7
 
7
- export type OnFileCompleted = (file: string) => Promise<void>;
8
8
  export type FileNameProvider = (rev: number) => string;
9
+ export type FileHeaderProvider = () => string | null; // must be sync
10
+ export type OnFileCompleted = (file: string) => Promise<void>;
9
11
 
10
12
  /** Record serializer to string, which will be appended to the file. If null, record will be skipped */
11
13
  export type RecordSerializer<R> = (rec: R) => string | null;
@@ -20,20 +22,22 @@ export interface FileWriterOptions<R> {
20
22
 
21
23
  /** Optional fileName generator for the new log file name (MUST BE UNIQUE for this dir) */
22
24
  fileNameProvider?: FileNameProvider,
23
- /* Optional recordSerializer to file. By default, JSON.serializer() (new line json) */
25
+ /** Called when the log file is first created (useful to create the csv header for csv format) */
26
+ fileHeaderProvider?: FileHeaderProvider;
27
+ /** Optional recordSerializer to file. By default, JSON.serializer() (new line json) */
24
28
  recordSerializer?: RecordSerializer<R>;
25
- /* Call when a log file is completed (i.e., new entries will go to another file) */
29
+ /** Called when a log file is completed (i.e., new entries will go to another file) */
26
30
  onFileCompleted?: OnFileCompleted;
27
31
 
28
32
  }
29
33
 
30
34
  export class FileWriter<R> implements LogWriter<R> {
31
- readonly name = 'to-deprecate'; // TODO: to deprecate
32
35
  private dir: string;
33
36
  private maxCount: number;
34
37
  private maxTime: number;
35
38
 
36
39
  private fileNameProvider: FileNameProvider;
40
+ private fileHeaderProvider: FileHeaderProvider;
37
41
  private recordSerializer: RecordSerializer<R>;
38
42
  private onFileCompleted?: OnFileCompleted;
39
43
 
@@ -43,13 +47,15 @@ export class FileWriter<R> implements LogWriter<R> {
43
47
  private nextUpload: number | null = null; // null means nothing scheduled
44
48
  private lastUpload?: number;
45
49
 
46
- private file?: string;
50
+ private filePath?: string;
51
+ private fileHandle?: FileHandle;
47
52
 
48
53
  constructor(opts: FileWriterOptions<R>) {
49
54
  this.maxCount = opts.maxCount;
50
55
  this.maxTime = opts.maxTime;
51
56
  this.dir = opts.dir;
52
57
  this.fileNameProvider = opts.fileNameProvider ?? defaultFileNameProvider;
58
+ this.fileHeaderProvider = opts.fileHeaderProvider ?? defaultFileHeaderProvider;
53
59
  this.onFileCompleted = opts.onFileCompleted;
54
60
  this.recordSerializer = opts.recordSerializer ?? defaultSerializer;
55
61
  }
@@ -62,14 +68,31 @@ export class FileWriter<R> implements LogWriter<R> {
62
68
  }
63
69
  }
64
70
 
65
- /** Update the revision file */
66
- private rev() {
71
+ /** Update the revision file and create the new file and call onFileStart */
72
+ private async rev() {
67
73
  this.count = 0;
68
74
  this._rev = this._rev + 1;
69
75
 
76
+ // make sure to reset the file info
77
+ this.filePath = undefined;
78
+ this.fileHandle = undefined;
79
+
80
+ // -- CREATE the new file
70
81
  const fileName = this.fileNameProvider(this._rev);
82
+ this.filePath = Path.join(this.dir, fileName);
83
+
84
+ // create and add the content Sync to make sure header is always first
85
+ let fd = openSync(this.filePath, 'a');
86
+ let fileHeader = this.fileHeaderProvider();
87
+ if (fileHeader != null) {
88
+ appendFileSync(fd, fileHeader);
89
+ } else {
90
+ // make sure it is created (might not be needed)
91
+ appendFileSync(fd, '');
92
+ }
71
93
 
72
- this.file = Path.join(this.dir, fileName)
94
+ // -- CREATE the file handler
95
+ this.fileHandle = await open(this.filePath, 'a');
73
96
  }
74
97
 
75
98
 
@@ -83,7 +106,7 @@ export class FileWriter<R> implements LogWriter<R> {
83
106
  const str = this.recordSerializer(rec);
84
107
  if (str != null) {
85
108
  const strWithNl = str + '\n'; // add the new line
86
- await appendFile(this.file!, strWithNl);
109
+ await appendFile(this.fileHandle!, strWithNl);
87
110
  }
88
111
 
89
112
  // add count
@@ -91,7 +114,6 @@ export class FileWriter<R> implements LogWriter<R> {
91
114
 
92
115
  // if we are above the count, we upload
93
116
  if (this.count > this.maxCount) {
94
- console.log(`->> rev ${this.name} because count ${this.count} > maxCount ${this.maxCount}`);
95
117
  await this.endFile();
96
118
  }
97
119
  // if still below the count, but do not have this.nextUpload, schedule one
@@ -104,7 +126,6 @@ export class FileWriter<R> implements LogWriter<R> {
104
126
  setTimeout(async () => {
105
127
  // perform only if this.nextUpload match the scheduled nextUpload (otherwise, was already processed and this schedule is outdated)
106
128
  if (this.nextUpload === nextUpload) {
107
- console.log(`->> rev ${this.name} because maxTimeMs ${maxTimeMs}`);
108
129
  await this.endFile();
109
130
  }
110
131
  }, maxTimeMs);
@@ -113,16 +134,19 @@ export class FileWriter<R> implements LogWriter<R> {
113
134
  }
114
135
 
115
136
  private async endFile() {
116
- const file = this.file!;
137
+ const file = this.filePath!;
138
+ const fileHandle = this.fileHandle;
139
+
117
140
  // we rev just before to make sure other logs will happen on new files
118
- this.rev();
141
+ await this.rev();
119
142
 
143
+ // process old file
120
144
  try {
121
145
  const exists = await pathExists(file);
122
146
  if (exists) {
147
+ await fileHandle?.close();
123
148
  if (this.onFileCompleted) {
124
149
  try {
125
- console.log(`->> endFile processing ${this.name} `);
126
150
  await this.onFileCompleted(file);
127
151
  } catch (ex: any) {
128
152
  console.log(`LOG PROCESSING ERROR - processing file '${file}' caused the following error: ${ex}`);
@@ -152,6 +176,13 @@ function defaultSerializer<R>(rec: R): string {
152
176
  return isString(rec) ? rec : JSON.stringify(rec);
153
177
  }
154
178
 
179
+ function defaultFileHeaderProvider(): string | null {
180
+ // Return null, meaning, no header
181
+ return null;
182
+
183
+ // For CSV, custom onFileStart will need to set the header
184
+ }
185
+
155
186
  function defaultFileNameProvider(rev: number): string {
156
187
  const date = new Date().toISOString().replace(/[T:.]/g, "-").slice(0, -1);
157
188
  const revStr = `${rev}`.padStart(5, '0');
package/src/log.ts CHANGED
@@ -8,25 +8,24 @@ export interface LogOptions<R> {
8
8
  }
9
9
 
10
10
  /**
11
- * Base Log class that handle the base log management logic.
11
+ * Base Log class that handle the log management logic and call `writer.writeRec` on the registered logWriters
12
12
  */
13
13
  export class BaseLog<R> {
14
- private logWriters: LogWriter<R>[] = [];
14
+ #logWriters: LogWriter<R>[] = [];
15
15
 
16
16
  constructor(opts: LogOptions<R>) {
17
- this.logWriters = [...opts.writers];
17
+ this.#logWriters = [...opts.writers];
18
18
  }
19
19
 
20
20
  async log(rec: R) {
21
21
 
22
- //
23
- for (const writer of this.logWriters) {
22
+ for (const writer of this.#logWriters) {
24
23
  if (writer.writeRec) {
25
24
  try {
26
25
  await writer.writeRec(rec);
27
26
  } catch (ex) {
28
27
  // here log console.log, no choise
29
- console.log(`ERROR - BACKLIB - Log exception when writeRec on logWriter ${writer}. ${ex}`);
28
+ console.log(`ERROR - BACKLIB - Log exception when calling writeRec on logWriter ${writer}. ${ex}`);
30
29
  }
31
30
  }
32
31
  }