@c9up/goldstone 0.0.0-stage → 0.1.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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +238 -2
  3. package/dist/GoldstoneProvider.d.ts +33 -0
  4. package/dist/GoldstoneProvider.d.ts.map +1 -0
  5. package/dist/GoldstoneProvider.js +55 -0
  6. package/dist/GoldstoneProvider.js.map +1 -0
  7. package/dist/InboxManager.d.ts +17 -0
  8. package/dist/InboxManager.d.ts.map +1 -0
  9. package/dist/InboxManager.js +39 -0
  10. package/dist/InboxManager.js.map +1 -0
  11. package/dist/Mailbox.d.ts +83 -0
  12. package/dist/Mailbox.d.ts.map +1 -0
  13. package/dist/Mailbox.js +326 -0
  14. package/dist/Mailbox.js.map +1 -0
  15. package/dist/ReceivedMessage.d.ts +152 -0
  16. package/dist/ReceivedMessage.d.ts.map +1 -0
  17. package/dist/ReceivedMessage.js +179 -0
  18. package/dist/ReceivedMessage.js.map +1 -0
  19. package/dist/augmentations.d.ts +18 -0
  20. package/dist/augmentations.d.ts.map +1 -0
  21. package/dist/augmentations.js +10 -0
  22. package/dist/augmentations.js.map +1 -0
  23. package/dist/authenticity.d.ts +81 -0
  24. package/dist/authenticity.d.ts.map +1 -0
  25. package/dist/authenticity.js +102 -0
  26. package/dist/authenticity.js.map +1 -0
  27. package/dist/config.d.ts +85 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +50 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/errors.d.ts +15 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +50 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/inbound/context.d.ts +43 -0
  36. package/dist/inbound/context.d.ts.map +1 -0
  37. package/dist/inbound/context.js +56 -0
  38. package/dist/inbound/context.js.map +1 -0
  39. package/dist/inbound/mailgun.d.ts +57 -0
  40. package/dist/inbound/mailgun.d.ts.map +1 -0
  41. package/dist/inbound/mailgun.js +132 -0
  42. package/dist/inbound/mailgun.js.map +1 -0
  43. package/dist/index.d.ts +11 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +11 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/native/generated.d.ts +106 -0
  48. package/dist/native/generated.d.ts.map +1 -0
  49. package/dist/native/generated.js +7 -0
  50. package/dist/native/generated.js.map +1 -0
  51. package/dist/native.d.ts +23 -0
  52. package/dist/native.d.ts.map +1 -0
  53. package/dist/native.js +45 -0
  54. package/dist/native.js.map +1 -0
  55. package/dist/services/main.d.ts +22 -0
  56. package/dist/services/main.d.ts.map +1 -0
  57. package/dist/services/main.js +43 -0
  58. package/dist/services/main.js.map +1 -0
  59. package/dist/vendor/nativeBinary.d.ts +67 -0
  60. package/dist/vendor/nativeBinary.d.ts.map +1 -0
  61. package/dist/vendor/nativeBinary.js +156 -0
  62. package/dist/vendor/nativeBinary.js.map +1 -0
  63. package/index.darwin-arm64.node +0 -0
  64. package/index.darwin-x64.node +0 -0
  65. package/index.linux-arm64-gnu.node +0 -0
  66. package/index.linux-x64-gnu.node +0 -0
  67. package/index.win32-x64-msvc.node +0 -0
  68. package/package.json +67 -3
  69. package/src/GoldstoneProvider.ts +75 -0
  70. package/src/InboxManager.ts +51 -0
  71. package/src/Mailbox.ts +433 -0
  72. package/src/ReceivedMessage.ts +287 -0
  73. package/src/augmentations.ts +22 -0
  74. package/src/authenticity.ts +183 -0
  75. package/src/config.ts +132 -0
  76. package/src/errors.ts +57 -0
  77. package/src/inbound/context.ts +92 -0
  78. package/src/inbound/mailgun.ts +201 -0
  79. package/src/index.ts +53 -0
  80. package/src/native/generated.ts +141 -0
  81. package/src/native.ts +62 -0
  82. package/src/services/main.ts +51 -0
  83. package/src/vendor/nativeBinary.ts +186 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Every `platform-arch` a binary is built for.
