@intentius/behold 0.2.3 → 0.4.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.
@@ -0,0 +1,88 @@
1
+ # Your first apply with behold
2
+
3
+ The smallest real thing: one S3 bucket, deployed from the browser by clicking
4
+ **Sync**. It exists to show where the delegated-write buttons come from and what
5
+ they do — behold never applies anything itself, it triggers the `ApplyOp` you
6
+ committed here, running `chant` on your machine.
7
+
8
+ ```
9
+ src/bucket.ts one S3 Bucket + a TLS-only policy (the whole "infra")
10
+ ops/apply.op.ts ApplyOp "prod-apply" — code → real AWS (aws cloudformation deploy)
11
+ ops/floci.op.ts Op "floci-apply" — code → local Floci (CloudFormation API), no account
12
+ ops/reconcile.op.ts ReconcileOp "prod-reconcile" — cloud → code PR (the Adopt button)
13
+ chant.config.ts lexicons [aws, temporal], environments [prod]
14
+ ```
15
+
16
+ The **Sync** button appears because a project declares an `ApplyOp`. A project with
17
+ no `*.op.ts` (like `../example`) shows no Sync — that's expected, not a bug.
18
+
19
+ ## Creds-free: deploy to a local emulator (`--local`)
20
+
21
+ No AWS account? Serve with `--local` and behold boots a local Floci emulator
22
+ (needs Docker), then the **floci-apply** Op deploys the bucket to it — the same
23
+ delegated-write path, zero cloud creds:
24
+
25
+ ```sh
26
+ # from the behold repo root
27
+ npm run dev -- serve example-writes --local
28
+ # → boots chant-floci, header shows "● local · chant-floci up"
29
+ ```
30
+
31
+ Click **floci-apply** (or `curl -XPOST localhost:4600/api/ops/floci-apply/run`).
32
+ The now-line streams Build → Apply → Verify; the bucket is created in Floci via
33
+ the CloudFormation API (`awsApply`, no `aws` CLI). The emulator is torn down when
34
+ you Ctrl-C. Everything below uses real AWS instead.
35
+
36
+ ## Prerequisites
37
+
38
+ - Node 20+, and **AWS credentials** in your environment (`aws sts get-caller-identity`
39
+ should work). The apply creates a real S3 bucket via CloudFormation — a few cents,
40
+ torn down at the end. behold holds no creds; `chant` uses yours on this machine.
41
+ - One edit: S3 bucket names are **globally unique**, so change `BucketName` in
42
+ [`src/bucket.ts`](src/bucket.ts) to something of your own (e.g. include your AWS
43
+ account id or a random suffix).
44
+
45
+ ## Steps
46
+
47
+ ```sh
48
+ # from this directory — installs the project's own chant + lexicons
49
+ npm install
50
+
51
+ # from the behold repo root — serve this project, with the prod overlay on
52
+ npm run dev -- serve example-writes --env prod
53
+ # → behold → http://localhost:4600
54
+ ```
55
+
56
+ 1. Open **http://localhost:4600**. You see the declared graph. With `--env prod`,
57
+ the bucket node is **blue (pending)** — declared, not deployed yet. (No AWS creds?
58
+ drop `--env` for the plain source graph; Sync still works, you just won't see the
59
+ colour flip.)
60
+ 2. In the header, click **Sync**. The now-line streams the Op's phases:
61
+ `▶ chant run prod-apply` → Build → Plan → **Apply** (`aws cloudformation deploy`).
62
+ `prod-apply` is **ungated**, so it applies straight away — no approval step.
63
+ 3. When it finishes, the `store` node flips **blue → green (managed)**. Click it: the
64
+ inspect panel's **live** section shows the bucket's observed **physical id** and
65
+ status. That's the hydration — the cloud's view of your declared resource.
66
+ 4. Click **Refresh** any time to re-check drift and drop a lanes frame.
67
+
68
+ ## What "gated" looks like
69
+
70
+ `prod-apply` here is additive and ungated, so Sync applies in one click. Make it
71
+ gated and Sync starts the Op but **pauses** at an approval gate — behold then shows
72
+ an **Approve** button that signals the gate (a durable Temporal wait). Authority for
73
+ the destructive step stays with a human:
74
+
75
+ ```ts
76
+ ApplyOp({ name: "prod-apply", env: "prod", target: "cloudformation", delete: "gated" });
77
+ ```
78
+
79
+ ## Tear down
80
+
81
+ ```sh
82
+ aws cloudformation delete-stack --stack-name prod
83
+ aws cloudformation wait stack-delete-complete --stack-name prod
84
+ ```
85
+
86
+ Or try the **Adopt** button on a *foreign* node (one that's in the cloud but not in
87
+ source) — it triggers `prod-reconcile`, which opens a PR pulling live back into
88
+ typed source. behold never writes source directly; a human merges the PR.
@@ -0,0 +1,12 @@
1
+ import type { TemporalChantConfig } from "@intentius/chant-lexicon-temporal";
2
+
3
+ export default {
4
+ lexicons: ["aws", "temporal"],
5
+ sourceDir: "src",
6
+ environments: ["prod"],
7
+ ownership: { stack: "behold-writes", env: "prod" },
8
+ temporal: {
9
+ profiles: { prod: { address: "localhost:7233", namespace: "default", taskQueue: "behold-writes", autoStart: true } },
10
+ defaultProfile: "prod",
11
+ } satisfies TemporalChantConfig,
12
+ };
@@ -0,0 +1,7 @@
1
+ import { ApplyOp } from "@intentius/chant-lexicon-temporal";
2
+
3
+ // code → cloud. Additive apply (no gate) runs one-shot on the local executor —
4
+ // behold's Sync button shells `chant run prod-apply`. Target cloudformation;
5
+ // output defaults to template.json (matching this project's `build` script).
6
+ const { op } = ApplyOp({ name: "prod-apply", env: "prod", target: "cloudformation" });
7
+ export default op;
@@ -0,0 +1,20 @@
1
+ import { Op, phase, build, awsApply, httpCheck } from "@intentius/chant-lexicon-temporal";
2
+
3
+ // Deploy the S3 bucket to the local Floci emulator via the CloudFormation API
4
+ // (awsApply — direct create-or-update + poll, no aws CLI, honours the endpoint).
5
+ // `behold serve … --local` boots Floci; this Op's Run button deploys to it. No
6
+ // cloud account, no creds — the creds-free first apply. (prod-apply is the
7
+ // real-AWS path; it shells the aws CLI.)
8
+ export default Op({
9
+ name: "floci-apply",
10
+ overview: "S3 bucket → local Floci (CloudFormation API), no cloud account",
11
+ taskQueue: "behold-local",
12
+ phases: [
13
+ phase("Build", [build(".", { script: "build" })]),
14
+ // Stack name = the env ("prod"), so `serve --local --env prod`'s overlay —
15
+ // which queries the CFN stack named after the env — observes this deploy and
16
+ // flips the node green (chant #926 points the live query at the emulator).
17
+ phase("Apply", [awsApply("template.json", { stackName: "prod", endpoint: "http://localhost:4566" })]),
18
+ phase("Verify", [httpCheck("http://localhost:4566/behold-floci-demo")]),
19
+ ],
20
+ });
@@ -0,0 +1,6 @@
1
+ import { ReconcileOp } from "@intentius/chant-lexicon-temporal";
2
+
3
+ // cloud → code. Snapshot live prod, diff vs source, open a PR for drift/orphans.
4
+ // Scoped to chant-owned resources. behold's Adopt button triggers this.
5
+ const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod", onDrift: "pull-request", scope: { owned: true } });
6
+ export default op;