@homeflare/alchemy 0.58.0 → 0.59.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.
package/README.md CHANGED
@@ -385,6 +385,23 @@ before export: every header dropped, every query string stripped, a denylisted h
385
385
  blanked. Options, the redaction policy and what a spike measured actually arriving at a collector:
386
386
  [docs/telemetry.md](./docs/telemetry.md) · [docs/telemetry-spike.md](./docs/telemetry-spike.md).
387
387
 
388
+ ## Duplicate resource ids — `@homeflare/alchemy/scope`
389
+
390
+ ⛔ Two resources of different types declaring the same logical id in one stack scope used to
391
+ collide silently — Alchemy's own idempotent-registration path treats the second one as a
392
+ reference to the first, and the second resource's props never reach a plan. `guardDuplicateIds`
393
+ wraps a resource class so a collision dies at registration, naming both types:
394
+
395
+ ```ts
396
+ import { Resource } from 'alchemy';
397
+ import { guardDuplicateIds } from '@homeflare/alchemy/scope';
398
+
399
+ export const MyResource = guardDuplicateIds(Resource<MyResource>('My.Resource'));
400
+ ```
401
+
402
+ The measured incident, what this does and does not cover, and the upstream issue proposed for
403
+ `alchemy` itself: [docs/duplicate-resource-id.md](./docs/duplicate-resource-id.md).
404
+
388
405
  ## Credentials
389
406
 
390
407
  ⛔ **Mint a short-lived, scoped token** — never a long-lived one, never a Global API Key. How each
@@ -28,6 +28,12 @@
28
28
  * place that discharges them — scoped to the handful of effects that actually call
29
29
  * `@distilled.cloud/caddy`'s operations, never leaking into a sibling fetch-based provider merged
