@bgord/bun 1.5.6 → 1.5.8

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": "@bgord/bun",
3
- "version": "1.5.6",
3
+ "version": "1.5.8",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": "Bartosz Gordon",
@@ -28,7 +28,7 @@
28
28
  "@types/nodemailer": "7.0.4",
29
29
  "@types/yazl": "3.3.0",
30
30
  "cspell": "9.4.0",
31
- "knip": "5.74.0",
31
+ "knip": "5.75.1",
32
32
  "lefthook": "2.0.12",
33
33
  "lockfile-lint": "4.14.1",
34
34
  "only-allow": "1.2.2",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@axiomhq/winston": "1.3.1",
42
- "@bgord/tools": "1.2.2",
42
+ "@bgord/tools": "1.2.3",
43
43
  "@hono/ua-blocker": "0.1.22",
44
44
  "better-auth": "1.4.7",
45
45
  "croner": "9.1.0",
package/readme.md CHANGED
@@ -208,6 +208,7 @@ src/
208
208
  │   ├── directory.ts
209
209
  │   ├── dns.ts
210
210
  │   ├── external-api.ts
211
+ │   ├── file.ts
211
212
  │   ├── jobs.ts
212
213
  │   ├── log-file.ts
213
214
  │   ├── mailer.ts
@@ -1,28 +1,29 @@
1
- import { constants } from "node:fs";
2
- import fsp from "node:fs/promises";
1
+ import { access, constants, stat } from "node:fs/promises";
3
2
  import * as tools from "@bgord/tools";
4
3
  import type { ClockPort } from "../clock.port";
5
4
  import * as prereqs from "../prerequisites.service";
6
5
 
6
+ export type PrerequisiteDirectoryPermissionsType = { read?: boolean; write?: boolean; execute?: boolean };
7
+
7
8
  export class PrerequisiteDirectory implements prereqs.Prerequisite {
8
9
  readonly kind = "directory";
9
10
  readonly label: prereqs.PrerequisiteLabelType;
10
11
  readonly enabled?: boolean = true;
11
12
 
12
13
  private readonly directory: tools.DirectoryPathAbsoluteType | tools.DirectoryPathRelativeType;
13
- private readonly access?: { write?: boolean; execute?: boolean };
14
+ private readonly permissions: PrerequisiteDirectoryPermissionsType;
14
15
 
15
16
  constructor(
16
17
  config: prereqs.PrerequisiteConfigType & {
17
18
  directory: tools.DirectoryPathAbsoluteType | tools.DirectoryPathRelativeType;
18
- access?: { write?: boolean; execute?: boolean };
19
+ permissions?: PrerequisiteDirectoryPermissionsType;
19
20
  },
20
21
  ) {
21
22
  this.label = config.label;
22
23
  this.enabled = config.enabled === undefined ? true : config.enabled;
23
24
 
24
25
  this.directory = config.directory;
25
- this.access = config.access;
26
+ this.permissions = config.permissions ?? {};
26
27
  }
27
28
 
28
29
  async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
@@ -30,17 +31,40 @@ export class PrerequisiteDirectory implements prereqs.Prerequisite {
30
31
 
31
32
  if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
32
33
 
33
- const write = this.access?.write ?? false;
34
- const execute = this.access?.execute ?? false;
34
+ try {
35
+ const stats = await stat(this.directory);
35
36
 
36
- const flags = constants.R_OK | (write ? constants.W_OK : 0) | (execute ? constants.X_OK : 0);
37
+ if (!stats.isDirectory()) {
38
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "Not a directory" });
39
+ }
40
+ } catch {
41
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "Directory does not exist" });
42
+ }
37
43
 
38
- try {
39
- await fsp.access(this.directory, flags);
44
+ if (this.permissions.read) {
45
+ try {
46
+ await access(this.directory, constants.R_OK);
47
+ } catch {
48
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "Directory is not readable" });
49
+ }
50
+ }
51
+
52
+ if (this.permissions.write) {
53
+ try {
54
+ await access(this.directory, constants.W_OK);
55
+ } catch {
56
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "Directory is not writable" });
57
+ }
58
+ }
40
59
 
41
- return prereqs.Verification.success(stopwatch.stop());
42
- } catch (error) {
43
- return prereqs.Verification.failure(stopwatch.stop(), error as Error);
60
+ if (this.permissions.execute) {
61
+ try {
62
+ await access(this.directory, constants.X_OK);
63
+ } catch {
64
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "Directory is not executable" });
65
+ }
44
66
  }
