@homeflare/alchemy 0.29.1 → 0.30.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 (87) hide show
  1. package/README.md +20 -0
  2. package/dist/caddy/config-reconcile.d.ts.map +1 -1
  3. package/dist/caddy/config.d.ts.map +1 -1
  4. package/dist/caddy/format-warnings.d.ts +29 -0
  5. package/dist/caddy/format-warnings.d.ts.map +1 -0
  6. package/dist/caddy/format.d.ts +50 -0
  7. package/dist/caddy/format.d.ts.map +1 -0
  8. package/dist/caddy/index.d.ts +1 -0
  9. package/dist/caddy/index.d.ts.map +1 -1
  10. package/dist/caddy/index.js +78 -10
  11. package/dist/caddy/index.js.map +7 -5
  12. package/dist/google-workspace/credentials.d.ts +54 -0
  13. package/dist/google-workspace/credentials.d.ts.map +1 -0
  14. package/dist/google-workspace/domain-alias.d.ts +74 -0
  15. package/dist/google-workspace/domain-alias.d.ts.map +1 -0
  16. package/dist/google-workspace/fake-google-workspace.d.ts +41 -0
  17. package/dist/google-workspace/fake-google-workspace.d.ts.map +1 -0
  18. package/dist/google-workspace/group-member.d.ts +73 -0
  19. package/dist/google-workspace/group-member.d.ts.map +1 -0
  20. package/dist/google-workspace/group.d.ts +87 -0
  21. package/dist/google-workspace/group.d.ts.map +1 -0
  22. package/dist/google-workspace/index.d.ts +19 -0
  23. package/dist/google-workspace/index.d.ts.map +1 -0
  24. package/dist/google-workspace/index.js +283 -0
  25. package/dist/google-workspace/index.js.map +17 -0
  26. package/dist/google-workspace/org-unit.d.ts +75 -0
  27. package/dist/google-workspace/org-unit.d.ts.map +1 -0
  28. package/dist/google-workspace/providers.d.ts +16 -0
  29. package/dist/google-workspace/providers.d.ts.map +1 -0
  30. package/dist/google-workspace/resource.d.ts +80 -0
  31. package/dist/google-workspace/resource.d.ts.map +1 -0
  32. package/dist/google-workspace/values.d.ts +28 -0
  33. package/dist/google-workspace/values.d.ts.map +1 -0
  34. package/dist/grafana/credentials.d.ts +38 -0
  35. package/dist/grafana/credentials.d.ts.map +1 -0
  36. package/dist/grafana/datasource.d.ts +90 -0
  37. package/dist/grafana/datasource.d.ts.map +1 -0
  38. package/dist/grafana/fake-grafana.d.ts +48 -0
  39. package/dist/grafana/fake-grafana.d.ts.map +1 -0
  40. package/dist/grafana/index.d.ts +17 -0
  41. package/dist/grafana/index.d.ts.map +1 -0
  42. package/dist/grafana/index.js +149 -0
  43. package/dist/grafana/index.js.map +13 -0
  44. package/dist/grafana/providers.d.ts +17 -0
  45. package/dist/grafana/providers.d.ts.map +1 -0
  46. package/dist/grafana/resource.d.ts +68 -0
  47. package/dist/grafana/resource.d.ts.map +1 -0
  48. package/docs/caddy-fmt.md +59 -0
  49. package/docs/caddy.md +7 -0
  50. package/docs/credentials.md +11 -0
  51. package/docs/google-workspace.md +105 -0
  52. package/docs/grafana.md +102 -0
  53. package/docs/peers.md +9 -0
  54. package/docs/upstream-conformance.md +37 -0
  55. package/package.json +9 -1
  56. package/src/caddy/config-format-warning.test.ts +91 -0
  57. package/src/caddy/config-reconcile.ts +6 -0
  58. package/src/caddy/config.ts +8 -1
  59. package/src/caddy/format-warnings.test.ts +50 -0
  60. package/src/caddy/format-warnings.ts +39 -0
  61. package/src/caddy/format.test.ts +105 -0
  62. package/src/caddy/format.ts +121 -0
  63. package/src/caddy/index.ts +7 -0
  64. package/src/caddy/providers.test.ts +8 -0
  65. package/src/google-workspace/credentials.test.ts +40 -0
  66. package/src/google-workspace/credentials.ts +75 -0
  67. package/src/google-workspace/domain-alias.test.ts +69 -0
  68. package/src/google-workspace/domain-alias.ts +116 -0
  69. package/src/google-workspace/fake-google-workspace.ts +54 -0
  70. package/src/google-workspace/group-member.test.ts +91 -0
  71. package/src/google-workspace/group-member.ts +126 -0
  72. package/src/google-workspace/group.test.ts +93 -0
  73. package/src/google-workspace/group.ts +128 -0
  74. package/src/google-workspace/index.ts +54 -0
  75. package/src/google-workspace/org-unit.test.ts +81 -0
  76. package/src/google-workspace/org-unit.ts +143 -0
  77. package/src/google-workspace/providers.ts +26 -0
  78. package/src/google-workspace/resource.test.ts +186 -0
  79. package/src/google-workspace/resource.ts +162 -0
  80. package/src/google-workspace/values.ts +36 -0
  81. package/src/grafana/credentials.ts +65 -0
  82. package/src/grafana/datasource.test.ts +183 -0
  83. package/src/grafana/datasource.ts +171 -0
  84. package/src/grafana/fake-grafana.ts +64 -0
  85. package/src/grafana/index.ts +22 -0
  86. package/src/grafana/providers.ts +19 -0
  87. package/src/grafana/resource.ts +120 -0