30
30
  * into the same stack (admin.ts's own ⛔; MEASURED 2026-09-26, admin-transport-scope.test.ts).
31
+ * ⛔ `CaddyConfig` IS WRAPPED IN `guardDuplicateIds` (scope/guard.ts). MEASURED, homeflare-mini PR
32
+ * 329: a `NixJobRetirement('caddy', …)` declared in the same stack as this resource's `CADDY_ID
33
+ * = 'caddy'` collided silently — Alchemy's own `Resource()` treated the second registration as
34
+ * an idempotent re-reference to the first, so the retirement's props were never written
35
+ * anywhere a plan could see (`scope/duplicate-id.ts` has the full mechanism). This resource was
36
+ * one half of that collision, so it is the first to carry the guard.
31
37
  */
32
38
  import { Resource } from 'alchemy';
33
39
  import * as Provider from 'alchemy/Provider';
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/caddy/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKhF,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEhF,MAAM,WAAW,WAAY,SAAQ,QAAQ,CAC3C,cAAc,EACd,gBAAgB,EAChB,qBAAqB,CACtB;CAAG;AAEJ,eAAO,MAAM,WAAW,8CAEtB,CAAC;AAoBH,eAAO,MAAM,mBAAmB,oHA+F7B,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/caddy/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAK7C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKhF,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEhF,MAAM,WAAW,WAAY,SAAQ,QAAQ,CAC3C,cAAc,EACd,gBAAgB,EAChB,qBAAqB,CACtB;CAAG;AAEJ,eAAO,MAAM,WAAW,8CAIvB,CAAC;AAoBF,eAAO,MAAM,mBAAmB,oHA+F7B,CAAC"}
@@ -169,7 +169,7 @@ import { Resource } from "alchemy";
169
169
  import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
170
170
  import { isResolved } from "alchemy/Diff";
171
171
  import * as Provider from "alchemy/Provider";
172
- import * as Effect11 from "effect/Effect";
172
+ import * as Effect13 from "effect/Effect";
173
173
 
174
174
  // src/launchd/host-effect.ts
175
175
  import * as Effect2 from "effect/Effect";
@@ -395,21 +395,88 @@ var refuseTakeover = (owner, what) => Effect6.gen(function* () {
395
395
  });
396
396
  var claimFor = (owner) => (what) => refuseTakeover(owner, what);
397
397
 
398
+ // src/scope/guard.ts
399
+ import * as Effect8 from "effect/Effect";
400
+
401
+ // src/scope/duplicate-id.ts
402
+ import { toFqn } from "alchemy/FQN";
403
+ import { CurrentNamespace } from "alchemy/Namespace";
404
+ import { Stack as Stack4 } from "alchemy/Stack";
405
+ import * as Data from "effect/Data";
406
+ import * as Effect7 from "effect/Effect";
407
+
408
+ class DuplicateResourceIdError extends Data.TaggedError("DuplicateResourceIdError") {
409
+ }
410
+ var scopeLabel = (namespace) => {
411
+ if (!namespace)
412
+ return "(root)";
413
+ const path = [];
414
+ let node = namespace;
415
+ while (node) {
416
+ path.unshift(node.Id);
417
+ node = node.Parent;
418
+ }
419
+ return path.join("/");
420
+ };
421
+ var registries = new WeakMap;
422
+ var registryFor = (stack) => {
423
+ const existing = registries.get(stack);
424
+ if (existing)
425
+ return existing;
426
+ const created = new Map;
427
+ registries.set(stack, created);
428
+ return created;
429
+ };
430
+ var claimResourceId = (type, id) => Effect7.gen(function* () {
431
+ const stack = yield* Stack4;
432
+ const namespace = yield* CurrentNamespace;
433
+ const fqn = toFqn(namespace, id);
434
+ const registry = registryFor(stack);
435
+ const firstType = registry.get(fqn);
436
+ if (firstType === undefined) {
437
+ registry.set(fqn, type);
438
+ return;
439
+ }
440
+ if (firstType !== type) {
441
+ return yield* Effect7.die(new DuplicateResourceIdError({
442
+ message: `REFUSING: duplicate resource id "${fqn}" in scope ${scopeLabel(namespace)}: ` + `first declared by ${firstType}, again by ${type}`,
443
+ fqn,
444
+ scope: scopeLabel(namespace),
445
+ firstType,
446
+ secondType: type
447
+ }));
448
+ }
449
+ });
450
+
451
+ // src/scope/guard.ts
452
+ var guardDuplicateIds = (resourceClass) => new Proxy(resourceClass, {
453
+ apply(target, thisArg, args) {
454
+ const id = args[0];
455
+ if (typeof id !== "string") {
456
+ return Reflect.apply(target, thisArg, args);
457
+ }
458
+ return Effect8.gen(function* () {
459
+ yield* claimResourceId(resourceClass.Type, id);
460
+ return yield* Reflect.apply(target, thisArg, args);
461
+ });
462
+ }
463
+ });
464
+
398
465
  // src/caddy/config-lifecycle.ts
399
- import * as Effect9 from "effect/Effect";
466
+ import * as Effect11 from "effect/Effect";
400
467
  import * as Result2 from "effect/Result";
401
468
 
402
469
  // src/caddy/admin-calls.ts
403
- import * as Effect7 from "effect/Effect";
470
+ import * as Effect9 from "effect/Effect";
404
471
  import * as Caddy from "@distilled.cloud/caddy";
405
472
  var CADDYFILE = "text/caddyfile";
406
473
  var describe = (warning) => `${warning.file ?? "Caddyfile"}:${String(warning.line ?? 0)}: ${warning.message ?? "(no message)"}`;
407
- var adaptCaddyfile = (caddyfile) => Effect7.map(Caddy.Services.admin.adaptConfig({ config: caddyfile, contentType: CADDYFILE }), (response) => ({
474
+ var adaptCaddyfile = (caddyfile) => Effect9.map(Caddy.Services.admin.adaptConfig({ config: caddyfile, contentType: CADDYFILE }), (response) => ({
408
475
  config: response.result ?? null,
409
476
  warnings: (response.warnings ?? []).map(describe)
410
477
  }));
411
- var readRunningConfig = () => Effect7.map(Caddy.Services.admin.getConfig({ path: "" }), (response) => response.value ?? null);
412
- var loadCaddyfile = (caddyfile, sourceFile) => Effect7.map(Caddy.Services.admin.loadConfig({
478
+ var readRunningConfig = () => Effect9.map(Caddy.Services.admin.getConfig({ path: "" }), (response) => response.value ?? null);
479
+ var loadCaddyfile = (caddyfile, sourceFile) => Effect9.map(Caddy.Services.admin.loadConfig({
413
480
  config: caddyfile,
414
481
  contentType: CADDYFILE,
415
482
  ...sourceFile === undefined ? {} : { sourceAdapter: "caddyfile", sourceFile }
@@ -494,12 +561,12 @@ var adminProblems = (adapted, transport) => {
494
561
  };
495
562
 
496
563
  // src/caddy/config-errors.ts
497
- import * as Effect8 from "effect/Effect";
564
+ import * as Effect10 from "effect/Effect";
498
565
  var refuse = (endpoint, message) => new Error(`Caddy.Config at ${endpoint}: ${message}`);
499
566
  var short = (digest) => digest.slice(0, 12);
500
567
  var messageOf = (error) => ("message" in error) && typeof error.message === "string" ? error.message : String(error);
501
568
  var operationFailure = (endpoint, op, error) => error._tag === "LoadRefused" ? refuse(endpoint, `Caddy refused the Caddyfile (${error._tag}, a 200 whose body carried the error, not a ` + `failure status) — ${error.message}`) : refuse(endpoint, `${op} failed (${error._tag}) — ${messageOf(error)}`);
502
- var wrapOperation = (endpoint, op) => (effect) => effect.pipe(Effect8.mapError((error) => isUnreachable(error) ? error : operationFailure(endpoint, op, error)));
569
+ var wrapOperation = (endpoint, op) => (effect) => effect.pipe(Effect10.mapError((error) => isUnreachable(error) ? error : operationFailure(endpoint, op, error)));
503
570
 
504
571
  // src/launchd/secret-tripwire.ts
505
572
  var ALTERNATIVE = "props are stored unencrypted in Alchemy state. Have a secret renderer (e.g. openbao-agent) " + "write it to a root-owned file and declare the file path instead (FOO_FILE=/path, --foo-file /path).";
@@ -848,18 +915,18 @@ var servesNothing = (config) => {
848
915
  const apps = typeof config === "object" && config !== null ? config.apps : undefined;
849
916
  return typeof apps !== "object" || apps === null || Object.keys(apps).length === 0;
850
917
  };
851
- var desiredConfig = (props) => Effect9.gen(function* () {
918
+ var desiredConfig = (props) => Effect11.gen(function* () {
852
919
  const { endpoint, listener } = yield* CaddyAdminService;
853
920
  const found = configProblems(props);
854
921
  if (found.length > 0)
855
- return yield* Effect9.fail(refuse(endpoint, found.join("; ")));
922
+ return yield* Effect11.fail(refuse(endpoint, found.join("; ")));
856
923
  const adapted = yield* adaptCaddyfile(props.caddyfile).pipe(wrapOperation(endpoint, "POST /adapt"));
857
924
  if (servesNothing(adapted.config)) {
858
- return yield* Effect9.fail(refuse(endpoint, "the Caddyfile adapts to no apps — loading it would stop every site"));
925
+ return yield* Effect11.fail(refuse(endpoint, "the Caddyfile adapts to no apps — loading it would stop every site"));
859
926
  }
860
927
  const guard = adminProblems(adapted.config, listener);
861
928
  if (guard.length > 0)
862
- return yield* Effect9.fail(refuse(endpoint, guard.join("; ")));
929
+ return yield* Effect11.fail(refuse(endpoint, guard.join("; ")));
863
930
  return { digest: configDigest(adapted.config), warnings: adapted.warnings };
864
931
  });
865
932
  var attributesOf = (endpoint, running, sourceFile) => ({
@@ -867,13 +934,13 @@ var attributesOf = (endpoint, running, sourceFile) => ({
867
934
  endpoint,
868
935
  ...sourceFile === undefined ? {} : { sourceFile }
869
936
  });
870
- var readLive = (sourceFile) => Effect9.gen(function* () {
937
+ var readLive = (sourceFile) => Effect11.gen(function* () {
871
938
  const { endpoint } = yield* CaddyAdminService;
872
939
  const running = yield* readRunningConfig().pipe(wrapOperation(endpoint, "GET /config/"));
873
940
  return attributesOf(endpoint, running, sourceFile);
874
941
  });
875
942
  var claimable = (running, declaredDigest) => servesNothing(running) || configDigest(running) === declaredDigest;
876
- var probeLive = (caddyfile, sourceFile) => Effect9.gen(function* () {
943
+ var probeLive = (caddyfile, sourceFile) => Effect11.gen(function* () {
877
944
  const { endpoint } = yield* CaddyAdminService;
878
945
  const running = yield* readRunningConfig();
879
946
  if (servesNothing(running))
@@ -882,12 +949,12 @@ var probeLive = (caddyfile, sourceFile) => Effect9.gen(function* () {
882
949
  if (caddyfile === undefined) {
883
950
  return { attributes, ours: false, unchecked: "the stored Caddyfile is not plain text" };
884
951
  }
885
- const desired = yield* Effect9.result(desiredConfig({ caddyfile }));
952
+ const desired = yield* Effect11.result(desiredConfig({ caddyfile }));
886
953
  if (Result2.isSuccess(desired)) {
887
954
  return { attributes, ours: claimable(running, desired.success.digest) };
888
955
  }
889
956
  if (isUnreachable(desired.failure))
890
- return yield* Effect9.fail(desired.failure);
957
+ return yield* Effect11.fail(desired.failure);
891
958
  const cause = desired.failure;
892
959
  return {
893
960
  attributes,
@@ -897,7 +964,7 @@ var probeLive = (caddyfile, sourceFile) => Effect9.gen(function* () {
897
964
  });
898
965
 
899
966
  // src/caddy/config-reconcile.ts
900
- import * as Effect10 from "effect/Effect";
967
+ import * as Effect12 from "effect/Effect";
901
968
  import * as Result3 from "effect/Result";
902
969
 
903
970
  // src/caddy/format-warnings.ts
@@ -909,100 +976,100 @@ var splitFormattingWarning = (warnings) => ({
909
976
  var formattingFixLine = (endpoint) => `Caddy.Config at ${endpoint}: Caddyfile is not formatted — run \`caddy fmt\` on it, or format ` + "it with this package's formatCaddyfile() before declaring it, to silence this warning.";
910
977
 
911
978
  // src/caddy/config-reconcile.ts
912
- var diffConfig = (news, output) => Effect10.gen(function* () {
979
+ var diffConfig = (news, output) => Effect12.gen(function* () {
913
980
  const { endpoint } = yield* CaddyAdminService;
914
981
  const want = yield* desiredConfig(news);
915
982
  const { formatting } = splitFormattingWarning(want.warnings);
916
983
  if (formatting.length > 0)
917
- yield* Effect10.logWarning(formattingFixLine(endpoint));
984
+ yield* Effect12.logWarning(formattingFixLine(endpoint));
918
985
  const live = yield* readLive();
919
986
  const converged = want.digest === live.configSha256 && live.configSha256 === output.configSha256 && news.sourceFile === output.sourceFile && endpoint === output.endpoint;
920
987
  return converged ? { action: "noop" } : { action: "update" };
921
988
  });
922
- var reconcileConfig = (props, authority) => Effect10.gen(function* () {
989
+ var reconcileConfig = (props, authority) => Effect12.gen(function* () {
923
990
  const { endpoint } = yield* CaddyAdminService;
924
991
  const want = yield* desiredConfig(props);
925
992
  const running = yield* readRunningConfig().pipe(wrapOperation(endpoint, "GET /config/"));
926
993
  const before = configDigest(running);
927
994
  const known = before === authority.stored || claimable(running, want.digest);
928
995
  if (!authority.takeOver && !known) {
929
- return yield* Effect10.fail(refuse(endpoint, `Caddy runs config ${short(before)}, which this stack did not load, and the Caddyfile ` + `adapts to ${short(want.digest)} — loading it would replace every site that config ` + "serves. Deploy with --adopt (or wrap the resource in adopt(true)) to take this Caddy " + "over, or point caddyProviders() at the Caddy you meant."));
996
+ return yield* Effect12.fail(refuse(endpoint, `Caddy runs config ${short(before)}, which this stack did not load, and the Caddyfile ` + `adapts to ${short(want.digest)} — loading it would replace every site that config ` + "serves. Deploy with --adopt (or wrap the resource in adopt(true)) to take this Caddy " + "over, or point caddyProviders() at the Caddy you meant."));
930
997
  }
931
998
  let warnings = want.warnings;
932
999
  const loaded = before !== want.digest;
933
1000
  if (loaded) {
934
- const outcome = yield* Effect10.result(loadCaddyfile(props.caddyfile, props.sourceFile));
1001
+ const outcome = yield* Effect12.result(loadCaddyfile(props.caddyfile, props.sourceFile));
935
1002
  if (Result3.isFailure(outcome)) {
936
1003
  const error = outcome.failure;
937
1004
  if (isUnreachable(error))
938
- return yield* Effect10.fail(error);
939
- const afterRead = yield* Effect10.result(readLive());
1005
+ return yield* Effect12.fail(error);
1006
+ const afterRead = yield* Effect12.result(readLive());
940
1007
  const after = Result3.isSuccess(afterRead) ? afterRead.success : undefined;
941
1008
  const state = after === undefined ? "and the running config could not be read back" : after.configSha256 === before ? "Caddy kept the previous config (still serving)" : `and the running config is now ${short(after.configSha256)}, not the previous ${short(before)}`;
942
1009
  const reason = error._tag === "LoadRefused" ? `${error.message} (LoadRefused: a 200 whose body carried the error, not a failure status)` : messageOf(error);
943
- return yield* Effect10.fail(refuse(endpoint, `Caddy refused the Caddyfile — ${reason}; ${state}`));
1010
+ return yield* Effect12.fail(refuse(endpoint, `Caddy refused the Caddyfile — ${reason}; ${state}`));
944
1011
  }
945
1012
  warnings = outcome.success;
946
1013
  }
947
1014
  const attributes = yield* readLive(props.sourceFile);
948
1015
  if (attributes.configSha256 !== want.digest) {
949
- return yield* Effect10.fail(refuse(endpoint, `after the load Caddy runs config ${short(attributes.configSha256)}, not the ` + `${short(want.digest)} this Caddyfile adapts to — another writer changed it, or it was ` + "not applied"));
1016
+ return yield* Effect12.fail(refuse(endpoint, `after the load Caddy runs config ${short(attributes.configSha256)}, not the ` + `${short(want.digest)} this Caddyfile adapts to — another writer changed it, or it was ` + "not applied"));
950
1017
  }
951
1018
  return { attributes, loaded, warnings };
952
1019
  });
953
1020
 
954
1021
  // src/caddy/config.ts
955
- var CaddyConfig = Resource("Caddy.Config", {
1022
+ var CaddyConfig = guardDuplicateIds(Resource("Caddy.Config", {
956
1023
  defaultRemovalPolicy: "retain"
957
- });
958
- var planWithoutCaddy = (admin, fallback) => (error) => Effect11.as(Effect11.logWarning(`Caddy.Config: no Caddy at ${admin.endpoint} ` + `(${error instanceof Error ? error.message : String(error)}); planning without it — ` + "the Caddyfile is validated when the deploy reaches Caddy"), fallback);
959
- var CaddyConfigProvider = () => Provider.effect(CaddyConfig, Effect11.gen(function* () {
1024
+ }));
1025
+ var planWithoutCaddy = (admin, fallback) => (error) => Effect13.as(Effect13.logWarning(`Caddy.Config: no Caddy at ${admin.endpoint} ` + `(${error instanceof Error ? error.message : String(error)}); planning without it — ` + "the Caddyfile is validated when the deploy reaches Caddy"), fallback);
1026
+ var CaddyConfigProvider = () => Provider.effect(CaddyConfig, Effect13.gen(function* () {
960
1027
  const admin = yield* CaddyAdminService;
961
1028
  const transportLayer = yield* CaddyAdminTransport;
962
- const probe = (caddyfile, sourceFile) => Effect11.flatMap(probeLive(caddyfile, sourceFile), (found) => {
1029
+ const probe = (caddyfile, sourceFile) => Effect13.flatMap(probeLive(caddyfile, sourceFile), (found) => {
963
1030
  if (found === undefined)
964
- return Effect11.succeed(undefined);
1031
+ return Effect13.succeed(undefined);
965
1032
  if (found.ours)
966
- return Effect11.succeed(found.attributes);
1033
+ return Effect13.succeed(found.attributes);
967
1034
  const unowned = Unowned2(found.attributes);
968
- return found.unchecked === undefined ? Effect11.succeed(unowned) : Effect11.as(Effect11.logWarning(`Caddy.Config at ${admin.endpoint}: the running config could not be compared ` + `with the declared Caddyfile (${found.unchecked}), so it is not treated as ours`), unowned);
1035
+ return found.unchecked === undefined ? Effect13.succeed(unowned) : Effect13.as(Effect13.logWarning(`Caddy.Config at ${admin.endpoint}: the running config could not be compared ` + `with the declared Caddyfile (${found.unchecked}), so it is not treated as ours`), unowned);
969
1036
  });
970
1037
  return CaddyConfig.Provider.of({
971
- list: () => Effect11.succeed([]),
972
- read: ({ olds, output }) => Effect11.gen(function* () {
1038
+ list: () => Effect13.succeed([]),
1039
+ read: ({ olds, output }) => Effect13.gen(function* () {
973
1040
  return output === undefined ? yield* probe(resolvedString(olds, "caddyfile"), resolvedString(olds, "sourceFile")) : yield* readLive(resolvedString(olds, "sourceFile"));
974
- }).pipe(Effect11.provide(transportLayer), Effect11.catchIf(isUnreachable, planWithoutCaddy(admin, undefined))),
1041
+ }).pipe(Effect13.provide(transportLayer), Effect13.catchIf(isUnreachable, planWithoutCaddy(admin, undefined))),
975
1042
  diff: ({ news, output }) => {
976
1043
  if (output === undefined)
977
- return Effect11.succeed(undefined);
1044
+ return Effect13.succeed(undefined);
978
1045
  const update = planWithoutCaddy(admin, { action: "update" });
979
1046
  if (isResolved(news)) {
980
- return diffConfig(news, output).pipe(Effect11.provide(transportLayer), Effect11.catchIf(isUnreachable, update));
1047
+ return diffConfig(news, output).pipe(Effect13.provide(transportLayer), Effect13.catchIf(isUnreachable, update));
981
1048
  }
982
1049
  const caddyfile = resolvedString(news, "caddyfile");
983
1050
  if (caddyfile === undefined)
984
- return Effect11.succeed(undefined);
985
- return Effect11.as(diffConfig({ caddyfile }, output), { action: "update" }).pipe(Effect11.provide(transportLayer), Effect11.catchIf(isUnreachable, update));
1051
+ return Effect13.succeed(undefined);
1052
+ return Effect13.as(diffConfig({ caddyfile }, output), { action: "update" }).pipe(Effect13.provide(transportLayer), Effect13.catchIf(isUnreachable, update));
986
1053
  },
987
- reconcile: ({ fqn, news, output }) => Effect11.gen(function* () {
1054
+ reconcile: ({ fqn, news, output }) => Effect13.gen(function* () {
988
1055
  const sameCaddy = output !== undefined && output.endpoint === admin.endpoint;
989
1056
  const takeOver = sameCaddy || (yield* adoptEnabled(fqn));
990
1057
  const stored = output === undefined ? {} : { stored: output.configSha256 };
991
- const applied = yield* reconcileConfig(news, { takeOver, ...stored }).pipe(Effect11.provide(transportLayer));
1058
+ const applied = yield* reconcileConfig(news, { takeOver, ...stored }).pipe(Effect13.provide(transportLayer));
992
1059
  const { formatting, rest } = splitFormattingWarning(applied.warnings);
993
1060
  if (formatting.length > 0) {
994
- yield* Effect11.logWarning(formattingFixLine(admin.endpoint));
1061
+ yield* Effect13.logWarning(formattingFixLine(admin.endpoint));
995
1062
  }
996
1063
  for (const warning of rest) {
997
- yield* Effect11.logWarning(`Caddy.Config at ${admin.endpoint}: ${warning}`);
1064
+ yield* Effect13.logWarning(`Caddy.Config at ${admin.endpoint}: ${warning}`);
998
1065
  }
999
1066
  return applied.attributes;
1000
1067
  }),
1001
- delete: () => Effect11.void
1068
+ delete: () => Effect13.void
1002
1069
  });
1003
1070
  }));
1004
1071
  // src/caddy/format.ts
1005
- import * as Effect12 from "effect/Effect";
1072
+ import * as Effect14 from "effect/Effect";
1006
1073
  import * as Stream from "effect/Stream";
1007
1074
  import * as ChildProcess from "effect/process/ChildProcess";
1008
1075
  import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
@@ -1029,7 +1096,7 @@ class CaddyFmtFailed extends Error {
1029
1096
  this.name = "CaddyFmtFailed";
1030
1097
  }
1031
1098
  }
1032
- var formatCaddyfile = (text, options = {}) => Effect12.gen(function* () {
1099
+ var formatCaddyfile = (text, options = {}) => Effect14.gen(function* () {
1033
1100
  const binaryPath = options.binaryPath ?? DEFAULT_CADDY_BINARY;
1034
1101
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
1035
1102
  const input = new TextEncoder().encode(text);
@@ -1038,13 +1105,13 @@ var formatCaddyfile = (text, options = {}) => Effect12.gen(function* () {
1038
1105
  stderr: "pipe",
1039
1106
  stdin: Stream.make(input),
1040
1107
  stdout: "pipe"
1041
- }).pipe(spawner.spawn, Effect12.flatMap((child) => Effect12.all({
1108
+ }).pipe(spawner.spawn, Effect14.flatMap((child) => Effect14.all({
1042
1109
  exitCode: child.exitCode,
1043
- stderr: child.stderr.pipe(Stream.decodeText, Stream.mkString, Effect12.map((out) => out.trim())),
1110
+ stderr: child.stderr.pipe(Stream.decodeText, Stream.mkString, Effect14.map((out) => out.trim())),
1044
1111
  stdout: child.stdout.pipe(Stream.decodeText, Stream.mkString)
1045
- }, { concurrency: "unbounded" })), Effect12.scoped, Effect12.catchTag("PlatformError", (error) => error.reason._tag === "NotFound" ? Effect12.fail(new CaddyFmtNotFound(binaryPath, error)) : Effect12.fail(error)));
1112
+ }, { concurrency: "unbounded" })), Effect14.scoped, Effect14.catchTag("PlatformError", (error) => error.reason._tag === "NotFound" ? Effect14.fail(new CaddyFmtNotFound(binaryPath, error)) : Effect14.fail(error)));
1046
1113
  if (result4.exitCode !== 0) {
1047
- return yield* Effect12.fail(new CaddyFmtFailed(binaryPath, result4.exitCode, result4.stderr));
1114
+ return yield* Effect14.fail(new CaddyFmtFailed(binaryPath, result4.exitCode, result4.stderr));
1048
1115
  }
1049
1116
  return result4.stdout;
1050
1117
  });
@@ -1115,7 +1182,7 @@ var localCaddyAdmin = (options = {}) => {
1115
1182
  import * as Layer4 from "effect/Layer";
1116
1183
  var caddyProviders = (transport = localCaddyAdmin()) => CaddyConfigProvider().pipe(Layer4.provideMerge(caddyAdminLayer(transport)));
1117
1184
  // src/caddy/with-file.ts
1118
- import * as Effect14 from "effect/Effect";
1185
+ import * as Effect16 from "effect/Effect";
1119
1186
  import * as RemovalPolicy from "alchemy/RemovalPolicy";
1120
1187
 
1121
1188
  // src/launchd/host-file.ts
@@ -1123,7 +1190,7 @@ import { Resource as Resource2 } from "alchemy";
1123
1190
  import { Unowned as Unowned3 } from "alchemy/AdoptPolicy";
1124
1191
  import { isResolved as isResolved2 } from "alchemy/Diff";
1125
1192
  import * as Provider2 from "alchemy/Provider";
1126
- import * as Effect13 from "effect/Effect";
1193
+ import * as Effect15 from "effect/Effect";
1127
1194
 
1128
1195
  // src/launchd/file-identity.ts
1129
1196
  var sameEntry = (a, b) => {
@@ -1318,10 +1385,10 @@ var deleteFile = (runner, output) => removeWholeFile(runner, output, refuse3);
1318
1385
 
1319
1386
  // src/launchd/host-file.ts
1320
1387
  var HostFile = Resource2("Host.File");
1321
- var HostFileProvider = () => Provider2.effect(HostFile, Effect13.gen(function* () {
1388
+ var HostFileProvider = () => Provider2.effect(HostFile, Effect15.gen(function* () {
1322
1389
  const runner = yield* HostRunnerService;
1323
1390
  return HostFile.Provider.of({
1324
- list: () => Effect13.succeed([]),
1391
+ list: () => Effect15.succeed([]),
1325
1392
  read: ({ olds, output }) => lift(async () => {
1326
1393
  const found = await readFileAttributes(runner, olds.path);
1327
1394
  if (found === undefined)
@@ -1335,19 +1402,19 @@ var HostFileProvider = () => Provider2.effect(HostFile, Effect13.gen(function* (
1335
1402
  return lift(() => diffFile(runner, news, output));
1336
1403
  const path = resolvedString(news, "path");
1337
1404
  if (path === undefined || path === output.path)
1338
- return Effect13.succeed(undefined);
1405
+ return Effect15.succeed(undefined);
1339
1406
  return lift(async () => await oneFile(runner, path, output.path) === true ? undefined : { action: "replace" });
1340
1407
  },
1341
- reconcile: ({ fqn, instanceId, news, output }) => Effect13.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) => lift(() => reconcileFile(runner, news, output, adopt))),
1408
+ reconcile: ({ fqn, instanceId, news, output }) => Effect15.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) => lift(() => reconcileFile(runner, news, output, adopt))),
1342
1409
  delete: ({ output }) => lift(() => deleteFile(runner, output))
1343
1410
  });
1344
1411
  }));
1345
1412
 
1346
1413
  // src/caddy/with-file.ts
1347
- var caddyWithFile = (id, props) => Effect14.gen(function* () {
1414
+ var caddyWithFile = (id, props) => Effect16.gen(function* () {
1348
1415
  const found = configProblems({ caddyfile: props.caddyfile, sourceFile: props.path });
1349
1416
  if (found.length > 0) {
1350
- return yield* Effect14.fail(new Error(`caddyWithFile ${id}: ${found.join("; ")}`));
1417
+ return yield* Effect16.fail(new Error(`caddyWithFile ${id}: ${found.join("; ")}`));
1351
1418
  }
1352
1419
  const file = yield* HostFile(`${id}-file`, {
1353
1420
  content: props.caddyfile,
@@ -1377,5 +1444,5 @@ export {
1377
1444
  verifierProblems
1378
1445
  };
1379
1446
 
1380
- //# debugId=A4890D1A8DCAD67064756E2164756E21
1447
+ //# debugId=E80D7FC971F2355764756E2164756E21
1381
1448
  //# sourceMappingURL=index.js.map