@intentius/behold 0.7.0 → 0.9.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 (104) hide show
  1. package/AGENTS.md +94 -2
  2. package/README.md +133 -2
  3. package/demos.json +25 -1
  4. package/dist/cli.js +3176 -330
  5. package/example-argo-estate/README.md +71 -0
  6. package/example-argo-estate/app-a/chant.config.ts +18 -0
  7. package/example-argo-estate/app-a/manifests/app.yaml +54 -0
  8. package/example-argo-estate/app-a/package.json +13 -0
  9. package/example-argo-estate/app-a/src/app.ts +35 -0
  10. package/example-argo-estate/app-a/tsconfig.json +1 -0
  11. package/example-argo-estate/app-b/chant.config.ts +18 -0
  12. package/example-argo-estate/app-b/manifests/app.yaml +54 -0
  13. package/example-argo-estate/app-b/package.json +13 -0
  14. package/example-argo-estate/app-b/src/app.ts +34 -0
  15. package/example-argo-estate/app-b/tsconfig.json +1 -0
  16. package/example-argo-estate/control-plane/chant.config.ts +29 -0
  17. package/example-argo-estate/control-plane/package.json +13 -0
  18. package/example-argo-estate/control-plane/src/argo.ts +69 -0
  19. package/example-argo-estate/control-plane/tsconfig.json +1 -0
  20. package/example-argo-estate/package-lock.json +1949 -0
  21. package/example-argo-estate/package.json +10 -0
  22. package/example-carve/README.md +194 -0
  23. package/example-carve/app/chant.config.ts +6 -0
  24. package/example-carve/app/package-lock.json +1075 -0
  25. package/example-carve/app/package.json +13 -0
  26. package/example-carve/app/src/carved.ts +30 -0
  27. package/example-carve/app/tsconfig.json +1 -0
  28. package/example-carve/carve-report.json +872 -0
  29. package/example-carve/legacy-tf/cdn.tf +23 -0
  30. package/example-carve/legacy-tf/compute.tf +63 -0
  31. package/example-carve/legacy-tf/floci-override.tf.disabled +61 -0
  32. package/example-carve/legacy-tf/modules/cdn/main.tf +72 -0
  33. package/example-carve/legacy-tf/naming.tf +10 -0
  34. package/example-carve/legacy-tf/network.tf +119 -0
  35. package/example-carve/legacy-tf/observability.tf +18 -0
  36. package/example-carve/legacy-tf/outputs.tf +16 -0
  37. package/example-carve/legacy-tf/storage.tf +33 -0
  38. package/example-carve/legacy-tf/terraform.tfstate +602 -0
  39. package/example-carve/legacy-tf/versions.tf +40 -0
  40. package/example-flux-estate/README.md +22 -12
  41. package/example-flux-estate/app-a/package.json +2 -2
  42. package/example-flux-estate/app-a/src/app.ts +2 -1
  43. package/example-flux-estate/app-b/chant.config.ts +4 -3
  44. package/example-flux-estate/app-b/package.json +2 -2
  45. package/example-flux-estate/app-b/src/app.ts +5 -3
  46. package/example-flux-estate/control-plane/package.json +2 -2
  47. package/example-flux-estate/control-plane/src/flux.ts +10 -2
  48. package/example-flux-estate/package-lock.json +17 -17
  49. package/example-k8s/README.md +16 -2
  50. package/example-k8s/base/deployment.yaml +21 -0
  51. package/example-k8s/base/kustomization.yaml +3 -0
  52. package/example-k8s/base/service.yaml +12 -0
  53. package/example-k8s/chant.config.ts +10 -0
  54. package/example-k8s/overlays/dev/kustomization.yaml +6 -0
  55. package/example-k8s/package-lock.json +18 -18
  56. package/example-k8s/package.json +3 -3
  57. package/example-writes/package-lock.json +14 -14
  58. package/example-writes/package.json +3 -3
  59. package/package.json +9 -6
  60. package/web/app.js +1027 -42
  61. package/web/carve-steps.js +610 -0
  62. package/web/carve-steps.test.js +233 -0
  63. package/web/demos.js +71 -0
  64. package/web/demos.test.js +83 -0
  65. package/web/icons/cncf/argo.svg +1 -0
  66. package/web/icons/cncf/flux.svg +1 -0
  67. package/web/icons/cncf/helm.svg +1 -0
  68. package/web/icons/k8s/c-role.svg +1 -0
  69. package/web/icons/k8s/cm.svg +1 -0
  70. package/web/icons/k8s/crb.svg +1 -0
  71. package/web/icons/k8s/crd.svg +1 -0
  72. package/web/icons/k8s/cronjob.svg +1 -0
  73. package/web/icons/k8s/deploy.svg +1 -0
  74. package/web/icons/k8s/ds.svg +1 -0
  75. package/web/icons/k8s/ep.svg +1 -0
  76. package/web/icons/k8s/group.svg +1 -0
  77. package/web/icons/k8s/hpa.svg +1 -0
  78. package/web/icons/k8s/ing.svg +1 -0
  79. package/web/icons/k8s/job.svg +1 -0
  80. package/web/icons/k8s/limits.svg +1 -0
  81. package/web/icons/k8s/netpol.svg +1 -0
  82. package/web/icons/k8s/ns.svg +1 -0
  83. package/web/icons/k8s/pod.svg +1 -0
  84. package/web/icons/k8s/psp.svg +1 -0
  85. package/web/icons/k8s/pv.svg +1 -0
  86. package/web/icons/k8s/pvc.svg +1 -0
  87. package/web/icons/k8s/quota.svg +1 -0
  88. package/web/icons/k8s/rb.svg +1 -0
  89. package/web/icons/k8s/role.svg +1 -0
  90. package/web/icons/k8s/rs.svg +1 -0
  91. package/web/icons/k8s/sa.svg +1 -0
  92. package/web/icons/k8s/sc.svg +1 -0
  93. package/web/icons/k8s/secret.svg +1 -0
  94. package/web/icons/k8s/sts.svg +1 -0
  95. package/web/icons/k8s/svc.svg +1 -0
  96. package/web/icons/k8s/user.svg +1 -0
  97. package/web/icons/k8s/vol.svg +1 -0
  98. package/web/index.html +285 -85
  99. package/web/json-view.js +334 -0
  100. package/web/json-view.test.js +218 -0
  101. package/web/layout-store.js +278 -0
  102. package/web/layout-store.test.js +388 -0
  103. package/web/panel.js +28 -0
  104. package/web/theme.js +114 -6