67
+
68
+ return prereqs.Verification.success(stopwatch.stop());
45
69
  }
46
70
  }
@@ -0,0 +1,69 @@
1
+ import { access, constants } from "node:fs/promises";
2
+ import * as tools from "@bgord/tools";
3
+ import type { ClockPort } from "../clock.port";
4
+ import * as prereqs from "../prerequisites.service";
5
+
6
+ export type PrerequisiteFilePermissionsType = { read?: boolean; write?: boolean; execute?: boolean };
7
+
8
+ export class PrerequisiteFile implements prereqs.Prerequisite {
9
+ readonly kind = "file";
10
+ readonly label: prereqs.PrerequisiteLabelType;
11
+ readonly enabled?: boolean = true;
12
+
13
+ private readonly file: tools.FilePathAbsolute | tools.FilePathRelative;
14
+ private readonly permissions: PrerequisiteFilePermissionsType;
15
+
16
+ constructor(
17
+ config: prereqs.PrerequisiteConfigType & {
18
+ file: tools.FilePathAbsolute | tools.FilePathRelative;
19
+ permissions?: PrerequisiteFilePermissionsType;
20
+ },
21
+ ) {
22
+ this.label = config.label;
23
+ this.enabled = config.enabled === undefined ? true : config.enabled;
24
+
25
+ this.file = config.file;
26
+ this.permissions = config.permissions ?? {};
27
+ }
28
+
29
+ async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
30
+ const stopwatch = new tools.Stopwatch(clock.now());
31
+
32
+ if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
33
+
34
+ try {
35
+ const path = this.file.get();
36
+
37
+ const exists = await Bun.file(path).exists();
38
+ if (!exists) return prereqs.Verification.failure(stopwatch.stop(), { message: "File does not exist" });
39
+
40
+ if (this.permissions.read) {
41
+ try {
42
+ await access(path, constants.R_OK);
43
+ } catch {
44
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "File is not readable" });
45
+ }
46
+ }
47
+
48
+ if (this.permissions.write) {
49
+ try {
50
+ await access(path, constants.W_OK);
51
+ } catch {
52
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "File is not writable" });
53
+ }
54
+ }
55
+
56
+ if (this.permissions.execute) {
57
+ try {
58
+ await access(path, constants.X_OK);
59
+ } catch {
60
+ return prereqs.Verification.failure(stopwatch.stop(), { message: "File is not executable" });
61
+ }
62
+ }
63
+
64
+ return prereqs.Verification.success(stopwatch.stop());
65
+ } catch (error) {
66
+ return prereqs.Verification.failure(stopwatch.stop(), error as Error);
67
+ }
68
+ }
69
+ }
@@ -5,6 +5,7 @@ export * from "./dependency-vulnerabilities";
5
5
  export * from "./directory";
6
6
  export * from "./dns";
7
7
  export * from "./external-api";
8
+ export * from "./file";
8
9
  export * from "./jobs";
9
10
  export * from "./log-file";
10
11
  export * from "./mailer";
@@ -2,6 +2,7 @@ import * as tools from "@bgord/tools";
2
2
  import type { ClockPort } from "../clock.port";
3
3
  import type { LoggerPort } from "../logger.port";
4
4
  import * as prereqs from "../prerequisites.service";
5
+ import { PrerequisiteFile } from "./file";
5
6
 
6
7
  type Dependencies = { Logger: LoggerPort };
7
8
 
@@ -27,10 +28,13 @@ export class PrerequisiteLogFile implements prereqs.Prerequisite {
27
28
  const path = this.deps.Logger.getFilePath();
28
29
  if (!path) return prereqs.Verification.undetermined(stopwatch.stop());
29
30
 
30
- const result = await Bun.file(path.get()).exists();
31
+ const file = new PrerequisiteFile({
32
+ label: this.label,
33
+ file: path,
34
+ permissions: { read: true, write: true },
35
+ });
31
36
 
32
- if (result) return prereqs.Verification.success(stopwatch.stop());
33
- return prereqs.Verification.failure(stopwatch.stop(), { message: `Missing file: ${path.get()}` });
37
+ return file.verify(clock);
34
38
  } catch (error) {
35
39
  return prereqs.Verification.failure(stopwatch.stop(), error as Error);
36
40
  }