@homeflare/alchemy 0.5.0 → 0.7.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 +68 -55
- package/dist/caddy/admin-calls.d.ts +48 -0
- package/dist/caddy/admin-calls.d.ts.map +1 -0
- package/dist/caddy/admin-guard.d.ts +40 -0
- package/dist/caddy/admin-guard.d.ts.map +1 -0
- package/dist/caddy/admin.d.ts +73 -0
- package/dist/caddy/admin.d.ts.map +1 -0
- package/dist/caddy/caddyfile-tripwire.d.ts +5 -0
- package/dist/caddy/caddyfile-tripwire.d.ts.map +1 -0
- package/dist/caddy/config-form.d.ts +27 -0
- package/dist/caddy/config-form.d.ts.map +1 -0
- package/dist/caddy/config-lifecycle.d.ts +45 -0
- package/dist/caddy/config-lifecycle.d.ts.map +1 -0
- package/dist/caddy/config.d.ts +30 -0
- package/dist/caddy/config.d.ts.map +1 -0
- package/dist/caddy/digest.d.ts +7 -0
- package/dist/caddy/digest.d.ts.map +1 -0
- package/dist/caddy/fake-caddy.d.ts +43 -0
- package/dist/caddy/fake-caddy.d.ts.map +1 -0
- package/dist/caddy/index.d.ts +21 -0
- package/dist/caddy/index.d.ts.map +1 -0
- package/dist/caddy/index.js +912 -0
- package/dist/caddy/index.js.map +28 -0
- package/dist/caddy/local-admin.d.ts +45 -0
- package/dist/caddy/local-admin.d.ts.map +1 -0
- package/dist/caddy/providers.d.ts +14 -0
- package/dist/caddy/providers.d.ts.map +1 -0
- package/dist/caddy/with-file.d.ts +47 -0
- package/dist/caddy/with-file.d.ts.map +1 -0
- package/dist/cloudflare/fake-mesh.d.ts +58 -0
- package/dist/cloudflare/fake-mesh.d.ts.map +1 -0
- package/dist/cloudflare/index.d.ts +9 -3
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +218 -7
- package/dist/cloudflare/index.js.map +9 -4
- package/dist/cloudflare/mesh-node-api.d.ts +75 -0
- package/dist/cloudflare/mesh-node-api.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-form.d.ts +82 -0
- package/dist/cloudflare/mesh-node-form.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-harness.d.ts +46 -0
- package/dist/cloudflare/mesh-node-harness.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-lifecycle.d.ts +22 -0
- package/dist/cloudflare/mesh-node-lifecycle.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-token.d.ts +23 -0
- package/dist/cloudflare/mesh-node-token.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node.d.ts +48 -0
- package/dist/cloudflare/mesh-node.d.ts.map +1 -0
- package/dist/cloudflare/providers.d.ts +1 -12
- package/dist/cloudflare/providers.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/launchd/fake-runner.d.ts +36 -0
- package/dist/launchd/fake-runner.d.ts.map +1 -0
- package/dist/launchd/host-effect.d.ts +19 -0
- package/dist/launchd/host-effect.d.ts.map +1 -0
- package/dist/launchd/host-file-form.d.ts +24 -0
- package/dist/launchd/host-file-form.d.ts.map +1 -0
- package/dist/launchd/host-file-lifecycle.d.ts +29 -0
- package/dist/launchd/host-file-lifecycle.d.ts.map +1 -0
- package/dist/launchd/host-file.d.ts +25 -0
- package/dist/launchd/host-file.d.ts.map +1 -0
- package/dist/launchd/host-lookup.d.ts +27 -0
- package/dist/launchd/host-lookup.d.ts.map +1 -0
- package/dist/launchd/index.d.ts +21 -0
- package/dist/launchd/index.d.ts.map +1 -0
- package/dist/launchd/index.js +969 -0
- package/dist/launchd/index.js.map +25 -0
- package/dist/launchd/job-form.d.ts +90 -0
- package/dist/launchd/job-form.d.ts.map +1 -0
- package/dist/launchd/job-lifecycle.d.ts +34 -0
- package/dist/launchd/job-lifecycle.d.ts.map +1 -0
- package/dist/launchd/job-preflight.d.ts +50 -0
- package/dist/launchd/job-preflight.d.ts.map +1 -0
- package/dist/launchd/job-validate.d.ts +25 -0
- package/dist/launchd/job-validate.d.ts.map +1 -0
- package/dist/launchd/job.d.ts +34 -0
- package/dist/launchd/job.d.ts.map +1 -0
- package/dist/launchd/launchctl.d.ts +62 -0
- package/dist/launchd/launchctl.d.ts.map +1 -0
- package/dist/launchd/local-runner.d.ts +7 -0
- package/dist/launchd/local-runner.d.ts.map +1 -0
- package/dist/launchd/plist.d.ts +41 -0
- package/dist/launchd/plist.d.ts.map +1 -0
- package/dist/launchd/providers.d.ts +15 -0
- package/dist/launchd/providers.d.ts.map +1 -0
- package/dist/launchd/runner.d.ts +91 -0
- package/dist/launchd/runner.d.ts.map +1 -0
- package/dist/launchd/secret-tripwire.d.ts +24 -0
- package/dist/launchd/secret-tripwire.d.ts.map +1 -0
- package/dist/openbao/auth-method-form.d.ts +7 -0
- package/dist/openbao/auth-method-form.d.ts.map +1 -1
- package/dist/openbao/auth-method-reconcile.d.ts +15 -0
- package/dist/openbao/auth-method-reconcile.d.ts.map +1 -0
- package/dist/openbao/auth-method.d.ts +6 -0
- package/dist/openbao/auth-method.d.ts.map +1 -1
- package/dist/openbao/auth-role-form.d.ts +9 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role.d.ts.map +1 -1
- package/dist/openbao/auth-token-form.d.ts +48 -0
- package/dist/openbao/auth-token-form.d.ts.map +1 -0
- package/dist/openbao/bao-identity.d.ts +81 -0
- package/dist/openbao/bao-identity.d.ts.map +1 -0
- package/dist/openbao/bao-namespace.d.ts +20 -0
- package/dist/openbao/bao-namespace.d.ts.map +1 -0
- package/dist/openbao/cloudflare-role.d.ts.map +1 -1
- package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -1
- package/dist/openbao/fake-engines.d.ts +30 -0
- package/dist/openbao/fake-engines.d.ts.map +1 -0
- package/dist/openbao/fake-stack.d.ts +29 -0
- package/dist/openbao/fake-stack.d.ts.map +1 -0
- package/dist/openbao/host-approles.d.ts +62 -0
- package/dist/openbao/host-approles.d.ts.map +1 -0
- package/dist/openbao/index.d.ts +19 -0
- package/dist/openbao/index.d.ts.map +1 -1
- package/dist/openbao/index.js +1518 -310
- package/dist/openbao/index.js.map +40 -17
- package/dist/openbao/jwt-config-form.d.ts +51 -0
- package/dist/openbao/jwt-config-form.d.ts.map +1 -0
- package/dist/openbao/jwt-config.d.ts +25 -0
- package/dist/openbao/jwt-config.d.ts.map +1 -0
- package/dist/openbao/jwt-role-form.d.ts +91 -0
- package/dist/openbao/jwt-role-form.d.ts.map +1 -0
- package/dist/openbao/jwt-role.d.ts +31 -0
- package/dist/openbao/jwt-role.d.ts.map +1 -0
- package/dist/openbao/kubernetes-role-form.d.ts +68 -0
- package/dist/openbao/kubernetes-role-form.d.ts.map +1 -0
- package/dist/openbao/kubernetes-role.d.ts +25 -0
- package/dist/openbao/kubernetes-role.d.ts.map +1 -0
- package/dist/openbao/mfa-enforcement-form.d.ts +46 -0
- package/dist/openbao/mfa-enforcement-form.d.ts.map +1 -0
- package/dist/openbao/mfa-enforcement.d.ts +41 -0
- package/dist/openbao/mfa-enforcement.d.ts.map +1 -0
- package/dist/openbao/mfa-totp-form.d.ts +52 -0
- package/dist/openbao/mfa-totp-form.d.ts.map +1 -0
- package/dist/openbao/mfa-totp.d.ts +33 -0
- package/dist/openbao/mfa-totp.d.ts.map +1 -0
- package/dist/openbao/mfa-wire.d.ts +63 -0
- package/dist/openbao/mfa-wire.d.ts.map +1 -0
- package/dist/openbao/mount-form.d.ts +7 -0
- package/dist/openbao/mount-form.d.ts.map +1 -1
- package/dist/openbao/mount-move.d.ts +49 -0
- package/dist/openbao/mount-move.d.ts.map +1 -0
- package/dist/openbao/mount-path.d.ts +8 -4
- package/dist/openbao/mount-path.d.ts.map +1 -1
- package/dist/openbao/mount-reconcile.d.ts +16 -0
- package/dist/openbao/mount-reconcile.d.ts.map +1 -0
- package/dist/openbao/mount.d.ts +9 -0
- package/dist/openbao/mount.d.ts.map +1 -1
- package/dist/openbao/pki-role-canonical.d.ts +46 -0
- package/dist/openbao/pki-role-canonical.d.ts.map +1 -0
- package/dist/openbao/pki-role-form.d.ts +38 -30
- package/dist/openbao/pki-role-form.d.ts.map +1 -1
- package/dist/openbao/pki-role.d.ts.map +1 -1
- package/dist/openbao/policy.d.ts +2 -0
- package/dist/openbao/policy.d.ts.map +1 -1
- package/dist/openbao/proxmox-role-form.d.ts +18 -8
- package/dist/openbao/proxmox-role-form.d.ts.map +1 -1
- package/dist/openbao/proxmox-role-wire.d.ts +18 -0
- package/dist/openbao/proxmox-role-wire.d.ts.map +1 -0
- package/dist/openbao/proxmox-role.d.ts.map +1 -1
- package/dist/openbao/remount-wire.d.ts +44 -0
- package/dist/openbao/remount-wire.d.ts.map +1 -0
- package/dist/openbao/rename.d.ts +106 -0
- package/dist/openbao/rename.d.ts.map +1 -0
- package/dist/openbao/role-reconcile.d.ts +40 -0
- package/dist/openbao/role-reconcile.d.ts.map +1 -0
- package/docs/caddy.md +180 -0
- package/docs/launchd.md +167 -0
- package/docs/mesh-node.md +188 -0
- package/package.json +12 -2
- package/src/caddy/admin-calls.ts +128 -0
- package/src/caddy/admin-guard.ts +170 -0
- package/src/caddy/admin.ts +74 -0
- package/src/caddy/caddyfile-tripwire.ts +133 -0
- package/src/caddy/config-form.ts +64 -0
- package/src/caddy/config-lifecycle.test.ts +218 -0
- package/src/caddy/config-lifecycle.ts +148 -0
- package/src/caddy/config.ts +116 -0
- package/src/caddy/digest.ts +44 -0
- package/src/caddy/fake-caddy.ts +160 -0
- package/src/caddy/guards.test.ts +156 -0
- package/src/caddy/index.ts +25 -0
- package/src/caddy/local-admin.test.ts +160 -0
- package/src/caddy/local-admin.ts +189 -0
- package/src/caddy/providers.test.ts +244 -0
- package/src/caddy/providers.ts +17 -0
- package/src/caddy/with-file.ts +62 -0
- package/src/cloudflare/fake-mesh.ts +181 -0
- package/src/cloudflare/index.ts +9 -3
- package/src/cloudflare/mesh-node-api.ts +127 -0
- package/src/cloudflare/mesh-node-edges.test.ts +103 -0
- package/src/cloudflare/mesh-node-form.test.ts +80 -0
- package/src/cloudflare/mesh-node-form.ts +115 -0
- package/src/cloudflare/mesh-node-harness.ts +124 -0
- package/src/cloudflare/mesh-node-lifecycle.ts +187 -0
- package/src/cloudflare/mesh-node-policy.test.ts +151 -0
- package/src/cloudflare/mesh-node-token.test.ts +117 -0
- package/src/cloudflare/mesh-node-token.ts +125 -0
- package/src/cloudflare/mesh-node.test.ts +172 -0
- package/src/cloudflare/mesh-node.ts +120 -0
- package/src/cloudflare/providers.ts +20 -2
- package/src/index.ts +2 -0
- package/src/launchd/fake-runner.ts +176 -0
- package/src/launchd/host-effect.ts +28 -0
- package/src/launchd/host-file-form.ts +71 -0
- package/src/launchd/host-file-lifecycle.test.ts +198 -0
- package/src/launchd/host-file-lifecycle.ts +164 -0
- package/src/launchd/host-file.ts +64 -0
- package/src/launchd/host-lookup.test.ts +92 -0
- package/src/launchd/host-lookup.ts +94 -0
- package/src/launchd/index.ts +26 -0
- package/src/launchd/job-form.test.ts +171 -0
- package/src/launchd/job-form.ts +180 -0
- package/src/launchd/job-identity.test.ts +147 -0
- package/src/launchd/job-lifecycle.test.ts +220 -0
- package/src/launchd/job-lifecycle.ts +194 -0
- package/src/launchd/job-preflight.ts +152 -0
- package/src/launchd/job-validate.ts +134 -0
- package/src/launchd/job.ts +96 -0
- package/src/launchd/launchctl.test.ts +181 -0
- package/src/launchd/launchctl.ts +188 -0
- package/src/launchd/local-runner.test.ts +125 -0
- package/src/launchd/local-runner.ts +143 -0
- package/src/launchd/plist.test.ts +186 -0
- package/src/launchd/plist.ts +156 -0
- package/src/launchd/providers.test.ts +222 -0
- package/src/launchd/providers.ts +21 -0
- package/src/launchd/runner.ts +95 -0
- package/src/launchd/secret-tripwire.test.ts +110 -0
- package/src/launchd/secret-tripwire.ts +81 -0
- package/src/openbao/README.md +181 -0
- package/src/openbao/REPLACE.md +163 -0
- package/src/openbao/auth-method-form.ts +7 -0
- package/src/openbao/auth-method-reconcile.ts +74 -0
- package/src/openbao/auth-method.ts +20 -41
- package/src/openbao/auth-role-form.test.ts +16 -1
- package/src/openbao/auth-role-form.ts +11 -0
- package/src/openbao/auth-role.ts +12 -0
- package/src/openbao/auth-token-form.ts +161 -0
- package/src/openbao/bao-identity.test.ts +131 -0
- package/src/openbao/bao-identity.ts +188 -0
- package/src/openbao/bao-namespace.ts +32 -0
- package/src/openbao/cloudflare-role-wire.test.ts +8 -34
- package/src/openbao/cloudflare-role.ts +30 -8
- package/src/openbao/cloudflare-roles-expand.ts +2 -5
- package/src/openbao/fake-engines.ts +119 -0
- package/src/openbao/fake-stack.ts +112 -0
- package/src/openbao/host-approles.test.ts +121 -0
- package/src/openbao/host-approles.ts +126 -0
- package/src/openbao/index.ts +19 -0
- package/src/openbao/jwt-config-form.ts +161 -0
- package/src/openbao/jwt-config.ts +85 -0
- package/src/openbao/jwt-role-form.test.ts +130 -0
- package/src/openbao/jwt-role-form.ts +231 -0
- package/src/openbao/jwt-role.ts +102 -0
- package/src/openbao/kubernetes-role-form.test.ts +82 -0
- package/src/openbao/kubernetes-role-form.ts +149 -0
- package/src/openbao/kubernetes-role.ts +94 -0
- package/src/openbao/mfa-enforcement-form.ts +147 -0
- package/src/openbao/mfa-enforcement.ts +143 -0
- package/src/openbao/mfa-totp-form.ts +155 -0
- package/src/openbao/mfa-totp.ts +118 -0
- package/src/openbao/mfa-wire.ts +117 -0
- package/src/openbao/mfa.test.ts +200 -0
- package/src/openbao/mount-form.ts +9 -1
- package/src/openbao/mount-move.test.ts +164 -0
- package/src/openbao/mount-move.ts +113 -0
- package/src/openbao/mount-path.test.ts +11 -1
- package/src/openbao/mount-path.ts +17 -11
- package/src/openbao/mount-reconcile.ts +75 -0
- package/src/openbao/mount.ts +26 -43
- package/src/openbao/pki-role-canonical.ts +163 -0
- package/src/openbao/pki-role-form.test.ts +112 -0
- package/src/openbao/pki-role-form.ts +76 -110
- package/src/openbao/pki-role.ts +12 -27
- package/src/openbao/policy-rename.test.ts +112 -0
- package/src/openbao/policy-wire.test.ts +7 -26
- package/src/openbao/policy.ts +27 -4
- package/src/openbao/proxmox-role-form.ts +27 -8
- package/src/openbao/proxmox-role-wire.ts +24 -0
- package/src/openbao/proxmox-role.ts +62 -37
- package/src/openbao/remount-wire.test.ts +87 -0
- package/src/openbao/remount-wire.ts +112 -0
- package/src/openbao/rename-occupied.test.ts +166 -0
- package/src/openbao/rename.ts +162 -0
- package/src/openbao/role-reconcile.test.ts +104 -0
- package/src/openbao/role-reconcile.ts +84 -0
- package/src/openbao/role-rename.test.ts +205 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import * as Exit from 'effect/Exit';
|
|
3
|
+
import { type FakeMesh } from './fake-mesh.ts';
|
|
4
|
+
import { MeshNode } from './mesh-node.ts';
|
|
5
|
+
import type { MeshNodeAttributes, MeshNodeProps } from './mesh-node-form.ts';
|
|
6
|
+
export declare const ids: {
|
|
7
|
+
fqn: string;
|
|
8
|
+
id: string;
|
|
9
|
+
instanceId: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const extra: {
|
|
12
|
+
bindings: never;
|
|
13
|
+
session: never;
|
|
14
|
+
};
|
|
15
|
+
export type P = Effect.Success<typeof MeshNode.Provider>;
|
|
16
|
+
export declare const handler: <F>(name: string, fn: F | undefined) => F;
|
|
17
|
+
/** Build the provider over the fake (as `accountId`'s environment) and hand it to `use`. */
|
|
18
|
+
export declare const run: <A, E>(fake: FakeMesh, use: (p: P) => Effect.Effect<A, E>, accountId?: string) => Promise<A>;
|
|
19
|
+
export declare const reconcile: (p: P, news: MeshNodeProps, output?: MeshNodeAttributes) => Effect.Effect<MeshNodeAttributes, any, never>;
|
|
20
|
+
export declare const read: (p: P, olds: MeshNodeProps, output?: MeshNodeAttributes) => Effect.Effect<MeshNodeAttributes | undefined, any, never>;
|
|
21
|
+
export declare const diff: (p: P, news: MeshNodeProps, olds: MeshNodeProps, output: MeshNodeAttributes) => Effect.Effect<void | import("alchemy").Diff, any, never>;
|
|
22
|
+
/** A stored attribute set for a node that may or may not exist in the fake. */
|
|
23
|
+
export declare const stored: (accountId: string, over?: Partial<MeshNodeAttributes>) => MeshNodeAttributes;
|
|
24
|
+
export declare const tokenReads: (fake: FakeMesh) => number;
|
|
25
|
+
/** The writes the fake saw, in order: `['POST', 'DELETE', …]`. */
|
|
26
|
+
export declare const writes: (fake: FakeMesh) => string[];
|
|
27
|
+
/**
|
|
28
|
+
* ★ THE REAL ENGINE, NOT A MODEL OF IT: Alchemy's own `Plan.make` + `apply` over an in-memory
|
|
29
|
+
* state store, which is what its Test harness's scratch stacks run (Test/Core.ts
|
|
30
|
+
* `scratchStack`), minus the profile, config and telemetry layers a fake Cloudflare does not
|
|
31
|
+
* need. Removal policy lives in the engine, so only this can show what it does to a replace.
|
|
32
|
+
* ⚠️ `FetchHttpClient.Fetch` IS READ PER REQUEST, from the fiber running the engine, so it is
|
|
33
|
+
* provided around the whole deploy. Provided only under the provider layer, the requests went
|
|
34
|
+
* to the real `fetch` (measured 2026-09-21: ENOTFOUND api.example.com, the RFC 2606 host, so
|
|
35
|
+
* no API answered — but a real DNS lookup went out).
|
|
36
|
+
*/
|
|
37
|
+
export declare const engine: (fake: FakeMesh) => {
|
|
38
|
+
deploy: <A, E, R>(declare: Effect.Effect<A, E, R>) => Promise<Exit.Exit<unknown, unknown>>;
|
|
39
|
+
/** The stored row's status (`created`, `replacing`, …), or `undefined` when there is none. */
|
|
40
|
+
status: (fqn: string) => "created" | "creating" | "deleting" | "replaced" | "replacing" | "updated" | "updating" | undefined;
|
|
41
|
+
/** ★ What `alchemy state rm` does ("Delete state records without deleting cloud resources"). */
|
|
42
|
+
forget: (fqn: string) => void;
|
|
43
|
+
};
|
|
44
|
+
/** The failure sentence of a deploy, or `''` when it succeeded. */
|
|
45
|
+
export declare const failureOf: (exit: Exit.Exit<unknown, unknown>) => string;
|
|
46
|
+
//# sourceMappingURL=mesh-node-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-node-harness.d.ts","sourceRoot":"","sources":["../../src/cloudflare/mesh-node-harness.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,KAAK,QAAQ,EAAqB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,eAAO,MAAM,GAAG;IAAK,GAAG;IAAgB,EAAE;IAAU,UAAU;CAAS,CAAC;AACxE,eAAO,MAAM,KAAK;IAAK,QAAQ,EAAQ,KAAK;IAAE,OAAO,EAAe,KAAK;CAAE,CAAC;AAE5E,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAEzD,eAAO,MAAM,OAAO,GAAI,CAAC,QAAQ,MAAM,MAAM,CAAC,GAAG,SAAS,KAAG,CAG5D,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,CAAC,QAAQ,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,MAAM,eAS7F,CAAC;AAEJ,eAAO,MAAM,SAAS,MAAO,CAAC,QAAQ,aAAa,WAAW,kBAAkB,kDACd,CAAC;AAEnE,eAAO,MAAM,IAAI,MAAO,CAAC,QAAQ,aAAa,WAAW,kBAAkB,8DACxB,CAAC;AAEpD,eAAO,MAAM,IAAI,MAAO,CAAC,QAAQ,aAAa,QAAQ,aAAa,UAAU,kBAAkB,6DAW3F,CAAC;AAEL,+EAA+E;AAC/E,eAAO,MAAM,MAAM,cACN,MAAM,SACX,OAAO,CAAC,kBAAkB,CAAC,KAChC,kBAOD,CAAC;AAEH,eAAO,MAAM,UAAU,SAAU,QAAQ,WACkB,CAAC;AAE5D,kEAAkE;AAClE,eAAO,MAAM,MAAM,SAAU,QAAQ,aAC6B,CAAC;AAInE;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,SAAU,QAAQ;aAInB,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IActD,8FAA8F;kBAChF,MAAM;IACpB,gGAAgG;kBAClF,MAAM;CAIvB,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,SAAS,SAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,WACG,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import { MeshNodeError } from './mesh-node-api.ts';
|
|
3
|
+
import { type MeshNodeAttributes, type MeshNodeProps } from './mesh-node-form.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Owned: refresh by the stored id. Cold: find the live node by exact name and hand it back
|
|
6
|
+
* `Unowned`, so Alchemy refuses to take it over until the stack says `adopt(true)` — the same
|
|
7
|
+
* gate `Cloudflare.Tunnel.WarpConnector` uses, because a `warp_connector` carries no ownership
|
|
8
|
+
* marker to prove it was ours.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ ADOPTION RECORDS THE DECLARED `ha`, BECAUSE NOTHING ELSE CAN. No documented read returns a
|
|
11
|
+
* node's HA flag. Adopting an existing node with the wrong `ha` records the wrong value, and no
|
|
12
|
+
* later plan can notice. Check the node's HA badge in the dashboard before adopting.
|
|
13
|
+
*/
|
|
14
|
+
export declare const readMeshNode: (accountId: string, olds: MeshNodeProps | undefined, output: MeshNodeAttributes | undefined) => Effect.Effect<MeshNodeAttributes | undefined, MeshNodeError | import("@distilled.cloud/cloudflare/zero-trust").ListTunnelWarpConnectorsError, import("@distilled.cloud/cloudflare/Protocol").CloudflareOpContext>;
|
|
15
|
+
export declare const reconcileMeshNode: (accountId: string, news: MeshNodeProps, output: MeshNodeAttributes | undefined) => Effect.Effect<MeshNodeAttributes, import("@distilled.cloud/cloudflare/zero-trust").Forbidden | MeshNodeError | import("@distilled.cloud/cloudflare/zero-trust").TunnelNotFound | import("@distilled.cloud/cloudflare/Protocol").CloudflareOpError, import("@distilled.cloud/cloudflare/Protocol").CloudflareOpContext>;
|
|
16
|
+
/**
|
|
17
|
+
* ⚠️ Cloudflare may refuse to delete a node while replicas are connected (Alchemy's WarpConnector
|
|
18
|
+
* notes "Deleting requires all connector sessions to be down"; unmeasured here). Stop the
|
|
19
|
+
* client on every replica first. A node already gone is a successful delete.
|
|
20
|
+
*/
|
|
21
|
+
export declare const deleteMeshNode: (output: MeshNodeAttributes) => Effect.Effect<void, import("@distilled.cloud/cloudflare/zero-trust").Forbidden | import("@distilled.cloud/cloudflare/Protocol").CloudflareOpError, import("@distilled.cloud/cloudflare/Protocol").CloudflareOpContext>;
|
|
22
|
+
//# sourceMappingURL=mesh-node-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-node-lifecycle.d.ts","sourceRoot":"","sources":["../../src/cloudflare/mesh-node-lifecycle.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EACL,aAAa,EAOd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAoB,MAAM,qBAAqB,CAAC;AAUpG;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,cACZ,MAAM,QACX,aAAa,GAAG,SAAS,UACvB,kBAAkB,GAAG,SAAS,sNAapC,CAAC;AAoGL,eAAO,MAAM,iBAAiB,cACjB,MAAM,QACX,aAAa,UACX,kBAAkB,GAAG,SAAS,2TAwBpC,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,cAAc,WAAY,kBAAkB,2NAChB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as zeroTrust from '@distilled.cloud/cloudflare/zero-trust';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import * as Redacted from 'effect/Redacted';
|
|
4
|
+
import { MeshNodeError } from './mesh-node-api.ts';
|
|
5
|
+
/** Which node: by id (the `MeshNode` attribute) or by its exact name. */
|
|
6
|
+
export type MeshNodeRef = {
|
|
7
|
+
readonly accountId: string;
|
|
8
|
+
} & ({
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly name?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly id?: undefined;
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* ⛔ An EMPTY token fails closed: `warp-cli connector new ""` would not enrol, and a script that
|
|
17
|
+
* wrote an empty file would report success over a host that never joined.
|
|
18
|
+
* ⛔ The failures made here name the node and account and quote no response body, because the
|
|
19
|
+
* success body IS the token. Other SDK errors pass through; they come only from non-2xx
|
|
20
|
+
* responses, which carry an error envelope, not a token.
|
|
21
|
+
*/
|
|
22
|
+
export declare const fetchMeshNodeToken: (ref: MeshNodeRef) => Effect.Effect<Redacted.Redacted<string>, import("@distilled.cloud/cloudflare/Errors").BadGateway | import("@distilled.cloud/cloudflare/Errors").CloudflareError | import("@distilled.cloud/cloudflare/Errors").CloudflareHttpError | import("@distilled.cloud/cloudflare/Errors").CloudflareParseError | import("@distilled.cloud/cloudflare/Errors").CloudflareRateLimited | import("@distilled.cloud/cloudflare/Errors").ConfigError | zeroTrust.Forbidden | import("@distilled.cloud/cloudflare/Errors").GatewayTimeout | import("effect/unstable/http/HttpClientError").HttpClientError | import("@distilled.cloud/cloudflare/Errors").InternalServerError | import("@distilled.cloud/cloudflare/Errors").InvalidRoute | MeshNodeError | import("@distilled.cloud/cloudflare/Credentials").OAuthRefreshError | import("@distilled.cloud/cloudflare/Errors").ServiceUnavailable | import("@distilled.cloud/cloudflare/Errors").TooManyRequests | import("@distilled.cloud/cloudflare/Errors").Unauthorized | import("@distilled.cloud/cloudflare/Errors").UnknownCloudflareError, zeroTrust.CloudflareOpContext>;
|
|
23
|
+
//# sourceMappingURL=mesh-node-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-node-token.d.ts","sourceRoot":"","sources":["../../src/cloudflare/mesh-node-token.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,SAAS,MAAM,wCAAwC,CAAC;AACpE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAkB,MAAM,oBAAoB,CAAC;AAEnE,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,CACvD;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,CAAA;CAAE,CACrD,CAAC;AAoDF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,QAAS,WAAW,wjCA4B/C,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Cloudflare.MeshNode` — a Cloudflare Mesh node (a `warp_connector` object), declared without
|
|
3
|
+
* its token ever touching Alchemy state. Usage and the enrolment step: docs/mesh-node.md.
|
|
4
|
+
*
|
|
5
|
+
* 🔴 WHY THIS EXISTS ALONGSIDE `Cloudflare.Tunnel.WarpConnector`. A Mesh node that fronts a
|
|
6
|
+
* private service needs a node record in the graph, so the Gateway rules and DNS records that
|
|
7
|
+
* name it deploy together. Alchemy beta.79's WarpConnector would put the node token — the
|
|
8
|
+
* credential that lets any Linux host join the account's Mesh as that node — into plaintext
|
|
9
|
+
* state on every read, and it cannot create an HA node. See mesh-node-form.ts.
|
|
10
|
+
*
|
|
11
|
+
* ★ REMOVAL POLICY: `retain` BY DEFAULT — see the ★ on `MeshNode` below, and what it does to an
|
|
12
|
+
* `ha` replace in mesh-node-lifecycle.ts.
|
|
13
|
+
*/
|
|
14
|
+
import { Credentials } from '@distilled.cloud/cloudflare/Credentials';
|
|
15
|
+
import * as Cloudflare from 'alchemy/Cloudflare';
|
|
16
|
+
import * as Provider from 'alchemy/Provider';
|
|
17
|
+
import { Resource, type ResourceClass } from 'alchemy/Resource';
|
|
18
|
+
import * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
19
|
+
import { type MeshNodeAttributes, type MeshNodeProps } from './mesh-node-form.ts';
|
|
20
|
+
import type { Providers } from './providers.ts';
|
|
21
|
+
export interface MeshNode extends Resource<'Cloudflare.MeshNode', MeshNodeProps, MeshNodeAttributes, never, Providers> {
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* ★ `defaultRemovalPolicy: 'retain'`, LIKE EVERY KIT RESOURCE WHOSE DELETION BREAKS ITS CONSUMERS
|
|
25
|
+
* (the `Bao.*` families, `R2BucketLock`, the Proxmox storage families; the reasoning is written
|
|
26
|
+
* once in proxmox/resource.ts). Deleting a node cuts every enrolled replica off the Mesh, and
|
|
27
|
+
* nothing brings it back: a new node has a new id, a new token and a new Mesh IP per replica, so
|
|
28
|
+
* each host must be re-enrolled by hand and every Gateway rule or allow-list that pins the old
|
|
29
|
+
* Mesh IP breaks. So dropping the declaration, or `alchemy destroy`, leaves the node live.
|
|
30
|
+
* ⚠️ IT ALSO SKIPS THE OLD NODE'S DELETE IN A REPLACE (Apply.ts, `deleteOldGenerations` and the
|
|
31
|
+
* GC's `retainOldGeneration`, beta.79). A same-name `ha` change therefore REFUSES, deleting
|
|
32
|
+
* nothing, until that deploy opts in with `.pipe(RemovalPolicy.destroy())`; a create-first
|
|
33
|
+
* replace leaves the old node live and unmanaged. Both measured in mesh-node-policy.test.ts.
|
|
34
|
+
* ⛔ `delete` STAYS FULLY IMPLEMENTED. Retain is Terraform's `prevent_destroy`, not a stub: it runs
|
|
35
|
+
* the moment a declaration opts in with `.pipe(RemovalPolicy.destroy())`.
|
|
36
|
+
*/
|
|
37
|
+
export declare const MeshNode: ResourceClass<MeshNode>;
|
|
38
|
+
/** What every call below needs: the account, credentials and HTTP — Alchemy's own trio. */
|
|
39
|
+
export type MeshNodeServices = Cloudflare.CloudflareEnvironment | Credentials | HttpClient.HttpClient;
|
|
40
|
+
/**
|
|
41
|
+
* ★ `Provider.effect`, CAPTURING THE THREE SERVICES AT BUILD. `Provider.succeed` (what Alchemy's
|
|
42
|
+
* own providers use) leaves each handler to find CloudflareEnvironment and Credentials in the
|
|
43
|
+
* engine's context at call time — which works for `Cloudflare.providers()` only because it
|
|
44
|
+
* `provideMerge`s them into the stack. Capturing them here keeps this provider correct whether
|
|
45
|
+
* or not the stack also merges `Cloudflare.providers()`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const MeshNodeProvider: () => import("effect/Layer").Layer<Provider.Provider<MeshNode>, never, Cloudflare.CloudflareEnvironment | Credentials | HttpClient.HttpClient>;
|
|
48
|
+
//# sourceMappingURL=mesh-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-node.d.ts","sourceRoot":"","sources":["../../src/cloudflare/mesh-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAGnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,WAAW,QAAS,SAAQ,QAAQ,CACxC,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,SAAS,CACV;CAAG;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAE3C,CAAC;AAEH,2FAA2F;AAC3F,MAAM,MAAM,gBAAgB,GACxB,UAAU,CAAC,qBAAqB,GAChC,WAAW,GACX,UAAU,CAAC,UAAU,CAAC;AAQ1B;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,gJA4C1B,CAAC"}
|
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The HomeFlare Cloudflare provider collection, in the shape `LiteLLM.providers()` has.
|
|
3
|
-
*
|
|
4
|
-
* ★ ONE LAYER, BUILT ONCE, so the single `Config.Redacted('CLOUDFLARE_API_TOKEN')` read is shared
|
|
5
|
-
* by every resource in the stack rather than repeated per resource.
|
|
6
|
-
*
|
|
7
|
-
* ⚠️ THIS IS NOT `alchemy/Cloudflare`'s COLLECTION AND DOES NOT REPLACE IT. A stack that declares
|
|
8
|
-
* both a `Cloudflare.R2.Bucket` and this lock merges the two:
|
|
9
|
-
* `Layer.mergeAll(Cloudflare.providers(), HomeflareCloudflare.providers())` — the shape
|
|
10
|
-
* a consuming stack names for one talking to more than one account.
|
|
11
|
-
*/
|
|
12
1
|
import * as Provider from 'alchemy/Provider';
|
|
13
2
|
import * as Layer from 'effect/Layer';
|
|
14
3
|
declare const Providers_base: Provider.ProviderCollection<Providers, "HomeflareCloudflare">;
|
|
15
4
|
export declare class Providers extends Providers_base {
|
|
16
5
|
}
|
|
17
|
-
export declare const providers: () => Layer.Layer<import("./client.ts").CloudflareApi | Providers, never,
|
|
6
|
+
export declare const providers: () => Layer.Layer<import("./client.ts").CloudflareApi | Providers, never, import("alchemy").AuthProviders | import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/Crypto").Crypto | import("effect/FileSystem").FileSystem | import("effect/unstable/http/HttpClient").HttpClient | import("effect/Path").Path>;
|
|
18
7
|
export {};
|
|
19
8
|
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/cloudflare/providers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/cloudflare/providers.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;;AAKtC,qBAAa,SAAU,SAAQ,cAA+D;CAAG;AAEjG,eAAO,MAAM,SAAS,sVAWnB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* import { BaoMount } from '@homeflare/alchemy/openbao';
|
|
10
10
|
* import { TalosCluster } from '@homeflare/alchemy/talos';
|
|
11
11
|
* import { ProxmoxAcl } from '@homeflare/alchemy/proxmox';
|
|
12
|
+
* import { LaunchdJob } from '@homeflare/alchemy/launchd';
|
|
13
|
+
* import { CaddyConfig } from '@homeflare/alchemy/caddy';
|
|
12
14
|
*
|
|
13
15
|
* ★ WHY THESE EXIST AT ALL. When Alchemy has no resource for something, the alternative
|
|
14
16
|
* is a runbook step a human runs once — and a plan can never show a missing runbook
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ExecResult, FileStat, HostRunner, HostUser } from './runner.ts';
|
|
2
|
+
type Entry = {
|
|
3
|
+
bytes: Uint8Array;
|
|
4
|
+
mode: number;
|
|
5
|
+
uid: number;
|
|
6
|
+
gid: number;
|
|
7
|
+
kind: FileStat['kind'];
|
|
8
|
+
};
|
|
9
|
+
export type FakeOptions = {
|
|
10
|
+
euid?: number;
|
|
11
|
+
privileged?: boolean;
|
|
12
|
+
/** Directories that exist, and their owner uid. */
|
|
13
|
+
dirs?: Record<string, number>;
|
|
14
|
+
users?: Record<string, HostUser>;
|
|
15
|
+
groups?: Record<string, number>;
|
|
16
|
+
};
|
|
17
|
+
export declare const fakeRunner: (options?: FakeOptions) => {
|
|
18
|
+
calls: string[][];
|
|
19
|
+
disabled: Set<string>;
|
|
20
|
+
dirs: Map<string, number>;
|
|
21
|
+
files: Map<string, Entry>;
|
|
22
|
+
loaded: Map<string, number | undefined>;
|
|
23
|
+
runner: HostRunner;
|
|
24
|
+
state: {
|
|
25
|
+
lingerPrints: number;
|
|
26
|
+
nextPid: number;
|
|
27
|
+
bootstrapFailure: ExecResult | undefined;
|
|
28
|
+
/** Returned by bootout in place of success. The job still goes, unless `bootoutKeepsJob`. */
|
|
29
|
+
bootoutFailure: ExecResult | undefined;
|
|
30
|
+
bootoutKeepsJob: boolean;
|
|
31
|
+
/** gui uids with no login session: every launchctl call into `gui/<uid>` exits 112. */
|
|
32
|
+
loggedOut: Set<number>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=fake-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-runner.d.ts","sourceRoot":"","sources":["../../src/launchd/fake-runner.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAE5F,KAAK,KAAK,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAEnG,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AA0BF,eAAO,MAAM,UAAU,aAAa,WAAW;;;;;;;;;;0BAaZ,UAAU,GAAG,SAAS;QACrD,6FAA6F;wBAChE,UAAU,GAAG,SAAS;;QAEnD,uFAAuF;;;CA4G1F,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place a HostRunner's promises become Effects — plus the one probe of an unresolved
|
|
3
|
+
* `news` both providers' diffs share.
|
|
4
|
+
*
|
|
5
|
+
* ★ The lifecycle files are plain async functions over a HostRunner (see runner.ts for why the
|
|
6
|
+
* runner is promise-based), so each provider handler is a single `lift(() => step(runner, …))`.
|
|
7
|
+
* ⚠️ A thrown Error stays that Error — its message is the refusal a deploy prints. Anything else
|
|
8
|
+
* thrown is wrapped, so the failure channel is always an Error with a readable message.
|
|
9
|
+
*/
|
|
10
|
+
import * as Effect from 'effect/Effect';
|
|
11
|
+
export declare const lift: <A>(step: () => Promise<A>) => Effect.Effect<A, Error>;
|
|
12
|
+
/**
|
|
13
|
+
* A string prop of a diff's `news`, when that one prop is already resolved; `undefined` while it
|
|
14
|
+
* is still an Output (a function-typed proxy), an Effect or a Config.
|
|
15
|
+
* ★ For the identity props a diff must see even when the rest of `news` is unresolved — a plain
|
|
16
|
+
* string is resolved by definition, so `typeof` is the whole test.
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolvedString: (news: unknown, key: string) => string | undefined;
|
|
19
|
+
//# sourceMappingURL=host-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-effect.d.ts","sourceRoot":"","sources":["../../src/launchd/host-effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,eAAO,MAAM,IAAI,GAAI,CAAC,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAInE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SAAU,OAAO,OAAO,MAAM,KAAG,MAAM,GAAG,SAIpE,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface HostFileProps {
|
|
2
|
+
/** Absolute path. The parent directory must already exist. */
|
|
3
|
+
path: string;
|
|
4
|
+
/** UTF-8 text. ⛔ Never a secret — see the file header. */
|
|
5
|
+
content: string;
|
|
6
|
+
/** Permission bits. @default 0o644 */
|
|
7
|
+
mode?: number;
|
|
8
|
+
/** User name or numeric uid. Omitted: whoever the runner writes as (a rewrite keeps no owner). */
|
|
9
|
+
owner?: string | number;
|
|
10
|
+
/** Group name or numeric gid. Omitted: the directory's default group. */
|
|
11
|
+
group?: string | number;
|
|
12
|
+
}
|
|
13
|
+
export interface HostFileAttributes {
|
|
14
|
+
path: string;
|
|
15
|
+
/** SHA-256 of the bytes on disk. */
|
|
16
|
+
sha256: string;
|
|
17
|
+
mode: number;
|
|
18
|
+
uid: number;
|
|
19
|
+
gid: number;
|
|
20
|
+
size: number;
|
|
21
|
+
}
|
|
22
|
+
export declare const DEFAULT_MODE = 420;
|
|
23
|
+
export declare const fileProblems: (props: HostFileProps) => string[];
|
|
24
|
+
//# sourceMappingURL=host-file-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-file-form.d.ts","sourceRoot":"","sources":["../../src/launchd/host-file-form.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,YAAY,MAAQ,CAAC;AAclC,eAAO,MAAM,YAAY,UAAW,aAAa,KAAG,MAAM,EAsBzD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HostFile's read / diff / reconcile / delete as plain async functions over a HostRunner, so the
|
|
3
|
+
* lifecycle runs against fake-runner.ts in tests.
|
|
4
|
+
*
|
|
5
|
+
* ⛔ SYMLINKS AND DIRECTORIES ARE REFUSED, NOT REPLACED. rename(2) over a symlink replaces the LINK,
|
|
6
|
+
* so a path that is a symlink (nix-darwin's /etc entries point into /nix/store) would be quietly
|
|
7
|
+
* taken from the tool that owns it — which puts it back, or refuses its next activation. Remove
|
|
8
|
+
* the path from its owner first, then declare it here.
|
|
9
|
+
*/
|
|
10
|
+
import type { Diff } from 'alchemy/Diff';
|
|
11
|
+
import { type HostFileAttributes, type HostFileProps } from './host-file-form.ts';
|
|
12
|
+
import { type HostRunner } from './runner.ts';
|
|
13
|
+
type Desired = {
|
|
14
|
+
readonly bytes: Uint8Array;
|
|
15
|
+
readonly sha256: string;
|
|
16
|
+
readonly mode: number;
|
|
17
|
+
readonly uid?: number;
|
|
18
|
+
readonly gid?: number;
|
|
19
|
+
};
|
|
20
|
+
/** Validate, then resolve owner/group names to ids through the runner. */
|
|
21
|
+
export declare const desiredFile: (runner: HostRunner, props: HostFileProps) => Promise<Desired>;
|
|
22
|
+
/** The file as it is now, or `undefined` when nothing is at the path. Non-files read with no digest. */
|
|
23
|
+
export declare const readFileAttributes: (runner: HostRunner, path: string) => Promise<HostFileAttributes | undefined>;
|
|
24
|
+
export declare const diffFile: (runner: HostRunner, news: HostFileProps, output: HostFileAttributes) => Promise<Diff>;
|
|
25
|
+
export declare const reconcileFile: (runner: HostRunner, props: HostFileProps, output?: HostFileAttributes) => Promise<HostFileAttributes>;
|
|
26
|
+
/** Remove the file. Idempotent. ⛔ Refuses a path that has since become a symlink or directory. */
|
|
27
|
+
export declare const deleteFile: (runner: HostRunner, output: HostFileAttributes) => Promise<void>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=host-file-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-file-lifecycle.d.ts","sourceRoot":"","sources":["../../src/launchd/host-file-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,UAAU,EAAgB,MAAM,aAAa,CAAC;AAE5D,KAAK,OAAO,GAAG;IACb,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAOF,0EAA0E;AAC1E,eAAO,MAAM,WAAW,WAAkB,UAAU,SAAS,aAAa,KAAG,OAAO,CAAC,OAAO,CAqB3F,CAAC;AAEF,wGAAwG;AACxG,eAAO,MAAM,kBAAkB,WACrB,UAAU,QACZ,MAAM,KACX,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAYxC,CAAC;AAQF,eAAO,MAAM,QAAQ,WACX,UAAU,QACZ,aAAa,UACX,kBAAkB,KACzB,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF,eAAO,MAAM,aAAa,WAChB,UAAU,SACX,aAAa,WACX,kBAAkB,KAC1B,OAAO,CAAC,kBAAkB,CA0D5B,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,UAAU,WAAkB,UAAU,UAAU,kBAAkB,KAAG,OAAO,CAAC,IAAI,CAK7F,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Host.File` — one text file on the host, declared: content, mode, owner, group.
|
|
3
|
+
*
|
|
4
|
+
* - create / update — atomic write (temp file in the same directory, mode and owner set, rename),
|
|
5
|
+
* skipped when the file already matches; then read back and compared.
|
|
6
|
+
* - read — lstat plus the SHA-256 of the bytes.
|
|
7
|
+
* - diff — declared SHA-256 against the stored and on-disk digest, plus mode and owner.
|
|
8
|
+
* - replace — only when `path` changes; create-before-delete.
|
|
9
|
+
* - delete — removes the file.
|
|
10
|
+
*
|
|
11
|
+
* ⛔ NEVER A SECRET — see host-file-form.ts. Secret files stay rendered by openbao-agent.
|
|
12
|
+
* ⚠️ NOTHING IS ADOPTED WITHOUT `--adopt`: a file already at the path reads as `Unowned`.
|
|
13
|
+
* ★ IT LIVES IN THE launchd SUBPATH because the two travel together: a Mac host stack declares a
|
|
14
|
+
* daemon's config file and the daemon that reads it, through the same HostRunner.
|
|
15
|
+
*/
|
|
16
|
+
import { Resource } from 'alchemy';
|
|
17
|
+
import * as Provider from 'alchemy/Provider';
|
|
18
|
+
import type { HostFileAttributes, HostFileProps } from './host-file-form.ts';
|
|
19
|
+
import { HostRunnerService } from './runner.ts';
|
|
20
|
+
export type { HostFileAttributes, HostFileProps } from './host-file-form.ts';
|
|
21
|
+
export interface HostFile extends Resource<'Host.File', HostFileProps, HostFileAttributes> {
|
|
22
|
+
}
|
|
23
|
+
export declare const HostFile: import("alchemy").ResourceClass<HostFile>;
|
|
24
|
+
export declare const HostFileProvider: () => import("effect/Layer").Layer<Provider.Provider<HostFile>, never, HostRunnerService>;
|
|
25
|
+
//# sourceMappingURL=host-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-file.d.ts","sourceRoot":"","sources":["../../src/launchd/host-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,MAAM,WAAW,QAAS,SAAQ,QAAQ,CAAC,WAAW,EAAE,aAAa,EAAE,kBAAkB,CAAC;CAAG;AAE7F,eAAO,MAAM,QAAQ,2CAAkC,CAAC;AAExD,eAAO,MAAM,gBAAgB,2FAgC1B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User and group lookups, as argv plus a parser — split out so the parsing is tested against the
|
|
3
|
+
* real output shapes without running anything.
|
|
4
|
+
*
|
|
5
|
+
* ★ macOS FIRST, getent ELSEWHERE. macOS has no `getent`; its directory service answers through
|
|
6
|
+
* `dscacheutil`. Shape MEASURED 2026-09-21 on macOS 27.2 (read-only query):
|
|
7
|
+
*
|
|
8
|
+
* name: someone
|
|
9
|
+
* password: ********
|
|
10
|
+
* uid: 501
|
|
11
|
+
* gid: 20
|
|
12
|
+
* dir: /Users/someone
|
|
13
|
+
* shell: /bin/zsh
|
|
14
|
+
*
|
|
15
|
+
* An unknown uid printed NOTHING and exited 0 — so "no record" is an empty parse, never an
|
|
16
|
+
* exit code. `getent` exits 2 for an unknown key; that also parses as no record.
|
|
17
|
+
* ⛔ NEVER PARSE OR KEEP THE `password:` LINE. It is a placeholder on macOS, but a parser that
|
|
18
|
+
* copies every field would carry a hash from any host where it is not.
|
|
19
|
+
*/
|
|
20
|
+
import type { HostUser } from './runner.ts';
|
|
21
|
+
/** argv for looking up a user, by name or numeric id. */
|
|
22
|
+
export declare const userQuery: (platform: string, nameOrId: string) => readonly string[];
|
|
23
|
+
/** argv for looking up a group, by name or numeric id. */
|
|
24
|
+
export declare const groupQuery: (platform: string, nameOrId: string) => readonly string[];
|
|
25
|
+
export declare const parseUser: (platform: string, stdout: string) => HostUser | undefined;
|
|
26
|
+
export declare const parseGroup: (platform: string, stdout: string) => number | undefined;
|
|
27
|
+
//# sourceMappingURL=host-lookup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-lookup.d.ts","sourceRoot":"","sources":["../../src/launchd/host-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,yDAAyD;AACzD,eAAO,MAAM,SAAS,aAAc,MAAM,YAAY,MAAM,KAAG,SAAS,MAAM,EAU1C,CAAC;AAErC,0DAA0D;AAC1D,eAAO,MAAM,UAAU,aAAc,MAAM,YAAY,MAAM,KAAG,SAAS,MAAM,EAU5C,CAAC;AAsBpC,eAAO,MAAM,SAAS,aAAc,MAAM,UAAU,MAAM,KAAG,QAAQ,GAAG,SAkBvE,CAAC;AAEF,eAAO,MAAM,UAAU,aAAc,MAAM,UAAU,MAAM,KAAG,MAAM,GAAG,SAItE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* launchd providers for Alchemy — declare a Mac host's jobs and their config files.
|
|
3
|
+
*
|
|
4
|
+
* ⛔ THIS BARREL IS THE PUBLIC API, AND IT IS DELIBERATELY SMALLER THAN THE DIRECTORY. The
|
|
5
|
+
* lifecycle files, the launchctl parsers and the fake runner are internals; an `export *` would
|
|
6
|
+
* publish them as API and make the next refactor a breaking change.
|
|
7
|
+
* ⛔ macOS HOSTS ONLY for LaunchdJob. HostFile and the runner work on any POSIX host, but the
|
|
8
|
+
* subpath exists for the Mac: see docs/launchd.md for the cutover from nix-darwin.
|
|
9
|
+
*/
|
|
10
|
+
export type { HostFileAttributes, HostFileProps } from './host-file.ts';
|
|
11
|
+
export { HostFile, HostFileProvider } from './host-file.ts';
|
|
12
|
+
export type { CalendarInterval, KeepAlive, LaunchdDomain, LaunchdJobAttributes, LaunchdJobProps, } from './job.ts';
|
|
13
|
+
export { LaunchdJob, LaunchdJobProvider } from './job.ts';
|
|
14
|
+
export type { LocalRunnerOptions } from './local-runner.ts';
|
|
15
|
+
export { localRunner } from './local-runner.ts';
|
|
16
|
+
export type { PlistDict, PlistValue } from './plist.ts';
|
|
17
|
+
export { PlistError, renderPlist } from './plist.ts';
|
|
18
|
+
export { launchdProviders } from './providers.ts';
|
|
19
|
+
export type { ExecResult, FileStat, HostRunner, HostUser, WriteOptions } from './runner.ts';
|
|
20
|
+
export { HostRunnerService, canActAsRoot, hostRunnerLayer } from './runner.ts';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/launchd/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|