@homeflare/alchemy 0.31.1 → 0.32.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 (166) hide show
  1. package/README.md +44 -7
  2. package/dist/grafana/index.d.ts +6 -5
  3. package/dist/grafana/index.d.ts.map +1 -1
  4. package/dist/linux/container-form.d.ts +129 -0
  5. package/dist/linux/container-form.d.ts.map +1 -0
  6. package/dist/linux/container-generator.d.ts +74 -0
  7. package/dist/linux/container-generator.d.ts.map +1 -0
  8. package/dist/linux/container-handlers.d.ts +15 -0
  9. package/dist/linux/container-handlers.d.ts.map +1 -0
  10. package/dist/linux/container-lifecycle.d.ts +37 -0
  11. package/dist/linux/container-lifecycle.d.ts.map +1 -0
  12. package/dist/linux/container-preflight.d.ts +34 -0
  13. package/dist/linux/container-preflight.d.ts.map +1 -0
  14. package/dist/linux/container-secrets.d.ts +37 -0
  15. package/dist/linux/container-secrets.d.ts.map +1 -0
  16. package/dist/linux/container-settle.d.ts +34 -0
  17. package/dist/linux/container-settle.d.ts.map +1 -0
  18. package/dist/linux/container.d.ts +30 -0
  19. package/dist/linux/container.d.ts.map +1 -0
  20. package/dist/linux/fake-quadlet.d.ts +25 -0
  21. package/dist/linux/fake-quadlet.d.ts.map +1 -0
  22. package/dist/linux/index.d.ts +6 -3
  23. package/dist/linux/index.d.ts.map +1 -1
  24. package/dist/linux/index.js +641 -268
  25. package/dist/linux/index.js.map +15 -7
  26. package/dist/linux/providers.d.ts +1 -1
  27. package/dist/linux/providers.d.ts.map +1 -1
  28. package/dist/linux/systemctl.d.ts +7 -1
  29. package/dist/linux/systemctl.d.ts.map +1 -1
  30. package/dist/opnsense/alias-form.d.ts +29 -0
  31. package/dist/opnsense/alias-form.d.ts.map +1 -0
  32. package/dist/opnsense/alias.d.ts +81 -0
  33. package/dist/opnsense/alias.d.ts.map +1 -0
  34. package/dist/opnsense/category-form.d.ts +10 -0
  35. package/dist/opnsense/category-form.d.ts.map +1 -0
  36. package/dist/opnsense/category.d.ts +58 -0
  37. package/dist/opnsense/category.d.ts.map +1 -0
  38. package/dist/opnsense/credentials.d.ts +36 -0
  39. package/dist/opnsense/credentials.d.ts.map +1 -0
  40. package/dist/opnsense/fake-opnsense.d.ts +51 -0
  41. package/dist/opnsense/fake-opnsense.d.ts.map +1 -0
  42. package/dist/opnsense/group-form.d.ts +11 -0
  43. package/dist/opnsense/group-form.d.ts.map +1 -0
  44. package/dist/opnsense/group.d.ts +62 -0
  45. package/dist/opnsense/group.d.ts.map +1 -0
  46. package/dist/opnsense/index.d.ts +16 -0
  47. package/dist/opnsense/index.d.ts.map +1 -0
  48. package/dist/opnsense/index.js +211 -0
  49. package/dist/opnsense/index.js.map +20 -0
  50. package/dist/opnsense/policy.d.ts +20 -0
  51. package/dist/opnsense/policy.d.ts.map +1 -0
  52. package/dist/opnsense/providers.d.ts +13 -0
  53. package/dist/opnsense/providers.d.ts.map +1 -0
  54. package/dist/opnsense/resource.d.ts +74 -0
  55. package/dist/opnsense/resource.d.ts.map +1 -0
  56. package/dist/opnsense/wire.d.ts +39 -0
  57. package/dist/opnsense/wire.d.ts.map +1 -0
  58. package/dist/proxmox/acl.d.ts.map +1 -1
  59. package/dist/proxmox/api-token.d.ts.map +1 -1
  60. package/dist/proxmox/group-wire.d.ts +44 -5
  61. package/dist/proxmox/group-wire.d.ts.map +1 -1
  62. package/dist/proxmox/group.d.ts.map +1 -1
  63. package/dist/proxmox/index.js +326 -264
  64. package/dist/proxmox/index.js.map +13 -11
  65. package/dist/proxmox/role.d.ts.map +1 -1
  66. package/dist/proxmox/storage-form.d.ts +54 -0
  67. package/dist/proxmox/storage-form.d.ts.map +1 -0
  68. package/dist/proxmox/storage-wire.d.ts +56 -0
  69. package/dist/proxmox/storage-wire.d.ts.map +1 -0
  70. package/dist/proxmox/storage.d.ts +55 -60
  71. package/dist/proxmox/storage.d.ts.map +1 -1
  72. package/dist/proxmox/user-wire.d.ts +34 -5
  73. package/dist/proxmox/user-wire.d.ts.map +1 -1
  74. package/dist/proxmox/user.d.ts +6 -6
  75. package/dist/proxmox/user.d.ts.map +1 -1
  76. package/dist/unifi/fake-unifi.d.ts +48 -0
  77. package/dist/unifi/fake-unifi.d.ts.map +1 -0
  78. package/dist/unifi/firewall-zone-form.d.ts +40 -0
  79. package/dist/unifi/firewall-zone-form.d.ts.map +1 -0
  80. package/dist/unifi/firewall-zone.d.ts +50 -0
  81. package/dist/unifi/firewall-zone.d.ts.map +1 -0
  82. package/dist/unifi/index.d.ts +13 -0
  83. package/dist/unifi/index.d.ts.map +1 -0
  84. package/dist/unifi/index.js +190 -0
  85. package/dist/unifi/index.js.map +16 -0
  86. package/dist/unifi/network-form.d.ts +67 -0
  87. package/dist/unifi/network-form.d.ts.map +1 -0
  88. package/dist/unifi/network.d.ts +67 -0
  89. package/dist/unifi/network.d.ts.map +1 -0
  90. package/dist/unifi/policy.d.ts +20 -0
  91. package/dist/unifi/policy.d.ts.map +1 -0
  92. package/dist/unifi/providers.d.ts +13 -0
  93. package/dist/unifi/providers.d.ts.map +1 -0
  94. package/dist/unifi/resource.d.ts +64 -0
  95. package/dist/unifi/resource.d.ts.map +1 -0
  96. package/dist/verify/fake-engine.d.ts +14 -0
  97. package/dist/verify/fake-engine.d.ts.map +1 -1
  98. package/docs/grafana.md +47 -17
  99. package/docs/opnsense.md +146 -0
  100. package/docs/provider-standard.md +1 -1
  101. package/docs/quadlet-container.md +132 -0
  102. package/docs/unifi.md +93 -0
  103. package/docs/upstream-conformance.md +14 -4
  104. package/package.json +13 -3
  105. package/src/grafana/index.ts +6 -5
  106. package/src/linux/container-fixture.test.ts +92 -0
  107. package/src/linux/container-form.ts +243 -0
  108. package/src/linux/container-generator.test.ts +195 -0
  109. package/src/linux/container-generator.ts +113 -0
  110. package/src/linux/container-handlers.ts +73 -0
  111. package/src/linux/container-lifecycle.test.ts +209 -0
  112. package/src/linux/container-lifecycle.ts +217 -0
  113. package/src/linux/container-preflight.ts +97 -0
  114. package/src/linux/container-secrets.test.ts +171 -0
  115. package/src/linux/container-secrets.ts +112 -0
  116. package/src/linux/container-settle.ts +97 -0
  117. package/src/linux/container.ts +60 -0
  118. package/src/linux/fake-quadlet.ts +127 -0
  119. package/src/linux/index.ts +11 -3
  120. package/src/linux/providers.ts +2 -0
  121. package/src/linux/systemctl.ts +9 -0
  122. package/src/opnsense/alias-form.test.ts +89 -0
  123. package/src/opnsense/alias-form.ts +53 -0
  124. package/src/opnsense/alias.test.ts +203 -0
  125. package/src/opnsense/alias.ts +117 -0
  126. package/src/opnsense/category-form.test.ts +54 -0
  127. package/src/opnsense/category-form.ts +20 -0
  128. package/src/opnsense/category.test.ts +138 -0
  129. package/src/opnsense/category.ts +82 -0
  130. package/src/opnsense/credentials.ts +41 -0
  131. package/src/opnsense/fake-opnsense.ts +79 -0
  132. package/src/opnsense/group-form.test.ts +75 -0
  133. package/src/opnsense/group-form.ts +25 -0
  134. package/src/opnsense/group.test.ts +141 -0
  135. package/src/opnsense/group.ts +78 -0
  136. package/src/opnsense/index.ts +45 -0
  137. package/src/opnsense/policy.ts +49 -0
  138. package/src/opnsense/providers.ts +21 -0
  139. package/src/opnsense/resource.ts +146 -0
  140. package/src/opnsense/wire.ts +56 -0
  141. package/src/opnsense/write-refusal.test.ts +148 -0
  142. package/src/proxmox/acl.ts +10 -4
  143. package/src/proxmox/api-token.ts +20 -12
  144. package/src/proxmox/group-wire.ts +62 -8
  145. package/src/proxmox/group.ts +23 -35
  146. package/src/proxmox/read-failure-propagation.test.ts +183 -0
  147. package/src/proxmox/role.ts +9 -2
  148. package/src/proxmox/storage-form.ts +144 -0
  149. package/src/proxmox/storage-read-failure.test.ts +214 -0
  150. package/src/proxmox/storage-wire.ts +124 -0
  151. package/src/proxmox/storage.ts +165 -175
  152. package/src/proxmox/user-wire.ts +44 -8
  153. package/src/proxmox/user.ts +29 -27
  154. package/src/unifi/fake-unifi.ts +60 -0
  155. package/src/unifi/firewall-zone-form.ts +65 -0
  156. package/src/unifi/firewall-zone.test.ts +88 -0
  157. package/src/unifi/firewall-zone.ts +66 -0
  158. package/src/unifi/index.ts +26 -0
  159. package/src/unifi/network-form.ts +207 -0
  160. package/src/unifi/network.test.ts +209 -0
  161. package/src/unifi/network.ts +83 -0
  162. package/src/unifi/policy.ts +37 -0
  163. package/src/unifi/providers.ts +15 -0
  164. package/src/unifi/resource.test.ts +133 -0
  165. package/src/unifi/resource.ts +131 -0
  166. package/src/verify/fake-engine.ts +23 -0