package/README.md CHANGED
@@ -208,6 +208,10 @@ with `HostFile`; `caddyProviders()` provides the transport, `http://127.0.0.1:20
208
208
  - ⛔ **Delete never unloads or stops Caddy.** Order of file and load: [docs/caddy.md](./docs/caddy.md).
209
209
  - ★ **Managed Caddies run `--resume` with their own `XDG_CONFIG_HOME`**, so a restart runs the last
210
210
  config Caddy accepted — and after one, SIGUSR1 has no file to reload. Why, and the rest: same doc.
211
+ - **`formatCaddyfile(text)`** runs the local `caddy fmt -` binary (no admin API does this); plan and
212
+ deploy both call out Caddy's own "not formatted" warning as its own clear line. Formatting should
213
+ never change the adapted JSON (reasoned from the grammar, not measured in this package — see the
214
+ doc). Details: [docs/caddy-fmt.md](./docs/caddy-fmt.md).
211
215
 
212
216
  ## PostgreSQL — `@homeflare/alchemy/postgres`
213
217
 
@@ -245,6 +249,22 @@ endpoint lives in ONE `general_settings` field (a whole-list read-modify-write),
245
249
  declared in `config.yaml` is refused rather than silently overridden, and a literal secret in a
246
250
  forwarded header is refused at plan: [docs/litellm.md](./docs/litellm.md).
247
251
 
252
+ ## Google Workspace — `@homeflare/alchemy/google-workspace`
253
+
254
+ `Group`, `GroupMember`, `DomainAlias` and `OrgUnit` over the Admin SDK Directory API, generated
255
+ from `@distilled.cloud/google-workspace@1.0.0-rc.12`. ⛔ No `User` resource — Google's own `User`
256
+ schema carries a `password` field, and Alchemy persists props unencrypted. Credential setup
257
+ (domain-wide delegation, the least scopes each resource needs, where the key lives in OpenBao):
258
+ [docs/google-workspace.md](./docs/google-workspace.md).
259
+
260
+ ## Grafana — `@homeflare/alchemy/grafana`
261
+
262
+ `Grafana.Datasource` declares one data source, keyed by `uid`, generated from
263
+ `@distilled.cloud/grafana`'s own typed `addDataSource`/`getDataSourceByUID`/
264
+ `updateDataSourceByUID`/`deleteDataSourceByUID` operations. ⛔ The SDK at `1.0.0-rc.12` has no
265
+ folder, dashboard, alert-rule or contact-point CRUD — only `Datasource` ships, and the gap is
266
+ recorded rather than worked around: [docs/grafana.md](./docs/grafana.md).
267
+
248
268
  ## GitHub — `@homeflare/alchemy/github`
249
269
 
250
270
  `declareRepoPolicy` declares one repository's merge policy and its default-branch ruleset in a
@@ -1 +1 @@
1
- {"version":3,"file":"config-reconcile.d.ts","sourceRoot":"","sources":["../../src/caddy/config-reconcile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,IAAI,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,KAAK,KAAK,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAI/C,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIhF;;;;GAIG;AACH,eAAO,MAAM,UAAU,SACf,gBAAgB,UACd,qBAAqB,KAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAc5F,CAAC;AAEL,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,UACnB,gBAAgB,aACZ,SAAS,KACnB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAmE1F,CAAC"}
1
+ {"version":3,"file":"config-reconcile.d.ts","sourceRoot":"","sources":["../../src/caddy/config-reconcile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,IAAI,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,KAAK,KAAK,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAI/C,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKhF;;;;GAIG;AACH,eAAO,MAAM,UAAU,SACf,gBAAgB,UACd,qBAAqB,KAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAmB5F,CAAC;AAEL,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,UACnB,gBAAgB,aACZ,SAAS,KACnB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAmE1F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/caddy/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIhF,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,gJA+E7B,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/caddy/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,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,gJAqF7B,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Pulls Caddy's adapter "Caddyfile input is not formatted" warning(s) out of a warnings list, so
3
+ * config.ts's reconcile (deploy) and config-reconcile.ts's diffConfig (plan) can show it as one
4
+ * clear, actionable line instead of burying it among the rest.
5
+ *
6
+ * ★ THIS IS THE COMMON CASE, NOT AN EDGE ONE. admin-calls.ts's module doc: the Caddyfile adapter
7
+ * warns on EVERY unformatted input (adapter.go FormattingDifference) — every declared Caddyfile
8
+ * that was not run through `caddy fmt` (or format.ts's formatCaddyfile()) carries this warning
9
+ * on every plan and every deploy, indistinguishable from the rest unless split out.
10
+ */
11
+ export type SplitWarnings = {
12
+ /**
13
+ * Every warning THAT IS the formatting one — usually one, but an `import`ed file can add
14
+ * another with its own file:line, and this keeps every one of them (never just the first): a
15
+ * `.find()` here would silently drop the rest, not merely leave them uncounted.
16
+ */
17
+ readonly formatting: readonly string[];
18
+ /** Every other warning, in order, formatting removed. */
19
+ readonly rest: readonly string[];
20
+ };
21
+ /** Separates the formatting warning(s) (by substring, matching admin-calls.ts's `describe()`). */
22
+ export declare const splitFormattingWarning: (warnings: readonly string[]) => SplitWarnings;
23
+ /**
24
+ * One clear line naming the fix — never just the adapter's own warning text, and never repeated
25
+ * per formatting warning: however many `formatting` holds, this is logged once (config.ts,
26
+ * config-reconcile.ts), since restating the same fix N times is its own noise.
27
+ */
28
+ export declare const formattingFixLine: (endpoint: string) => string;
29
+ //# sourceMappingURL=format-warnings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-warnings.d.ts","sourceRoot":"","sources":["../../src/caddy/format-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,sBAAsB,aAAc,SAAS,MAAM,EAAE,KAAG,aAGnE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,aAAc,MAAM,KAAG,MAEqC,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * `formatCaddyfile(text)` — pipes a Caddyfile through the LOCAL `caddy fmt -` binary (stdin in,
3
+ * formatted text out), the same formatter the `caddy fmt` CLI command runs
4
+ * (caddyconfig/caddyfile Format in caddyserver/caddy).
5
+ *
6
+ * ⛔ THERE IS NO ADMIN API FOR THIS. `caddy fmt` is a CLI-only feature (cmd/commandfuncs.go); no
7
+ * `/adapt`, `/load` or other admin endpoint formats a Caddyfile, so this never belongs in
8
+ * `@distilled.cloud/caddy` — measured 2026-09-24. It shells out instead, the same pattern
9
+ * talos/talosctl.ts uses for a vendor CLI Alchemy does not wrap.
10
+ * ⛔ NEVER REIMPLEMENTED IN TS. The Caddyfile grammar's formatting rules live in the Go adapter;
11
+ * a hand-rolled formatter would drift from it silently. This module only ever runs the real
12
+ * binary.
13
+ * ⛔ A MISSING OR FAILING BINARY FAILS THE EFFECT — IT NEVER RETURNS THE INPUT UNCHANGED.
14
+ * `CaddyFmtNotFound` and `CaddyFmtFailed` are typed, catchTag-able failures (S21); there is no
15
+ * fallback path that silently skips formatting.
16
+ * ★ WHY THIS MATTERS: admin-calls.ts's module doc — Caddy's adapter warns "Caddyfile input is not
17
+ * formatted" on EVERY unformatted input (adapter.go FormattingDifference), which shares the
18
+ * `/load` response body with the refused-but-200 trap. format-warnings.ts surfaces that warning
19
+ * distinctly in plan/deploy output; this function is how a caller silences it — by formatting
20
+ * the Caddyfile before declaring it, not by ignoring the warning.
21
+ */
22
+ import * as Effect from 'effect/Effect';
23
+ import * as ChildProcessSpawner from 'effect/unstable/process/ChildProcessSpawner';
24
+ import type * as PlatformError from 'effect/PlatformError';
25
+ /** `caddy` resolved on `PATH`, unless the caller points at a specific build. */
26
+ export declare const DEFAULT_CADDY_BINARY = "caddy";
27
+ /** The configured binary is not on `PATH` (or not executable) — install Caddy, or fix the path. */
28
+ export declare class CaddyFmtNotFound extends Error {
29
+ readonly binaryPath: string;
30
+ readonly _tag = "CaddyFmtNotFound";
31
+ constructor(binaryPath: string, cause: PlatformError.PlatformError);
32
+ }
33
+ /** The binary ran but exited non-zero — a syntax error in `text`, most likely. */
34
+ export declare class CaddyFmtFailed extends Error {
35
+ readonly binaryPath: string;
36
+ readonly exitCode: number;
37
+ readonly _tag = "CaddyFmtFailed";
38
+ constructor(binaryPath: string, exitCode: number, stderr: string);
39
+ }
40
+ export type FormatCaddyfileOptions = {
41
+ /** The `caddy` binary to run `fmt -` against. @default DEFAULT_CADDY_BINARY, resolved on PATH. */
42
+ readonly binaryPath?: string;
43
+ };
44
+ /**
45
+ * Format a Caddyfile the way `caddy fmt` would, by actually running it — never a TS
46
+ * reimplementation. Requires `ChildProcessSpawner` (S19: no `node:child_process`, no
47
+ * `async`/`await`); provide `@effect/platform-node`'s or `@effect/platform-bun`'s layer.
48
+ */
49
+ export declare const formatCaddyfile: (text: string, options?: FormatCaddyfileOptions) => Effect.Effect<string, CaddyFmtNotFound | CaddyFmtFailed | PlatformError.PlatformError, ChildProcessSpawner.ChildProcessSpawner>;
50
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/caddy/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,mBAAmB,MAAM,6CAA6C,CAAC;AACnF,OAAO,KAAK,KAAK,aAAa,MAAM,sBAAsB,CAAC;AAE3D,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,mGAAmG;AACnG,qBAAa,gBAAiB,SAAQ,KAAK;IAGvC,QAAQ,CAAC,UAAU,EAAE,MAAM;IAF7B,QAAQ,CAAC,IAAI,sBAAsB;IACnC,YACW,UAAU,EAAE,MAAM,EAC3B,KAAK,EAAE,aAAa,CAAC,aAAa,EAOnC;CACF;AAED,kFAAkF;AAClF,qBAAa,cAAe,SAAQ,KAAK;IAGrC,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAH3B,QAAQ,CAAC,IAAI,oBAAoB;IACjC,YACW,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EAMf;CACF;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,kGAAkG;IAClG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,SACpB,MAAM,YACH,sBAAsB,KAC9B,MAAM,CAAC,MAAM,CACd,MAAM,EAGN,gBAAgB,GAAG,cAAc,GAAG,aAAa,CAAC,aAAa,EAC/D,mBAAmB,CAAC,mBAAmB,CA0CrC,CAAC"}
@@ -20,6 +20,7 @@ export { CaddyAdminService, caddyAdminLayer } from './admin.ts';
20
20
  export { isUnreachable } from './caddy-http-client.ts';
21
21
  export type { CaddyConfigAttributes, CaddyConfigProps } from './config.ts';
22
22
  export { CaddyConfig, CaddyConfigProvider } from './config.ts';
23
+ export { CaddyFmtFailed, CaddyFmtNotFound, DEFAULT_CADDY_BINARY, formatCaddyfile, type FormatCaddyfileOptions, } from './format.ts';
23
24
  export type { LocalCaddyAdminOptions } from './local-admin.ts';
24
25
  export { DEFAULT_ADMIN_ADDRESS, localCaddyAdmin } from './local-admin.ts';
25
26
  export { caddyProviders } from './providers.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/caddy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH;;;;GAIG;AACH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,sBAAsB,GAC5B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC/D,YAAY,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/caddy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH;;;;GAIG;AACH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,sBAAsB,GAC5B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
@@ -862,9 +862,22 @@ var probeLive = (caddyfile, sourceFile) => Effect9.gen(function* () {
862
862
  // src/caddy/config-reconcile.ts
863
863
  import * as Effect10 from "effect/Effect";
864
864
  import * as Result3 from "effect/Result";
865
+
866
+ // src/caddy/format-warnings.ts
867
+ var NOT_FORMATTED = "Caddyfile input is not formatted";
868
+ var splitFormattingWarning = (warnings) => ({
869
+ formatting: warnings.filter((warning) => warning.includes(NOT_FORMATTED)),
870
+ rest: warnings.filter((warning) => !warning.includes(NOT_FORMATTED))
871
+ });
872
+ 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.";
873
+
874
+ // src/caddy/config-reconcile.ts
865
875
  var diffConfig = (news, output) => Effect10.gen(function* () {
866
876
  const { endpoint } = yield* CaddyAdminService;
867
877
  const want = yield* desiredConfig(news);
878
+ const { formatting } = splitFormattingWarning(want.warnings);
879
+ if (formatting.length > 0)
880
+ yield* Effect10.logWarning(formattingFixLine(endpoint));
868
881
  const live = yield* readLive();
869
882
  const converged = want.digest === live.configSha256 && live.configSha256 === output.configSha256 && news.sourceFile === output.sourceFile && endpoint === output.endpoint;
870
883
  return converged ? { action: "noop" } : { action: "update" };
@@ -938,7 +951,11 @@ var CaddyConfigProvider = () => Provider.effect(CaddyConfig, Effect11.gen(functi
938
951
  const takeOver = sameCaddy || (yield* adoptEnabled(fqn));
939
952
  const stored = output === undefined ? {} : { stored: output.configSha256 };
940
953
  const applied = yield* reconcileConfig(news, { takeOver, ...stored });
941
- for (const warning of applied.warnings) {
954
+ const { formatting, rest } = splitFormattingWarning(applied.warnings);
955
+ if (formatting.length > 0) {
956
+ yield* Effect11.logWarning(formattingFixLine(admin.endpoint));
957
+ }
958
+ for (const warning of rest) {
942
959
  yield* Effect11.logWarning(`Caddy.Config at ${admin.endpoint}: ${warning}`);
943
960
  }
944
961
  return applied.attributes;
@@ -946,6 +963,53 @@ var CaddyConfigProvider = () => Provider.effect(CaddyConfig, Effect11.gen(functi
946
963
  delete: () => Effect11.void
947
964
  });
948
965
  }));
966
+ // src/caddy/format.ts
967
+ import * as Effect12 from "effect/Effect";
968
+ import * as Stream from "effect/Stream";
969
+ import * as ChildProcess from "effect/unstable/process/ChildProcess";
970
+ import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
971
+ var DEFAULT_CADDY_BINARY = "caddy";
972
+
973
+ class CaddyFmtNotFound extends Error {
974
+ binaryPath;
975
+ _tag = "CaddyFmtNotFound";
976
+ constructor(binaryPath, cause) {
977
+ super(`formatCaddyfile: "${binaryPath}" was not found (${cause.message}). Install Caddy so it is ` + "on PATH, or pass { binaryPath } naming the exact build the target Caddy runs.");
978
+ this.binaryPath = binaryPath;
979
+ this.name = "CaddyFmtNotFound";
980
+ }
981
+ }
982
+
983
+ class CaddyFmtFailed extends Error {
984
+ binaryPath;
985
+ exitCode;
986
+ _tag = "CaddyFmtFailed";
987
+ constructor(binaryPath, exitCode, stderr) {
988
+ super(`formatCaddyfile: "${binaryPath} fmt -" exited ${String(exitCode)}: ${stderr.slice(0, 300)}`);
989
+ this.binaryPath = binaryPath;
990
+ this.exitCode = exitCode;
991
+ this.name = "CaddyFmtFailed";
992
+ }
993
+ }
994
+ var formatCaddyfile = (text, options = {}) => Effect12.gen(function* () {
995
+ const binaryPath = options.binaryPath ?? DEFAULT_CADDY_BINARY;
996
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
997
+ const input = new TextEncoder().encode(text);
998
+ const result4 = yield* ChildProcess.make(binaryPath, ["fmt", "-"], {
999
+ detached: false,
1000
+ stderr: "pipe",
1001
+ stdin: Stream.make(input),
1002
+ stdout: "pipe"
1003
+ }).pipe(spawner.spawn, Effect12.flatMap((child) => Effect12.all({
1004
+ exitCode: child.exitCode,
1005
+ stderr: child.stderr.pipe(Stream.decodeText, Stream.mkString, Effect12.map((out) => out.trim())),
1006
+ stdout: child.stdout.pipe(Stream.decodeText, Stream.mkString)
1007
+ }, { concurrency: "unbounded" })), Effect12.scoped, Effect12.catchTag("PlatformError", (error) => error.reason._tag === "NotFound" ? Effect12.fail(new CaddyFmtNotFound(binaryPath, error)) : Effect12.fail(error)));
1008
+ if (result4.exitCode !== 0) {
1009
+ return yield* Effect12.fail(new CaddyFmtFailed(binaryPath, result4.exitCode, result4.stderr));
1010
+ }
1011
+ return result4.stdout;
1012
+ });
949
1013
  // src/caddy/local-admin.ts
950
1014
  import * as Layer3 from "effect/Layer";
951
1015
  import * as Caddy2 from "@distilled.cloud/caddy";
@@ -1013,7 +1077,7 @@ var localCaddyAdmin = (options = {}) => {
1013
1077
  import * as Layer4 from "effect/Layer";
1014
1078
  var caddyProviders = (transport = localCaddyAdmin()) => CaddyConfigProvider().pipe(Layer4.provideMerge(caddyAdminLayer(transport)));
1015
1079
  // src/caddy/with-file.ts
1016
- import * as Effect13 from "effect/Effect";
1080
+ import * as Effect14 from "effect/Effect";
1017
1081
  import * as RemovalPolicy from "alchemy/RemovalPolicy";
1018
1082
 
1019
1083
  // src/launchd/host-file.ts
@@ -1021,7 +1085,7 @@ import { Resource as Resource2 } from "alchemy";
1021
1085
  import { Unowned as Unowned3 } from "alchemy/AdoptPolicy";
1022
1086
  import { isResolved as isResolved2 } from "alchemy/Diff";
1023
1087
  import * as Provider2 from "alchemy/Provider";
1024
- import * as Effect12 from "effect/Effect";
1088
+ import * as Effect13 from "effect/Effect";
1025
1089
 
1026
1090
  // src/launchd/file-identity.ts
1027
1091
  var sameEntry = (a, b) => {
@@ -1216,10 +1280,10 @@ var deleteFile = (runner, output) => removeWholeFile(runner, output, refuse3);
1216
1280
 
1217
1281
  // src/launchd/host-file.ts
1218
1282
  var HostFile = Resource2("Host.File");
1219
- var HostFileProvider = () => Provider2.effect(HostFile, Effect12.gen(function* () {
1283
+ var HostFileProvider = () => Provider2.effect(HostFile, Effect13.gen(function* () {
1220
1284
  const runner = yield* HostRunnerService;
1221
1285
  return HostFile.Provider.of({
1222
- list: () => Effect12.succeed([]),
1286
+ list: () => Effect13.succeed([]),
1223
1287
  read: ({ olds, output }) => lift(async () => {
1224
1288
  const found = await readFileAttributes(runner, olds.path);
1225
1289
  if (found === undefined)
@@ -1233,19 +1297,19 @@ var HostFileProvider = () => Provider2.effect(HostFile, Effect12.gen(function* (
1233
1297
  return lift(() => diffFile(runner, news, output));
1234
1298
  const path = resolvedString(news, "path");
1235
1299
  if (path === undefined || path === output.path)
1236
- return Effect12.succeed(undefined);
1300
+ return Effect13.succeed(undefined);
1237
1301
  return lift(async () => await oneFile(runner, path, output.path) === true ? undefined : { action: "replace" });
1238
1302
  },
1239
- reconcile: ({ fqn, instanceId, news, output }) => Effect12.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) => lift(() => reconcileFile(runner, news, output, adopt))),
1303
+ reconcile: ({ fqn, instanceId, news, output }) => Effect13.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) => lift(() => reconcileFile(runner, news, output, adopt))),
1240
1304
  delete: ({ output }) => lift(() => deleteFile(runner, output))
1241
1305
  });
1242
1306
  }));
1243
1307
 
1244
1308
  // src/caddy/with-file.ts
1245
- var caddyWithFile = (id, props) => Effect13.gen(function* () {
1309
+ var caddyWithFile = (id, props) => Effect14.gen(function* () {
1246
1310
  const found = configProblems({ caddyfile: props.caddyfile, sourceFile: props.path });
1247
1311
  if (found.length > 0) {
1248
- return yield* Effect13.fail(new Error(`caddyWithFile ${id}: ${found.join("; ")}`));
1312
+ return yield* Effect14.fail(new Error(`caddyWithFile ${id}: ${found.join("; ")}`));
1249
1313
  }
1250
1314
  const file = yield* HostFile(`${id}-file`, {
1251
1315
  content: props.caddyfile,
@@ -1261,15 +1325,19 @@ export {
1261
1325
  CaddyAdminService,
1262
1326
  CaddyConfig,
1263
1327
  CaddyConfigProvider,
1328
+ CaddyFmtFailed,
1329
+ CaddyFmtNotFound,
1264
1330
  DEFAULT_ADMIN_ADDRESS,
1331
+ DEFAULT_CADDY_BINARY,
1265
1332
  accessForwardAuth,
1266
1333
  caddyAdminLayer,
1267
1334
  caddyProviders,
1268
1335
  caddyWithFile,
1336
+ formatCaddyfile,
1269
1337
  isUnreachable,
1270
1338
  localCaddyAdmin,
1271
1339
  verifierProblems
1272
1340
  };
1273
1341
 
1274
- //# debugId=643BF5F5D21610F364756E2164756E21
1342
+ //# debugId=CC0C3E3E18BF8F0664756E2164756E21
1275
1343
  //# sourceMappingURL=index.js.map