@bgord/bun 1.2.1 → 1.2.3
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/dist/crypto-key-provider-env.adapter.d.ts +8 -0
- package/dist/crypto-key-provider-env.adapter.d.ts.map +1 -0
- package/dist/crypto-key-provider-env.adapter.js +14 -0
- package/dist/crypto-key-provider-env.adapter.js.map +1 -0
- package/dist/crypto-key-provider-noop.adapter.d.ts +5 -0
- package/dist/crypto-key-provider-noop.adapter.d.ts.map +1 -0
- package/dist/crypto-key-provider-noop.adapter.js +7 -0
- package/dist/crypto-key-provider-noop.adapter.js.map +1 -0
- package/dist/crypto-key-provider.port.d.ts +4 -0
- package/dist/crypto-key-provider.port.d.ts.map +1 -0
- package/dist/crypto-key-provider.port.js +2 -0
- package/dist/crypto-key-provider.port.js.map +1 -0
- package/dist/encryption-bun.adapter.d.ts +12 -0
- package/dist/encryption-bun.adapter.d.ts.map +1 -0
- package/dist/encryption-bun.adapter.js +34 -0
- package/dist/encryption-bun.adapter.js.map +1 -0
- package/dist/encryption-iv.vo.d.ts +5 -0
- package/dist/encryption-iv.vo.d.ts.map +1 -0
- package/dist/encryption-iv.vo.js +9 -0
- package/dist/encryption-iv.vo.js.map +1 -0
- package/dist/encryption-key.vo.d.ts +8 -0
- package/dist/encryption-key.vo.d.ts.map +1 -0
- package/dist/encryption-key.vo.js +11 -0
- package/dist/encryption-key.vo.js.map +1 -0
- package/dist/encryption-noop.adapter.d.ts +6 -0
- package/dist/encryption-noop.adapter.d.ts.map +1 -0
- package/dist/encryption-noop.adapter.js +9 -0
- package/dist/encryption-noop.adapter.js.map +1 -0
- package/dist/encryption.port.d.ts +10 -0
- package/dist/encryption.port.d.ts.map +1 -0
- package/dist/encryption.port.js +2 -0
- package/dist/encryption.port.js.map +1 -0
- package/dist/gzip-bun.adapter.d.ts +5 -0
- package/dist/gzip-bun.adapter.d.ts.map +1 -0
- package/dist/gzip-bun.adapter.js +9 -0
- package/dist/gzip-bun.adapter.js.map +1 -0
- package/dist/gzip-noop.adapter.d.ts +5 -0
- package/dist/gzip-noop.adapter.d.ts.map +1 -0
- package/dist/gzip-noop.adapter.js +6 -0
- package/dist/gzip-noop.adapter.js.map +1 -0
- package/dist/gzip-stream.adapter.d.ts +5 -0
- package/dist/gzip-stream.adapter.d.ts.map +1 -0
- package/dist/gzip-stream.adapter.js +12 -0
- package/dist/gzip-stream.adapter.js.map +1 -0
- package/dist/gzip.port.d.ts +9 -0
- package/dist/gzip.port.d.ts.map +1 -0
- package/dist/gzip.port.js +2 -0
- package/dist/gzip.port.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/prerequisites/binary.d.ts.map +1 -1
- package/dist/prerequisites/binary.js +3 -4
- package/dist/prerequisites/binary.js.map +1 -1
- package/dist/prerequisites/external-api.d.ts +4 -1
- package/dist/prerequisites/external-api.d.ts.map +1 -1
- package/dist/prerequisites/external-api.js +4 -1
- package/dist/prerequisites/external-api.js.map +1 -1
- package/dist/prerequisites/index.d.ts +1 -0
- package/dist/prerequisites/index.d.ts.map +1 -1
- package/dist/prerequisites/index.js +1 -0
- package/dist/prerequisites/index.js.map +1 -1
- package/dist/prerequisites/os.d.ts +13 -0
- package/dist/prerequisites/os.d.ts.map +1 -0
- package/dist/prerequisites/os.js +27 -0
- package/dist/prerequisites/os.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/readme.md +13 -0
- package/src/crypto-key-provider-env.adapter.ts +16 -0
- package/src/crypto-key-provider-noop.adapter.ts +9 -0
- package/src/crypto-key-provider.port.ts +3 -0
- package/src/encryption-bun.adapter.ts +54 -0
- package/src/encryption-iv.vo.ts +9 -0
- package/src/encryption-key.vo.ts +15 -0
- package/src/encryption-noop.adapter.ts +11 -0
- package/src/encryption.port.ts +11 -0
- package/src/gzip-bun.adapter.ts +10 -0
- package/src/gzip-noop.adapter.ts +7 -0
- package/src/gzip-stream.adapter.ts +19 -0
- package/src/gzip.port.ts +10 -0
- package/src/index.ts +11 -0
- package/src/prerequisites/binary.ts +3 -4
- package/src/prerequisites/external-api.ts +11 -3
- package/src/prerequisites/index.ts +1 -0
- package/src/prerequisites/os.ts +33 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bgord/bun",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Bartosz Gordon",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"preinstall": "bunx only-allow bun"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@biomejs/biome": "2.3.
|
|
23
|
+
"@biomejs/biome": "2.3.4",
|
|
24
24
|
"@commitlint/cli": "20.1.0",
|
|
25
25
|
"@commitlint/config-conventional": "20.0.0",
|
|
26
26
|
"@types/bun": "1.3.1",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@types/mime-types": "3.0.1",
|
|
29
29
|
"@types/nodemailer": "7.0.3",
|
|
30
30
|
"@types/yazl": "3.3.0",
|
|
31
|
-
"cspell": "9.
|
|
31
|
+
"cspell": "9.3.0",
|
|
32
32
|
"knip": "5.67.1",
|
|
33
33
|
"lefthook": "2.0.2",
|
|
34
34
|
"only-allow": "1.2.1",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"mime-types": "3.0.1",
|
|
50
50
|
"node-cache": "5.1.2",
|
|
51
51
|
"nodemailer": "7.0.10",
|
|
52
|
-
"sharp": "0.34.
|
|
52
|
+
"sharp": "0.34.5",
|
|
53
53
|
"winston": "3.18.3",
|
|
54
54
|
"yazl": "3.3.1"
|
|
55
55
|
},
|
package/readme.md
CHANGED
|
@@ -53,6 +53,9 @@ src/
|
|
|
53
53
|
├── context.middleware.ts
|
|
54
54
|
├── correlation-id.vo.ts
|
|
55
55
|
├── correlation-storage.service.ts
|
|
56
|
+
├── crypto-key-provider-env.adapter.ts
|
|
57
|
+
├── crypto-key-provider-noop.adapter.ts
|
|
58
|
+
├── crypto-key-provider.port.ts
|
|
56
59
|
├── csv-stringifier.adapter.ts
|
|
57
60
|
├── csv-stringifier.port.ts
|
|
58
61
|
├── decorators.service.ts
|
|
@@ -60,6 +63,11 @@ src/
|
|
|
60
63
|
├── disk-space-checker-noop.adapter.ts
|
|
61
64
|
├── disk-space-checker.port.ts
|
|
62
65
|
├── dispatching-event-store.ts
|
|
66
|
+
├── encryption-bun.adapter.ts
|
|
67
|
+
├── encryption-iv.vo.ts
|
|
68
|
+
├── encryption-key.vo.ts
|
|
69
|
+
├── encryption-noop.adapter.ts
|
|
70
|
+
├── encryption.port.ts
|
|
63
71
|
├── env-validator.service.ts
|
|
64
72
|
├── etag-extractor.middleware.ts
|
|
65
73
|
├── event-bus-like.types.ts
|
|
@@ -86,6 +94,10 @@ src/
|
|
|
86
94
|
├── file-renamer.port.ts
|
|
87
95
|
├── file-uploader.middleware.ts
|
|
88
96
|
├── graceful-shutdown.service.ts
|
|
97
|
+
├── gzip-bun.adapter.ts
|
|
98
|
+
├── gzip-noop.adapter.ts
|
|
99
|
+
├── gzip-stream.adapter.ts
|
|
100
|
+
├── gzip.port.ts
|
|
89
101
|
├── hcaptcha-secret-key.vo.ts
|
|
90
102
|
├── hcaptcha-site-key.vo.ts
|
|
91
103
|
├── healthcheck.service.ts
|
|
@@ -188,6 +200,7 @@ src/
|
|
|
188
200
|
│ ├── mailer.ts
|
|
189
201
|
│ ├── memory.ts
|
|
190
202
|
│ ├── node.ts
|
|
203
|
+
│ ├── os.ts
|
|
191
204
|
│ ├── outside-connectivity.ts
|
|
192
205
|
│ ├── port.ts
|
|
193
206
|
│ ├── ram.ts
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CryptoKeyProviderPort } from "./crypto-key-provider.port";
|
|
2
|
+
import type { EncryptionKeyType } from "./encryption-key.vo";
|
|
3
|
+
|
|
4
|
+
export class CryptoKeyProviderEnvAdapter implements CryptoKeyProviderPort {
|
|
5
|
+
constructor(private readonly ENCRYPTION_KEY: EncryptionKeyType) {}
|
|
6
|
+
|
|
7
|
+
async get(): Promise<CryptoKey> {
|
|
8
|
+
const bytes = new Uint8Array(32);
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < 32; i++) {
|
|
11
|
+
bytes[i] = Number.parseInt(this.ENCRYPTION_KEY.slice(i * 2, i * 2 + 2), 16);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return crypto.subtle.importKey("raw", bytes, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CryptoKeyProviderPort } from "./crypto-key-provider.port";
|
|
2
|
+
|
|
3
|
+
export class CryptoKeyProviderNoopAdapter implements CryptoKeyProviderPort {
|
|
4
|
+
async get(): Promise<CryptoKey> {
|
|
5
|
+
const bytes = new Uint8Array(32);
|
|
6
|
+
|
|
7
|
+
return crypto.subtle.importKey("raw", bytes, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CryptoKeyProviderPort } from "./crypto-key-provider.port";
|
|
2
|
+
import type { EncryptionPort, EncryptionRecipe } from "./encryption.port";
|
|
3
|
+
import { EncryptionIV } from "./encryption-iv.vo";
|
|
4
|
+
|
|
5
|
+
export const EncryptionBunAdapterError = { InvalidPayload: "encryption.bun.adapter.invalid.payload" };
|
|
6
|
+
|
|
7
|
+
export class EncryptionBunAdapter implements EncryptionPort {
|
|
8
|
+
constructor(private readonly cryptoKeyProvider: CryptoKeyProviderPort) {}
|
|
9
|
+
|
|
10
|
+
async encrypt(recipe: EncryptionRecipe) {
|
|
11
|
+
const key = await this.cryptoKeyProvider.get();
|
|
12
|
+
const iv = EncryptionIV.generate();
|
|
13
|
+
|
|
14
|
+
const plaintext = await Bun.file(recipe.input.get()).arrayBuffer();
|
|
15
|
+
|
|
16
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
17
|
+
{ name: "AES-GCM", iv: iv.buffer as ArrayBuffer },
|
|
18
|
+
key,
|
|
19
|
+
plaintext,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const ciphertext = new Uint8Array(encrypted);
|
|
23
|
+
const output = new Uint8Array(iv.length + ciphertext.length);
|
|
24
|
+
output.set(iv, 0);
|
|
25
|
+
output.set(ciphertext, iv.length);
|
|
26
|
+
|
|
27
|
+
await Bun.write(recipe.output.get(), output);
|
|
28
|
+
|
|
29
|
+
return recipe.output;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async decrypt(recipe: EncryptionRecipe) {
|
|
33
|
+
const key = await this.cryptoKeyProvider.get();
|
|
34
|
+
|
|
35
|
+
const bytes = new Uint8Array(await Bun.file(recipe.input.get()).arrayBuffer());
|
|
36
|
+
if (bytes.length < EncryptionIV.LENGTH + 1) throw new Error(EncryptionBunAdapterError.InvalidPayload);
|
|
37
|
+
|
|
38
|
+
const iv = bytes.subarray(0, EncryptionIV.LENGTH);
|
|
39
|
+
const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
|
|
40
|
+
|
|
41
|
+
const ciphertext = bytes.subarray(EncryptionIV.LENGTH);
|
|
42
|
+
|
|
43
|
+
const ciphertextBuffer = ciphertext.buffer.slice(
|
|
44
|
+
ciphertext.byteOffset,
|
|
45
|
+
ciphertext.byteOffset + ciphertext.byteLength,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: ivBuffer }, key, ciphertextBuffer);
|
|
49
|
+
|
|
50
|
+
await Bun.write(recipe.output.get(), new Uint8Array(decrypted));
|
|
51
|
+
|
|
52
|
+
return recipe.output;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
|
|
3
|
+
export const EncryptionKeyError = {
|
|
4
|
+
Type: "encryption.key.type",
|
|
5
|
+
InvalidHex: "encryption.key.invalid.hex",
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
const CHARS_WHITELIST = /^[0-9a-fA-F]{64}$/;
|
|
9
|
+
|
|
10
|
+
export const EncryptionKey = z
|
|
11
|
+
.string(EncryptionKeyError.Type)
|
|
12
|
+
.regex(CHARS_WHITELIST, EncryptionKeyError.InvalidHex)
|
|
13
|
+
.brand("EncryptionKey");
|
|
14
|
+
|
|
15
|
+
export type EncryptionKeyType = z.infer<typeof EncryptionKey>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EncryptionPort, EncryptionRecipe } from "./encryption.port";
|
|
2
|
+
|
|
3
|
+
export class EncryptionNoopAdapter implements EncryptionPort {
|
|
4
|
+
async encrypt(recipe: EncryptionRecipe) {
|
|
5
|
+
return recipe.output;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async decrypt(recipe: EncryptionRecipe) {
|
|
9
|
+
return recipe.output;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
|
|
3
|
+
export type EncryptionRecipe = {
|
|
4
|
+
input: tools.FilePathRelative | tools.FilePathAbsolute;
|
|
5
|
+
output: tools.FilePathRelative | tools.FilePathAbsolute;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export interface EncryptionPort {
|
|
9
|
+
encrypt(recipe: EncryptionRecipe): Promise<tools.FilePathRelative | tools.FilePathAbsolute>;
|
|
10
|
+
decrypt(recipe: EncryptionRecipe): Promise<tools.FilePathRelative | tools.FilePathAbsolute>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GzipPort, GzipRecipe } from "./gzip.port";
|
|
2
|
+
|
|
3
|
+
export class GzipBunAdapter implements GzipPort {
|
|
4
|
+
async pack(recipe: GzipRecipe) {
|
|
5
|
+
const file = await Bun.file(recipe.input.get()).arrayBuffer();
|
|
6
|
+
const archive = Bun.gzipSync(file);
|
|
7
|
+
await Bun.write(recipe.output.get(), archive);
|
|
8
|
+
return recipe.output;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
2
|
+
import { pipeline } from "node:stream/promises";
|
|
3
|
+
import { constants, createGzip } from "node:zlib";
|
|
4
|
+
import type { GzipPort, GzipRecipe } from "./gzip.port";
|
|
5
|
+
|
|
6
|
+
export class GzipStreamAdapter implements GzipPort {
|
|
7
|
+
async pack(recipe: GzipRecipe) {
|
|
8
|
+
const inputPath = recipe.input.get();
|
|
9
|
+
const outputPath = recipe.output.get();
|
|
10
|
+
|
|
11
|
+
await pipeline(
|
|
12
|
+
createReadStream(inputPath),
|
|
13
|
+
createGzip({ level: constants.Z_BEST_SPEED }),
|
|
14
|
+
createWriteStream(outputPath),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return recipe.output;
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/gzip.port.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
|
|
3
|
+
export type GzipRecipe = {
|
|
4
|
+
input: tools.FilePathRelative | tools.FilePathAbsolute;
|
|
5
|
+
output: tools.FilePathRelative | tools.FilePathAbsolute;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export interface GzipPort {
|
|
9
|
+
pack(recipe: GzipRecipe): Promise<tools.FilePathRelative | tools.FilePathAbsolute>;
|
|
10
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,9 @@ export * from "./command-logger.service";
|
|
|
26
26
|
export * from "./context.middleware";
|
|
27
27
|
export * from "./correlation-id.vo";
|
|
28
28
|
export * from "./correlation-storage.service";
|
|
29
|
+
export * from "./crypto-key-provider.port";
|
|
30
|
+
export * from "./crypto-key-provider-env.adapter";
|
|
31
|
+
export * from "./crypto-key-provider-noop.adapter";
|
|
29
32
|
export * from "./csv-stringifier.adapter";
|
|
30
33
|
export * from "./csv-stringifier.port";
|
|
31
34
|
export * from "./decorators.service";
|
|
@@ -33,6 +36,10 @@ export * from "./disk-space-checker.port";
|
|
|
33
36
|
export * from "./disk-space-checker-bun.adapter";
|
|
34
37
|
export * from "./disk-space-checker-noop.adapter";
|
|
35
38
|
export * from "./dispatching-event-store";
|
|
39
|
+
export * from "./encryption.port";
|
|
40
|
+
export * from "./encryption-bun.adapter";
|
|
41
|
+
export * from "./encryption-key.vo";
|
|
42
|
+
export * from "./encryption-noop.adapter";
|
|
36
43
|
export * from "./env-validator.service";
|
|
37
44
|
export * from "./etag-extractor.middleware";
|
|
38
45
|
export * from "./event.types";
|
|
@@ -62,6 +69,10 @@ export * from "./file-renamer-noop.adapter";
|
|
|
62
69
|
export * from "./file-renamer-noop.adapter";
|
|
63
70
|
export * from "./file-uploader.middleware";
|
|
64
71
|
export * from "./graceful-shutdown.service";
|
|
72
|
+
export * from "./gzip.port";
|
|
73
|
+
export * from "./gzip-bun.adapter";
|
|
74
|
+
export * from "./gzip-noop.adapter";
|
|
75
|
+
export * from "./gzip-stream.adapter";
|
|
65
76
|
export * from "./hcaptcha-secret-key.vo";
|
|
66
77
|
export * from "./hcaptcha-site-key.vo";
|
|
67
78
|
export * from "./healthcheck.service";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import bun from "bun";
|
|
2
1
|
import * as tools from "@bgord/tools";
|
|
3
2
|
import type { BinaryType } from "../binary.vo";
|
|
4
3
|
import type { ClockPort } from "../clock.port";
|
|
@@ -23,10 +22,10 @@ export class PrerequisiteBinary implements prereqs.Prerequisite {
|
|
|
23
22
|
try {
|
|
24
23
|
if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
|
|
25
24
|
|
|
26
|
-
const result =
|
|
25
|
+
const result = Bun.which(this.binary);
|
|
27
26
|
|
|
28
|
-
if (result
|
|
29
|
-
return prereqs.Verification.failure(stopwatch.stop()
|
|
27
|
+
if (result) return prereqs.Verification.success(stopwatch.stop());
|
|
28
|
+
return prereqs.Verification.failure(stopwatch.stop());
|
|
30
29
|
} catch (error) {
|
|
31
30
|
return prereqs.Verification.failure(stopwatch.stop(), error as Error);
|
|
32
31
|
}
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import * as tools from "@bgord/tools";
|
|
2
2
|
import type { ClockPort } from "../clock.port";
|
|
3
3
|
import * as prereqs from "../prerequisites.service";
|
|
4
|
+
import { Timeout } from "../timeout.service";
|
|
4
5
|
|
|
5
6
|
export class PrerequisiteExternalApi implements prereqs.Prerequisite {
|
|
6
7
|
readonly kind = "external-api";
|
|
7
8
|
readonly label: prereqs.PrerequisiteLabelType;
|
|
8
9
|
readonly enabled?: boolean = true;
|
|
9
10
|
|
|
10
|
-
private readonly request: () => Promise<Response>;
|
|
11
|
+
private readonly request: (signal: AbortSignal) => Promise<Response>;
|
|
12
|
+
readonly timeout: tools.Duration;
|
|
11
13
|
|
|
12
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
config: prereqs.PrerequisiteConfigType & {
|
|
16
|
+
request: (signal: AbortSignal) => Promise<Response>;
|
|
17
|
+
timeout?: tools.Duration;
|
|
18
|
+
},
|
|
19
|
+
) {
|
|
13
20
|
this.label = config.label;
|
|
14
21
|
this.enabled = config.enabled === undefined ? true : config.enabled;
|
|
15
22
|
|
|
16
23
|
this.request = config.request;
|
|
24
|
+
this.timeout = config.timeout ?? tools.Duration.Seconds(2);
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
|
|
@@ -22,7 +30,7 @@ export class PrerequisiteExternalApi implements prereqs.Prerequisite {
|
|
|
22
30
|
if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
|
|
23
31
|
|
|
24
32
|
try {
|
|
25
|
-
const response = await this.request();
|
|
33
|
+
const response = await Timeout.cancellable((signal: AbortSignal) => this.request(signal), this.timeout);
|
|
26
34
|
|
|
27
35
|
if (response.ok) return prereqs.Verification.success(stopwatch.stop());
|
|
28
36
|
return prereqs.Verification.failure(stopwatch.stop(), { message: `HTTP ${response.status}` });
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import * as tools from "@bgord/tools";
|
|
3
|
+
import type { ClockPort } from "../clock.port";
|
|
4
|
+
import * as prereqs from "../prerequisites.service";
|
|
5
|
+
|
|
6
|
+
export class PrerequisiteOs implements prereqs.Prerequisite {
|
|
7
|
+
readonly kind = "os";
|
|
8
|
+
readonly label: prereqs.PrerequisiteLabelType;
|
|
9
|
+
readonly enabled?: boolean = true;
|
|
10
|
+
|
|
11
|
+
private readonly accepted: string[];
|
|
12
|
+
|
|
13
|
+
constructor(config: prereqs.PrerequisiteConfigType & { accepted: string[] }) {
|
|
14
|
+
this.label = config.label;
|
|
15
|
+
this.enabled = config.enabled === undefined ? true : config.enabled;
|
|
16
|
+
this.accepted = config.accepted;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
|
|
20
|
+
const stopwatch = new tools.Stopwatch(clock.now());
|
|
21
|
+
|
|
22
|
+
if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
|
|
23
|
+
|
|
24
|
+
const type = os.type();
|
|
25
|
+
|
|
26
|
+
if (this.accepted.map((type) => type.toLowerCase()).includes(type.toLowerCase())) {
|
|
27
|
+
return prereqs.Verification.success(stopwatch.stop());
|
|
28
|
+
}
|
|
29
|
+
return prereqs.Verification.failure(stopwatch.stop(), {
|
|
30
|
+
message: `Unacceptable os: ${this.accepted.join(", ")}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|