@@ -419,11 +419,14 @@ var HostDirectoryProvider = () => Provider.effect(HostDirectory, Effect6.gen(fun
419
419
  // src/linux/providers.ts
420
420
  import * as Layer2 from "effect/Layer";
421
421
 
422
- // src/linux/remote-file.ts
422
+ // src/linux/container.ts
423
423
  import { Resource as Resource2 } from "alchemy";
424
+ import * as Provider2 from "alchemy/Provider";
425
+ import * as Effect8 from "effect/Effect";
426
+
427
+ // src/linux/container-handlers.ts
424
428
  import { Unowned as Unowned3 } from "alchemy/AdoptPolicy";
425
429
  import { isResolved as isResolved2 } from "alchemy/Diff";
426
- import * as Provider2 from "alchemy/Provider";
427
430
  import * as Effect7 from "effect/Effect";
428
431
 
429
432
  // src/launchd/job-form.ts
@@ -594,27 +597,556 @@ var jobPlistDict = (props) => {
594
597
  if (calendar !== undefined) {
595
598
  dict["StartCalendarInterval"] = Array.isArray(calendar) ? calendar.map(calendarDict) : calendarDict(calendar);
596
599
  }
597
- if (props.throttleInterval !== undefined)
598
- dict["ThrottleInterval"] = props.throttleInterval;
599
- if (props.standardOutPath !== undefined)
600
- dict["StandardOutPath"] = props.standardOutPath;
601
- if (props.standardErrorPath !== undefined)
602
- dict["StandardErrorPath"] = props.standardErrorPath;
603
- if (props.workingDirectory !== undefined)
604
- dict["WorkingDirectory"] = props.workingDirectory;
605
- if (props.userName !== undefined)
606
- dict["UserName"] = props.userName;
607
- if (props.groupName !== undefined)
608
- dict["GroupName"] = props.groupName;
609
- return dict;
600
+ if (props.throttleInterval !== undefined)
601
+ dict["ThrottleInterval"] = props.throttleInterval;
602
+ if (props.standardOutPath !== undefined)
603
+ dict["StandardOutPath"] = props.standardOutPath;
604
+ if (props.standardErrorPath !== undefined)
605
+ dict["StandardErrorPath"] = props.standardErrorPath;
606
+ if (props.workingDirectory !== undefined)
607
+ dict["WorkingDirectory"] = props.workingDirectory;
608
+ if (props.userName !== undefined)
609
+ dict["UserName"] = props.userName;
610
+ if (props.groupName !== undefined)
611
+ dict["GroupName"] = props.groupName;
612
+ return dict;
613
+ };
614
+ var sha256Hex = (bytes) => createHash("sha256").update(bytes).digest("hex");
615
+ var renderJob = (props) => {
616
+ const text = renderPlist(jobPlistDict(props));
617
+ const bytes = new TextEncoder().encode(text);
618
+ return { bytes, sha256: sha256Hex(bytes), text };
619
+ };
620
+
621
+ // src/linux/unit-form.ts
622
+ var DEFAULT_UNIT_DIRECTORY = "/etc/systemd/system";
623
+ var UNIT_SEARCH_DIRECTORIES = [
624
+ "/etc/systemd/system",
625
+ "/run/systemd/system",
626
+ "/usr/local/lib/systemd/system",
627
+ "/usr/lib/systemd/system",
628
+ "/lib/systemd/system"
629
+ ];
630
+ var UNIT_WRITE = { gid: 0, mode: 420, uid: 0 };
631
+ var digestOf = (text) => sha256Hex(new TextEncoder().encode(text));
632
+ var configDigest = (restartOn) => digestOf((restartOn ?? []).join(`
633
+ `));
634
+ var isUnitRunning = (activeState, subState, started) => {
635
+ if (activeState === "active")
636
+ return true;
637
+ if (activeState !== "activating")
638
+ return false;
639
+ if (subState === "auto-restart" || subState === "auto-restart-queued")
640
+ return true;
641
+ return started;
642
+ };
643
+ var renderUnit = (sections) => `${sections.map((section) => [`[${section.name}]`, ...section.lines.map(([key, value]) => `${key}=${value}`)].join(`
644
+ `)).join(`
645
+
646
+ `)}
647
+ `;
648
+ var unitText = (props) => props.content ?? renderUnit(props.sections ?? []);
649
+ var unitPathFor = (props) => `${props.directory ?? DEFAULT_UNIT_DIRECTORY}/${props.name}`;
650
+ var NAME = /^[A-Za-z0-9][A-Za-z0-9_.@:-]*\.([a-z]+)$/;
651
+ var TYPES = new Set([
652
+ "automount",
653
+ "device",
654
+ "mount",
655
+ "path",
656
+ "scope",
657
+ "service",
658
+ "slice",
659
+ "socket",
660
+ "swap",
661
+ "target",
662
+ "timer"
663
+ ]);
664
+ var INSTALL_KEYS = new Set(["WantedBy", "RequiredBy", "UpsertedBy", "Also", "Alias"]);
665
+ var unitProblems = (props, expect) => {
666
+ const found = [];
667
+ const type = NAME.exec(props.name)?.[1];
668
+ if (type === undefined || !TYPES.has(type)) {
669
+ found.push(`name must be <unit>.<type> with a systemd unit type, got ${JSON.stringify(props.name)}`);
670
+ } else if (expect !== undefined && type !== expect) {
671
+ found.push(`this resource declares a .${expect} unit; ${props.name} is a .${type}`);
672
+ }
673
+ if (props.content === undefined === (props.sections === undefined)) {
674
+ found.push("declare exactly one of content or sections");
675
+ }
676
+ const directory = props.directory ?? DEFAULT_UNIT_DIRECTORY;
677
+ if (!directory.startsWith("/") || directory.endsWith("/") || directory.includes("/..")) {
678
+ found.push("directory must be an absolute, normalised path with no trailing slash");
679
+ }
680
+ found.push(...textProblems(unitText(props)));
681
+ if (props.enabled !== false && !UNIT_SEARCH_DIRECTORIES.includes(directory)) {
682
+ found.push(`an enabled unit must live where systemd looks for it by name (${UNIT_SEARCH_DIRECTORIES.join(", ")}); ` + `${directory} is not one of them. Move it, or declare enabled: false.`);
683
+ }
684
+ if (props.enabled !== false && !hasInstall(props)) {
685
+ found.push("enabled units need an [Install] section with WantedBy/RequiredBy/Also/Alias; without one " + 'systemd calls the unit "static" and `systemctl enable` has nothing to link. Add one, or ' + "declare enabled: false and let something else pull it in.");
686
+ }
687
+ if (type === "timer" && !unitText(props).includes("[Timer]")) {
688
+ found.push("a .timer needs a [Timer] section");
689
+ }
690
+ return found;
691
+ };
692
+ var hasInstall = (props) => {
693
+ const text = unitText(props);
694
+ if (!text.includes("[Install]"))
695
+ return false;
696
+ const after = text.slice(text.indexOf("[Install]"));
697
+ return [...INSTALL_KEYS].some((key) => new RegExp(`^${key}=`, "m").test(after));
698
+ };
699
+ var textProblems = (text) => {
700
+ const found = [];
701
+ if (text.trim() === "")
702
+ found.push("the unit file is empty");
703
+ if (text.includes("\x00"))
704
+ found.push("the unit file contains NUL");
705
+ if (!/^\s*\[[A-Za-z]+]/.test(text))
706
+ found.push("a unit file must begin with a [Section]");
707
+ return found;
708
+ };
709
+
710
+ // src/linux/systemctl.ts
711
+ var SYSTEMCTL = "systemctl";
712
+ var SHOW_PROPERTIES = [
713
+ "Id",
714
+ "LoadState",
715
+ "ActiveState",
716
+ "SubState",
717
+ "UnitFileState",
718
+ "FragmentPath",
719
+ "SourcePath",
720
+ "NeedDaemonReload"
721
+ ];
722
+
723
+ class SystemctlError extends Error {
724
+ constructor(command, exitCode, stderr) {
725
+ super(`systemctl ${command} -> ${String(exitCode)}: ${stderr.trim().slice(0, 300)}`);
726
+ this.name = "SystemctlError";
727
+ }
728
+ }
729
+ var parseShow = (stdout) => {
730
+ const fields = new Map;
731
+ for (const line of stdout.split(`
732
+ `)) {
733
+ const at = line.indexOf("=");
734
+ if (at <= 0)
735
+ continue;
736
+ const key = line.slice(0, at);
737
+ if (!fields.has(key))
738
+ fields.set(key, line.slice(at + 1));
739
+ }
740
+ return fields;
741
+ };
742
+ var statusOf = (stdout) => {
743
+ const fields = parseShow(stdout);
744
+ const loadState = fields.get("LoadState") ?? "not-found";
745
+ const unitFileState = fields.get("UnitFileState") ?? "";
746
+ const fragmentPath = fields.get("FragmentPath") ?? "";
747
+ const sourcePath = fields.get("SourcePath") ?? "";
748
+ const subState = fields.get("SubState") ?? "";
749
+ return {
750
+ activeState: fields.get("ActiveState") ?? "inactive",
751
+ known: loadState !== "not-found" || unitFileState !== "",
752
+ loadState,
753
+ needDaemonReload: fields.get("NeedDaemonReload") === "yes",
754
+ ...subState === "" ? {} : { subState },
755
+ ...unitFileState === "" ? {} : { unitFileState },
756
+ ...fragmentPath === "" ? {} : { fragmentPath },
757
+ ...sourcePath === "" ? {} : { sourcePath }
758
+ };
759
+ };
760
+ var showUnit = async (runner, name) => {
761
+ const result = await runner.exec([
762
+ SYSTEMCTL,
763
+ "show",
764
+ "--no-pager",
765
+ "-p",
766
+ SHOW_PROPERTIES.join(","),
767
+ "--",
768
+ name
769
+ ]);
770
+ if (result.exitCode !== 0)
771
+ throw new SystemctlError(`show ${name}`, result.exitCode, result.stderr);
772
+ return statusOf(result.stdout);
773
+ };
774
+ var run = async (runner, args) => {
775
+ const result = await runner.exec([SYSTEMCTL, ...args]);
776
+ if (result.exitCode !== 0) {
777
+ throw new SystemctlError(args.join(" "), result.exitCode, result.stderr);
778
+ }
779
+ };
780
+ var daemonReload = (runner) => run(runner, ["daemon-reload"]);
781
+ var enableUnit = (runner, name) => run(runner, ["enable", "--", name]);
782
+ var disableUnit = (runner, name) => run(runner, ["disable", "--", name]);
783
+ var startUnit = (runner, name) => run(runner, ["start", "--", name]);
784
+ var stopUnit = (runner, name) => run(runner, ["stop", "--", name]);
785
+ var restartUnit = (runner, name) => run(runner, ["restart", "--", name]);
786
+
787
+ // src/linux/container-generator.ts
788
+ class QuadletGeneratorError extends Error {
789
+ constructor(name, detail) {
790
+ super(`Podman.Container ${name}: ${detail}`);
791
+ this.name = "QuadletGeneratorError";
792
+ }
793
+ }
794
+ var generatedMatches = (containerPath, status) => status.known && status.loadState === "loaded" && (status.sourcePath === undefined || status.sourcePath === containerPath);
795
+ var needsVerificationReload = (containerPath, status) => !generatedMatches(containerPath, status);
796
+ var verifyGenerated = (name, containerPath, serviceName, status) => {
797
+ if (!status.known || status.loadState !== "loaded") {
798
+ throw new QuadletGeneratorError(name, `${serviceName} does not exist after daemon-reload (LoadState=${status.loadState}). The ` + ".container file was written and reloaded, so Quadlet’s generator refused it — a bad " + "key, a bad value, or an interaction this validation does not check. Debug on the host " + "with '/usr/lib/systemd/system-generators/podman-system-generator --dryrun' or " + `'systemd-analyze --generators=true verify ${serviceName}' (podman-systemd.unit(5), Podman 5.4).`);
799
+ }
800
+ if (status.sourcePath !== undefined && status.sourcePath !== containerPath) {
801
+ throw new QuadletGeneratorError(name, `${serviceName}'s SourcePath is ${status.sourcePath}, not ${containerPath} — a same-named ` + ".container file earlier in Quadlet’s search path is generating this unit instead of ours " + "(podman-systemd.unit(5) “Podman Unit Search Path”, Podman 5.4).");
802
+ }
803
+ };
804
+
805
+ // src/linux/container-secrets.ts
806
+ var SECRET_KEY_NAME = /(SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE_KEY|API_?KEY|CREDENTIAL|ACCESS_KEY|CLIENT_SECRET|AUTH_?KEY|DSN)/i;
807
+ var SECRET_VALUE_PREFIX = /^(Bearer\s|Basic\s|sk-|ghp_|gho_|glpat-|xox[baprs]-|AKIA|eyJ)/;
808
+ var SECRET_VALUE_ANYWHERE = new RegExp(SECRET_VALUE_PREFIX.source.replace(/^\^/, ""));
809
+ var EMBEDDED_SECRET_ASSIGNMENT = new RegExp(`[A-Za-z0-9_]*(?:${SECRET_KEY_NAME.source})[A-Za-z0-9_]*\\s*=\\s*\\S+`, "i");
810
+ var ENV_FLAG = /^(?:-e|--env)(?:=|$|[A-Za-z_])/;
811
+ var secretLikeEnvironment = (environment) => {
812
+ const found = [];
813
+ for (const [key, value] of Object.entries(environment)) {
814
+ if (SECRET_KEY_NAME.test(key)) {
815
+ found.push(`environment key ${JSON.stringify(key)} looks like a secret by its name. Environment= is ` + "rendered into a world-readable file and stored in Alchemy state; use environmentFile " + "instead, pointing at a host path a secret renderer maintains.");
816
+ } else if (SECRET_VALUE_PREFIX.test(value)) {
817
+ found.push(`environment key ${JSON.stringify(key)}'s value looks like a credential. Environment= is ` + "rendered into a world-readable file and stored in Alchemy state; use environmentFile " + "instead, pointing at a host path a secret renderer maintains.");
818
+ }
819
+ }
820
+ return found;
821
+ };
822
+ var secretLikeLines = (lines) => {
823
+ const found = [];
824
+ for (const [key, value] of lines) {
825
+ if (SECRET_VALUE_ANYWHERE.test(value)) {
826
+ found.push(`${key}=${JSON.stringify(value)} looks like it carries a credential by its value. This ` + "line is rendered into a world-readable file and stored in Alchemy state; use " + "container.environmentFile instead, pointing at a host path a secret renderer maintains.");
827
+ } else if (EMBEDDED_SECRET_ASSIGNMENT.test(value)) {
828
+ found.push(`${key}=${JSON.stringify(value)} embeds a KEY=VALUE pair whose key looks like a secret ` + "name. This line is rendered into a world-readable file and stored in Alchemy state; use " + "container.environment (checked for secrets) or container.environmentFile instead.");
829
+ }
830
+ }
831
+ return found;
832
+ };
833
+ var podmanArgsProblems = (args) => args.filter((arg) => ENV_FLAG.test(arg)).map((arg) => `podmanArgs entry ${JSON.stringify(arg)} sets a container environment variable outside ` + "the typed props, which this family never checks for a secret. Use container.environment " + "(checked) or container.environmentFile (for anything secret) instead.");
834
+
835
+ // src/linux/container-form.ts
836
+ var QUADLET_SEARCH_DIRECTORIES = [
837
+ "/run/containers/systemd",
838
+ "/etc/containers/systemd",
839
+ "/usr/share/containers/systemd"
840
+ ];
841
+ var QUADLET_DEFAULT_DIRECTORY = "/etc/containers/systemd";
842
+ var NAME2 = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
843
+ var containerPathFor = (props) => `${props.directory ?? QUADLET_DEFAULT_DIRECTORY}/${props.name}.container`;
844
+ var serviceNameFor = (props) => `${props.name}.service`;
845
+ var unitLines = (props) => [
846
+ ...props.unit?.description === undefined ? [] : [["Description", props.unit.description]],
847
+ ...props.unit?.documentation === undefined ? [] : [["Documentation", props.unit.documentation]],
848
+ ...props.unit?.lines ?? []
849
+ ];
850
+ var containerLines = (c) => [
851
+ ["Image", c.image],
852
+ ...c.containerName === undefined ? [] : [["ContainerName", c.containerName]],
853
+ ...c.network === undefined ? [] : [["Network", c.network]],
854
+ ...c.user === undefined ? [] : [["User", c.user]],
855
+ ...c.exec === undefined ? [] : [["Exec", c.exec]],
856
+ ...c.autoUpdate === undefined ? [] : [["AutoUpdate", c.autoUpdate]],
857
+ ...(c.environmentFile ?? []).map((file) => ["EnvironmentFile", file]),
858
+ ...Object.keys(c.environment ?? {}).sort().map((key) => [
859
+ "Environment",
860
+ `${key}=${c.environment[key]}`
861
+ ]),
862
+ ...(c.volume ?? []).map((volume) => ["Volume", volume]),
863
+ ...(c.publishPort ?? []).map((port) => ["PublishPort", port]),
864
+ ...(c.podmanArgs ?? []).map((arg) => ["PodmanArgs", arg])
865
+ ];
866
+ var serviceLines = (props) => [
867
+ ...props.service?.restart === undefined ? [] : [["Restart", props.service.restart]],
868
+ ...props.service?.restartSec === undefined ? [] : [["RestartSec", props.service.restartSec]],
869
+ ...props.service?.lines ?? []
870
+ ];
871
+ var installLines = (props) => [
872
+ ...(props.install?.wantedBy ?? []).map((target) => ["WantedBy", target]),
873
+ ...(props.install?.requiredBy ?? []).map((target) => ["RequiredBy", target]),
874
+ ...(props.install?.alias ?? []).map((name) => ["Alias", name])
875
+ ];
876
+ var renderContainerFile = (props) => {
877
+ const sections = [
878
+ { name: "Unit", lines: unitLines(props) },
879
+ { name: "Container", lines: containerLines(props.container) },
880
+ { name: "Service", lines: serviceLines(props) },
881
+ { name: "Install", lines: installLines(props) }
882
+ ];
883
+ return renderUnit(sections.filter((section) => section.lines.length > 0));
884
+ };
885
+ var refuseContainer = (name, message) => new Error(`Podman.Container ${name}: ${message}`);
886
+ var containerProblems = (props) => {
887
+ const found = [];
888
+ if (!NAME2.test(props.name)) {
889
+ found.push(`name must match ${String(NAME2)}, with no '.container' suffix; got ${JSON.stringify(props.name)}`);
890
+ }
891
+ const directory = props.directory ?? QUADLET_DEFAULT_DIRECTORY;
892
+ if (!directory.startsWith("/") || directory.endsWith("/") || directory.includes("/..")) {
893
+ found.push("directory must be an absolute, normalised path with no trailing slash");
894
+ } else if (!QUADLET_SEARCH_DIRECTORIES.includes(directory)) {
895
+ found.push(`directory must be one of Quadlet's own rootful search path (${QUADLET_SEARCH_DIRECTORIES.join(", ")}); ` + `${directory} is never read by the generator (podman-systemd.unit(5), Podman 5.4).`);
896
+ }
897
+ if (props.container.image.trim() === "")
898
+ found.push("container.image is required");
899
+ if (props.container.network === "host" && (props.container.publishPort?.length ?? 0) > 0) {
900
+ found.push("container.publishPort has no effect with container.network 'host': the container already " + "binds the host’s ports directly. Drop publishPort, or use a different network.");
901
+ }
902
+ found.push(...secretLikeEnvironment(props.container.environment ?? {}).map((problem) => `container.${problem}`));
903
+ found.push(...podmanArgsProblems(props.container.podmanArgs ?? []).map((problem) => `container.${problem}`));
904
+ found.push(...secretLikeLines([
905
+ ...unitLines(props),
906
+ ...containerLines(props.container).filter(([key]) => key !== "Environment"),
907
+ ...serviceLines(props),
908
+ ...installLines(props)
909
+ ]));
910
+ if (renderContainerFile(props).includes("\x00"))
911
+ found.push("the rendered .container file contains NUL");
912
+ return found;
913
+ };
914
+
915
+ // src/linux/container-preflight.ts
916
+ var decoder = new TextDecoder;
917
+ var assertValid = (props) => {
918
+ const found = containerProblems(props);
919
+ if (found.length > 0)
920
+ throw refuseContainer(props.name, found.join("; "));
921
+ };
922
+ var assertMayWrite = (runner, name) => {
923
+ if (canActAsRoot(runner))
924
+ return;
925
+ throw refuseContainer(name, "a Quadlet .container file is root-owned and daemon-reload/systemctl need root. Point the " + "runner at a destination whose ssh user is root, or provide a privileged HostRunner. This " + "provider never calls sudo.");
926
+ };
927
+ var assertUsable = (props, status) => {
928
+ if (status.loadState === "masked" || status.unitFileState === "masked") {
929
+ throw refuseContainer(props.name, `${serviceNameFor(props)} is masked. If that is stale, \`systemctl unmask\` it deliberately, ` + "then redeploy. Nothing was written.");
930
+ }
931
+ };
932
+ var assertUnclaimed = async (runner, props) => {
933
+ const path = containerPathFor(props);
934
+ const bytes = await runner.readFile(path);
935
+ const live = bytes === undefined ? undefined : digestOf(decoder.decode(bytes));
936
+ if (live !== undefined && live !== digestOf(renderContainerFile(props))) {
937
+ throw refuseContainer(props.name, `${path} is already on this host and is not this resource. Remove it, or declare it as a ` + "new resource and deploy with --adopt.");
938
+ }
939
+ };
940
+ var assertRenameTarget = async (runner, old, name) => {
941
+ assertMayWrite(runner, old.name);
942
+ assertMayWrite(runner, name);
943
+ assertUsable({ name }, await showUnit(runner, serviceNameFor({ name })));
944
+ };
945
+ var assertReplaceable = async (runner, next, old) => {
946
+ assertValid(next);
947
+ await assertRenameTarget(runner, old, next.name);
948
+ await assertUnclaimed(runner, next);
949
+ await runner.checkWrite?.(containerPathFor(next), UNIT_WRITE);
950
+ };
951
+
952
+ // src/linux/container-settle.ts
953
+ var attributesOf = (props, configSha256, containerSha256, containerPath, serviceName, status) => ({
954
+ active: status.activeState === "active" || status.activeState === "activating",
955
+ activeState: status.activeState,
956
+ configSha256,
957
+ containerPath,
958
+ containerSha256,
959
+ loadState: status.loadState,
960
+ name: props.name,
961
+ serviceName,
962
+ ...status.unitFileState === undefined ? {} : { unitFileState: status.unitFileState },
963
+ ...status.sourcePath === undefined ? {} : { sourcePath: status.sourcePath }
964
+ });
965
+ var settle = async (runner, props, configSha256, step) => {
966
+ const wantStarted = props.started !== false;
967
+ const running = isUnitRunning(step.status.activeState, step.status.subState, wantStarted);
968
+ const undo = async (detail) => {
969
+ if (step.before === undefined) {
970
+ await runner.removeFile(step.path).catch(() => {
971
+ return;
972
+ });
973
+ await daemonReload(runner).catch(() => {
974
+ return;
975
+ });
976
+ }
977
+ throw refuseContainer(props.name, `${detail} The container's unit is NOT running.`);
978
+ };
979
+ try {
980
+ if (!wantStarted) {
981
+ if (running)
982
+ await stopUnit(runner, step.serviceName);
983
+ } else if (!running)
984
+ await startUnit(runner, step.serviceName);
985
+ else if (step.changed || step.configChanged)
986
+ await restartUnit(runner, step.serviceName);
987
+ } catch (cause) {
988
+ return undo(cause instanceof Error ? cause.message : String(cause));
989
+ }
990
+ const after = await showUnit(runner, step.serviceName);
991
+ if (wantStarted && !isUnitRunning(after.activeState, after.subState, wantStarted)) {
992
+ return undo(`systemctl reported success but the unit is ${after.activeState}.`);
993
+ }
994
+ return attributesOf(props, configSha256, step.desired, step.path, step.serviceName, after);
995
+ };
996
+
997
+ // src/linux/container-lifecycle.ts
998
+ var encoder = new TextEncoder;
999
+ var decoder2 = new TextDecoder;
1000
+ var readContainer = async (runner, props) => {
1001
+ const path = containerPathFor(props);
1002
+ const bytes = await runner.readFile(path);
1003
+ const status = await showUnit(runner, serviceNameFor(props));
1004
+ if (bytes === undefined && !status.known)
1005
+ return;
1006
+ const sha = bytes === undefined ? "" : digestOf(decoder2.decode(bytes));
1007
+ return attributesOf(props, configDigest(props.restartOn), sha, path, serviceNameFor(props), status);
1008
+ };
1009
+ var diffContainer = async (runner, news, output) => {
1010
+ assertValid(news);
1011
+ if (news.name !== output.name || containerPathFor(news) !== output.containerPath) {
1012
+ await assertReplaceable(runner, news, output);
1013
+ return { action: "replace", deleteFirst: true };
1014
+ }
1015
+ const desired2 = digestOf(renderContainerFile(news));
1016
+ const update = async () => {
1017
+ assertMayWrite(runner, news.name);
1018
+ await runner.checkWrite?.(containerPathFor(news), UNIT_WRITE);
1019
+ return { action: "update" };
1020
+ };
1021
+ if (desired2 !== output.containerSha256)
1022
+ return update();
1023
+ if (configDigest(news.restartOn) !== output.configSha256)
1024
+ return update();
1025
+ const live = await readContainer(runner, news);
1026
+ if (live === undefined || live.containerSha256 !== desired2)
1027
+ return update();
1028
+ const status = await showUnit(runner, serviceNameFor(news));
1029
+ const wantStarted = news.started !== false;
1030
+ if (isUnitRunning(status.activeState, status.subState, wantStarted) !== wantStarted)
1031
+ return update();
1032
+ return status.needDaemonReload ? update() : { action: "noop" };
1033
+ };
1034
+ var reconcileContainer = async (runner, props, output, adopt = false) => {
1035
+ assertValid(props);
1036
+ assertMayWrite(runner, props.name);
1037
+ const path = containerPathFor(props);
1038
+ const serviceName = serviceNameFor(props);
1039
+ const text = renderContainerFile(props);
1040
+ const desired2 = digestOf(text);
1041
+ const before = await runner.readFile(path);
1042
+ const liveSha = before === undefined ? undefined : digestOf(decoder2.decode(before));
1043
+ const moved = output !== undefined && (output.name !== props.name || output.containerPath !== path);
1044
+ if (moved && output !== undefined)
1045
+ await assertReplaceable(runner, props, output);
1046
+ const prior = moved ? undefined : output;
1047
+ if (prior === undefined && !(adopt && output === undefined) && liveSha !== undefined && liveSha !== desired2) {
1048
+ throw refuseContainer(props.name, `${path} is already on this host and is not this resource. Remove it, or declare it as a ` + "new resource and deploy with --adopt.");
1049
+ }
1050
+ if (moved && output !== undefined)
1051
+ await deleteContainer(runner, output);
1052
+ const wrote = liveSha !== desired2;
1053
+ const stale = prior !== undefined && prior.containerSha256 !== desired2;
1054
+ const preStatus = await showUnit(runner, serviceName);
1055
+ assertUsable(props, preStatus);
1056
+ const needsReload = wrote || stale || preStatus.needDaemonReload || prior === undefined && needsVerificationReload(path, preStatus);
1057
+ if (wrote)
1058
+ await runner.writeFileAtomic(path, encoder.encode(text), UNIT_WRITE);
1059
+ if (needsReload)
1060
+ await daemonReload(runner);
1061
+ const status = needsReload ? await showUnit(runner, serviceName) : preStatus;
1062
+ try {
1063
+ verifyGenerated(props.name, path, serviceName, status);
1064
+ } catch (cause) {
1065
+ if (wrote) {
1066
+ if (before === undefined)
1067
+ await runner.removeFile(path).catch(() => {
1068
+ return;
1069
+ });
1070
+ else
1071
+ await runner.writeFileAtomic(path, before, UNIT_WRITE).catch(() => {
1072
+ return;
1073
+ });
1074
+ await daemonReload(runner).catch(() => {
1075
+ return;
1076
+ });
1077
+ }
1078
+ throw cause;
1079
+ }
1080
+ const configChanged = prior !== undefined && prior.configSha256 !== configDigest(props.restartOn);
1081
+ const changed = wrote || stale || preStatus.needDaemonReload;
1082
+ return settle(runner, props, configDigest(props.restartOn), {
1083
+ before,
1084
+ changed,
1085
+ configChanged,
1086
+ desired: desired2,
1087
+ path,
1088
+ serviceName,
1089
+ status
1090
+ });
610
1091
  };
611
- var sha256Hex = (bytes) => createHash("sha256").update(bytes).digest("hex");
612
- var renderJob = (props) => {
613
- const text = renderPlist(jobPlistDict(props));
614
- const bytes = new TextEncoder().encode(text);
615
- return { bytes, sha256: sha256Hex(bytes), text };
1092
+ var deleteContainer = async (runner, output) => {
1093
+ assertMayWrite(runner, output.name);
1094
+ const status = await showUnit(runner, output.serviceName);
1095
+ if (status.activeState === "active" || status.activeState === "activating") {
1096
+ await stopUnit(runner, output.serviceName);
1097
+ }
1098
+ const stat = await runner.stat(output.containerPath);
1099
+ if (stat !== undefined) {
1100
+ if (stat.kind !== "file")
1101
+ throw refuseContainer(output.name, `${output.containerPath} is a ${stat.kind}`);
1102
+ await runner.removeFile(output.containerPath);
1103
+ }
1104
+ await daemonReload(runner);
616
1105
  };
617
1106
 
1107
+ // src/linux/container-handlers.ts
1108
+ var readHandler = (runner, olds, output) => lift(async () => {
1109
+ const found = await readContainer(runner, olds);
1110
+ if (found === undefined)
1111
+ return;
1112
+ return output === undefined ? Unowned3(found) : found;
1113
+ });
1114
+ var diffHandler = (runner, instanceId, news, output) => {
1115
+ if (output === undefined)
1116
+ return noteUnfinished(instanceId);
1117
+ if (isResolved2(news))
1118
+ return lift(() => diffContainer(runner, news, output));
1119
+ const name = resolvedString(news, "name");
1120
+ if (name === undefined || name === output.name)
1121
+ return Effect7.succeed(undefined);
1122
+ return lift(async () => {
1123
+ await assertRenameTarget(runner, output, name);
1124
+ return { action: "replace", deleteFirst: true };
1125
+ });
1126
+ };
1127
+ var reconcileHandler = (runner, args) => Effect7.flatMap(adoptsAtApply(args), (adopt) => lift(() => reconcileContainer(runner, args.news, args.output, adopt)));
1128
+ var deleteHandler = (runner, output) => lift(() => deleteContainer(runner, output));
1129
+
1130
+ // src/linux/container.ts
1131
+ var PodmanContainer = Resource2("Podman.Container");
1132
+ var PodmanContainerProvider = () => Provider2.effect(PodmanContainer, Effect8.gen(function* () {
1133
+ const runner = yield* HostRunnerService;
1134
+ return PodmanContainer.Provider.of({
1135
+ list: () => Effect8.succeed([]),
1136
+ read: ({ olds, output }) => readHandler(runner, olds, output),
1137
+ diff: ({ instanceId, news, output }) => diffHandler(runner, instanceId, news, output),
1138
+ reconcile: (args) => reconcileHandler(runner, args),
1139
+ delete: ({ output }) => deleteHandler(runner, output)
1140
+ });
1141
+ }));
1142
+
1143
+ // src/linux/remote-file.ts
1144
+ import { Resource as Resource3 } from "alchemy";
1145
+ import { Unowned as Unowned4 } from "alchemy/AdoptPolicy";
1146
+ import { isResolved as isResolved3 } from "alchemy/Diff";
1147
+ import * as Provider3 from "alchemy/Provider";
1148
+ import * as Effect9 from "effect/Effect";
1149
+
618
1150
  // src/linux/region.ts
619
1151
  var DEFAULT_COMMENT = "#";
620
1152
  var tokens = (spec) => {
@@ -726,8 +1258,8 @@ var fileProblems2 = (props) => {
726
1258
  };
727
1259
 
728
1260
  // src/linux/remote-file-plan.ts
729
- var decoder = new TextDecoder;
730
- var encoder = new TextEncoder;
1261
+ var decoder3 = new TextDecoder;
1262
+ var encoder2 = new TextEncoder;
731
1263
  var refuse3 = (path, message) => new Error(`Remote.File ${path}: ${message}`);
732
1264
  var numericId2 = (value) => typeof value === "number" ? value : /^\d+$/.test(value) ? Number(value) : undefined;
733
1265
  var identity = async (runner, props) => {
@@ -748,7 +1280,7 @@ var identity = async (runner, props) => {
748
1280
  }
749
1281
  return { ...uid === undefined ? {} : { uid }, ...gid === undefined ? {} : { gid } };
750
1282
  };
751
- var digestOf = (text) => sha256Hex(encoder.encode(text));
1283
+ var digestOf2 = (text) => sha256Hex(encoder2.encode(text));
752
1284
  var relocation = (props, output) => {
753
1285
  if (props.path !== output.path)
754
1286
  return "path";
@@ -763,16 +1295,16 @@ var ownedDigest = (file, region) => {
763
1295
  if (file === undefined)
764
1296
  return;
765
1297
  if (region === undefined)
766
- return digestOf(file);
1298
+ return digestOf2(file);
767
1299
  const body = readRegion(file, region);
768
- return body === undefined ? undefined : digestOf(body);
1300
+ return body === undefined ? undefined : digestOf2(body);
769
1301
  };
770
1302
  var readFileAttributes = async (runner, path, region) => {
771
1303
  const stat = await runner.stat(path);
772
1304
  if (stat === undefined)
773
1305
  return;
774
1306
  const bytes = stat.kind === "file" ? await runner.readFile(path) : undefined;
775
- const text = bytes === undefined ? undefined : decoder.decode(bytes);
1307
+ const text = bytes === undefined ? undefined : decoder3.decode(bytes);
776
1308
  return {
777
1309
  contentSha256: ownedDigest(text, region) ?? "",
778
1310
  gid: stat.gid,
@@ -791,13 +1323,13 @@ var planWrite = async (runner, props, want) => {
791
1323
  throw refuse3(props.path, `is a ${stat.kind}; remove it from whatever owns it before declaring it here`);
792
1324
  }
793
1325
  const current = stat === undefined ? undefined : await runner.readFile(props.path);
794
- const before = current === undefined ? undefined : decoder.decode(current);
1326
+ const before = current === undefined ? undefined : decoder3.decode(current);
795
1327
  const declaredMode = props.mode ?? DEFAULT_MODE2;
796
1328
  if (props.region === undefined) {
797
1329
  const write = { mode: declaredMode, ...want };
798
1330
  return {
799
1331
  before,
800
- bytes: encoder.encode(props.content),
1332
+ bytes: encoder2.encode(props.content),
801
1333
  converged: before === props.content && matches(stat, write),
802
1334
  write
803
1335
  };
@@ -808,7 +1340,7 @@ var planWrite = async (runner, props, want) => {
808
1340
  }
809
1341
  return {
810
1342
  before,
811
- bytes: encoder.encode(spliceRegion("", props.region, props.content)),
1343
+ bytes: encoder2.encode(spliceRegion("", props.region, props.content)),
812
1344
  converged: false,
813
1345
  write: { mode: declaredMode, ...want }
814
1346
  };
@@ -816,7 +1348,7 @@ var planWrite = async (runner, props, want) => {
816
1348
  const next = spliceRegion(before, props.region, props.content);
817
1349
  return {
818
1350
  before,
819
- bytes: encoder.encode(next),
1351
+ bytes: encoder2.encode(next),
820
1352
  converged: next === before,
821
1353
  write: { gid: stat?.gid ?? 0, mode: stat?.mode ?? declaredMode, uid: stat?.uid ?? 0 }
822
1354
  };
@@ -830,7 +1362,7 @@ var diffFile = async (runner, news, output) => {
830
1362
  return { action: "replace" };
831
1363
  }
832
1364
  const planned = await planWrite(runner, news, want);
833
- if (planned.converged && output.contentSha256 === digestOf(news.content)) {
1365
+ if (planned.converged && output.contentSha256 === digestOf2(news.content)) {
834
1366
  return { action: "noop" };
835
1367
  }
836
1368
  await runner.checkWrite?.(news.path, planned.write);
@@ -845,7 +1377,7 @@ var reconcileFile = async (runner, props, output, adopt = false) => {
845
1377
  const prior = move === "none" ? output : undefined;
846
1378
  const planned = await planWrite(runner, props, want);
847
1379
  const live = ownedDigest(planned.before, props.region);
848
- const declared = digestOf(props.content);
1380
+ const declared = digestOf2(props.content);
849
1381
  if (prior === undefined && live !== undefined && live !== declared && !(adopt && output === undefined)) {
850
1382
  throw refuse3(props.path, `${props.region === undefined ? "already exists" : "already carries that managed region"}` + " and is not this resource. Remove it, or declare it as a new resource and deploy --adopt.");
851
1383
  }
@@ -884,11 +1416,11 @@ var deleteFile = async (runner, output) => {
884
1416
  const bytes = await runner.readFile(output.path);
885
1417
  if (bytes === undefined)
886
1418
  return;
887
- const before = decoder.decode(bytes);
1419
+ const before = decoder3.decode(bytes);
888
1420
  const next = removeRegion(before, output.region);
889
1421
  if (next === before)
890
1422
  return;
891
- await runner.writeFileAtomic(output.path, encoder.encode(next), {
1423
+ await runner.writeFileAtomic(output.path, encoder2.encode(next), {
892
1424
  gid: stat.gid,
893
1425
  mode: stat.mode,
894
1426
  uid: stat.uid
@@ -896,208 +1428,45 @@ var deleteFile = async (runner, output) => {
896
1428
  };
897
1429
 
898
1430
  // src/linux/remote-file.ts
899
- var RemoteFile = Resource2("Remote.File");
900
- var RemoteFileProvider = () => Provider2.effect(RemoteFile, Effect7.gen(function* () {
1431
+ var RemoteFile = Resource3("Remote.File");
1432
+ var RemoteFileProvider = () => Provider3.effect(RemoteFile, Effect9.gen(function* () {
901
1433
  const runner = yield* HostRunnerService;
902
1434
  return RemoteFile.Provider.of({
903
- list: () => Effect7.succeed([]),
1435
+ list: () => Effect9.succeed([]),
904
1436
  read: ({ olds, output }) => lift(async () => {
905
1437
  const found = await readFileAttributes(runner, olds.path, olds.region);
906
1438
  if (found === undefined)
907
1439
  return;
908
1440
  if (olds.region !== undefined && found.contentSha256 === "")
909
1441
  return;
910
- return output === undefined ? Unowned3(found) : found;
1442
+ return output === undefined ? Unowned4(found) : found;
911
1443
  }),
912
1444
  diff: ({ instanceId, news, output }) => {
913
1445
  if (output === undefined)
914
1446
  return noteUnfinished(instanceId);
915
- if (isResolved2(news))
1447
+ if (isResolved3(news))
916
1448
  return lift(() => diffFile(runner, news, output));
917
1449
  const path = resolvedString(news, "path");
918
- return Effect7.succeed(path !== undefined && path !== output.path ? { action: "replace" } : undefined);
1450
+ return Effect9.succeed(path !== undefined && path !== output.path ? { action: "replace" } : undefined);
919
1451
  },
920
- reconcile: ({ fqn, instanceId, news, output }) => Effect7.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) => lift(() => reconcileFile(runner, news, output, adopt))),
1452
+ reconcile: ({ fqn, instanceId, news, output }) => Effect9.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) => lift(() => reconcileFile(runner, news, output, adopt))),
921
1453
  delete: ({ output }) => lift(() => deleteFile(runner, output))
922
1454
  });
923
1455
  }));
924
1456
 
925
1457
  // src/linux/unit.ts
926
- import { Resource as Resource3 } from "alchemy";
927
- import * as Provider3 from "alchemy/Provider";
928
- import * as Effect9 from "effect/Effect";
1458
+ import { Resource as Resource4 } from "alchemy";
1459
+ import * as Provider4 from "alchemy/Provider";
1460
+ import * as Effect11 from "effect/Effect";
929
1461
 
930
1462
  // src/linux/unit-handlers.ts
931
- import { Unowned as Unowned4 } from "alchemy/AdoptPolicy";
932
- import { isResolved as isResolved3 } from "alchemy/Diff";
933
- import * as Effect8 from "effect/Effect";
934
-
935
- // src/linux/systemctl.ts
936
- var SYSTEMCTL = "systemctl";
937
- var SHOW_PROPERTIES = [
938
- "Id",
939
- "LoadState",
940
- "ActiveState",
941
- "SubState",
942
- "UnitFileState",
943
- "FragmentPath",
944
- "NeedDaemonReload"
945
- ];
946
-
947
- class SystemctlError extends Error {
948
- constructor(command, exitCode, stderr) {
949
- super(`systemctl ${command} -> ${String(exitCode)}: ${stderr.trim().slice(0, 300)}`);
950
- this.name = "SystemctlError";
951
- }
952
- }
953
- var parseShow = (stdout) => {
954
- const fields = new Map;
955
- for (const line of stdout.split(`
956
- `)) {
957
- const at = line.indexOf("=");
958
- if (at <= 0)
959
- continue;
960
- const key = line.slice(0, at);
961
- if (!fields.has(key))
962
- fields.set(key, line.slice(at + 1));
963
- }
964
- return fields;
965
- };
966
- var statusOf = (stdout) => {
967
- const fields = parseShow(stdout);
968
- const loadState = fields.get("LoadState") ?? "not-found";
969
- const unitFileState = fields.get("UnitFileState") ?? "";
970
- const fragmentPath = fields.get("FragmentPath") ?? "";
971
- const subState = fields.get("SubState") ?? "";
972
- return {
973
- activeState: fields.get("ActiveState") ?? "inactive",
974
- known: loadState !== "not-found" || unitFileState !== "",
975
- loadState,
976
- needDaemonReload: fields.get("NeedDaemonReload") === "yes",
977
- ...subState === "" ? {} : { subState },
978
- ...unitFileState === "" ? {} : { unitFileState },
979
- ...fragmentPath === "" ? {} : { fragmentPath }
980
- };
981
- };
982
- var showUnit = async (runner, name) => {
983
- const result = await runner.exec([
984
- SYSTEMCTL,
985
- "show",
986
- "--no-pager",
987
- "-p",
988
- SHOW_PROPERTIES.join(","),
989
- "--",
990
- name
991
- ]);
992
- if (result.exitCode !== 0)
993
- throw new SystemctlError(`show ${name}`, result.exitCode, result.stderr);
994
- return statusOf(result.stdout);
995
- };
996
- var run = async (runner, args) => {
997
- const result = await runner.exec([SYSTEMCTL, ...args]);
998
- if (result.exitCode !== 0) {
999
- throw new SystemctlError(args.join(" "), result.exitCode, result.stderr);
1000
- }
1001
- };
1002
- var daemonReload = (runner) => run(runner, ["daemon-reload"]);
1003
- var enableUnit = (runner, name) => run(runner, ["enable", "--", name]);
1004
- var disableUnit = (runner, name) => run(runner, ["disable", "--", name]);
1005
- var startUnit = (runner, name) => run(runner, ["start", "--", name]);
1006
- var stopUnit = (runner, name) => run(runner, ["stop", "--", name]);
1007
- var restartUnit = (runner, name) => run(runner, ["restart", "--", name]);
1008
-
1009
- // src/linux/unit-form.ts
1010
- var DEFAULT_UNIT_DIRECTORY = "/etc/systemd/system";
1011
- var UNIT_SEARCH_DIRECTORIES = [
1012
- "/etc/systemd/system",
1013
- "/run/systemd/system",
1014
- "/usr/local/lib/systemd/system",
1015
- "/usr/lib/systemd/system",
1016
- "/lib/systemd/system"
1017
- ];
1018
- var UNIT_WRITE = { gid: 0, mode: 420, uid: 0 };
1019
- var digestOf2 = (text) => sha256Hex(new TextEncoder().encode(text));
1020
- var configDigest = (restartOn) => digestOf2((restartOn ?? []).join(`
1021
- `));
1022
- var isUnitRunning = (activeState, subState, started) => {
1023
- if (activeState === "active")
1024
- return true;
1025
- if (activeState !== "activating")
1026
- return false;
1027
- if (subState === "auto-restart" || subState === "auto-restart-queued")
1028
- return true;
1029
- return started;
1030
- };
1031
- var renderUnit = (sections) => `${sections.map((section) => [`[${section.name}]`, ...section.lines.map(([key, value]) => `${key}=${value}`)].join(`
1032
- `)).join(`
1033
-
1034
- `)}
1035
- `;
1036
- var unitText = (props) => props.content ?? renderUnit(props.sections ?? []);
1037
- var unitPathFor = (props) => `${props.directory ?? DEFAULT_UNIT_DIRECTORY}/${props.name}`;
1038
- var NAME = /^[A-Za-z0-9][A-Za-z0-9_.@:-]*\.([a-z]+)$/;
1039
- var TYPES = new Set([
1040
- "automount",
1041
- "device",
1042
- "mount",
1043
- "path",
1044
- "scope",
1045
- "service",
1046
- "slice",
1047
- "socket",
1048
- "swap",
1049
- "target",
1050
- "timer"
1051
- ]);
1052
- var INSTALL_KEYS = new Set(["WantedBy", "RequiredBy", "UpsertedBy", "Also", "Alias"]);
1053
- var unitProblems = (props, expect) => {
1054
- const found = [];
1055
- const type = NAME.exec(props.name)?.[1];
1056
- if (type === undefined || !TYPES.has(type)) {
1057
- found.push(`name must be <unit>.<type> with a systemd unit type, got ${JSON.stringify(props.name)}`);
1058
- } else if (expect !== undefined && type !== expect) {
1059
- found.push(`this resource declares a .${expect} unit; ${props.name} is a .${type}`);
1060
- }
1061
- if (props.content === undefined === (props.sections === undefined)) {
1062
- found.push("declare exactly one of content or sections");
1063
- }
1064
- const directory = props.directory ?? DEFAULT_UNIT_DIRECTORY;
1065
- if (!directory.startsWith("/") || directory.endsWith("/") || directory.includes("/..")) {
1066
- found.push("directory must be an absolute, normalised path with no trailing slash");
1067
- }
1068
- found.push(...textProblems(unitText(props)));
1069
- if (props.enabled !== false && !UNIT_SEARCH_DIRECTORIES.includes(directory)) {
1070
- found.push(`an enabled unit must live where systemd looks for it by name (${UNIT_SEARCH_DIRECTORIES.join(", ")}); ` + `${directory} is not one of them. Move it, or declare enabled: false.`);
1071
- }
1072
- if (props.enabled !== false && !hasInstall(props)) {
1073
- found.push("enabled units need an [Install] section with WantedBy/RequiredBy/Also/Alias; without one " + 'systemd calls the unit "static" and `systemctl enable` has nothing to link. Add one, or ' + "declare enabled: false and let something else pull it in.");
1074
- }
1075
- if (type === "timer" && !unitText(props).includes("[Timer]")) {
1076
- found.push("a .timer needs a [Timer] section");
1077
- }
1078
- return found;
1079
- };
1080
- var hasInstall = (props) => {
1081
- const text = unitText(props);
1082
- if (!text.includes("[Install]"))
1083
- return false;
1084
- const after = text.slice(text.indexOf("[Install]"));
1085
- return [...INSTALL_KEYS].some((key) => new RegExp(`^${key}=`, "m").test(after));
1086
- };
1087
- var textProblems = (text) => {
1088
- const found = [];
1089
- if (text.trim() === "")
1090
- found.push("the unit file is empty");
1091
- if (text.includes("\x00"))
1092
- found.push("the unit file contains NUL");
1093
- if (!/^\s*\[[A-Za-z]+]/.test(text))
1094
- found.push("a unit file must begin with a [Section]");
1095
- return found;
1096
- };
1463
+ import { Unowned as Unowned5 } from "alchemy/AdoptPolicy";
1464
+ import { isResolved as isResolved4 } from "alchemy/Diff";
1465
+ import * as Effect10 from "effect/Effect";
1097
1466
 
1098
1467
  // src/linux/unit-settle.ts
1099
1468
  var refuse4 = (name, message) => new Error(`Systemd.Unit ${name}: ${message}`);
1100
- var attributesOf = (props, unitSha256, status) => ({
1469
+ var attributesOf2 = (props, unitSha256, status) => ({
1101
1470
  active: status.activeState === "active" || status.activeState === "activating",
1102
1471
  activeState: status.activeState,
1103
1472
  configSha256: configDigest(props.restartOn),
@@ -1108,7 +1477,7 @@ var attributesOf = (props, unitSha256, status) => ({
1108
1477
  unitSha256,
1109
1478
  ...status.unitFileState === undefined ? {} : { unitFileState: status.unitFileState }
1110
1479
  });
1111
- var settle = async (runner, props, step) => {
1480
+ var settle2 = async (runner, props, step) => {
1112
1481
  const wantEnabled = props.enabled !== false;
1113
1482
  const wantStarted = props.started !== false;
1114
1483
  const isEnabled = step.status.unitFileState === "enabled" || step.status.unitFileState === "enabled-runtime";
@@ -1143,7 +1512,7 @@ var settle = async (runner, props, step) => {
1143
1512
  if (wantStarted && !isUnitRunning(after.activeState, after.subState, wantStarted)) {
1144
1513
  return undo(`systemctl reported success but the unit is ${after.activeState}.`);
1145
1514
  }
1146
- const settled = attributesOf(props, step.desired, after);
1515
+ const settled = attributesOf2(props, step.desired, after);
1147
1516
  if (wantEnabled && !settled.enabled) {
1148
1517
  return undo(`systemctl enable reported success but systemd calls the unit ` + `${JSON.stringify(after.unitFileState ?? "")}, not enabled.`);
1149
1518
  }
@@ -1151,61 +1520,61 @@ var settle = async (runner, props, step) => {
1151
1520
  };
1152
1521
 
1153
1522
  // src/linux/unit-preflight.ts
1154
- var decoder2 = new TextDecoder;
1155
- var assertValid = (props, expect) => {
1523
+ var decoder4 = new TextDecoder;
1524
+ var assertValid2 = (props, expect) => {
1156
1525
  const found = unitProblems(props, expect);
1157
1526
  if (found.length > 0)
1158
1527
  throw refuse4(props.name, found.join("; "));
1159
1528
  };
1160
- var assertMayWrite = (runner, name) => {
1529
+ var assertMayWrite2 = (runner, name) => {
1161
1530
  if (canActAsRoot(runner))
1162
1531
  return;
1163
1532
  throw refuse4(name, "a systemd unit is root-owned and systemctl needs root. Point the runner at a destination " + "whose ssh user is root, or provide a privileged HostRunner. This provider never calls sudo.");
1164
1533
  };
1165
- var assertUsable = (props, status) => {
1534
+ var assertUsable2 = (props, status) => {
1166
1535
  if (status.loadState === "masked" || status.unitFileState === "masked") {
1167
1536
  throw refuse4(props.name, "is masked. If that is stale, `systemctl unmask` it deliberately, then redeploy. Nothing " + "was written.");
1168
1537
  }
1169
1538
  };
1170
- var assertUnclaimed = async (runner, props) => {
1539
+ var assertUnclaimed2 = async (runner, props) => {
1171
1540
  const path = unitPathFor(props);
1172
1541
  const bytes = await runner.readFile(path);
1173
- const live = bytes === undefined ? undefined : digestOf2(decoder2.decode(bytes));
1174
- if (live !== undefined && live !== digestOf2(unitText(props))) {
1542
+ const live = bytes === undefined ? undefined : digestOf(decoder4.decode(bytes));
1543
+ if (live !== undefined && live !== digestOf(unitText(props))) {
1175
1544
  throw refuse4(props.name, `${path} is already on this host and is not this resource. Remove it, or declare it as a ` + "new resource and deploy with --adopt.");
1176
1545
  }
1177
1546
  };
1178
- var assertRenameTarget = async (runner, old, name) => {
1179
- assertMayWrite(runner, old.name);
1180
- assertMayWrite(runner, name);
1181
- assertUsable({ name }, await showUnit(runner, name));
1547
+ var assertRenameTarget2 = async (runner, old, name) => {
1548
+ assertMayWrite2(runner, old.name);
1549
+ assertMayWrite2(runner, name);
1550
+ assertUsable2({ name }, await showUnit(runner, name));
1182
1551
  };
1183
- var assertReplaceable = async (runner, next, old, expect) => {
1184
- assertValid(next, expect);
1185
- await assertRenameTarget(runner, old, next.name);
1186
- await assertUnclaimed(runner, next);
1552
+ var assertReplaceable2 = async (runner, next, old, expect) => {
1553
+ assertValid2(next, expect);
1554
+ await assertRenameTarget2(runner, old, next.name);
1555
+ await assertUnclaimed2(runner, next);
1187
1556
  await runner.checkWrite?.(unitPathFor(next), UNIT_WRITE);
1188
1557
  };
1189
1558
 
1190
1559
  // src/linux/unit-lifecycle.ts
1191
- var encoder2 = new TextEncoder;
1192
- var decoder3 = new TextDecoder;
1560
+ var encoder3 = new TextEncoder;
1561
+ var decoder5 = new TextDecoder;
1193
1562
  var readUnit = async (runner, props) => {
1194
1563
  const bytes = await runner.readFile(unitPathFor(props));
1195
1564
  const status = await showUnit(runner, props.name);
1196
1565
  if (bytes === undefined && !status.known)
1197
1566
  return;
1198
- return attributesOf(props, bytes === undefined ? "" : digestOf2(decoder3.decode(bytes)), status);
1567
+ return attributesOf2(props, bytes === undefined ? "" : digestOf(decoder5.decode(bytes)), status);
1199
1568
  };
1200
1569
  var diffUnit = async (runner, news, output, expect) => {
1201
- assertValid(news, expect);
1570
+ assertValid2(news, expect);
1202
1571
  if (news.name !== output.name || unitPathFor(news) !== output.unitPath) {
1203
- await assertReplaceable(runner, news, output, expect);
1572
+ await assertReplaceable2(runner, news, output, expect);
1204
1573
  return { action: "replace", deleteFirst: true };
1205
1574
  }
1206
- const desired2 = digestOf2(unitText(news));
1575
+ const desired2 = digestOf(unitText(news));
1207
1576
  const update = async () => {
1208
- assertMayWrite(runner, news.name);
1577
+ assertMayWrite2(runner, news.name);
1209
1578
  await runner.checkWrite?.(unitPathFor(news), UNIT_WRITE);
1210
1579
  return { action: "update" };
1211
1580
  };
@@ -1226,18 +1595,18 @@ var diffUnit = async (runner, news, output, expect) => {
1226
1595
  return status.needDaemonReload ? update() : { action: "noop" };
1227
1596
  };
1228
1597
  var reconcileUnit = async (runner, props, output, adopt = false, expect) => {
1229
- assertValid(props, expect);
1230
- assertMayWrite(runner, props.name);
1598
+ assertValid2(props, expect);
1599
+ assertMayWrite2(runner, props.name);
1231
1600
  const path = unitPathFor(props);
1232
1601
  const status = await showUnit(runner, props.name);
1233
- assertUsable(props, status);
1602
+ assertUsable2(props, status);
1234
1603
  const text = unitText(props);
1235
- const desired2 = digestOf2(text);
1604
+ const desired2 = digestOf(text);
1236
1605
  const before = await runner.readFile(path);
1237
- const liveSha = before === undefined ? undefined : digestOf2(decoder3.decode(before));
1606
+ const liveSha = before === undefined ? undefined : digestOf(decoder5.decode(before));
1238
1607
  const moved = output !== undefined && (output.name !== props.name || output.unitPath !== path);
1239
1608
  if (moved && output !== undefined)
1240
- await assertReplaceable(runner, props, output, expect);
1609
+ await assertReplaceable2(runner, props, output, expect);
1241
1610
  const prior = moved ? undefined : output;
1242
1611
  if (prior === undefined && !(adopt && output === undefined) && liveSha !== undefined && liveSha !== desired2) {
1243
1612
  throw refuse4(props.name, `${path} is already on this host and is not this resource. Remove it, or declare it as a ` + "new resource and deploy with --adopt.");
@@ -1248,14 +1617,14 @@ var reconcileUnit = async (runner, props, output, adopt = false, expect) => {
1248
1617
  const stale = prior !== undefined && prior.unitSha256 !== desired2;
1249
1618
  const configChanged = prior !== undefined && prior.configSha256 !== configDigest(props.restartOn);
1250
1619
  if (wrote)
1251
- await runner.writeFileAtomic(path, encoder2.encode(text), UNIT_WRITE);
1620
+ await runner.writeFileAtomic(path, encoder3.encode(text), UNIT_WRITE);
1252
1621
  if (wrote || status.needDaemonReload)
1253
1622
  await daemonReload(runner);
1254
1623
  const changed = wrote || stale || status.needDaemonReload;
1255
- return settle(runner, props, { before, changed, configChanged, desired: desired2, path, status });
1624
+ return settle2(runner, props, { before, changed, configChanged, desired: desired2, path, status });
1256
1625
  };
1257
1626
  var deleteUnit = async (runner, output) => {
1258
- assertMayWrite(runner, output.name);
1627
+ assertMayWrite2(runner, output.name);
1259
1628
  const status = await showUnit(runner, output.name);
1260
1629
  if (status.activeState === "active" || status.activeState === "activating") {
1261
1630
  await stopUnit(runner, output.name);
@@ -1273,54 +1642,54 @@ var deleteUnit = async (runner, output) => {
1273
1642
  };
1274
1643
 
1275
1644
  // src/linux/unit-handlers.ts
1276
- var readHandler = (runner, olds, output) => lift(async () => {
1645
+ var readHandler2 = (runner, olds, output) => lift(async () => {
1277
1646
  const found = await readUnit(runner, olds);
1278
1647
  if (found === undefined)
1279
1648
  return;
1280
- return output === undefined ? Unowned4(found) : found;
1649
+ return output === undefined ? Unowned5(found) : found;
1281
1650
  });
1282
- var diffHandler = (runner, instanceId, news, output, expect) => {
1651
+ var diffHandler2 = (runner, instanceId, news, output, expect) => {
1283
1652
  if (output === undefined)
1284
1653
  return noteUnfinished(instanceId);
1285
- if (isResolved3(news))
1654
+ if (isResolved4(news))
1286
1655
  return lift(() => diffUnit(runner, news, output, expect));
1287
1656
  const name = resolvedString(news, "name");
1288
1657
  if (name === undefined || name === output.name)
1289
- return Effect8.succeed(undefined);
1658
+ return Effect10.succeed(undefined);
1290
1659
  return lift(async () => {
1291
- await assertRenameTarget(runner, output, name);
1660
+ await assertRenameTarget2(runner, output, name);
1292
1661
  return { action: "replace", deleteFirst: true };
1293
1662
  });
1294
1663
  };
1295
- var reconcileHandler = (runner, args, expect) => Effect8.flatMap(adoptsAtApply(args), (adopt) => lift(() => reconcileUnit(runner, args.news, args.output, adopt, expect)));
1296
- var deleteHandler = (runner, output) => lift(() => deleteUnit(runner, output));
1664
+ var reconcileHandler2 = (runner, args, expect) => Effect10.flatMap(adoptsAtApply(args), (adopt) => lift(() => reconcileUnit(runner, args.news, args.output, adopt, expect)));
1665
+ var deleteHandler2 = (runner, output) => lift(() => deleteUnit(runner, output));
1297
1666
 
1298
1667
  // src/linux/unit.ts
1299
- var SystemdUnit = Resource3("Systemd.Unit");
1300
- var SystemdTimer = Resource3("Systemd.Timer");
1301
- var SystemdUnitProvider = () => Provider3.effect(SystemdUnit, Effect9.gen(function* () {
1668
+ var SystemdUnit = Resource4("Systemd.Unit");
1669
+ var SystemdTimer = Resource4("Systemd.Timer");
1670
+ var SystemdUnitProvider = () => Provider4.effect(SystemdUnit, Effect11.gen(function* () {
1302
1671
  const runner = yield* HostRunnerService;
1303
1672
  return SystemdUnit.Provider.of({
1304
- list: () => Effect9.succeed([]),
1305
- read: ({ olds, output }) => readHandler(runner, olds, output),
1306
- diff: ({ instanceId, news, output }) => diffHandler(runner, instanceId, news, output),
1307
- reconcile: (args) => reconcileHandler(runner, args),
1308
- delete: ({ output }) => deleteHandler(runner, output)
1673
+ list: () => Effect11.succeed([]),
1674
+ read: ({ olds, output }) => readHandler2(runner, olds, output),
1675
+ diff: ({ instanceId, news, output }) => diffHandler2(runner, instanceId, news, output),
1676
+ reconcile: (args) => reconcileHandler2(runner, args),
1677
+ delete: ({ output }) => deleteHandler2(runner, output)
1309
1678
  });
1310
1679
  }));
1311
- var SystemdTimerProvider = () => Provider3.effect(SystemdTimer, Effect9.gen(function* () {
1680
+ var SystemdTimerProvider = () => Provider4.effect(SystemdTimer, Effect11.gen(function* () {
1312
1681
  const runner = yield* HostRunnerService;
1313
1682
  return SystemdTimer.Provider.of({
1314
- list: () => Effect9.succeed([]),
1315
- read: ({ olds, output }) => readHandler(runner, olds, output),
1316
- diff: ({ instanceId, news, output }) => diffHandler(runner, instanceId, news, output, "timer"),
1317
- reconcile: (args) => reconcileHandler(runner, args, "timer"),
1318
- delete: ({ output }) => deleteHandler(runner, output)
1683
+ list: () => Effect11.succeed([]),
1684
+ read: ({ olds, output }) => readHandler2(runner, olds, output),
1685
+ diff: ({ instanceId, news, output }) => diffHandler2(runner, instanceId, news, output, "timer"),
1686
+ reconcile: (args) => reconcileHandler2(runner, args, "timer"),
1687
+ delete: ({ output }) => deleteHandler2(runner, output)
1319
1688
  });
1320
1689
  }));
1321
1690
 
1322
1691
  // src/linux/providers.ts
1323
- var linuxProviders = (runner) => Layer2.mergeAll(HostDirectoryProvider(), RemoteFileProvider(), SystemdTimerProvider(), SystemdUnitProvider()).pipe(Layer2.provide(hostRunnerLayer(runner)));
1692
+ var linuxProviders = (runner) => Layer2.mergeAll(HostDirectoryProvider(), PodmanContainerProvider(), RemoteFileProvider(), SystemdTimerProvider(), SystemdUnitProvider()).pipe(Layer2.provide(hostRunnerLayer(runner)));
1324
1693
  // src/linux/ssh-runner.ts
1325
1694
  import { spawn } from "node:child_process";
1326
1695
  import { randomBytes } from "node:crypto";
@@ -2726,6 +3095,10 @@ export {
2726
3095
  HostDirectory,
2727
3096
  HostDirectoryProvider,
2728
3097
  HostRunnerService,
3098
+ PodmanContainer,
3099
+ PodmanContainerProvider,
3100
+ QUADLET_DEFAULT_DIRECTORY,
3101
+ QUADLET_SEARCH_DIRECTORIES,
2729
3102
  RemoteFile,
2730
3103
  RemoteFileProvider,
2731
3104
  SystemdTimer,
@@ -2740,5 +3113,5 @@ export {
2740
3113
  sshSudoRunner
2741
3114
  };
2742
3115
 
2743
- //# debugId=19CF970890A2548664756E2164756E21
3116
+ //# debugId=1EC8A0E327D500A164756E2164756E21
2744
3117
  //# sourceMappingURL=index.js.map