3
+ *
4
+ * For the message a package raises when it refuses: "no binary for
5
+ * linux-riscv64" is only actionable next to the list of what there IS.
6
+ */
7
+ export declare function supportedTargets(): readonly string[];
8
+ /** The suffix a given `platform-arch` builds under, or `undefined`. */
9
+ export declare function nativeTargetSuffix(target: string): string | undefined;
10
+ /** The suffix for THIS platform, or `undefined` where no binary is built. */
11
+ export declare function nativeBinarySuffix(): string | undefined;
12
+ /**
13
+ * Why the binary is not there, phrased for whoever has to fix it.
14
+ *
15
+ * "not found" and "not built for your platform" call for different actions,
16
+ * and a single "unavailable" leaves the reader to guess which one they are
17
+ * looking at.
18
+ */
19
+ export declare function unavailableReason(cause?: unknown): string;
20
+ /**
21
+ * `musl` builds under a different suffix, and the failure is otherwise
22
+ * baffling: the file is there, and `require` still refuses it. Worth saying so
23
+ * in a message rather than leaving a reader to discover glibc.
24
+ */
25
+ export declare function muslHint(): string;
26
+ /** What a load attempt did, so the caller can apply its own policy. */
27
+ export type NativeBinaryResult<T> = {
28
+ loaded: true;
29
+ binary: T;
30
+ } | {
31
+ loaded: false;
32
+ suffix: string | undefined;
33
+ cause?: unknown;
34
+ };
35
+ /**
36
+ * The names among `names` that `value` does not carry as functions.
37
+ *
38
+ * Classes count, being functions, and so does a class's static member: `value`
39
+ * may itself be a function. What a guard rejects is only useful named, so the
40
+ * loader reports this list rather than a bare "no".
41
+ */
42
+ export declare function missingFunctions(value: unknown, names: readonly string[]): string[];
43
+ /**
44
+ * Whether `value` carries every one of `names` as a function.
45
+ *
46
+ * The building block of the guard a package hands to `loadNativeBinary`, over
47
+ * the list of what it actually calls on its binary — the same list it passes
48
+ * as `expects`, so the message can name what is missing.
49
+ */
50
+ export declare function hasFunctions(value: unknown, names: readonly string[]): value is object;
51
+ /**
52
+ * Load `<package root>/index.<suffix>.node`, and check it is the binary the
53
+ * package calls.
54
+ *
55
+ * The path is fixed rather than passed: this file is generated into
56
+ * `<package>/src/vendor/`, so the package root is always two levels up, from
57
+ * `src` and from `dist` alike.
58
+ *
59
+ * `isBinary` is the package's own check of what it calls. A declaration only
60
+ * says what the Rust promises: a stale build, or one from another version,
61
+ * loads just as well and then fails on the first missing call, far from here.
62
+ * A rejected module is reported as a failed load, so the package's policy
63
+ * (degrade or refuse) applies to it unchanged. `expects`, the list the guard is
64
+ * built from, lets that report name the missing calls.
65
+ */
66
+ export declare function loadNativeBinary<T>(isBinary: (value: unknown) => value is T, expects?: readonly string[]): NativeBinaryResult<T>;
67
+ //# sourceMappingURL=nativeBinary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeBinary.d.ts","sourceRoot":"","sources":["../../src/vendor/nativeBinary.ts"],"names":[],"mappings":"AAoCA;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,MAAM,EAAE,CAEpD;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAQzD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAIjC;AAED,uEAAuE;AACvE,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAC7B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAC3B;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAQlE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,GACtB,MAAM,EAAE,CAQV;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,GACtB,KAAK,IAAI,MAAM,CAQjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EACjC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GACzB,kBAAkB,CAAC,CAAC,CAAC,CAoBvB"}
@@ -0,0 +1,156 @@
1
+ // Generated from scripts/vendor/nativeBinary.ts — do not edit.
2
+ //
3
+ // This package is published and built from its own repository, so the file
4
+ // has to exist here rather than be imported. `pnpm vendor:sync` rewrites it,
5
+ // and `pnpm vendor:check` fails if this copy has drifted from the original.
6
+ /**
7
+ * Finding the NAPI binary a package ships beside itself.
8
+ *
9
+ * Every package with a Rust engine repeats the same table: napi-rs names its
10
+ * artefacts `index.<platform>-<arch>-<abi>.node`, and the mapping from Node's
11
+ * `platform`/`arch` to that suffix is the part that must never differ between
12
+ * packages. Adding a target means adding it everywhere, and a package that
13
+ * missed the edit fails only on that platform — which is exactly the failure
14
+ * nobody reproduces.
15
+ *
16
+ * What is NOT here is the policy. Some packages degrade when the binary is
17
+ * absent and answer `undefined`; others refuse loudly with build instructions.
18
+ * Both are right for their package, so the loader reports what happened and
19
+ * the caller decides.
20
+ */
21
+ import { createRequire } from "node:module";
22
+ import { dirname, join } from "node:path";
23
+ import { arch, platform } from "node:process";
24
+ import { fileURLToPath } from "node:url";
25
+ /** Node's `platform-arch` → the suffix napi-rs builds under. */
26
+ const TARGETS = {
27
+ "linux-x64": "linux-x64-gnu",
28
+ "linux-arm64": "linux-arm64-gnu",
29
+ "darwin-x64": "darwin-x64",
30
+ "darwin-arm64": "darwin-arm64",
31
+ "win32-x64": "win32-x64-msvc",
32
+ };
33
+ /**
34
+ * Every `platform-arch` a binary is built for.
35
+ *
36
+ * For the message a package raises when it refuses: "no binary for
37
+ * linux-riscv64" is only actionable next to the list of what there IS.
38
+ */
39
+ export function supportedTargets() {
40
+ return Object.keys(TARGETS);
41
+ }
42
+ /** The suffix a given `platform-arch` builds under, or `undefined`. */
43
+ export function nativeTargetSuffix(target) {
44
+ return TARGETS[target];
45
+ }
46
+ /** The suffix for THIS platform, or `undefined` where no binary is built. */
47
+ export function nativeBinarySuffix() {
48
+ return nativeTargetSuffix(`${platform}-${arch}`);
49
+ }
50
+ /**
51
+ * Why the binary is not there, phrased for whoever has to fix it.
52
+ *
53
+ * "not found" and "not built for your platform" call for different actions,
54
+ * and a single "unavailable" leaves the reader to guess which one they are
55
+ * looking at.
56
+ */
57
+ export function unavailableReason(cause) {
58
+ if (cause !== undefined) {
59
+ return `failed to load (${cause instanceof Error ? cause.message : String(cause)})`;
60
+ }
61
+ const target = `${platform}-${arch}`;
62
+ return nativeTargetSuffix(target) !== undefined
63
+ ? "binary not found"
64
+ : `no prebuilt binary for ${target}`;
65
+ }
66
+ /**
67
+ * `musl` builds under a different suffix, and the failure is otherwise
68
+ * baffling: the file is there, and `require` still refuses it. Worth saying so
69
+ * in a message rather than leaving a reader to discover glibc.
70
+ */
71
+ export function muslHint() {
72
+ return platform === "linux"
73
+ ? " On Alpine/musl, the gnu binary will not load — build the musl target."
74
+ : "";
75
+ }
76
+ /** Whether `value` carries a function under `name` (a napi class is one too). */
77
+ function hasFunction(value, name) {
78
+ const member = Reflect.get(value, name);
79
+ return typeof member === "function";
80
+ }
81
+ /**
82
+ * The names among `names` that `value` does not carry as functions.
83
+ *
84
+ * Classes count, being functions, and so does a class's static member: `value`
85
+ * may itself be a function. What a guard rejects is only useful named, so the
86
+ * loader reports this list rather than a bare "no".
87
+ */
88
+ export function missingFunctions(value, names) {
89
+ if (value === null ||
90
+ (typeof value !== "object" && typeof value !== "function")) {
91
+ return [...names];
92
+ }
93
+ return names.filter((name) => !hasFunction(value, name));
94
+ }
95
+ /**
96
+ * Whether `value` carries every one of `names` as a function.
97
+ *
98
+ * The building block of the guard a package hands to `loadNativeBinary`, over
99
+ * the list of what it actually calls on its binary — the same list it passes
100
+ * as `expects`, so the message can name what is missing.
101
+ */
102
+ export function hasFunctions(value, names) {
103
+ if (value === null ||
104
+ (typeof value !== "object" && typeof value !== "function")) {
105
+ return false;
106
+ }
107
+ return missingFunctions(value, names).length === 0;
108
+ }
109
+ /**
110
+ * Load `<package root>/index.<suffix>.node`, and check it is the binary the
111
+ * package calls.
112
+ *
113
+ * The path is fixed rather than passed: this file is generated into
114
+ * `<package>/src/vendor/`, so the package root is always two levels up, from
115
+ * `src` and from `dist` alike.
116
+ *
117
+ * `isBinary` is the package's own check of what it calls. A declaration only
118
+ * says what the Rust promises: a stale build, or one from another version,
119
+ * loads just as well and then fails on the first missing call, far from here.
120
+ * A rejected module is reported as a failed load, so the package's policy
121
+ * (degrade or refuse) applies to it unchanged. `expects`, the list the guard is
122
+ * built from, lets that report name the missing calls.
123
+ */
124
+ export function loadNativeBinary(isBinary, expects) {
125
+ const suffix = nativeBinarySuffix();
126
+ if (suffix === undefined)
127
+ return { loaded: false, suffix };
128
+ const here = dirname(fileURLToPath(import.meta.url));
129
+ let loaded;
130
+ try {
131
+ const nodeRequire = createRequire(import.meta.url);
132
+ loaded = nodeRequire(join(here, `../../index.${suffix}.node`));
133
+ }
134
+ catch (cause) {
135
+ return { loaded: false, suffix, cause };
136
+ }
137
+ if (isBinary(loaded))
138
+ return { loaded: true, binary: loaded };
139
+ return {
140
+ loaded: false,
141
+ suffix,
142
+ cause: new Error(`index.${suffix}.node loaded, but ${rejection(loaded, expects)}. ` +
143
+ "The binary is stale or from another version: rebuild it."),
144
+ };
145
+ }
146
+ /** What a rejected binary lacks, or, without a list to check, what it has. */
147
+ function rejection(loaded, expects) {
148
+ const missing = expects === undefined ? [] : missingFunctions(loaded, expects);
149
+ if (missing.length > 0)
150
+ return `it lacks ${missing.join(", ")}`;
151
+ const exported = typeof loaded === "object" && loaded !== null
152
+ ? Object.keys(loaded).filter((name) => hasFunction(loaded, name))
153
+ : [];
154
+ return `it is not the binary this package calls (it exports: ${exported.length > 0 ? exported.join(", ") : "none"})`;
155
+ }
156
+ //# sourceMappingURL=nativeBinary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeBinary.js","sourceRoot":"","sources":["../../src/vendor/nativeBinary.ts"],"names":[],"mappings":"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"}
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,70 @@
1
1
  {
2
2
  "name": "@c9up/goldstone",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Goldstone — reading mail for the Ream framework: IMAP mailboxes and inbound mail, received as hostile input",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./provider": {
15
+ "types": "./dist/GoldstoneProvider.d.ts",
16
+ "import": "./dist/GoldstoneProvider.js"
17
+ },
18
+ "./services/main": {
19
+ "types": "./dist/services/main.d.ts",
20
+ "import": "./dist/services/main.js"
21
+ }
22
+ },
23
+ "dependencies": {
24
+ "imapflow": "^2.4.2"
25
+ },
26
+ "devDependencies": {
27
+ "@biomejs/biome": "^2.5.12",
28
+ "@c9up/ream": "^0.2.26",
29
+ "@types/node": "^22.20.1",
30
+ "@vitest/coverage-v8": "4.1.11",
31
+ "typescript": "^6.0.3",
32
+ "vitest": "4.1.11"
33
+ },
34
+ "//engines": "Node 24, not 22, because AsyncLocalStorage sits on the request hot path — the container resolves through it, HttpContext is it, and the emitter reads it on every event. Node 24 backs it with AsyncContextFrame by default, and measured on that exact pattern (one context per request, six async boundaries, several reads) it costs 0.61 us per request instead of 1.55 us: 2.5x, on every request, for free. Before 24 the same mechanism existed only behind an experimental flag, and a framework cannot base its performance on a flag the application has to remember to pass. This is NOT 'track the current LTS' — security fixes still land in 22 until 2027, npm 11 is irrelevant under pnpm, and node:sqlite is not what atlas uses.",
35
+ "engines": {
36
+ "node": ">=24.0.0"
37
+ },
38
+ "files": [
39
+ "LICENSE",
40
+ "README.md",
41
+ "dist",
42
+ "index.*.node",
43
+ "src"
44
+ ],
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/C9up/goldstone.git"
51
+ },
52
+ "peerDependencies": {
53
+ "@c9up/ream": "^0.2.26"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "@c9up/ream": {
57
+ "optional": true
58
+ }
59
+ },
60
+ "scripts": {
61
+ "build": "tsc -p tsconfig.build.json",
62
+ "build:napi": "cargo build --locked --release -p goldstone-engine-napi && pnpm build:napi-types && node scripts/copy-napi.mjs",
63
+ "build:napi-types": "node scripts/build-napi-types.mjs",
64
+ "test": "vitest run",
65
+ "test:rust": "cargo test --locked",
66
+ "lint": "biome check src/ tests/",
67
+ "test:coverage": "vitest run --coverage",
68
+ "typecheck": "tsc --noEmit -p ."
69
+ }
6
70
  }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Wires `config/inbox.ts` into the container as `'inbox'`, and seats the