@@ -0,0 +1,71 @@
1
+ # argo-estate — behold's Argo CD estate demo (#235)
2
+
3
+ Three chant projects served as one composed estate, the Argo mirror of
4
+ [example-flux-estate](../example-flux-estate):
5
+
6
+ - **control-plane/** — the Argo machinery: an `AppProject` fencing which repo
7
+ and which namespaces the estate may deploy, and one `Application` per app
8
+ syncing that app's committed manifests from behold's own public repo. Argo's
9
+ controller does the applying; this project never applies a workload itself.
10
+ - **app-a/**, **app-b/** — small web workloads in namespaces `app-a` and
11
+ `app-b`, the namespaces the Applications name as their sync destinations.
12
+
13
+ ```sh
14
+ npx @intentius/behold demo argo-estate
15
+ ```
16
+
17
+ The demo path is **declared only** — no cluster, no Argo install, no Docker. It
18
+ copies out, `npm install`s, and serves. (There is a live lane, but it is an
19
+ acceptance run rather than part of the demo: see "Live" below.) What to look
20
+ at:
21
+
22
+ - The **estate**: per-project boundary boxes, and the `project` edges joining
23
+ both Applications to the AppProject they name (behold#222) — the join chant
24
+ lints as ARGO002, so an estate whose lint passes cannot be drawn wrong.
25
+ The entity graph carries them at the attributes tier (`?detail=3`).
26
+ - The **logical lens** (zoom: logical): cluster ⊃ `namespace app-a` and
27
+ `namespace app-b`, each holding that app's Deployment + Service, plus
28
+ `namespace argocd` holding both Applications and the AppProject — drawn
29
+ even though the control plane declares no `Namespace` object anywhere. The
30
+ app namespaces come from each Application's `spec.destination.namespace`; a
31
+ namespace Argo will own objects in is a namespace the estate is committed
32
+ to, and behold#224 taught the composed estate to draw that projection.
33
+ Serve `control-plane` alone (`behold serve control-plane`, zoom: logical)
34
+ and the same boxes appear empty — the destination harvest still names them,
35
+ but there is nothing from app-a/app-b in the graph to fill them with.
36
+
37
+ That alone-vs-composed split is the Argo/Flux difference worth noticing:
38
+ flux-estate's control plane must declare the app namespaces itself (a
39
+ Kustomization's `targetNamespace` must already exist), while here
40
+ `CreateNamespace=true` means Argo makes them — so the box exists on the
41
+ strength of the destination alone.
42
+
43
+ Argo's ordering is the `argocd.argoproj.io/sync-wave` annotation, so unlike
44
+ Flux's `dependsOn` (behold#223) there is no edge to draw for it: app-a is wave
45
+ 0, app-b wave 1, and the picture says nothing about it.
46
+
47
+ The app `manifests/` are committed `chant build` output — the path each
48
+ Application syncs. Changing an app's source means a rebuild (`npm run build` in
49
+ the app), and the rebuilt manifests have to be on `main` before Argo can sync
50
+ them. `chant build` in the control plane warns ARGO005 on both Applications:
51
+ `source.path` is repo-relative (that's what Argo resolves it against), not
52
+ relative to the build root, so it doesn't resolve locally. Fine here, and the
53
+ check's own message says so.
54
+
55
+ ## Live
56
+
57
+ Nothing above needs a cluster, but the estate as committed does reconcile
58
+ against a real one — the Applications point at this repo on `main` and the app
59
+ `manifests/` are already there, so an Argo CD install has everything it needs.
60
+ `just e2e-argo-estate` (behold#269) is that run: a scratch k3d cluster, Argo
61
+ from the pinned `core-install` manifest, the control plane applied once, and
62
+ then the composed estate served against the result — the destination-namespace
63
+ boxes filled with live cards, #238's health verdicts read off each
64
+ Application's health/sync pair, and the unhappy arm (an Application pointed at
65
+ a path that does not exist, then restored). It creates and deletes its own
66
+ cluster and touches no other context.
67
+
68
+ Each member's `chant.config.ts` therefore binds a `local` profile to the
69
+ context `k3d-behold-argo-demo`, which is what that run aliases its scratch
70
+ cluster to. Serving without `--env` — what `behold demo argo-estate` does —
71
+ reads none of it.
@@ -0,0 +1,18 @@
1
+ import type { ChantConfig } from "@intentius/chant";
2
+ import type { K8sChantConfig } from "@intentius/chant-lexicon-k8s";
3
+
4
+ // App project A. Argo syncs its committed manifests/ (chant build output) from
5
+ // the repo; this project applies nothing itself. behold serves it as part of
6
+ // the estate, and the live overlay reads the cluster through the same binding
7
+ // as every other member — see ../control-plane/chant.config.ts.
8
+ export default {
9
+ lexicons: ["k8s"],
10
+ sourceDir: "src",
11
+ environments: ["local"],
12
+ ownership: { stack: "argo-app-a" },
13
+ k8s: {
14
+ profiles: {
15
+ local: { context: "k3d-behold-argo-demo" },
16
+ },
17
+ } satisfies K8sChantConfig,
18
+ } satisfies ChantConfig;
@@ -0,0 +1,54 @@
1
+ apiVersion: apps/v1
2
+ kind: Deployment
3
+ metadata:
4
+ name: app-a
5
+ namespace: app-a
6
+ labels:
7
+ app.kubernetes.io/managed-by: chant
8
+ chant.intentius.io/stack: argo-app-a
9
+ app: app-a
10
+ spec:
11
+ replicas: 1
12
+ selector:
13
+ matchLabels:
14
+ app: app-a
15
+ template:
16
+ metadata:
17
+ labels:
18
+ app: app-a
19
+ spec:
20
+ containers:
21
+ - name: web
22
+ image: nginxinc/nginx-unprivileged:1.27-alpine
23
+ ports:
24
+ - containerPort: 8080
25
+ securityContext:
26
+ runAsNonRoot: true
27
+ runAsUser: 101
28
+ allowPrivilegeEscalation: false
29
+ capabilities:
30
+ drop:
31
+ - ALL
32
+ resources:
33
+ requests:
34
+ cpu: '25m'
35
+ memory: '32Mi'
36
+ limits:
37
+ cpu: '100m'
38
+ memory: '64Mi'
39
+
40
+ ---
41
+ apiVersion: v1
42
+ kind: Service
43
+ metadata:
44
+ name: app-a
45
+ namespace: app-a
46
+ labels:
47
+ app.kubernetes.io/managed-by: chant
48
+ chant.intentius.io/stack: argo-app-a
49
+ spec:
50
+ selector:
51
+ app: app-a
52
+ ports:
53
+ - port: 80
54
+ targetPort: 8080
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "behold-example-argo-app-a",
3
+ "private": true,
4
+ "type": "module",
5
+ "description": "App project A: a small web workload in namespace app-a, synced by the control plane's Argo Application.",
6
+ "scripts": {
7
+ "build": "chant build src -o manifests/app.yaml --format yaml"
8
+ },
9
+ "dependencies": {
10
+ "@intentius/chant": "^0.44.6",
11
+ "@intentius/chant-lexicon-k8s": "^0.44.6"
12
+ }
13
+ }
@@ -0,0 +1,35 @@
1
+ // App A: one small web workload, namespace declared on every object — the same
2
+ // namespace the control plane's Application names as its sync destination.
3
+ // That agreement is the point: behold draws the namespace box from the
4
+ // Application's destination and fills it with these cards.
5
+ import { Deployment, Service } from "@intentius/chant-lexicon-k8s";
6
+
7
+ const labels = { app: "app-a" };
8
+ const image = "nginxinc/nginx-unprivileged:1.27-alpine";
9
+
10
+ export const deployment = new Deployment({
11
+ metadata: { name: "app-a", namespace: "app-a", labels },
12
+ spec: {
13
+ replicas: 1,
14
+ selector: { matchLabels: labels },
15
+ template: {
16
+ metadata: { labels },
17
+ spec: {
18
+ containers: [
19
+ {
20
+ name: "web",
21
+ image,
22
+ ports: [{ containerPort: 8080 }],
23
+ securityContext: { runAsNonRoot: true, runAsUser: 101, allowPrivilegeEscalation: false, capabilities: { drop: ["ALL"] } },
24
+ resources: { requests: { cpu: "25m", memory: "32Mi" }, limits: { cpu: "100m", memory: "64Mi" } },
25
+ },
26
+ ],
27
+ },
28
+ },
29
+ },
30
+ });
31
+
32
+ export const service = new Service({
33
+ metadata: { name: "app-a", namespace: "app-a" },
34
+ spec: { selector: labels, ports: [{ port: 80, targetPort: 8080 }] },
35
+ });
@@ -0,0 +1 @@
1
+ { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*", "ops/**/*", "chant.config.ts"] }
@@ -0,0 +1,18 @@
1
+ import type { ChantConfig } from "@intentius/chant";
2
+ import type { K8sChantConfig } from "@intentius/chant-lexicon-k8s";
3
+
4
+ // App project B — same shape as app-a, second sync wave. Unlike flux-estate's
5
+ // app-b this one declares its own namespace on every object (Argo has no
6
+ // targetNamespace to stamp one at apply time), so a live read resolves it
7
+ // straight away. See ../control-plane/chant.config.ts for the binding.
8
+ export default {
9
+ lexicons: ["k8s"],
10
+ sourceDir: "src",
11
+ environments: ["local"],
12
+ ownership: { stack: "argo-app-b" },
13
+ k8s: {
14
+ profiles: {
15
+ local: { context: "k3d-behold-argo-demo" },
16
+ },
17
+ } satisfies K8sChantConfig,
18
+ } satisfies ChantConfig;
@@ -0,0 +1,54 @@
1
+ apiVersion: apps/v1
2
+ kind: Deployment
3
+ metadata:
4
+ name: app-b
5
+ namespace: app-b
6
+ labels:
7
+ app.kubernetes.io/managed-by: chant
8
+ chant.intentius.io/stack: argo-app-b
9
+ app: app-b
10
+ spec:
11
+ replicas: 2
12
+ selector:
13
+ matchLabels:
14
+ app: app-b
15
+ template:
16
+ metadata:
17
+ labels:
18
+ app: app-b
19
+ spec:
20
+ containers:
21
+ - name: web
22
+ image: nginxinc/nginx-unprivileged:1.27-alpine
23
+ ports:
24
+ - containerPort: 8080
25
+ securityContext:
26
+ runAsNonRoot: true
27
+ runAsUser: 101
28
+ allowPrivilegeEscalation: false
29
+ capabilities:
30
+ drop:
31
+ - ALL
32
+ resources:
33
+ requests:
34
+ cpu: '25m'
35
+ memory: '32Mi'
36
+ limits:
37
+ cpu: '100m'
38
+ memory: '64Mi'
39
+
40
+ ---
41
+ apiVersion: v1
42
+ kind: Service
43
+ metadata:
44
+ name: app-b
45
+ namespace: app-b
46
+ labels:
47
+ app.kubernetes.io/managed-by: chant
48
+ chant.intentius.io/stack: argo-app-b
49
+ spec:
50
+ selector:
51
+ app: app-b
52
+ ports:
53
+ - port: 80
54
+ targetPort: 8080
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "behold-example-argo-app-b",
3
+ "private": true,
4
+ "type": "module",
5
+ "description": "App project B: the same workload in namespace app-b, synced one wave later.",
6
+ "scripts": {
7
+ "build": "chant build src -o manifests/app.yaml --format yaml"
8
+ },
9
+ "dependencies": {
10
+ "@intentius/chant": "^0.44.6",
11
+ "@intentius/chant-lexicon-k8s": "^0.44.6"
12
+ }
13
+ }
@@ -0,0 +1,34 @@
1
+ // App B: the same workload in namespace app-b, the estate's second sync wave.
2
+ // Two apps rather than one so the AppProject has more than a single Application
3
+ // hanging off it — the fan-out is what an app-of-apps picture is for.
4
+ import { Deployment, Service } from "@intentius/chant-lexicon-k8s";
5
+
6
+ const labels = { app: "app-b" };
7
+ const image = "nginxinc/nginx-unprivileged:1.27-alpine";
8
+
9
+ export const deployment = new Deployment({
10
+ metadata: { name: "app-b", namespace: "app-b", labels },
11
+ spec: {
12
+ replicas: 2,
13
+ selector: { matchLabels: labels },
14
+ template: {
15
+ metadata: { labels },
16
+ spec: {
17
+ containers: [
18
+ {
19
+ name: "web",
20
+ image,
21
+ ports: [{ containerPort: 8080 }],
22
+ securityContext: { runAsNonRoot: true, runAsUser: 101, allowPrivilegeEscalation: false, capabilities: { drop: ["ALL"] } },
23
+ resources: { requests: { cpu: "25m", memory: "32Mi" }, limits: { cpu: "100m", memory: "64Mi" } },
24
+ },
25
+ ],
26
+ },
27
+ },
28
+ },
29
+ });
30
+
31
+ export const service = new Service({
32
+ metadata: { name: "app-b", namespace: "app-b" },
33
+ spec: { selector: labels, ports: [{ port: 80, targetPort: 8080 }] },
34
+ });
@@ -0,0 +1 @@
1
+ { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*", "ops/**/*", "chant.config.ts"] }
@@ -0,0 +1,29 @@
1
+ import type { ChantConfig } from "@intentius/chant";
2
+ import type { K8sChantConfig } from "@intentius/chant-lexicon-k8s";
3
+
4
+ // The estate's control plane: it declares the Argo machinery (an AppProject +
5
+ // one Application per app), and Argo's application controller deploys the app
6
+ // projects — this project never applies a workload itself.
7
+ //
8
+ // `npx @intentius/behold demo argo-estate` still needs no cluster: it serves
9
+ // the source graph with no `--env`, and nothing below is read on that path.
10
+ // The `local` profile exists for the live lane (behold#269,
11
+ // `just e2e-argo-estate`), which stands up a scratch k3d cluster and aliases
12
+ // its context to the name pinned here — so a live read resolves the DECLARED
13
+ // binding and can never observe whatever kubectl context happens to be
14
+ // ambient (chant#1100).
15
+ //
16
+ // Deliberately no `ownership.env`: the app members' committed manifests/ are
17
+ // what Argo syncs from `main`, so a label that changes their build output
18
+ // would have to be merged before any live run could agree with the cluster.
19
+ export default {
20
+ lexicons: ["k8s"],
21
+ sourceDir: "src",
22
+ environments: ["local"],
23
+ ownership: { stack: "argo-control-plane" },
24
+ k8s: {
25
+ profiles: {
26
+ local: { context: "k3d-behold-argo-demo" },
27
+ },
28
+ } satisfies K8sChantConfig,
29
+ } satisfies ChantConfig;
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "behold-example-argo-control-plane",
3
+ "private": true,
4
+ "type": "module",
5
+ "description": "The estate's control plane: the Argo CD CRs (an AppProject + one Application per app project).",
6
+ "scripts": {
7
+ "build": "chant build src -o dist/control-plane.yaml --format yaml"
8
+ },
9
+ "dependencies": {
10
+ "@intentius/chant": "^0.44.6",
11
+ "@intentius/chant-lexicon-k8s": "^0.44.6"
12
+ }
13
+ }
@@ -0,0 +1,69 @@
1
+ // The control plane, Argo-style: one AppProject that fences what the estate is
2
+ // allowed to deploy, and one Application per app project, each syncing that
3
+ // app's committed manifests from this repo. Argo's application controller does
4
+ // the applying — this project never applies a workload itself.
5
+ //
6
+ // Written with the raw declarables rather than the ArgoAppFor composite on
7
+ // purpose: the two fields the whole demo is about, `spec.project` and
8
+ // `spec.destination.namespace`, are the ones a stranger reading Argo YAML
9
+ // already knows by sight, and here they sit in the source verbatim. (For real
10
+ // estates the composite is fewer lines: ArgoAppFor("app-a", { repo, path,
11
+ // project, destination }) renders this same Application.)
12
+ import { AppProject, Application } from "@intentius/chant-lexicon-k8s";
13
+
14
+ const REPO = "https://github.com/INTENTIUS/behold";
15
+ // The in-cluster target every Argo install has. Naming it (rather than a
16
+ // registered cluster Secret) is what keeps this estate a one-cluster story.
17
+ const IN_CLUSTER = "https://kubernetes.default.svc";
18
+
19
+ // The fence: which repo the apps may sync from, and which namespaces Argo may
20
+ // own objects in. Both Applications name it in spec.project — the join behold
21
+ // draws (behold#222) and chant lints as ARGO002.
22
+ export const project = new AppProject({
23
+ metadata: { name: "estate", namespace: "argocd" },
24
+ spec: {
25
+ description: "behold's demo estate: two app projects, one cluster.",
26
+ sourceRepos: [REPO],
27
+ destinations: [
28
+ { server: IN_CLUSTER, namespace: "app-a" },
29
+ { server: IN_CLUSTER, namespace: "app-b" },
30
+ ],
31
+ // CreateNamespace=true below means Argo creates the destination namespaces,
32
+ // so the project has to permit that one cluster-scoped kind.
33
+ clusterResourceWhitelist: [{ group: "", kind: "Namespace" }],
34
+ },
35
+ });
36
+
37
+ export const appA = new Application({
38
+ metadata: {
39
+ name: "app-a",
40
+ namespace: "argocd",
41
+ // Argo's ordering idiom is a wave annotation, not a reference — so unlike
42
+ // Flux's dependsOn (behold#223) there is no edge to draw for it. app-a
43
+ // syncs first; app-b follows.
44
+ annotations: { "argocd.argoproj.io/sync-wave": "0" },
45
+ },
46
+ spec: {
47
+ project: "estate",
48
+ source: { repoURL: REPO, targetRevision: "main", path: "example-argo-estate/app-a/manifests" },
49
+ // The namespace Argo will own objects in. app-a's own objects declare it
50
+ // too, so the box behold draws holds the app's cards; declaring it here is
51
+ // what makes the box a fact about the CONTROL PLANE's graph as well.
52
+ destination: { server: IN_CLUSTER, namespace: "app-a" },
53
+ syncPolicy: { automated: { prune: true, selfHeal: true }, syncOptions: ["CreateNamespace=true"] },
54
+ },
55
+ });
56
+
57
+ export const appB = new Application({
58
+ metadata: {
59
+ name: "app-b",
60
+ namespace: "argocd",
61
+ annotations: { "argocd.argoproj.io/sync-wave": "1" },
62
+ },
63
+ spec: {
64
+ project: "estate",
65
+ source: { repoURL: REPO, targetRevision: "main", path: "example-argo-estate/app-b/manifests" },
66
+ destination: { server: IN_CLUSTER, namespace: "app-b" },
67
+ syncPolicy: { automated: { prune: true, selfHeal: true }, syncOptions: ["CreateNamespace=true"] },
68
+ },
69
+ });
@@ -0,0 +1 @@
1
+ { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*", "ops/**/*", "chant.config.ts"] }