@bgord/bun 1.2.2 → 1.2.4

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.
Files changed (72) hide show
  1. package/dist/crypto-key-provider-env.adapter.d.ts +8 -0
  2. package/dist/crypto-key-provider-env.adapter.d.ts.map +1 -0
  3. package/dist/crypto-key-provider-env.adapter.js +14 -0
  4. package/dist/crypto-key-provider-env.adapter.js.map +1 -0
  5. package/dist/crypto-key-provider-noop.adapter.d.ts +5 -0
  6. package/dist/crypto-key-provider-noop.adapter.d.ts.map +1 -0
  7. package/dist/crypto-key-provider-noop.adapter.js +7 -0
  8. package/dist/crypto-key-provider-noop.adapter.js.map +1 -0
  9. package/dist/crypto-key-provider.port.d.ts +4 -0
  10. package/dist/crypto-key-provider.port.d.ts.map +1 -0
  11. package/dist/crypto-key-provider.port.js +2 -0
  12. package/dist/crypto-key-provider.port.js.map +1 -0
  13. package/dist/encryption-bun.adapter.d.ts +12 -0
  14. package/dist/encryption-bun.adapter.d.ts.map +1 -0
  15. package/dist/encryption-bun.adapter.js +34 -0
  16. package/dist/encryption-bun.adapter.js.map +1 -0
  17. package/dist/encryption-iv.vo.d.ts +5 -0
  18. package/dist/encryption-iv.vo.d.ts.map +1 -0
  19. package/dist/encryption-iv.vo.js +9 -0
  20. package/dist/encryption-iv.vo.js.map +1 -0
  21. package/dist/encryption-key.vo.d.ts +8 -0
  22. package/dist/encryption-key.vo.d.ts.map +1 -0
  23. package/dist/encryption-key.vo.js +11 -0
  24. package/dist/encryption-key.vo.js.map +1 -0
  25. package/dist/encryption-noop.adapter.d.ts +6 -0
  26. package/dist/encryption-noop.adapter.d.ts.map +1 -0
  27. package/dist/encryption-noop.adapter.js +9 -0
  28. package/dist/encryption-noop.adapter.js.map +1 -0
  29. package/dist/encryption.port.d.ts +10 -0
  30. package/dist/encryption.port.d.ts.map +1 -0
  31. package/dist/encryption.port.js +2 -0
  32. package/dist/encryption.port.js.map +1 -0
  33. package/dist/gzip-bun.adapter.d.ts +5 -0
  34. package/dist/gzip-bun.adapter.d.ts.map +1 -0
  35. package/dist/gzip-bun.adapter.js +9 -0
  36. package/dist/gzip-bun.adapter.js.map +1 -0
  37. package/dist/gzip-noop.adapter.d.ts +5 -0
  38. package/dist/gzip-noop.adapter.d.ts.map +1 -0
  39. package/dist/gzip-noop.adapter.js +6 -0
  40. package/dist/gzip-noop.adapter.js.map +1 -0
  41. package/dist/gzip-stream.adapter.d.ts +5 -0
  42. package/dist/gzip-stream.adapter.d.ts.map +1 -0
  43. package/dist/gzip-stream.adapter.js +12 -0
  44. package/dist/gzip-stream.adapter.js.map +1 -0
  45. package/dist/gzip.port.d.ts +9 -0
  46. package/dist/gzip.port.d.ts.map +1 -0
  47. package/dist/gzip.port.js +2 -0
  48. package/dist/gzip.port.js.map +1 -0
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +11 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/prerequisites/binary.d.ts.map +1 -1
  54. package/dist/prerequisites/binary.js +3 -4
  55. package/dist/prerequisites/binary.js.map +1 -1
  56. package/dist/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +10 -10
  58. package/readme.md +12 -0
  59. package/src/crypto-key-provider-env.adapter.ts +16 -0
  60. package/src/crypto-key-provider-noop.adapter.ts +9 -0
  61. package/src/crypto-key-provider.port.ts +3 -0
  62. package/src/encryption-bun.adapter.ts +54 -0
  63. package/src/encryption-iv.vo.ts +9 -0
  64. package/src/encryption-key.vo.ts +15 -0
  65. package/src/encryption-noop.adapter.ts +11 -0
  66. package/src/encryption.port.ts +11 -0
  67. package/src/gzip-bun.adapter.ts +10 -0
  68. package/src/gzip-noop.adapter.ts +7 -0
  69. package/src/gzip-stream.adapter.ts +19 -0
  70. package/src/gzip.port.ts +10 -0
  71. package/src/index.ts +11 -0
  72. package/src/prerequisites/binary.ts +3 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bgord/bun",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": "Bartosz Gordon",
@@ -20,17 +20,17 @@
20
20
  "preinstall": "bunx only-allow bun"
21
21
  },
22
22
  "devDependencies": {
23
- "@biomejs/biome": "2.3.4",
23
+ "@biomejs/biome": "2.3.5",
24
24
  "@commitlint/cli": "20.1.0",
25
25
  "@commitlint/config-conventional": "20.0.0",
26
- "@types/bun": "1.3.1",
26
+ "@types/bun": "1.3.2",
27
27
  "@types/lodash": "4.17.20",
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.3.0",
32
- "knip": "5.67.1",
33
- "lefthook": "2.0.2",
31
+ "cspell": "9.3.1",
32
+ "knip": "5.69.1",
33
+ "lefthook": "2.0.4",
34
34
  "only-allow": "1.2.1",
35
35
  "shellcheck": "4.1.0",
36
36
  "typescript": "5.9.3",
@@ -38,18 +38,18 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@axiomhq/winston": "1.3.1",
41
- "@bgord/tools": "1.1.6",
42
- "@hono/ua-blocker": "0.1.15",
41
+ "@bgord/tools": "1.1.7",
42
+ "@hono/ua-blocker": "0.1.16",
43
43
  "better-auth": "1.3.34",
44
44
  "croner": "9.1.0",
45
45
  "csv": "6.4.1",
46
46
  "hcaptcha": "0.2.0",
47
- "hono": "4.10.4",
47
+ "hono": "4.10.6",
48
48
  "lodash": "4.17.21",
49
49
  "mime-types": "3.0.1",
50
50
  "node-cache": "5.1.2",
51
51
  "nodemailer": "7.0.10",
52
- "sharp": "0.34.4",
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
@@ -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,3 @@
1
+ export interface CryptoKeyProviderPort {
2
+ get(): Promise<CryptoKey>;
3
+ }
@@ -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,9 @@
1
+ export class EncryptionIV {
2
+ static LENGTH = 12;
3
+
4
+ static generate(): Uint8Array {
5
+ const iv = new Uint8Array(EncryptionIV.LENGTH);
6
+ crypto.getRandomValues(iv);
7
+ return iv;
8
+ }
9
+ }
@@ -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,7 @@
1
+ import type { GzipPort, GzipRecipe } from "./gzip.port";
2
+
3
+ export class GzipNoopAdapter implements GzipPort {
4
+ async pack(recipe: GzipRecipe) {
5
+ return recipe.output;
6
+ }
7
+ }
@@ -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
+ }
@@ -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 = await bun.$`which ${this.binary}`.quiet();
25
+ const result = Bun.which(this.binary);
27
26
 
28
- if (result.exitCode === 0) return prereqs.Verification.success(stopwatch.stop());
29
- return prereqs.Verification.failure(stopwatch.stop(), { message: `Exit code ${result.exitCode}` });
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
  }