@agenticmail/core 0.3.3 → 0.3.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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +56 -48
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -230,6 +230,7 @@ declare class StalwartAdmin {
|
|
|
230
230
|
* Note: stalwart-cli may return a 500 error even when the operation succeeds.
|
|
231
231
|
* We verify by listing the config afterwards.
|
|
232
232
|
*/
|
|
233
|
+
private cliArgs;
|
|
233
234
|
updateSetting(key: string, value: string): Promise<void>;
|
|
234
235
|
/**
|
|
235
236
|
* Set the server hostname used in SMTP EHLO greetings.
|
package/dist/index.js
CHANGED
|
@@ -813,24 +813,31 @@ var StalwartAdmin = class {
|
|
|
813
813
|
* Note: stalwart-cli may return a 500 error even when the operation succeeds.
|
|
814
814
|
* We verify by listing the config afterwards.
|
|
815
815
|
*/
|
|
816
|
-
|
|
817
|
-
const { execSync: execSync3 } = await import("child_process");
|
|
816
|
+
cliArgs() {
|
|
818
817
|
const creds = `${this.options.adminUser}:${this.options.adminPassword}`;
|
|
818
|
+
return ["exec", "agenticmail-stalwart", "stalwart-cli", "-u", "http://localhost:8080", "-c", creds];
|
|
819
|
+
}
|
|
820
|
+
async updateSetting(key, value) {
|
|
821
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
822
|
+
const cli = this.cliArgs();
|
|
819
823
|
try {
|
|
820
|
-
|
|
821
|
-
|
|
824
|
+
execFileSync3(
|
|
825
|
+
"docker",
|
|
826
|
+
[...cli, "server", "delete-config", key],
|
|
822
827
|
{ timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
|
|
823
828
|
);
|
|
824
829
|
} catch {
|
|
825
830
|
}
|
|
826
831
|
try {
|
|
827
|
-
|
|
828
|
-
|
|
832
|
+
execFileSync3(
|
|
833
|
+
"docker",
|
|
834
|
+
[...cli, "server", "add-config", key, value],
|
|
829
835
|
{ timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
|
|
830
836
|
);
|
|
831
837
|
} catch {
|
|
832
|
-
const output =
|
|
833
|
-
|
|
838
|
+
const output = execFileSync3(
|
|
839
|
+
"docker",
|
|
840
|
+
[...cli, "server", "list-config", key],
|
|
834
841
|
{ timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
|
|
835
842
|
).toString();
|
|
836
843
|
if (!output.includes(value)) {
|
|
@@ -875,16 +882,15 @@ var StalwartAdmin = class {
|
|
|
875
882
|
* Returns the public key (base64, no headers) for DNS TXT record.
|
|
876
883
|
*/
|
|
877
884
|
async createDkimSignature(domain, selector = "agenticmail") {
|
|
878
|
-
const {
|
|
885
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
879
886
|
const signatureId = `agenticmail-${domain.replace(/\./g, "-")}`;
|
|
880
|
-
const
|
|
881
|
-
const cli = `docker exec agenticmail-stalwart stalwart-cli -u http://localhost:8080 -c ${creds}`;
|
|
887
|
+
const cli = this.cliArgs();
|
|
882
888
|
const existing = await this.getSettings(`signature.${signatureId}`);
|
|
883
889
|
if (existing["private-key"] && existing["domain"]) {
|
|
884
890
|
console.log(`[DKIM] Reusing existing signature "${signatureId}" from Stalwart DB`);
|
|
885
891
|
} else {
|
|
886
892
|
try {
|
|
887
|
-
|
|
893
|
+
execFileSync3("docker", [...cli, "server", "delete-config", `signature.${signatureId}`], {
|
|
888
894
|
timeout: 1e4,
|
|
889
895
|
stdio: ["ignore", "pipe", "pipe"]
|
|
890
896
|
});
|
|
@@ -892,7 +898,7 @@ var StalwartAdmin = class {
|
|
|
892
898
|
}
|
|
893
899
|
console.log(`[DKIM] Creating RSA signature for ${domain} via stalwart-cli`);
|
|
894
900
|
try {
|
|
895
|
-
|
|
901
|
+
execFileSync3("docker", [...cli, "dkim", "create", "rsa", domain, signatureId, selector], {
|
|
896
902
|
timeout: 15e3,
|
|
897
903
|
stdio: ["ignore", "pipe", "pipe"]
|
|
898
904
|
});
|
|
@@ -904,12 +910,12 @@ var StalwartAdmin = class {
|
|
|
904
910
|
if (!Object.keys(signRule).length) {
|
|
905
911
|
console.log(`[DKIM] Configuring DKIM signing rule`);
|
|
906
912
|
const rules = [
|
|
907
|
-
[
|
|
908
|
-
[
|
|
909
|
-
[
|
|
913
|
+
["auth.dkim.sign.0000.if", `listener != 'smtp'`],
|
|
914
|
+
["auth.dkim.sign.0000.then", `['${signatureId}']`],
|
|
915
|
+
["auth.dkim.sign.0001.else", "false"]
|
|
910
916
|
];
|
|
911
917
|
for (const [key, value] of rules) {
|
|
912
|
-
|
|
918
|
+
execFileSync3("docker", [...cli, "server", "add-config", key, value], {
|
|
913
919
|
timeout: 1e4,
|
|
914
920
|
stdio: ["ignore", "pipe", "pipe"]
|
|
915
921
|
});
|
|
@@ -917,7 +923,7 @@ var StalwartAdmin = class {
|
|
|
917
923
|
}
|
|
918
924
|
let publicKey;
|
|
919
925
|
try {
|
|
920
|
-
const output =
|
|
926
|
+
const output = execFileSync3("docker", [...cli, "dkim", "get-public-key", signatureId], {
|
|
921
927
|
timeout: 1e4,
|
|
922
928
|
stdio: ["ignore", "pipe", "pipe"]
|
|
923
929
|
}).toString();
|
|
@@ -928,7 +934,7 @@ var StalwartAdmin = class {
|
|
|
928
934
|
throw new Error(`Failed to get DKIM public key: ${err.message}`);
|
|
929
935
|
}
|
|
930
936
|
try {
|
|
931
|
-
|
|
937
|
+
execFileSync3("docker", [...cli, "server", "reload-config"], {
|
|
932
938
|
timeout: 1e4,
|
|
933
939
|
stdio: ["ignore", "pipe", "pipe"]
|
|
934
940
|
});
|
|
@@ -941,9 +947,9 @@ var StalwartAdmin = class {
|
|
|
941
947
|
* Restart the Stalwart Docker container and wait for it to be ready.
|
|
942
948
|
*/
|
|
943
949
|
async restartContainer() {
|
|
944
|
-
const {
|
|
950
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
945
951
|
try {
|
|
946
|
-
|
|
952
|
+
execFileSync3("docker", ["restart", "agenticmail-stalwart"], { timeout: 3e4, stdio: ["ignore", "pipe", "pipe"] });
|
|
947
953
|
for (let i = 0; i < 15; i++) {
|
|
948
954
|
try {
|
|
949
955
|
const res = await fetch(`${this.baseUrl}/health`, { signal: AbortSignal.timeout(2e3) });
|
|
@@ -3813,8 +3819,8 @@ var CloudflareClient = class {
|
|
|
3813
3819
|
let available = false;
|
|
3814
3820
|
if (result.supported_tld && !hasRegistration) {
|
|
3815
3821
|
try {
|
|
3816
|
-
const {
|
|
3817
|
-
const whoisOutput =
|
|
3822
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
3823
|
+
const whoisOutput = execFileSync3("whois", [domain], { timeout: 1e4, stdio: ["ignore", "pipe", "pipe"] }).toString().toLowerCase();
|
|
3818
3824
|
available = whoisOutput.includes("domain not found") || whoisOutput.includes("no match") || whoisOutput.includes("not found") || whoisOutput.includes("no data found") || whoisOutput.includes("status: free") || whoisOutput.includes("no entries found");
|
|
3819
3825
|
} catch {
|
|
3820
3826
|
available = false;
|
|
@@ -4278,8 +4284,8 @@ var TunnelManager = class {
|
|
|
4278
4284
|
return this.binPath;
|
|
4279
4285
|
}
|
|
4280
4286
|
try {
|
|
4281
|
-
const {
|
|
4282
|
-
const sysPath =
|
|
4287
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
4288
|
+
const sysPath = execFileSync3("which", ["cloudflared"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
4283
4289
|
if (sysPath && existsSync2(sysPath)) {
|
|
4284
4290
|
this.binPath = sysPath;
|
|
4285
4291
|
return sysPath;
|
|
@@ -5351,7 +5357,7 @@ import { join as join7 } from "path";
|
|
|
5351
5357
|
import { homedir as homedir6 } from "os";
|
|
5352
5358
|
|
|
5353
5359
|
// src/setup/deps.ts
|
|
5354
|
-
import {
|
|
5360
|
+
import { execFileSync } from "child_process";
|
|
5355
5361
|
import { existsSync as existsSync3 } from "fs";
|
|
5356
5362
|
import { join as join5 } from "path";
|
|
5357
5363
|
import { homedir as homedir4 } from "os";
|
|
@@ -5365,7 +5371,7 @@ var DependencyChecker = class {
|
|
|
5365
5371
|
}
|
|
5366
5372
|
async checkDocker() {
|
|
5367
5373
|
try {
|
|
5368
|
-
const output =
|
|
5374
|
+
const output = execFileSync("docker", ["--version"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
5369
5375
|
const match = output.match(/Docker version ([\d.]+)/);
|
|
5370
5376
|
return {
|
|
5371
5377
|
name: "docker",
|
|
@@ -5383,8 +5389,9 @@ var DependencyChecker = class {
|
|
|
5383
5389
|
}
|
|
5384
5390
|
async checkStalwart() {
|
|
5385
5391
|
try {
|
|
5386
|
-
const output =
|
|
5387
|
-
|
|
5392
|
+
const output = execFileSync(
|
|
5393
|
+
"docker",
|
|
5394
|
+
["ps", "--filter", "name=agenticmail-stalwart", "--format", "{{.Status}}"],
|
|
5388
5395
|
{ timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }
|
|
5389
5396
|
).toString().trim();
|
|
5390
5397
|
const running = output.length > 0 && output.toLowerCase().includes("up");
|
|
@@ -5407,7 +5414,7 @@ var DependencyChecker = class {
|
|
|
5407
5414
|
if (existsSync3(binPath)) {
|
|
5408
5415
|
let version;
|
|
5409
5416
|
try {
|
|
5410
|
-
const output =
|
|
5417
|
+
const output = execFileSync(binPath, ["--version"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
5411
5418
|
const match = output.match(/cloudflared version ([\d.]+)/);
|
|
5412
5419
|
version = match?.[1];
|
|
5413
5420
|
} catch {
|
|
@@ -5415,7 +5422,7 @@ var DependencyChecker = class {
|
|
|
5415
5422
|
return { name: "cloudflared", installed: true, version, description: "Cloudflare Tunnel for custom domain email" };
|
|
5416
5423
|
}
|
|
5417
5424
|
try {
|
|
5418
|
-
const output =
|
|
5425
|
+
const output = execFileSync("cloudflared", ["--version"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
5419
5426
|
const match = output.match(/cloudflared version ([\d.]+)/);
|
|
5420
5427
|
return { name: "cloudflared", installed: true, version: match?.[1], description: "Cloudflare Tunnel for custom domain email" };
|
|
5421
5428
|
} catch {
|
|
@@ -5425,9 +5432,9 @@ var DependencyChecker = class {
|
|
|
5425
5432
|
};
|
|
5426
5433
|
|
|
5427
5434
|
// src/setup/installer.ts
|
|
5428
|
-
import {
|
|
5435
|
+
import { execFileSync as execFileSync2, execSync } from "child_process";
|
|
5429
5436
|
import { existsSync as existsSync4 } from "fs";
|
|
5430
|
-
import { writeFile, rename, chmod as chmod2, mkdir as mkdir2 } from "fs/promises";
|
|
5437
|
+
import { writeFile, rename, chmod as chmod2, mkdir as mkdir2, unlink } from "fs/promises";
|
|
5431
5438
|
import { join as join6 } from "path";
|
|
5432
5439
|
import { homedir as homedir5, platform as platform2, arch as arch2 } from "os";
|
|
5433
5440
|
var DependencyInstaller = class {
|
|
@@ -5444,13 +5451,13 @@ var DependencyInstaller = class {
|
|
|
5444
5451
|
async installDocker() {
|
|
5445
5452
|
let cliInstalled = false;
|
|
5446
5453
|
try {
|
|
5447
|
-
|
|
5454
|
+
execFileSync2("docker", ["--version"], { timeout: 5e3, stdio: "ignore" });
|
|
5448
5455
|
cliInstalled = true;
|
|
5449
5456
|
} catch {
|
|
5450
5457
|
}
|
|
5451
5458
|
if (cliInstalled) {
|
|
5452
5459
|
try {
|
|
5453
|
-
|
|
5460
|
+
execFileSync2("docker", ["info"], { timeout: 1e4, stdio: "ignore" });
|
|
5454
5461
|
return;
|
|
5455
5462
|
} catch {
|
|
5456
5463
|
this.onProgress("Docker found but not running \u2014 starting it now...");
|
|
@@ -5463,18 +5470,18 @@ var DependencyInstaller = class {
|
|
|
5463
5470
|
if (os === "darwin") {
|
|
5464
5471
|
this.onProgress("Installing Docker via Homebrew...");
|
|
5465
5472
|
try {
|
|
5466
|
-
|
|
5473
|
+
execFileSync2("brew", ["--version"], { timeout: 5e3, stdio: "ignore" });
|
|
5467
5474
|
} catch {
|
|
5468
5475
|
throw new Error("Homebrew is required to install Docker on macOS. Install it from https://brew.sh then try again.");
|
|
5469
5476
|
}
|
|
5470
|
-
|
|
5477
|
+
execFileSync2("brew", ["install", "--cask", "docker"], { timeout: 3e5, stdio: "inherit" });
|
|
5471
5478
|
this.onProgress("Docker installed. Starting Docker Desktop...");
|
|
5472
5479
|
this.startDockerDaemon();
|
|
5473
5480
|
await this.waitForDocker();
|
|
5474
5481
|
} else if (os === "linux") {
|
|
5475
5482
|
this.onProgress("Installing Docker...");
|
|
5476
5483
|
try {
|
|
5477
|
-
|
|
5484
|
+
execSync("curl -fsSL https://get.docker.com | sh", { timeout: 3e5, stdio: "inherit" });
|
|
5478
5485
|
} catch {
|
|
5479
5486
|
throw new Error("Failed to install Docker. Install it manually: https://docs.docker.com/get-docker/");
|
|
5480
5487
|
}
|
|
@@ -5492,12 +5499,12 @@ var DependencyInstaller = class {
|
|
|
5492
5499
|
const os = platform2();
|
|
5493
5500
|
if (os === "darwin") {
|
|
5494
5501
|
try {
|
|
5495
|
-
|
|
5502
|
+
execFileSync2("open", ["-a", "Docker"], { timeout: 1e4, stdio: "ignore" });
|
|
5496
5503
|
} catch {
|
|
5497
5504
|
}
|
|
5498
5505
|
} else if (os === "linux") {
|
|
5499
5506
|
try {
|
|
5500
|
-
|
|
5507
|
+
execFileSync2("sudo", ["systemctl", "start", "docker"], { timeout: 15e3, stdio: "ignore" });
|
|
5501
5508
|
} catch {
|
|
5502
5509
|
}
|
|
5503
5510
|
}
|
|
@@ -5513,7 +5520,7 @@ var DependencyInstaller = class {
|
|
|
5513
5520
|
let attempts = 0;
|
|
5514
5521
|
while (Date.now() - start < maxWait) {
|
|
5515
5522
|
try {
|
|
5516
|
-
|
|
5523
|
+
execFileSync2("docker", ["info"], { timeout: 5e3, stdio: "ignore" });
|
|
5517
5524
|
return;
|
|
5518
5525
|
} catch {
|
|
5519
5526
|
}
|
|
@@ -5536,14 +5543,14 @@ var DependencyInstaller = class {
|
|
|
5536
5543
|
throw new Error(`docker-compose.yml not found at: ${composePath}`);
|
|
5537
5544
|
}
|
|
5538
5545
|
try {
|
|
5539
|
-
|
|
5546
|
+
execFileSync2("docker", ["info"], { timeout: 1e4, stdio: "ignore" });
|
|
5540
5547
|
} catch {
|
|
5541
5548
|
this.onProgress("Starting Docker...");
|
|
5542
5549
|
this.startDockerDaemon();
|
|
5543
5550
|
await this.waitForDocker();
|
|
5544
5551
|
}
|
|
5545
5552
|
this.onProgress("Starting Stalwart mail server...");
|
|
5546
|
-
|
|
5553
|
+
execFileSync2("docker", ["compose", "-f", composePath, "up", "-d"], {
|
|
5547
5554
|
timeout: 12e4,
|
|
5548
5555
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5549
5556
|
});
|
|
@@ -5551,8 +5558,9 @@ var DependencyInstaller = class {
|
|
|
5551
5558
|
const start = Date.now();
|
|
5552
5559
|
while (Date.now() - start < maxWait) {
|
|
5553
5560
|
try {
|
|
5554
|
-
const output =
|
|
5555
|
-
|
|
5561
|
+
const output = execFileSync2(
|
|
5562
|
+
"docker",
|
|
5563
|
+
["ps", "--filter", "name=agenticmail-stalwart", "--format", "{{.Status}}"],
|
|
5556
5564
|
{ timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }
|
|
5557
5565
|
).toString().trim();
|
|
5558
5566
|
if (output.toLowerCase().includes("up")) {
|
|
@@ -5575,7 +5583,7 @@ var DependencyInstaller = class {
|
|
|
5575
5583
|
return binPath;
|
|
5576
5584
|
}
|
|
5577
5585
|
try {
|
|
5578
|
-
const sysPath =
|
|
5586
|
+
const sysPath = execFileSync2("which", ["cloudflared"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
5579
5587
|
if (sysPath && existsSync4(sysPath)) return sysPath;
|
|
5580
5588
|
} catch {
|
|
5581
5589
|
}
|
|
@@ -5599,11 +5607,11 @@ var DependencyInstaller = class {
|
|
|
5599
5607
|
const tgzPath = join6(binDir, "cloudflared.tgz");
|
|
5600
5608
|
await writeFile(tgzPath, buffer);
|
|
5601
5609
|
try {
|
|
5602
|
-
|
|
5610
|
+
execFileSync2("tar", ["-xzf", tgzPath, "-C", binDir, "cloudflared"], { timeout: 15e3, stdio: "ignore" });
|
|
5603
5611
|
await chmod2(binPath, 493);
|
|
5604
5612
|
} finally {
|
|
5605
5613
|
try {
|
|
5606
|
-
|
|
5614
|
+
await unlink(tgzPath);
|
|
5607
5615
|
} catch {
|
|
5608
5616
|
}
|
|
5609
5617
|
}
|