3
+ * manager on `@c9up/goldstone/services/main`.
4
+ *
5
+ * // reamrc.ts
6
+ * providers: [() => import('@c9up/goldstone/provider')]
7
+ *
8
+ * The host is duck-typed — this package stays publishable without importing
9
+ * `@c9up/ream`. `register` opens no connection: mailboxes open on first use.
10
+ */
11
+
12
+ import "./augmentations.js";
13
+ import type { InboxConfig, MailboxConfig } from "./config.js";
14
+ import { InboxManager } from "./InboxManager.js";
15
+ import { clearInbox, setInbox } from "./services/main.js";
16
+
17
+ interface GoldstoneContainer {
18
+ singleton(token: unknown, factory: () => unknown): void;
19
+ }
20
+ interface GoldstoneConfigStore {
21
+ get(key: string): unknown;
22
+ }
23
+ export interface GoldstoneAppContext {
24
+ container: GoldstoneContainer;
25
+ config: GoldstoneConfigStore;
26
+ }
27
+
28
+ function isInboxConfig(
29
+ value: unknown,
30
+ ): value is InboxConfig<Record<string, MailboxConfig>> {
31
+ if (typeof value !== "object" || value === null) return false;
32
+ const mailboxes = Reflect.get(value, "mailboxes");
33
+ return (
34
+ typeof Reflect.get(value, "mailbox") === "string" &&
35
+ typeof mailboxes === "object" &&
36
+ mailboxes !== null
37
+ );
38
+ }
39
+
40
+ export default class GoldstoneProvider {
41
+ readonly #app: GoldstoneAppContext;
42
+ #manager: InboxManager | undefined;
43
+
44
+ constructor(app: GoldstoneAppContext) {
45
+ this.#app = app;
46
+ }
47
+
48
+ register(): void {
49
+ const raw = this.#app.config.get("inbox");
50
+ if (raw === undefined) throw new Error("[inbox] missing config/inbox.ts");
51
+ if (!isInboxConfig(raw)) {
52
+ throw new Error(
53
+ "[inbox] config/inbox.ts must export defineConfig({ mailbox, mailboxes }).",
54
+ );
55
+ }
56
+ const manager = new InboxManager(raw);
57
+ this.#manager = manager;
58
+ setInbox(manager);
59
+ this.#app.container.singleton(InboxManager, () => manager);
60
+ this.#app.container.singleton("goldstone.inbox", () => manager);
61
+ this.#app.container.singleton("inbox", () => manager);
62
+ }
63
+
64
+ /**
65
+ * Log out of every mailbox and stop every watch. Without it, an IDLE
66
+ * connection keeps the process alive and the server looks hung on stop.
67
+ */
68
+ async shutdown(): Promise<void> {
69
+ const manager = this.#manager;
70
+ if (!manager) return;
71
+ await manager.closeAll();
72
+ clearInbox(manager);
73
+ this.#manager = undefined;
74
+ }
75
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The configured mailboxes, each opened on first use.
3
+ *
4
+ * inbox.mailbox() // the default one
5
+ * inbox.mailbox('billing')
6
+ */
7
+
8
+ import type { InboxConfig, MailboxConfig } from "./config.js";
9
+ import { GoldstoneError } from "./errors.js";
10
+ import { Mailbox } from "./Mailbox.js";
11
+
12
+ export class InboxManager<
13
+ Mailboxes extends Record<string, MailboxConfig> = Record<
14
+ string,
15
+ MailboxConfig
16
+ >,
17
+ > {
18
+ readonly #config: InboxConfig<Mailboxes>;
19
+ readonly #open = new Map<string, Mailbox>();
20
+
21
+ constructor(config: InboxConfig<Mailboxes>) {
22
+ this.#config = config;
23
+ }
24
+
25
+ /** A mailbox by name; the default one without. Opens nothing yet. */
26
+ mailbox(name: keyof Mailboxes & string = this.#config.mailbox): Mailbox {
27
+ const existing = this.#open.get(name);
28
+ if (existing) return existing;
29
+ const config = this.#config.mailboxes[name];
30
+ if (config === undefined) {
31
+ throw new GoldstoneError(
32
+ "E_GOLDSTONE_UNKNOWN_MAILBOX",
33
+ `[inbox] no mailbox "${name}" — got ${Object.keys(this.#config.mailboxes).join(", ")}`,
34
+ );
35
+ }
36
+ const mailbox = new Mailbox(name, config, {
37
+ limits: this.#config.limits,
38
+ authenticate: this.#config.authenticate,
39
+ remoteContent: this.#config.remoteContent,
40
+ });
41
+ this.#open.set(name, mailbox);
42
+ return mailbox;
43
+ }
44
+
45
+ /** Stop every watch and log out of every mailbox. */
46
+ async closeAll(): Promise<void> {
47
+ const mailboxes = [...this.#open.values()];
48
+ this.#open.clear();
49
+ await Promise.all(mailboxes.map((mailbox) => mailbox.close()));
50
+ }
51
+ }