@rakay-technology/kraft 0.7.8 → 0.7.9

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.
@@ -43,7 +43,7 @@ import {
43
43
  resolvePorts,
44
44
  sourceBuildDir,
45
45
  verifyHostChannel
46
- } from "./chunk-OTBBNOIV.js";
46
+ } from "./chunk-ULEEWX5M.js";
47
47
  import {
48
48
  startUnitHint,
49
49
  thisHost
@@ -1942,7 +1942,7 @@ async function runForeground(opts, source) {
1942
1942
  const uiSpinner = ora("Preparing the dashboard\u2026").start();
1943
1943
  try {
1944
1944
  const bundle = await ensureDashboard({
1945
- tag: source ? "local" : opts.uiVersion || `v${"0.7.8"}`,
1945
+ tag: source ? "local" : opts.uiVersion || `v${"0.7.9"}`,
1946
1946
  onProgress: (received, total) => {
1947
1947
  if (total) {
1948
1948
  uiSpinner.text = `Downloading dashboard\u2026 ${Math.round(received / total * 100)}%`;
@@ -1776,7 +1776,7 @@ function operatorEnvPassthrough(managed, prev) {
1776
1776
  }
1777
1777
  var PRESERVED_ENV_HEADER = "# Preserved from your existing .env \u2014 set by you, not by `kraft up` (#485).";
1778
1778
  function resolveImageVersion(opts) {
1779
- return opts.version?.trim() || process.env.KRAFT_VERSION?.trim() || (true ? "0.7.8" : "latest");
1779
+ return opts.version?.trim() || process.env.KRAFT_VERSION?.trim() || (true ? "0.7.9" : "latest");
1780
1780
  }
1781
1781
  function managedEnvLines(opts, host, cfg, prev) {
1782
1782
  const lines = [
@@ -5,7 +5,7 @@ const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  checkHostChannel,
7
7
  verifyHostChannel
8
- } from "./chunk-OTBBNOIV.js";
8
+ } from "./chunk-ULEEWX5M.js";
9
9
  import "./chunk-2UQFOUSZ.js";
10
10
  import "./chunk-5GPXMTE4.js";
11
11
  import "./chunk-XZYFZ6A5.js";
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  upCommand,
39
39
  validateGithubToken,
40
40
  writeCliInstall
41
- } from "./chunk-S7UU7WAK.js";
41
+ } from "./chunk-7O6MARHJ.js";
42
42
  import {
43
43
  bootstrapAdmin,
44
44
  detectPublicIp,
@@ -92,7 +92,7 @@ import {
92
92
  sourceBuildDir,
93
93
  storedApiPort,
94
94
  storedDashboardPort
95
- } from "./chunk-OTBBNOIV.js";
95
+ } from "./chunk-ULEEWX5M.js";
96
96
  import {
97
97
  startUnitHint
98
98
  } from "./chunk-2UQFOUSZ.js";
@@ -330,7 +330,7 @@ function getDashboardUrl(name) {
330
330
  }
331
331
 
332
332
  // src/lib/api-client.ts
333
- var USER_AGENT = `kraft-cli/${true ? "0.7.8" : "dev"}`;
333
+ var USER_AGENT = `kraft-cli/${true ? "0.7.9" : "dev"}`;
334
334
  function getApiUrl2() {
335
335
  return `${getApiUrl()}/api`;
336
336
  }
@@ -1276,7 +1276,7 @@ function dockerNameRunning(nameFilter) {
1276
1276
  return r.stdout.trim().length > 0;
1277
1277
  }
1278
1278
  async function hostControlCheck(api) {
1279
- const { checkHostChannel } = await import("./host-channel-preflight-IWQHVFG5.js");
1279
+ const { checkHostChannel } = await import("./host-channel-preflight-Z64G3NIM.js");
1280
1280
  return hostControlRow(await checkHostChannel().catch(() => null), api);
1281
1281
  }
1282
1282
  var NEVER_PROVISIONED_DETAIL = `never provisioned \u2014 run \`${HOST_CHANNEL_PROVISION_COMMAND}\``;
@@ -1835,7 +1835,7 @@ async function interactiveDoctor() {
1835
1835
  continue;
1836
1836
  }
1837
1837
  if (action2 === "host-control") {
1838
- const { verifyHostChannel } = await import("./host-channel-preflight-IWQHVFG5.js");
1838
+ const { verifyHostChannel } = await import("./host-channel-preflight-Z64G3NIM.js");
1839
1839
  const report3 = await verifyHostChannel().catch(() => null);
1840
1840
  if (report3?.status === "fixed")
1841
1841
  log2.success("Host control is reachable now.");
@@ -5495,7 +5495,7 @@ function printMonitoringNextSteps() {
5495
5495
  info(" kraft edge analytics -p <project> per-domain analytics");
5496
5496
  }
5497
5497
  async function runMonitoringInstall(opts) {
5498
- const up = await import("./up-7WW25O2I.js");
5498
+ const up = await import("./up-TU7622HW.js");
5499
5499
  let adminName = opts.adminName;
5500
5500
  let adminEmail = opts.adminEmail;
5501
5501
  let adminPassword = opts.adminPassword;
@@ -8069,7 +8069,7 @@ function applyOnlyArgv(selfArgs, json) {
8069
8069
  // src/commands/update.ts
8070
8070
  async function verifyHostChannelAfterUpdate() {
8071
8071
  if (isJsonMode()) return;
8072
- const { verifyHostChannel } = await import("./host-channel-preflight-IWQHVFG5.js");
8072
+ const { verifyHostChannel } = await import("./host-channel-preflight-Z64G3NIM.js");
8073
8073
  await verifyHostChannel().catch(() => {
8074
8074
  });
8075
8075
  }
@@ -8169,7 +8169,7 @@ async function runSourceUpdate(source, opts) {
8169
8169
  }
8170
8170
  var REINSTALL_HINT = "curl -fsSL https://get.kraft.io | sh";
8171
8171
  async function runTarballUpdate(install, opts) {
8172
- const current = "0.7.8";
8172
+ const current = "0.7.9";
8173
8173
  let latest;
8174
8174
  try {
8175
8175
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -8290,7 +8290,7 @@ var updateCommand = new Command26("update").description("Update the Kraft CLI +
8290
8290
  const cliInstall = readCliInstall();
8291
8291
  if (cliInstall?.method === "tarball")
8292
8292
  return runTarballUpdate(cliInstall, opts);
8293
- const current = "0.7.8";
8293
+ const current = "0.7.9";
8294
8294
  let latest;
8295
8295
  try {
8296
8296
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -9137,7 +9137,7 @@ async function runWizard() {
9137
9137
  }
9138
9138
  }
9139
9139
  }
9140
- const uiTag = `v${"0.7.8"}`;
9140
+ const uiTag = `v${"0.7.9"}`;
9141
9141
  if (method === "bare") {
9142
9142
  const dl = spinner4();
9143
9143
  dl.start("Pulling the Kraft dist from GitHub");
@@ -9205,7 +9205,7 @@ async function runWizard() {
9205
9205
  const dashboardPort = String(ports.dashboard);
9206
9206
  const moved = portMoveNotice(ports, composeTrustedOriginUrls());
9207
9207
  if (moved.length) log5.info(moved.join("\n"));
9208
- if (!pinnedImagesReady({ version: "0.7.8" })) {
9208
+ if (!pinnedImagesReady({ version: "0.7.9" })) {
9209
9209
  cancel4(
9210
9210
  "The pinned Kraft image tag isn't in the registry yet \u2014 nothing on this box was changed."
9211
9211
  );
@@ -9256,7 +9256,7 @@ async function runWizard() {
9256
9256
  dashboardPort,
9257
9257
  publicUrl,
9258
9258
  trustProxy: behindProxy,
9259
- version: "0.7.8",
9259
+ version: "0.7.9",
9260
9260
  noHostControl: !allowHostControl
9261
9261
  });
9262
9262
  if (!fetched.ok) {
@@ -9287,7 +9287,7 @@ async function runWizard() {
9287
9287
  dashboardPort,
9288
9288
  publicUrl,
9289
9289
  trustProxy: behindProxy,
9290
- version: "0.7.8",
9290
+ version: "0.7.9",
9291
9291
  noHostControl: !allowHostControl
9292
9292
  });
9293
9293
  if (!up.ok) {
@@ -9379,7 +9379,7 @@ async function runWizard() {
9379
9379
  if (!result.domainRegistered)
9380
9380
  liveUrl2 = `http://localhost:${started.dashPort}`;
9381
9381
  for (const w of result.warnings) log5.warn(w);
9382
- const { verifyHostChannel } = await import("./host-channel-preflight-IWQHVFG5.js");
9382
+ const { verifyHostChannel } = await import("./host-channel-preflight-Z64G3NIM.js");
9383
9383
  await verifyHostChannel().catch(() => {
9384
9384
  });
9385
9385
  finishSetup({
@@ -9683,7 +9683,7 @@ function attachCompletion(program2) {
9683
9683
 
9684
9684
  // src/index.ts
9685
9685
  var program = new Command29();
9686
- program.name("kraft").description("Kraft CLI \u2014 install, run, and manage Kraft from your terminal").version("0.7.8").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
9686
+ program.name("kraft").description("Kraft CLI \u2014 install, run, and manage Kraft from your terminal").version("0.7.9").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
9687
9687
  if (thisCommand.opts().json) setJsonMode(true);
9688
9688
  }).action(async () => {
9689
9689
  const installed = serviceStatus().installed || readInstallMethod() === "compose";
@@ -5033,6 +5033,14 @@ var init_kraft_config = __esm(() => {
5033
5033
  init_parse();
5034
5034
  });
5035
5035
  // ../../packages/core/src/mail-server/routing/build-routes.ts
5036
+ function buildMailServerRoutes(input) {
5037
+ const normalized = normalizeInput(input);
5038
+ return {
5039
+ input: normalized,
5040
+ routes: buildRoutes(normalized),
5041
+ dns: buildDnsRecords(normalized)
5042
+ };
5043
+ }
5036
5044
  function mailServerRouteHostnames(userDomain) {
5037
5045
  return [
5038
5046
  mailHostname(userDomain),
@@ -5061,6 +5069,164 @@ function mailHostBaseDomain(hostname) {
5061
5069
  const base = host.slice(prefix.length);
5062
5070
  return base.includes(".") ? base : null;
5063
5071
  }
5072
+ function buildRoutes(input) {
5073
+ const d = input.userDomain;
5074
+ const [clientHost, apiHost, autodiscoverHost, autoconfigHost] = mailServerRouteHostnames(d);
5075
+ return [
5076
+ {
5077
+ id: "mail-client",
5078
+ hostname: clientHost,
5079
+ targetUrl: input.zeroClientOrigin,
5080
+ tls: true,
5081
+ description: "Zero web client - the user-facing webmail UI."
5082
+ },
5083
+ {
5084
+ id: "mail-api",
5085
+ hostname: apiHost,
5086
+ targetUrl: input.zeroServerOrigin,
5087
+ tls: true,
5088
+ description: "Zero server - tRPC API consumed by the Zero client (auth via Dovecot IMAP)."
5089
+ },
5090
+ {
5091
+ id: "autodiscover",
5092
+ hostname: autodiscoverHost,
5093
+ targetUrl: input.kraftApiOrigin,
5094
+ tls: true,
5095
+ description: "Outlook / Thunderbird autodiscover XML - served by kraft's API controller."
5096
+ },
5097
+ {
5098
+ id: "autoconfig",
5099
+ hostname: autoconfigHost,
5100
+ targetUrl: input.kraftApiOrigin,
5101
+ tls: true,
5102
+ description: "Thunderbird / Apple / K-9 autoconfig XML - served by kraft's API controller."
5103
+ }
5104
+ ];
5105
+ }
5106
+ function buildDnsRecords(input) {
5107
+ const d = input.userDomain;
5108
+ const apex = d;
5109
+ return [
5110
+ {
5111
+ id: "mailservice-a",
5112
+ type: "A",
5113
+ name: `mailservice.${d}`,
5114
+ value: input.mailServerIp,
5115
+ description: `Points to the mail VPS itself. The MX record (next row) references this host so external mail servers know where to deliver mail for ${apex}.`,
5116
+ required: true
5117
+ },
5118
+ {
5119
+ id: "apex-mx",
5120
+ type: "MX",
5121
+ name: apex,
5122
+ value: `mailservice.${d}.`,
5123
+ priority: 10,
5124
+ description: `Tells the world: mail for any @${apex} address should be delivered to mailservice.${d}.`,
5125
+ required: true
5126
+ },
5127
+ {
5128
+ id: "spf",
5129
+ type: "TXT",
5130
+ name: apex,
5131
+ value: "v=spf1 mx -all",
5132
+ description: `SPF: only the IP behind mailservice.${d} is authorized to send mail from @${apex}. Without this, your mail will be marked spam by Gmail/Outlook.`,
5133
+ required: false
5134
+ },
5135
+ {
5136
+ id: "dkim",
5137
+ type: "TXT",
5138
+ name: `dkim._domainkey.${d}`,
5139
+ value: "<DKIM public key - generated during mail server install; copy from kraft dashboard once provisioning completes>",
5140
+ description: `DKIM signs outgoing mail with a private key the mail server holds; recipients verify against this public key. Critical for deliverability to Gmail/Outlook.`,
5141
+ required: false
5142
+ },
5143
+ {
5144
+ id: "dmarc",
5145
+ type: "TXT",
5146
+ name: `_dmarc.${d}`,
5147
+ value: `v=DMARC1; p=quarantine; rua=mailto:dmarc@${apex}`,
5148
+ description: `DMARC: tells recipient servers what to do if SPF + DKIM fail (quarantine = send to spam). Reports of failures get mailed to dmarc@${apex}.`,
5149
+ required: false
5150
+ },
5151
+ {
5152
+ id: "mail-client-cname",
5153
+ type: "CNAME",
5154
+ name: mailHostname(d),
5155
+ value: hostnameFromUrl(input.zeroClientOrigin),
5156
+ description: `Routes ${mailHostname(d)} (the webmail UI) to kraft's app-deploy ingress where the Zero client is hosted.`,
5157
+ required: true
5158
+ },
5159
+ {
5160
+ id: "mail-api-cname",
5161
+ type: "CNAME",
5162
+ name: apiMailHostname(d),
5163
+ value: hostnameFromUrl(input.zeroServerOrigin),
5164
+ description: `Routes ${apiMailHostname(d)} (the Zero server's tRPC API) to the mail VPS via kraft's routing layer.`,
5165
+ required: true
5166
+ },
5167
+ {
5168
+ id: "autodiscover-cname",
5169
+ type: "CNAME",
5170
+ name: `autodiscover.${d}`,
5171
+ value: hostnameFromUrl(input.kraftApiOrigin),
5172
+ description: `Routes autodiscover.${d} to kraft's API, which serves the XML mail clients use to auto-configure (Outlook, Thunderbird).`,
5173
+ required: true
5174
+ },
5175
+ {
5176
+ id: "autoconfig-cname",
5177
+ type: "CNAME",
5178
+ name: `autoconfig.${d}`,
5179
+ value: hostnameFromUrl(input.kraftApiOrigin),
5180
+ description: `Routes autoconfig.${d} to kraft's API, which serves the Thunderbird-style XML mail clients use to auto-configure (Thunderbird, Apple Mail, K-9).`,
5181
+ required: true
5182
+ },
5183
+ {
5184
+ id: "srv-imaps",
5185
+ type: "SRV",
5186
+ name: `_imaps._tcp.${d}`,
5187
+ value: mailHostname(d),
5188
+ priority: 0,
5189
+ port: 993,
5190
+ description: `Directs IMAP clients to ${mailHostname(d)} port 993 (RFC 6186).`,
5191
+ required: false
5192
+ },
5193
+ {
5194
+ id: "srv-submission",
5195
+ type: "SRV",
5196
+ name: `_submission._tcp.${d}`,
5197
+ value: mailHostname(d),
5198
+ priority: 0,
5199
+ port: 587,
5200
+ description: `Directs SMTP-submission clients to ${mailHostname(d)} port 587 (RFC 6186).`,
5201
+ required: false
5202
+ },
5203
+ {
5204
+ id: "srv-autodiscover",
5205
+ type: "SRV",
5206
+ name: `_autodiscover._tcp.${d}`,
5207
+ value: `autodiscover.${d}`,
5208
+ priority: 0,
5209
+ port: 443,
5210
+ description: `Outlook's last-resort lookup: HTTPS config service on autodiscover.${d} port 443.`,
5211
+ required: false
5212
+ }
5213
+ ];
5214
+ }
5215
+ function normalizeInput(input) {
5216
+ return {
5217
+ userDomain: input.userDomain.trim().toLowerCase().replace(/^\.+|\.+$/g, ""),
5218
+ mailServerIp: input.mailServerIp.trim(),
5219
+ zeroServerOrigin: input.zeroServerOrigin.trim(),
5220
+ zeroClientOrigin: input.zeroClientOrigin.trim(),
5221
+ kraftApiOrigin: input.kraftApiOrigin.trim()
5222
+ };
5223
+ }
5224
+ function hostnameFromUrl(value) {
5225
+ const noScheme = value.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "");
5226
+ const noPath = noScheme.split("/", 1)[0];
5227
+ const noPort = noPath.split(":", 1)[0];
5228
+ return noPort;
5229
+ }
5064
5230
  var MAIL_HOST_LABEL = "mail";
5065
5231
 
5066
5232
  // ../../packages/core/src/mail-server/routing/index.ts
@@ -126602,7 +126768,7 @@ var require_es5 = __commonJS((exports, module2) => {
126602
126768
 
126603
126769
  // ../../node_modules/@aws-sdk/core/dist-cjs/submodules/client/index.js
126604
126770
  var require_client2 = __commonJS((exports) => {
126605
- var __dirname = "/home/runner/work/kraft/kraft/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
126771
+ var __dirname = "/home/runner/work/kraft-ci/kraft-ci/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
126606
126772
  var retry = require_retry();
126607
126773
  var protocols = require_protocols();
126608
126774
  var lambdaInvokeStore = require_invoke_store();
@@ -186084,7 +186250,7 @@ WD9f
186084
186250
 
186085
186251
  // ../../node_modules/ioredis/built/utils/index.js
186086
186252
  var require_utils4 = __commonJS((exports) => {
186087
- var __dirname = "/home/runner/work/kraft/kraft/node_modules/ioredis/built/utils";
186253
+ var __dirname = "/home/runner/work/kraft-ci/kraft-ci/node_modules/ioredis/built/utils";
186088
186254
  Object.defineProperty(exports, "__esModule", { value: true });
186089
186255
  exports.noop = exports.defaults = exports.Debug = exports.getPackageMeta = exports.zipMap = exports.CONNECTION_CLOSED_ERROR_MSG = exports.shuffle = exports.sample = exports.resolveTLSProfile = exports.parseURL = exports.optimizeErrorStack = exports.toArg = exports.convertMapToArray = exports.convertObjectToArray = exports.timeout = exports.packObject = exports.isInt = exports.wrapMultiResult = exports.convertBufferToString = undefined;
186090
186256
  var fs_1 = __require("fs");
@@ -186370,7 +186536,7 @@ var require_argumentParsers = __commonJS((exports) => {
186370
186536
 
186371
186537
  // ../../node_modules/ioredis/built/Command.js
186372
186538
  var require_Command = __commonJS((exports) => {
186373
- var __dirname = "/home/runner/work/kraft/kraft/node_modules/ioredis/built";
186539
+ var __dirname = "/home/runner/work/kraft-ci/kraft-ci/node_modules/ioredis/built";
186374
186540
  Object.defineProperty(exports, "__esModule", { value: true });
186375
186541
  var commands_1 = require_built();
186376
186542
  var calculateSlot = require_lib3();
@@ -268837,22 +269003,6 @@ var init_mail_port_reachability_service = __esm(() => {
268837
269003
  healthCache = new Map;
268838
269004
  });
268839
269005
 
268840
- // ../api/src/lib/container-ref.ts
268841
- function usableRef(ref) {
268842
- const trimmed3 = ref?.trim();
268843
- if (!trimmed3 || trimmed3 === COMPOSE_SENTINEL)
268844
- return null;
268845
- return trimmed3;
268846
- }
268847
- function isRealContainerRef(ref) {
268848
- return usableRef(ref) !== null;
268849
- }
268850
- function isArtifactRef(ref) {
268851
- const usable = usableRef(ref);
268852
- return usable !== null && usable.startsWith("/");
268853
- }
268854
- var COMPOSE_SENTINEL = "compose";
268855
-
268856
269006
  // ../api/src/lib/acme-config.ts
268857
269007
  function resolveAcmeProviderOptions() {
268858
269008
  return {
@@ -268924,6 +269074,55 @@ var init_controller_helpers = __esm(async () => {
268924
269074
  await init_src3();
268925
269075
  });
268926
269076
 
269077
+ // ../api/src/modules/mail-server/routing/register.service.ts
269078
+ async function registerMailServerRoutes(input, opts) {
269079
+ const plan = buildMailServerRoutes(input);
269080
+ const { routing: routing2 } = getPlatform();
269081
+ const wanted = opts?.only ? new Set(opts.only) : null;
269082
+ const results = [];
269083
+ for (const route of plan.routes) {
269084
+ if (wanted && !wanted.has(route.id))
269085
+ continue;
269086
+ try {
269087
+ await routing2.registerRoute({
269088
+ domain: route.hostname,
269089
+ tls: route.tls,
269090
+ terminatesTlsLocally: route.tls,
269091
+ targetUrl: route.targetUrl
269092
+ });
269093
+ results.push({ routeId: route.id, hostname: route.hostname, ok: true });
269094
+ } catch (err2) {
269095
+ results.push({
269096
+ routeId: route.id,
269097
+ hostname: route.hostname,
269098
+ ok: false,
269099
+ error: safeErrorMessage(err2)
269100
+ });
269101
+ }
269102
+ }
269103
+ return { plan, routes: results };
269104
+ }
269105
+ var init_register_service = __esm(async () => {
269106
+ init_src();
269107
+ await init_controller_helpers();
269108
+ });
269109
+
269110
+ // ../api/src/lib/container-ref.ts
269111
+ function usableRef(ref) {
269112
+ const trimmed3 = ref?.trim();
269113
+ if (!trimmed3 || trimmed3 === COMPOSE_SENTINEL)
269114
+ return null;
269115
+ return trimmed3;
269116
+ }
269117
+ function isRealContainerRef(ref) {
269118
+ return usableRef(ref) !== null;
269119
+ }
269120
+ function isArtifactRef(ref) {
269121
+ const usable = usableRef(ref);
269122
+ return usable !== null && usable.startsWith("/");
269123
+ }
269124
+ var COMPOSE_SENTINEL = "compose";
269125
+
268927
269126
  // ../api/src/lib/remote-state.ts
268928
269127
  function isConnectionLoss(err2) {
268929
269128
  if (isRemoteConnectionError(err2))
@@ -272098,6 +272297,23 @@ async function stepEnsureReverseProxy(exec2, _domain, log11) {
272098
272297
  };
272099
272298
  }
272100
272299
  log11(stepId, "info", "The kraft edge holds :80 / :443");
272300
+ try {
272301
+ const reg = await registerMailServerRoutes({
272302
+ userDomain: _domain,
272303
+ mailServerIp: "",
272304
+ zeroServerOrigin: "",
272305
+ zeroClientOrigin: "",
272306
+ kraftApiOrigin: internalApiUrl
272307
+ }, { only: ["autodiscover", "autoconfig"] });
272308
+ for (const r of reg.routes) {
272309
+ if (r.ok)
272310
+ log11(stepId, "info", `Client-config route ready: ${r.hostname}`);
272311
+ else
272312
+ log11(stepId, "warn", `Client-config route skipped for ${r.hostname}: ${r.error ?? "unknown error"}`);
272313
+ }
272314
+ } catch (err2) {
272315
+ log11(stepId, "warn", `Client-config routes not registered (${errMsg(err2)}). Mail works without them; Thunderbird/Outlook auto-configuration will not.`);
272316
+ }
272101
272317
  return {
272102
272318
  stepId,
272103
272319
  success: true,
@@ -272611,6 +272827,7 @@ var init_mail_service = __esm(async () => {
272611
272827
  init_src2();
272612
272828
  await __promiseAll([
272613
272829
  init_mail_health_service(),
272830
+ init_register_service(),
272614
272831
  init_mail_engine()
272615
272832
  ]);
272616
272833
  STEP_TIMEOUT_MS = {
@@ -273497,6 +273714,21 @@ var init_mailboxes_service = __esm(async () => {
273497
273714
  });
273498
273715
 
273499
273716
  // ../api/src/modules/mail/admin/domains.service.ts
273717
+ var exports_domains_service = {};
273718
+ __export(exports_domains_service, {
273719
+ validateDomain: () => validateDomain,
273720
+ updateDomain: () => updateDomain,
273721
+ retryDomainDkim: () => retryDomainDkim,
273722
+ recountDomain: () => recountDomain,
273723
+ listDomains: () => listDomains,
273724
+ getDomain: () => getDomain,
273725
+ deleteDomain: () => deleteDomain,
273726
+ createDomain: () => createDomain,
273727
+ countDomainDependents: () => countDomainDependents,
273728
+ DomainNotFoundError: () => DomainNotFoundError,
273729
+ DomainHasDependentsError: () => DomainHasDependentsError,
273730
+ DomainExistsError: () => DomainExistsError
273731
+ });
273500
273732
  function validateDomain(domain4) {
273501
273733
  const d2 = domain4.trim().toLowerCase();
273502
273734
  if (!DOMAIN_RE4.test(d2) || d2.length > 255) {
@@ -279155,7 +279387,7 @@ WD9f
279155
279387
 
279156
279388
  // ../../node_modules/bullmq/node_modules/ioredis/built/utils/index.js
279157
279389
  var require_utils5 = __commonJS((exports) => {
279158
- var __dirname = "/home/runner/work/kraft/kraft/node_modules/bullmq/node_modules/ioredis/built/utils";
279390
+ var __dirname = "/home/runner/work/kraft-ci/kraft-ci/node_modules/bullmq/node_modules/ioredis/built/utils";
279159
279391
  Object.defineProperty(exports, "__esModule", { value: true });
279160
279392
  exports.noop = exports.defaults = exports.Debug = exports.getPackageMeta = exports.zipMap = exports.CONNECTION_CLOSED_ERROR_MSG = exports.shuffle = exports.sample = exports.resolveTLSProfile = exports.parseURL = exports.optimizeErrorStack = exports.toArg = exports.convertMapToArray = exports.convertObjectToArray = exports.timeout = exports.packObject = exports.isInt = exports.wrapMultiResult = exports.convertBufferToString = undefined;
279161
279393
  var fs_1 = __require("fs");
@@ -279441,7 +279673,7 @@ var require_argumentParsers2 = __commonJS((exports) => {
279441
279673
 
279442
279674
  // ../../node_modules/bullmq/node_modules/ioredis/built/Command.js
279443
279675
  var require_Command2 = __commonJS((exports) => {
279444
- var __dirname = "/home/runner/work/kraft/kraft/node_modules/bullmq/node_modules/ioredis/built";
279676
+ var __dirname = "/home/runner/work/kraft-ci/kraft-ci/node_modules/bullmq/node_modules/ioredis/built";
279445
279677
  Object.defineProperty(exports, "__esModule", { value: true });
279446
279678
  var commands_1 = require_built4();
279447
279679
  var calculateSlot = require_lib3();
@@ -287169,7 +287401,7 @@ var require_node_gyp_build_optional_packages = __commonJS((exports, module2) =>
287169
287401
 
287170
287402
  // ../../node_modules/msgpackr-extract/index.js
287171
287403
  var require_msgpackr_extract = __commonJS((exports, module2) => {
287172
- var __dirname = "/home/runner/work/kraft/kraft/node_modules/msgpackr-extract";
287404
+ var __dirname = "/home/runner/work/kraft-ci/kraft-ci/node_modules/msgpackr-extract";
287173
287405
  module2.exports = require_node_gyp_build_optional_packages()(__dirname);
287174
287406
  });
287175
287407
 
@@ -321505,7 +321737,7 @@ var package_default;
321505
321737
  var init_package = __esm(() => {
321506
321738
  package_default = {
321507
321739
  name: "@repo/api",
321508
- version: "0.7.8",
321740
+ version: "0.7.9",
321509
321741
  license: "Apache-2.0",
321510
321742
  private: true,
321511
321743
  type: "module",
@@ -348253,12 +348485,12 @@ async function collectKnownHostnames() {
348253
348485
  for (const h3 of mailServerRouteHostnames(d2))
348254
348486
  out2.add(normalizeServedHostname(h3));
348255
348487
  }
348256
- const publicHost = hostnameFromUrl(env.KRAFT_PUBLIC_URL);
348488
+ const publicHost = hostnameFromUrl2(env.KRAFT_PUBLIC_URL);
348257
348489
  if (publicHost)
348258
348490
  out2.add(publicHost);
348259
348491
  return [...out2];
348260
348492
  }
348261
- function hostnameFromUrl(value2) {
348493
+ function hostnameFromUrl2(value2) {
348262
348494
  if (!value2)
348263
348495
  return null;
348264
348496
  try {
@@ -384446,6 +384678,165 @@ var init_restore_verify_service = __esm(async () => {
384446
384678
  ]);
384447
384679
  });
384448
384680
 
384681
+ // ../api/src/modules/mail/admin/client-config-routes.service.ts
384682
+ function poxProbeBody(domain4) {
384683
+ return `<?xml version="1.0" encoding="utf-8"?>` + `<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">` + `<Request><EMailAddress>probe@${domain4}</EMailAddress>` + `<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>` + `</Request></Autodiscover>`;
384684
+ }
384685
+ async function fetchText(url3, init3) {
384686
+ const res = await fetch(url3, {
384687
+ ...init3,
384688
+ redirect: "manual",
384689
+ signal: AbortSignal.timeout(20000),
384690
+ headers: { "User-Agent": "kraft-client-config-probe", ...init3?.headers }
384691
+ });
384692
+ const contentType = res.headers.get("content-type") ?? "";
384693
+ const body2 = await res.text().catch(() => "");
384694
+ return { status: res.status, contentType, body: body2 };
384695
+ }
384696
+ function classifyFetchError(err2) {
384697
+ const msg = err2 instanceof Error ? err2.message : String(err2);
384698
+ if (/certificate|self.signed|unable to verify|UNABLE_TO_VERIFY|CERT_|DEPTH_ZERO_SELF_SIGNED/i.test(msg))
384699
+ return `TLS failed (${msg.slice(0, 160)}): no valid certificate for this hostname — the edge serves its default cert, so no vhost exists yet.`;
384700
+ if (/timeout|timed out|abort/i.test(msg))
384701
+ return `No answer within 20s (${msg.slice(0, 120)}): DNS, firewall, or nothing listening on :443.`;
384702
+ if (/ENOTFOUND|EAI_AGAIN|getaddrinfo/i.test(msg))
384703
+ return `DNS does not resolve this hostname (${msg.slice(0, 120)}). Publish the CNAME first.`;
384704
+ if (/ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH/i.test(msg))
384705
+ return `TCP refused/reset (${msg.slice(0, 120)}): nothing serves :443 there — firewall or no edge.`;
384706
+ return `Probe failed: ${msg.slice(0, 200)}`;
384707
+ }
384708
+ async function checkClientConfigRoutes(domain4) {
384709
+ const d2 = domain4.trim().toLowerCase();
384710
+ const checks8 = [];
384711
+ const adHost = autodiscoverHostname(d2);
384712
+ const adUrl = `https://${adHost}/autodiscover/autodiscover.xml`;
384713
+ try {
384714
+ const res = await fetchText(adUrl, {
384715
+ method: "POST",
384716
+ headers: { "Content-Type": "text/xml" },
384717
+ body: poxProbeBody(d2)
384718
+ });
384719
+ if (res.status === 200 && res.body.includes("<Action>settings</Action>")) {
384720
+ checks8.push({
384721
+ id: "autodiscover",
384722
+ hostname: adHost,
384723
+ url: adUrl,
384724
+ ok: true,
384725
+ detail: "Outlook autodiscover answers with account settings."
384726
+ });
384727
+ } else {
384728
+ checks8.push({
384729
+ id: "autodiscover",
384730
+ hostname: adHost,
384731
+ url: adUrl,
384732
+ ok: false,
384733
+ detail: res.status !== 200 ? `HTTP ${res.status} — the edge answers, but not the XML responder (missing vhost or dashboard fallback page).` : `HTTP 200 without account settings — the responder refused (unmanaged domain?) or a proxy page sits in front.`
384734
+ });
384735
+ }
384736
+ } catch (err2) {
384737
+ checks8.push({
384738
+ id: "autodiscover",
384739
+ hostname: adHost,
384740
+ url: adUrl,
384741
+ ok: false,
384742
+ detail: classifyFetchError(err2)
384743
+ });
384744
+ }
384745
+ const acHost = autoconfigHostname(d2);
384746
+ const acUrl = `https://${acHost}/mail/config-v1.1.xml?emailaddress=${encodeURIComponent(`probe@${d2}`)}`;
384747
+ try {
384748
+ const res = await fetchText(acUrl);
384749
+ if (res.status === 200 && res.body.includes("<clientConfig") && res.body.includes(d2)) {
384750
+ checks8.push({
384751
+ id: "autoconfig",
384752
+ hostname: acHost,
384753
+ url: acUrl,
384754
+ ok: true,
384755
+ detail: "Thunderbird autoconfig answers for this domain."
384756
+ });
384757
+ } else {
384758
+ checks8.push({
384759
+ id: "autoconfig",
384760
+ hostname: acHost,
384761
+ url: acUrl,
384762
+ ok: false,
384763
+ detail: res.status !== 200 ? `HTTP ${res.status} — the edge answers, but not the XML responder (missing vhost or dashboard fallback page).` : `HTTP 200 without this domain's config — wrong responder or proxy page in front.`
384764
+ });
384765
+ }
384766
+ } catch (err2) {
384767
+ checks8.push({
384768
+ id: "autoconfig",
384769
+ hostname: acHost,
384770
+ url: acUrl,
384771
+ ok: false,
384772
+ detail: classifyFetchError(err2)
384773
+ });
384774
+ }
384775
+ return checks8;
384776
+ }
384777
+ async function repairClientConfigRoutes(serverId, domain4, organizationId) {
384778
+ const d2 = domain4.trim().toLowerCase();
384779
+ const { validateDomain: validateDomain2 } = await init_domains_service().then(() => exports_domains_service);
384780
+ validateDomain2(d2);
384781
+ const { resolveTargetPlatform: resolveTargetPlatform2, disposePlatform: disposePlatform2 } = await init_deployment_runtime().then(() => exports_deployment_runtime);
384782
+ const results = [];
384783
+ try {
384784
+ const reg = await registerMailServerRoutes({
384785
+ userDomain: d2,
384786
+ mailServerIp: "",
384787
+ zeroServerOrigin: "",
384788
+ zeroClientOrigin: "",
384789
+ kraftApiOrigin: internalApiUrl
384790
+ }, { only: ["autodiscover", "autoconfig"] });
384791
+ const byId = new Map(reg.routes.map((r29) => [r29.routeId, r29]));
384792
+ const platform = await resolveTargetPlatform2("server", "bare", serverId, organizationId);
384793
+ disposePlatform2(platform);
384794
+ const { recordMailCertDomain: recordMailCertDomain2 } = await init_domain_ssl().then(() => exports_domain_ssl);
384795
+ for (const id2 of ["autodiscover", "autoconfig"]) {
384796
+ const hostname7 = id2 === "autodiscover" ? autodiscoverHostname(d2) : autoconfigHostname(d2);
384797
+ const route = byId.get(id2);
384798
+ const entry = {
384799
+ hostname: hostname7,
384800
+ routeOk: route?.ok ?? false,
384801
+ certOk: false
384802
+ };
384803
+ if (!route?.ok) {
384804
+ entry.routeError = route?.error ?? "route registration failed";
384805
+ results.push(entry);
384806
+ continue;
384807
+ }
384808
+ try {
384809
+ const cert = await platform.ssl.provisionCert(hostname7, {});
384810
+ if (cert.verified) {
384811
+ entry.certOk = true;
384812
+ await recordMailCertDomain2(hostname7, cert).catch(() => {});
384813
+ } else {
384814
+ entry.certError = cert.reason ?? "certificate not confirmed";
384815
+ }
384816
+ } catch (err2) {
384817
+ entry.certError = err2 instanceof Error ? err2.message.slice(0, 300) : String(err2);
384818
+ }
384819
+ results.push(entry);
384820
+ }
384821
+ } catch (err2) {
384822
+ const message2 = err2 instanceof Error ? err2.message : String(err2);
384823
+ for (const id2 of ["autodiscover", "autoconfig"]) {
384824
+ results.push({
384825
+ hostname: id2 === "autodiscover" ? autodiscoverHostname(d2) : autoconfigHostname(d2),
384826
+ routeOk: false,
384827
+ routeError: message2.slice(0, 300),
384828
+ certOk: false
384829
+ });
384830
+ }
384831
+ }
384832
+ return results;
384833
+ }
384834
+ var init_client_config_routes_service = __esm(async () => {
384835
+ init_src();
384836
+ init_config();
384837
+ await init_register_service();
384838
+ });
384839
+
384449
384840
  // ../api/src/modules/mail/admin/sending-policy.service.ts
384450
384841
  function parseIredApdSettings(text4) {
384451
384842
  const plugins = (PLUGINS_RE.exec(text4)?.[1] ?? "").split(",").map((p4) => p4.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
@@ -386041,6 +386432,55 @@ async function getComponentLogsHandler(c2) {
386041
386432
  return errorJson(c2, err2);
386042
386433
  }
386043
386434
  }
386435
+ async function getClientConfigStatusHandler(c2) {
386436
+ const guard4 = assertNotCloud(c2);
386437
+ if (guard4)
386438
+ return guard4;
386439
+ const serverId = param(c2, "serverId");
386440
+ await permission.assert(getRequestContext(c2), {
386441
+ resourceType: "mail_server",
386442
+ resourceId: serverId,
386443
+ action: "read"
386444
+ });
386445
+ const ctx2 = getRequestContext(c2);
386446
+ if (!await isServerInOrg(ctx2, serverId)) {
386447
+ return c2.json({ error: "Server not found" }, 404);
386448
+ }
386449
+ const domain4 = c2.req.query("domain")?.trim().toLowerCase();
386450
+ if (!domain4)
386451
+ return c2.json({ error: "domain query is required" }, 400);
386452
+ try {
386453
+ const routes = await checkClientConfigRoutes(domain4);
386454
+ return c2.json({ domain: domain4, routes });
386455
+ } catch (err2) {
386456
+ return errorJson(c2, err2);
386457
+ }
386458
+ }
386459
+ async function repairClientConfigRoutesHandler(c2) {
386460
+ const guard4 = assertNotCloud(c2);
386461
+ if (guard4)
386462
+ return guard4;
386463
+ const serverId = param(c2, "serverId");
386464
+ await permission.assert(getRequestContext(c2), {
386465
+ resourceType: "mail_server",
386466
+ resourceId: serverId,
386467
+ action: "write"
386468
+ });
386469
+ const ctx2 = getRequestContext(c2);
386470
+ if (!await isServerInOrg(ctx2, serverId)) {
386471
+ return c2.json({ error: "Server not found" }, 404);
386472
+ }
386473
+ const body2 = await c2.req.json().catch(() => ({}));
386474
+ const domain4 = typeof body2.domain === "string" ? body2.domain.trim().toLowerCase() : "";
386475
+ if (!domain4)
386476
+ return c2.json({ error: "domain is required" }, 400);
386477
+ try {
386478
+ const routes = await repairClientConfigRoutes(serverId, domain4, ctx2.organizationId);
386479
+ return c2.json({ domain: domain4, routes });
386480
+ } catch (err2) {
386481
+ return errorJson(c2, err2);
386482
+ }
386483
+ }
386044
386484
  function errorJson(c2, err2) {
386045
386485
  if (err2 instanceof AppError)
386046
386486
  return handleApiError(err2, c2);
@@ -386065,6 +386505,7 @@ var init_admin_controller = __esm(async () => {
386065
386505
  init_dmarc_ingest_service(),
386066
386506
  init_av_policy_service(),
386067
386507
  init_restore_verify_service(),
386508
+ init_client_config_routes_service(),
386068
386509
  init_sending_policy_service(),
386069
386510
  init_test_email_service(),
386070
386511
  init_components_service(),
@@ -386471,6 +386912,8 @@ var init_mail_routes = __esm(async () => {
386471
386912
  r29.get("/admin/:serverId/domains", { tag: "mail_server:list" }, listDomainsHandler);
386472
386913
  r29.post("/admin/:serverId/domains", { tag: "mail_server:write" }, createDomainHandler);
386473
386914
  r29.post("/admin/:serverId/domains/:domain/dkim", { tag: "mail_server:write" }, retryDomainDkimHandler);
386915
+ r29.get("/admin/:serverId/client-config", { tag: "mail_server:read" }, getClientConfigStatusHandler);
386916
+ r29.post("/admin/:serverId/client-config/repair", { tag: "mail_server:write" }, repairClientConfigRoutesHandler);
386474
386917
  r29.get("/admin/:serverId/dmarc/summary", { tag: "mail_server:read" }, getDmarcSummaryHandler);
386475
386918
  r29.post("/admin/:serverId/dmarc/ingest", { tag: "mail_server:write" }, runDmarcIngestHandler);
386476
386919
  r29.get("/admin/:serverId/av-policy", { tag: "mail_server:read" }, getAvPolicyHandler);
@@ -7,10 +7,10 @@ import {
7
7
  runHeadlessProvision,
8
8
  startService,
9
9
  upCommand
10
- } from "./chunk-S7UU7WAK.js";
10
+ } from "./chunk-7O6MARHJ.js";
11
11
  import "./chunk-JK7KKBXI.js";
12
12
  import "./chunk-IGTODKUA.js";
13
- import "./chunk-OTBBNOIV.js";
13
+ import "./chunk-ULEEWX5M.js";
14
14
  import "./chunk-2UQFOUSZ.js";
15
15
  import "./chunk-5GPXMTE4.js";
16
16
  import "./chunk-XZYFZ6A5.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rakay-technology/kraft",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "description": "Kraft CLI - deploy, manage, and open your Kraft platform from the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {