@homeflare/alchemy 0.19.1 → 0.20.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.
@@ -624,6 +624,7 @@ var tokens = (spec) => {
624
624
  end: `${comment} END ${spec.name}`
625
625
  };
626
626
  };
627
+ var sameRegion = (a, b) => a === undefined || b === undefined ? a === undefined && b === undefined : a.name === b.name && (a.comment ?? DEFAULT_COMMENT) === (b.comment ?? DEFAULT_COMMENT);
627
628
  var regionProblems = (spec) => {
628
629
  const found = [];
629
630
  const comment = spec.comment ?? DEFAULT_COMMENT;
@@ -748,6 +749,16 @@ var identity = async (runner, props) => {
748
749
  return { ...uid === undefined ? {} : { uid }, ...gid === undefined ? {} : { gid } };
749
750
  };
750
751
  var digestOf = (text) => sha256Hex(encoder.encode(text));
752
+ var relocation = (props, output) => {
753
+ if (props.path !== output.path)
754
+ return "path";
755
+ if (sameRegion(props.region, output.region))
756
+ return "none";
757
+ if (props.region === undefined || output.region === undefined) {
758
+ throw refuse3(props.path, `changes between owning the whole file and owning the managed region ` + `${JSON.stringify((props.region ?? output.region)?.name ?? "")} at the same path. Those ` + "are two different claims on one file: destroy this resource and declare a new one.");
759
+ }
760
+ return "region";
761
+ };
751
762
  var ownedDigest = (file, region) => {
752
763
  if (file === undefined)
753
764
  return;
@@ -814,7 +825,7 @@ var planWrite = async (runner, props, want) => {
814
825
  // src/linux/remote-file-lifecycle.ts
815
826
  var diffFile = async (runner, news, output) => {
816
827
  const want = await identity(runner, news);
817
- if (news.path !== output.path) {
828
+ if (relocation(news, output) === "path") {
818
829
  await runner.checkWrite?.(news.path, { mode: news.mode ?? DEFAULT_MODE2, ...want });
819
830
  return { action: "replace" };
820
831
  }
@@ -830,8 +841,8 @@ var reconcileFile = async (runner, props, output, adopt = false) => {
830
841
  if (want.uid !== undefined && want.uid !== runner.effectiveUid() && !canActAsRoot(runner)) {
831
842
  throw refuse3(props.path, `owner ${String(props.owner)} is not the deploying user; only root may chown. Deploy through ` + "a root destination or a privileged HostRunner. This provider never calls sudo itself.");
832
843
  }
833
- const moved = output !== undefined && output.path !== props.path;
834
- const prior = moved ? undefined : output;
844
+ const move = output === undefined ? "none" : relocation(props, output);
845
+ const prior = move === "none" ? output : undefined;
835
846
  const planned = await planWrite(runner, props, want);
836
847
  const live = ownedDigest(planned.before, props.region);
837
848
  const declared = digestOf(props.content);
@@ -849,9 +860,16 @@ var reconcileFile = async (runner, props, output, adopt = false) => {
849
860
  }
850
861
  throw refuse3(props.path, "the write returned but the file on disk does not match the declaration");
851
862
  }
852
- if (moved && output !== undefined)
853
- await deleteFile(runner, output);
854
- return after;
863
+ if (move === "none" || output === undefined)
864
+ return after;
865
+ await deleteFile(runner, output);
866
+ if (move === "path")
867
+ return after;
868
+ const settled = await readFileAttributes(runner, props.path, props.region);
869
+ if (settled === undefined || settled.contentSha256 !== declared) {
870
+ throw refuse3(props.path, "removing the previous managed block did not leave ours intact");
871
+ }
872
+ return settled;
855
873
  };
856
874
  var deleteFile = async (runner, output) => {
857
875
  const stat = await runner.stat(output.path);
@@ -1148,11 +1166,14 @@ var assertUnclaimed = async (runner, props) => {
1148
1166
  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.");
1149
1167
  }
1150
1168
  };
1169
+ var assertRenameTarget = async (runner, old, name) => {
1170
+ assertMayWrite(runner, old.name);
1171
+ assertMayWrite(runner, name);
1172
+ assertUsable({ name }, await showUnit(runner, name));
1173
+ };
1151
1174
  var assertReplaceable = async (runner, next, old, expect) => {
1152
1175
  assertValid(next, expect);
1153
- assertMayWrite(runner, old.name);
1154
- assertMayWrite(runner, next.name);
1155
- assertUsable(next, await showUnit(runner, next.name));
1176
+ await assertRenameTarget(runner, old, next.name);
1156
1177
  await assertUnclaimed(runner, next);
1157
1178
  await runner.checkWrite?.(unitPathFor(next), UNIT_WRITE);
1158
1179
  };
@@ -1253,7 +1274,12 @@ var diffHandler = (runner, instanceId, news, output, expect) => {
1253
1274
  if (isResolved3(news))
1254
1275
  return lift(() => diffUnit(runner, news, output, expect));
1255
1276
  const name = resolvedString(news, "name");
1256
- return Effect8.succeed(name !== undefined && name !== output.name ? { action: "replace", deleteFirst: true } : undefined);
1277
+ if (name === undefined || name === output.name)
1278
+ return Effect8.succeed(undefined);
1279
+ return lift(async () => {
1280
+ await assertRenameTarget(runner, output, name);
1281
+ return { action: "replace", deleteFirst: true };
1282
+ });
1257
1283
  };
1258
1284
  var reconcileHandler = (runner, args, expect) => Effect8.flatMap(adoptsAtApply(args), (adopt) => lift(() => reconcileUnit(runner, args.news, args.output, adopt, expect)));
1259
1285
  var deleteHandler = (runner, output) => lift(() => deleteUnit(runner, output));
@@ -1571,5 +1597,5 @@ export {
1571
1597
  sshRunner
1572
1598
  };
1573
1599
 
1574
- //# debugId=6BC8BE5DBFF285E364756E2164756E21
1600
+ //# debugId=999A0F25FFF74BEF64756E2164756E21
1575
1601
  //# sourceMappingURL=index.js.map