camunda-cloud-idac 1.0.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/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/camunda/client.js +33 -0
- package/dist/camunda/client.js.map +1 -0
- package/dist/camunda/list-all.js +166 -0
- package/dist/camunda/list-all.js.map +1 -0
- package/dist/camunda/ops.js +63 -0
- package/dist/camunda/ops.js.map +1 -0
- package/dist/cli.js +140 -0
- package/dist/cli.js.map +1 -0
- package/dist/colors.js +19 -0
- package/dist/colors.js.map +1 -0
- package/dist/progress.js +67 -0
- package/dist/progress.js.map +1 -0
- package/dist/reconcile/apply.js +31 -0
- package/dist/reconcile/apply.js.map +1 -0
- package/dist/reconcile/diff.js +280 -0
- package/dist/reconcile/diff.js.map +1 -0
- package/dist/reconcile/format.js +92 -0
- package/dist/reconcile/format.js.map +1 -0
- package/dist/reconcile/order.js +58 -0
- package/dist/reconcile/order.js.map +1 -0
- package/dist/reconcile/protect.js +78 -0
- package/dist/reconcile/protect.js.map +1 -0
- package/dist/reconcile/types.js +18 -0
- package/dist/reconcile/types.js.map +1 -0
- package/dist/spec/load.js +46 -0
- package/dist/spec/load.js.map +1 -0
- package/dist/spec/schema.js +274 -0
- package/dist/spec/schema.js.map +1 -0
- package/package.json +53 -0
package/dist/progress.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
2
|
+
const SPINNER_INTERVAL_MS = 80;
|
|
3
|
+
/**
|
|
4
|
+
* A dependency-free, single-line status reporter (braille spinner + elapsed
|
|
5
|
+
* time), rewritten in place via `\r`/ANSI clear-to-end-of-line. Writes to
|
|
6
|
+
* `stderr` by default so it never pollutes a command's piped/CI-consumed
|
|
7
|
+
* stdout. Falls back to plain, non-animated lines when the stream isn't a
|
|
8
|
+
* TTY (CI, redirected output) so logs stay readable there.
|
|
9
|
+
*/
|
|
10
|
+
export function createProgressReporter(stream = process.stderr) {
|
|
11
|
+
const isTTY = stream.isTTY === true;
|
|
12
|
+
const start = Date.now();
|
|
13
|
+
let frame = 0;
|
|
14
|
+
let lineIsOpen = false;
|
|
15
|
+
let currentText = "";
|
|
16
|
+
let timer;
|
|
17
|
+
const elapsed = () => `${((Date.now() - start) / 1000).toFixed(1)}s`;
|
|
18
|
+
function render() {
|
|
19
|
+
const line = `${SPINNER_FRAMES[frame % SPINNER_FRAMES.length]} ${currentText} (${elapsed()})`;
|
|
20
|
+
// A line longer than the terminal wraps onto a second row, and `\r\x1b[K`
|
|
21
|
+
// only rewinds/clears the current row - the wrapped remainder of the
|
|
22
|
+
// previous frame would then be left behind on the row above. Truncating
|
|
23
|
+
// to the terminal width keeps every frame a single row, so redraws always
|
|
24
|
+
// cleanly overwrite the last one.
|
|
25
|
+
const width = stream.columns;
|
|
26
|
+
const truncated = width && line.length > width ? `${line.slice(0, width - 1)}…` : line;
|
|
27
|
+
stream.write(`\r\x1b[K${truncated}`);
|
|
28
|
+
frame++;
|
|
29
|
+
lineIsOpen = true;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
update(text) {
|
|
33
|
+
if (!isTTY) {
|
|
34
|
+
stream.write(`${text}\n`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
currentText = text;
|
|
38
|
+
render();
|
|
39
|
+
if (!timer) {
|
|
40
|
+
timer = setInterval(render, SPINNER_INTERVAL_MS);
|
|
41
|
+
timer.unref();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
log(text) {
|
|
45
|
+
if (isTTY && lineIsOpen) {
|
|
46
|
+
stream.write(`\r\x1b[K${text}\n`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
stream.write(`${text}\n`);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
stop(finalText) {
|
|
53
|
+
if (timer) {
|
|
54
|
+
clearInterval(timer);
|
|
55
|
+
timer = undefined;
|
|
56
|
+
}
|
|
57
|
+
if (isTTY && lineIsOpen) {
|
|
58
|
+
stream.write(`\r\x1b[K`);
|
|
59
|
+
}
|
|
60
|
+
lineIsOpen = false;
|
|
61
|
+
if (finalText) {
|
|
62
|
+
stream.write(`${finalText}\n`);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1E,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAW/B;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAA6B,OAAO,CAAC,MAAM;IAChF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI,KAAiC,CAAC;IAEtC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAErE,SAAS,MAAM;QACb,MAAM,IAAI,GAAG,GAAG,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,WAAW,KAAK,OAAO,EAAE,GAAG,CAAC;QAC9F,0EAA0E;QAC1E,qEAAqE;QACrE,wEAAwE;QACxE,0EAA0E;QAC1E,kCAAkC;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC;QAC7B,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,MAAM,CAAC,KAAK,CAAC,WAAW,SAAS,EAAE,CAAC,CAAC;QACrC,KAAK,EAAE,CAAC;QACR,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,OAAO;QACL,MAAM,CAAC,IAAY;YACjB,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;gBAC1B,OAAO;YACT,CAAC;YACD,WAAW,GAAG,IAAI,CAAC;YACnB,MAAM,EAAE,CAAC;YACT,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;gBACjD,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QACD,GAAG,CAAC,IAAY;YACd,IAAI,KAAK,IAAI,UAAU,EAAE,CAAC;gBACxB,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,SAAkB;YACrB,IAAI,KAAK,EAAE,CAAC;gBACV,aAAa,CAAC,KAAK,CAAC,CAAC;gBACrB,KAAK,GAAG,SAAS,CAAC;YACpB,CAAC;YACD,IAAI,KAAK,IAAI,UAAU,EAAE,CAAC;gBACxB,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC3B,CAAC;YACD,UAAU,GAAG,KAAK,CAAC;YACnB,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,IAAI,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort executor: run every planned action in order, continue past
|
|
3
|
+
* individual failures, and report a summary. A transient failure on one of many
|
|
4
|
+
* independent actions shouldn't abort a run that already correctly applied the
|
|
5
|
+
* rest - and because the whole tool is idempotent, "best-effort + rerun" is a
|
|
6
|
+
* strictly simpler recovery path than "fail-fast + manual cleanup."
|
|
7
|
+
*
|
|
8
|
+
* `plan.actions` is already ordered by buildPlan (via sortActions), so this just
|
|
9
|
+
* executes in the given order.
|
|
10
|
+
*
|
|
11
|
+
* `onProgress`, if given, is called before and after each action - purely for
|
|
12
|
+
* caller-side UX (e.g. a CLI progress indicator); it never affects execution.
|
|
13
|
+
*/
|
|
14
|
+
export async function applyPlan(plan, onProgress) {
|
|
15
|
+
const succeeded = [];
|
|
16
|
+
const failed = [];
|
|
17
|
+
const total = plan.actions.length;
|
|
18
|
+
for (const [index, action] of plan.actions.entries()) {
|
|
19
|
+
onProgress?.({ type: "start", index, total, action });
|
|
20
|
+
const result = await action.execute();
|
|
21
|
+
if (result.ok) {
|
|
22
|
+
succeeded.push(action);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
failed.push({ action, error: result.error });
|
|
26
|
+
}
|
|
27
|
+
onProgress?.({ type: "done", index, total, action, ok: result.ok });
|
|
28
|
+
}
|
|
29
|
+
return { succeeded, failed, skippedProtected: plan.warnings };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/reconcile/apply.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAwB,EACxB,UAAgD;IAEhD,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAgD,EAAE,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAElC,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACrD,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { tenantOps, roleOps, groupOps, mappingRuleOps, authorizationOps } from "../camunda/ops.js";
|
|
2
|
+
import { applyProtections } from "./protect.js";
|
|
3
|
+
import { sortActions } from "./order.js";
|
|
4
|
+
import { DESTRUCTIVE_KINDS } from "./types.js";
|
|
5
|
+
function mkAction(kind, description, execute, target = { kind: "other" }) {
|
|
6
|
+
return { kind, description, target, destructive: DESTRUCTIVE_KINDS.has(kind), execute };
|
|
7
|
+
}
|
|
8
|
+
function descChanged(current, desired) {
|
|
9
|
+
return (current ?? "") !== (desired ?? "");
|
|
10
|
+
}
|
|
11
|
+
function diffTenants(spec, current, mode, actions) {
|
|
12
|
+
const curById = new Map(current.tenants.map((t) => [t.tenantId, t]));
|
|
13
|
+
const desiredIds = new Set(spec.tenants.map((t) => t.tenantId));
|
|
14
|
+
for (const desired of spec.tenants) {
|
|
15
|
+
const existing = curById.get(desired.tenantId);
|
|
16
|
+
if (!existing) {
|
|
17
|
+
actions.push(mkAction("create-tenant", `create tenant "${desired.tenantId}" (${desired.name})`, () => tenantOps.create(desired.tenantId, desired.name, desired.description)));
|
|
18
|
+
}
|
|
19
|
+
else if (existing.name !== desired.name || descChanged(existing.description, desired.description)) {
|
|
20
|
+
actions.push(mkAction("update-tenant", `update tenant "${desired.tenantId}"`, () => tenantOps.update(desired.tenantId, desired.name, desired.description)));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (mode === "prune") {
|
|
24
|
+
for (const existing of current.tenants) {
|
|
25
|
+
if (!desiredIds.has(existing.tenantId)) {
|
|
26
|
+
actions.push(mkAction("delete-tenant", `delete tenant "${existing.tenantId}"`, () => tenantOps.delete(existing.tenantId), { kind: "delete-tenant", tenantId: existing.tenantId }));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function diffRoles(spec, current, mode, actions) {
|
|
32
|
+
const curById = new Map(current.roles.map((r) => [r.roleId, r]));
|
|
33
|
+
const desiredIds = new Set(spec.roles.map((r) => r.roleId));
|
|
34
|
+
for (const desired of spec.roles) {
|
|
35
|
+
const existing = curById.get(desired.roleId);
|
|
36
|
+
if (!existing) {
|
|
37
|
+
actions.push(mkAction("create-role", `create role "${desired.roleId}" (${desired.name})`, () => roleOps.create(desired.roleId, desired.name, desired.description)));
|
|
38
|
+
}
|
|
39
|
+
else if (existing.name !== desired.name || descChanged(existing.description, desired.description)) {
|
|
40
|
+
actions.push(mkAction("update-role", `update role "${desired.roleId}"`, () => roleOps.update(desired.roleId, desired.name, desired.description)));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (mode === "prune") {
|
|
44
|
+
for (const existing of current.roles) {
|
|
45
|
+
if (!desiredIds.has(existing.roleId)) {
|
|
46
|
+
actions.push(mkAction("delete-role", `delete role "${existing.roleId}"`, () => roleOps.delete(existing.roleId), {
|
|
47
|
+
kind: "delete-role",
|
|
48
|
+
roleId: existing.roleId,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function diffGroups(spec, current, mode, actions) {
|
|
55
|
+
const curById = new Map(current.groups.map((g) => [g.groupId, g]));
|
|
56
|
+
const desiredIds = new Set(spec.groups.map((g) => g.groupId));
|
|
57
|
+
for (const desired of spec.groups) {
|
|
58
|
+
const existing = curById.get(desired.groupId);
|
|
59
|
+
if (!existing) {
|
|
60
|
+
actions.push(mkAction("create-group", `create group "${desired.groupId}" (${desired.name})`, () => groupOps.create(desired.groupId, desired.name, desired.description)));
|
|
61
|
+
}
|
|
62
|
+
else if (existing.name !== desired.name || descChanged(existing.description, desired.description)) {
|
|
63
|
+
actions.push(mkAction("update-group", `update group "${desired.groupId}"`, () => groupOps.update(desired.groupId, desired.name, desired.description)));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (mode === "prune") {
|
|
67
|
+
for (const existing of current.groups) {
|
|
68
|
+
if (!desiredIds.has(existing.groupId)) {
|
|
69
|
+
actions.push(mkAction("delete-group", `delete group "${existing.groupId}"`, () => groupOps.delete(existing.groupId), {
|
|
70
|
+
kind: "delete-group",
|
|
71
|
+
groupId: existing.groupId,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function claimKey(claimName, claimValue) {
|
|
78
|
+
return `${claimName}::${claimValue}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Camunda enforces a single mapping rule per (claimName, claimValue) pair
|
|
82
|
+
* cluster-wide - creating a second one with the same claim under a different
|
|
83
|
+
* mappingRuleId is rejected by the live API. `diffMappingRules` only ever
|
|
84
|
+
* matched by id, so a spec declaring a fresh id that happens to reuse a claim
|
|
85
|
+
* already owned by some other mapping rule (e.g. one created by Camunda 8.8's
|
|
86
|
+
* built-in boot-time Identity-as-code feature, or left over from an earlier,
|
|
87
|
+
* differently-keyed run) produced a doomed create-mapping-rule action - which
|
|
88
|
+
* failed at apply time, and then cascaded into further failures for every
|
|
89
|
+
* relationship/authorization action that referenced the never-created id.
|
|
90
|
+
*
|
|
91
|
+
* This runs against `current` (live cluster state) before diffing, so the
|
|
92
|
+
* conflict is surfaced as a clear, actionable message at `plan` time instead
|
|
93
|
+
* of an opaque API error mid-`apply`, and the doomed downstream actions are
|
|
94
|
+
* never generated in the first place.
|
|
95
|
+
*/
|
|
96
|
+
function findMappingRuleClaimConflicts(spec, current) {
|
|
97
|
+
const currentIds = new Set(current.mappingRules.map((m) => m.mappingRuleId));
|
|
98
|
+
const currentIdByClaim = new Map();
|
|
99
|
+
for (const m of current.mappingRules) {
|
|
100
|
+
currentIdByClaim.set(claimKey(m.claimName, m.claimValue), m.mappingRuleId);
|
|
101
|
+
}
|
|
102
|
+
const conflictedIds = new Set();
|
|
103
|
+
const conflicts = [];
|
|
104
|
+
for (const desired of spec.mappingRules) {
|
|
105
|
+
if (currentIds.has(desired.mappingRuleId))
|
|
106
|
+
continue; // update path, not a create - no conflict possible
|
|
107
|
+
const existingId = currentIdByClaim.get(claimKey(desired.claimName, desired.claimValue));
|
|
108
|
+
if (existingId !== undefined && existingId !== desired.mappingRuleId) {
|
|
109
|
+
conflictedIds.add(desired.mappingRuleId);
|
|
110
|
+
conflicts.push(`mapping rule "${desired.mappingRuleId}" (claim ${desired.claimName}=${desired.claimValue}) cannot be created: ` +
|
|
111
|
+
`mapping rule "${existingId}" already uses this exact claim, and Camunda allows only one mapping rule per claim. ` +
|
|
112
|
+
`Skipped creating "${desired.mappingRuleId}" and any relationship/authorization entries in the spec that reference it. ` +
|
|
113
|
+
`To resolve: change mappingRuleId "${desired.mappingRuleId}" in your spec to "${existingId}" to adopt the existing rule; ` +
|
|
114
|
+
`or, if "${existingId}" isn't declared in your spec and you're running with --prune, rerun after this apply prunes it, which frees the claim for "${desired.mappingRuleId}".`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { conflictedIds, conflicts };
|
|
118
|
+
}
|
|
119
|
+
function diffMappingRules(spec, current, mode, actions, conflictedIds) {
|
|
120
|
+
const curById = new Map(current.mappingRules.map((m) => [m.mappingRuleId, m]));
|
|
121
|
+
const desiredIds = new Set(spec.mappingRules.map((m) => m.mappingRuleId));
|
|
122
|
+
for (const desired of spec.mappingRules) {
|
|
123
|
+
if (conflictedIds.has(desired.mappingRuleId))
|
|
124
|
+
continue;
|
|
125
|
+
// The SDK requires `name` on create/update; the YAML schema leaves it optional
|
|
126
|
+
// (matching the example spec, which omits it) - fall back to the mapping rule's
|
|
127
|
+
// own id so a name-less spec entry still round-trips.
|
|
128
|
+
const effectiveName = desired.name ?? desired.mappingRuleId;
|
|
129
|
+
const existing = curById.get(desired.mappingRuleId);
|
|
130
|
+
if (!existing) {
|
|
131
|
+
actions.push(mkAction("create-mapping-rule", `create mapping rule "${desired.mappingRuleId}"`, () => mappingRuleOps.create(desired.mappingRuleId, desired.claimName, desired.claimValue, effectiveName)));
|
|
132
|
+
}
|
|
133
|
+
else if (existing.claimName !== desired.claimName ||
|
|
134
|
+
existing.claimValue !== desired.claimValue ||
|
|
135
|
+
existing.name !== effectiveName) {
|
|
136
|
+
actions.push(mkAction("update-mapping-rule", `update mapping rule "${desired.mappingRuleId}"`, () => mappingRuleOps.update(desired.mappingRuleId, desired.claimName, desired.claimValue, effectiveName)));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (mode === "prune") {
|
|
140
|
+
for (const existing of current.mappingRules) {
|
|
141
|
+
if (!desiredIds.has(existing.mappingRuleId)) {
|
|
142
|
+
actions.push(mkAction("delete-mapping-rule", `delete mapping rule "${existing.mappingRuleId}"`, () => mappingRuleOps.delete(existing.mappingRuleId), { kind: "delete-mapping-rule", mappingRuleId: existing.mappingRuleId }));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function diffRelationship(desiredPairs, currentPairs, mode, assignKind, unassignKind, describe, doAssign, doUnassign, actions,
|
|
148
|
+
// Lets specific relationship types (currently just role<->client) attach a
|
|
149
|
+
// structured target so protect.ts can guard one exact edge, e.g. "this tool's
|
|
150
|
+
// own client keeping the admin role." Defaults to untargeted for every other
|
|
151
|
+
// relationship type, which has no such per-edge protection need.
|
|
152
|
+
makeUnassignTarget = () => ({ kind: "other" })) {
|
|
153
|
+
for (const pair of desiredPairs) {
|
|
154
|
+
if (!currentPairs.has(pair)) {
|
|
155
|
+
const [parentId, childId] = pair.split("::");
|
|
156
|
+
actions.push(mkAction(assignKind, describe(parentId, childId), () => doAssign(parentId, childId)));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (mode === "prune") {
|
|
160
|
+
for (const pair of currentPairs) {
|
|
161
|
+
if (!desiredPairs.has(pair)) {
|
|
162
|
+
const [parentId, childId] = pair.split("::");
|
|
163
|
+
actions.push(mkAction(unassignKind, `un${describe(parentId, childId)}`, () => doUnassign(parentId, childId), makeUnassignTarget(parentId, childId)));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function diffRelationships(spec, current, mode, actions, conflictedIds) {
|
|
169
|
+
const roleGroupDesired = new Set();
|
|
170
|
+
const roleMappingRuleDesired = new Set();
|
|
171
|
+
const roleUserDesired = new Set();
|
|
172
|
+
const roleClientDesired = new Set();
|
|
173
|
+
for (const role of spec.roles) {
|
|
174
|
+
for (const groupId of role.groups)
|
|
175
|
+
roleGroupDesired.add(`${role.roleId}::${groupId}`);
|
|
176
|
+
for (const mappingRuleId of role.mappingRules) {
|
|
177
|
+
if (conflictedIds.has(mappingRuleId))
|
|
178
|
+
continue;
|
|
179
|
+
roleMappingRuleDesired.add(`${role.roleId}::${mappingRuleId}`);
|
|
180
|
+
}
|
|
181
|
+
for (const username of role.users)
|
|
182
|
+
roleUserDesired.add(`${role.roleId}::${username}`);
|
|
183
|
+
for (const clientId of role.clients)
|
|
184
|
+
roleClientDesired.add(`${role.roleId}::${clientId}`);
|
|
185
|
+
}
|
|
186
|
+
const groupMappingRuleDesired = new Set();
|
|
187
|
+
const groupUserDesired = new Set();
|
|
188
|
+
const groupClientDesired = new Set();
|
|
189
|
+
for (const group of spec.groups) {
|
|
190
|
+
for (const mappingRuleId of group.mappingRules) {
|
|
191
|
+
if (conflictedIds.has(mappingRuleId))
|
|
192
|
+
continue;
|
|
193
|
+
groupMappingRuleDesired.add(`${group.groupId}::${mappingRuleId}`);
|
|
194
|
+
}
|
|
195
|
+
for (const username of group.users)
|
|
196
|
+
groupUserDesired.add(`${group.groupId}::${username}`);
|
|
197
|
+
for (const clientId of group.clients)
|
|
198
|
+
groupClientDesired.add(`${group.groupId}::${clientId}`);
|
|
199
|
+
}
|
|
200
|
+
const tenantRoleDesired = new Set();
|
|
201
|
+
const tenantGroupDesired = new Set();
|
|
202
|
+
const tenantMappingRuleDesired = new Set();
|
|
203
|
+
for (const tenant of spec.tenants) {
|
|
204
|
+
for (const roleId of tenant.roles)
|
|
205
|
+
tenantRoleDesired.add(`${tenant.tenantId}::${roleId}`);
|
|
206
|
+
for (const groupId of tenant.groups)
|
|
207
|
+
tenantGroupDesired.add(`${tenant.tenantId}::${groupId}`);
|
|
208
|
+
for (const mappingRuleId of tenant.mappingRules) {
|
|
209
|
+
if (conflictedIds.has(mappingRuleId))
|
|
210
|
+
continue;
|
|
211
|
+
tenantMappingRuleDesired.add(`${tenant.tenantId}::${mappingRuleId}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
diffRelationship(groupMappingRuleDesired, current.relationships.groupMappingRule, mode, "assign-group-mapping-rule", "unassign-group-mapping-rule", (groupId, mappingRuleId) => `assign mapping rule "${mappingRuleId}" to group "${groupId}"`, (groupId, mappingRuleId) => groupOps.assignMappingRule(groupId, mappingRuleId), (groupId, mappingRuleId) => groupOps.unassignMappingRule(groupId, mappingRuleId), actions);
|
|
215
|
+
diffRelationship(groupUserDesired, current.relationships.groupUser, mode, "assign-group-user", "unassign-group-user", (groupId, username) => `assign user "${username}" to group "${groupId}"`, (groupId, username) => groupOps.assignUser(groupId, username), (groupId, username) => groupOps.unassignUser(groupId, username), actions);
|
|
216
|
+
diffRelationship(groupClientDesired, current.relationships.groupClient, mode, "assign-group-client", "unassign-group-client", (groupId, clientId) => `assign client "${clientId}" to group "${groupId}"`, (groupId, clientId) => groupOps.assignClient(groupId, clientId), (groupId, clientId) => groupOps.unassignClient(groupId, clientId), actions);
|
|
217
|
+
diffRelationship(roleUserDesired, current.relationships.roleUser, mode, "assign-role-user", "unassign-role-user", (roleId, username) => `assign user "${username}" to role "${roleId}"`, (roleId, username) => roleOps.assignUser(roleId, username), (roleId, username) => roleOps.unassignUser(roleId, username), actions);
|
|
218
|
+
diffRelationship(roleClientDesired, current.relationships.roleClient, mode, "assign-role-client", "unassign-role-client", (roleId, clientId) => `assign client "${clientId}" to role "${roleId}"`, (roleId, clientId) => roleOps.assignClient(roleId, clientId), (roleId, clientId) => roleOps.unassignClient(roleId, clientId), actions, (roleId, clientId) => ({ kind: "unassign-role-client", roleId, clientId }));
|
|
219
|
+
diffRelationship(roleMappingRuleDesired, current.relationships.roleMappingRule, mode, "assign-role-mapping-rule", "unassign-role-mapping-rule", (roleId, mappingRuleId) => `assign mapping rule "${mappingRuleId}" to role "${roleId}"`, (roleId, mappingRuleId) => roleOps.assignMappingRule(roleId, mappingRuleId), (roleId, mappingRuleId) => roleOps.unassignMappingRule(roleId, mappingRuleId), actions);
|
|
220
|
+
diffRelationship(roleGroupDesired, current.relationships.roleGroup, mode, "assign-role-group", "unassign-role-group", (roleId, groupId) => `assign role "${roleId}" to group "${groupId}"`, (roleId, groupId) => roleOps.assignGroup(roleId, groupId), (roleId, groupId) => roleOps.unassignGroup(roleId, groupId), actions);
|
|
221
|
+
diffRelationship(tenantRoleDesired, current.relationships.tenantRole, mode, "assign-tenant-role", "unassign-tenant-role", (tenantId, roleId) => `assign role "${roleId}" to tenant "${tenantId}"`, (tenantId, roleId) => tenantOps.assignRole(tenantId, roleId), (tenantId, roleId) => tenantOps.unassignRole(tenantId, roleId), actions, (tenantId, roleId) => ({ kind: "unassign-tenant-role", tenantId, roleId }));
|
|
222
|
+
diffRelationship(tenantGroupDesired, current.relationships.tenantGroup, mode, "assign-tenant-group", "unassign-tenant-group", (tenantId, groupId) => `assign group "${groupId}" to tenant "${tenantId}"`, (tenantId, groupId) => tenantOps.assignGroup(tenantId, groupId), (tenantId, groupId) => tenantOps.unassignGroup(tenantId, groupId), actions);
|
|
223
|
+
diffRelationship(tenantMappingRuleDesired, current.relationships.tenantMappingRule, mode, "assign-tenant-mapping-rule", "unassign-tenant-mapping-rule", (tenantId, mappingRuleId) => `assign mapping rule "${mappingRuleId}" to tenant "${tenantId}"`, (tenantId, mappingRuleId) => tenantOps.assignMappingRule(tenantId, mappingRuleId), (tenantId, mappingRuleId) => tenantOps.unassignMappingRule(tenantId, mappingRuleId), actions);
|
|
224
|
+
}
|
|
225
|
+
function authTupleKey(t) {
|
|
226
|
+
return `${t.ownerType}::${t.ownerId}::${t.resourceType}::${t.resourceId}`;
|
|
227
|
+
}
|
|
228
|
+
function samePermissionSet(a, b) {
|
|
229
|
+
return a.length === b.length && new Set(a).size === new Set([...a, ...b]).size;
|
|
230
|
+
}
|
|
231
|
+
function diffAuthorizations(spec, current, mode, actions, conflictedIds) {
|
|
232
|
+
const curByTuple = new Map(current.authorizations.map((a) => [authTupleKey(a), a]));
|
|
233
|
+
const desiredTuples = new Set();
|
|
234
|
+
for (const desired of spec.authorizations) {
|
|
235
|
+
if ((desired.ownerType === "MAPPING_RULE" && conflictedIds.has(desired.ownerId)) ||
|
|
236
|
+
(desired.resourceType === "MAPPING_RULE" && conflictedIds.has(desired.resourceId))) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const key = authTupleKey(desired);
|
|
240
|
+
desiredTuples.add(key);
|
|
241
|
+
const tuple = {
|
|
242
|
+
ownerType: desired.ownerType,
|
|
243
|
+
ownerId: desired.ownerId,
|
|
244
|
+
resourceType: desired.resourceType,
|
|
245
|
+
resourceId: desired.resourceId,
|
|
246
|
+
permissions: desired.permissions,
|
|
247
|
+
};
|
|
248
|
+
const label = `${desired.ownerType}:${desired.ownerId} -> ${desired.resourceType}:${desired.resourceId}`;
|
|
249
|
+
const target = { kind: "authorization", ownerType: desired.ownerType, ownerId: desired.ownerId };
|
|
250
|
+
const existing = curByTuple.get(key);
|
|
251
|
+
if (!existing) {
|
|
252
|
+
actions.push(mkAction("create-authorization", `create authorization ${label} [${desired.permissions.join(", ")}]`, () => authorizationOps.create(tuple), target));
|
|
253
|
+
}
|
|
254
|
+
else if (!samePermissionSet(existing.permissionTypes, desired.permissions)) {
|
|
255
|
+
actions.push(mkAction("update-authorization", `update authorization ${label} permissions -> [${desired.permissions.join(", ")}]`, () => authorizationOps.update(existing.authorizationKey, tuple), target));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (mode === "prune") {
|
|
259
|
+
for (const existing of current.authorizations) {
|
|
260
|
+
const key = authTupleKey(existing);
|
|
261
|
+
if (!desiredTuples.has(key)) {
|
|
262
|
+
const label = `${existing.ownerType}:${existing.ownerId} -> ${existing.resourceType}:${existing.resourceId}`;
|
|
263
|
+
actions.push(mkAction("delete-authorization", `delete authorization ${label}`, () => authorizationOps.delete(existing.authorizationKey), { kind: "authorization", ownerType: existing.ownerType, ownerId: existing.ownerId }));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
export function buildPlan(spec, current, mode) {
|
|
269
|
+
const actions = [];
|
|
270
|
+
const { conflictedIds, conflicts } = findMappingRuleClaimConflicts(spec, current);
|
|
271
|
+
diffTenants(spec, current, mode, actions);
|
|
272
|
+
diffRoles(spec, current, mode, actions);
|
|
273
|
+
diffGroups(spec, current, mode, actions);
|
|
274
|
+
diffMappingRules(spec, current, mode, actions, conflictedIds);
|
|
275
|
+
diffRelationships(spec, current, mode, actions, conflictedIds);
|
|
276
|
+
diffAuthorizations(spec, current, mode, actions, conflictedIds);
|
|
277
|
+
const { actions: protectedActions, warnings } = applyProtections(actions);
|
|
278
|
+
return { actions: sortActions(protectedActions), warnings, conflicts };
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/reconcile/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { cyan, dim, green, red, yellow } from "../colors.js";
|
|
2
|
+
function symbolFor(kind) {
|
|
3
|
+
if (kind.startsWith("create-"))
|
|
4
|
+
return "+";
|
|
5
|
+
if (kind.startsWith("update-"))
|
|
6
|
+
return "~";
|
|
7
|
+
if (kind.startsWith("delete-"))
|
|
8
|
+
return "-";
|
|
9
|
+
if (kind.startsWith("unassign-"))
|
|
10
|
+
return "<-";
|
|
11
|
+
if (kind.startsWith("assign-"))
|
|
12
|
+
return "->";
|
|
13
|
+
return "?";
|
|
14
|
+
}
|
|
15
|
+
/** Destructive actions (deletes and unassigns) are red regardless of exact
|
|
16
|
+
* kind - that's the one distinction operators scanning a plan most need to
|
|
17
|
+
* catch at a glance. Non-destructive kinds get a lighter, purely cosmetic
|
|
18
|
+
* hint (create/update/assign). */
|
|
19
|
+
function colorFor(action) {
|
|
20
|
+
if (action.destructive)
|
|
21
|
+
return red;
|
|
22
|
+
if (action.kind.startsWith("create-"))
|
|
23
|
+
return green;
|
|
24
|
+
if (action.kind.startsWith("update-"))
|
|
25
|
+
return yellow;
|
|
26
|
+
if (action.kind.startsWith("assign-"))
|
|
27
|
+
return cyan;
|
|
28
|
+
return (text) => text;
|
|
29
|
+
}
|
|
30
|
+
/** Shared renderer used by both `plan` and the pre-confirmation display in `apply`,
|
|
31
|
+
* so what `apply` is about to do is guaranteed to match what `plan` reported.
|
|
32
|
+
*
|
|
33
|
+
* Protection warnings (admin role/authorizations/guardian client blocked from a
|
|
34
|
+
* would-be deletion, the <default> tenant, etc.) are structural and permanent -
|
|
35
|
+
* they'll fire on every single prune run for as long as those invariants exist,
|
|
36
|
+
* so they're noise once you already know the policy. Hidden by default; pass
|
|
37
|
+
* `showProtected: true` to see them (e.g. while first verifying the guard). */
|
|
38
|
+
export function formatPlan(plan, opts = {}) {
|
|
39
|
+
const lines = [];
|
|
40
|
+
if (plan.actions.length === 0) {
|
|
41
|
+
lines.push("No changes - cluster state already matches the spec.");
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
for (const action of plan.actions) {
|
|
45
|
+
lines.push(colorFor(action)(` ${symbolFor(action.kind)} ${action.description}`));
|
|
46
|
+
}
|
|
47
|
+
lines.push("");
|
|
48
|
+
lines.push(`${plan.actions.length} action(s) planned.`);
|
|
49
|
+
}
|
|
50
|
+
if (plan.conflicts.length > 0) {
|
|
51
|
+
lines.push("");
|
|
52
|
+
lines.push(red("Conflicts (need manual resolution):"));
|
|
53
|
+
for (const conflict of plan.conflicts)
|
|
54
|
+
lines.push(red(` ! ${conflict}`));
|
|
55
|
+
}
|
|
56
|
+
if (opts.showProtected && plan.warnings.length > 0) {
|
|
57
|
+
lines.push("");
|
|
58
|
+
lines.push("Protected (left untouched):");
|
|
59
|
+
for (const warning of plan.warnings)
|
|
60
|
+
lines.push(dim(` ! ${warning}`));
|
|
61
|
+
}
|
|
62
|
+
return lines.join("\n");
|
|
63
|
+
}
|
|
64
|
+
function errorMessage(error) {
|
|
65
|
+
if (error instanceof Error)
|
|
66
|
+
return error.message;
|
|
67
|
+
try {
|
|
68
|
+
return JSON.stringify(error);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return String(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function formatApplyResult(result, opts = {}) {
|
|
75
|
+
const lines = [];
|
|
76
|
+
lines.push(`${result.succeeded.length} succeeded, ${result.failed.length} failed.`);
|
|
77
|
+
if (result.failed.length > 0) {
|
|
78
|
+
lines.push("");
|
|
79
|
+
lines.push("Failures:");
|
|
80
|
+
for (const { action, error } of result.failed) {
|
|
81
|
+
lines.push(red(` x ${action.description}: ${errorMessage(error)}`));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (opts.showProtected && result.skippedProtected.length > 0) {
|
|
85
|
+
lines.push("");
|
|
86
|
+
lines.push("Protected (left untouched):");
|
|
87
|
+
for (const warning of result.skippedProtected)
|
|
88
|
+
lines.push(dim(` ! ${warning}`));
|
|
89
|
+
}
|
|
90
|
+
return lines.join("\n");
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/reconcile/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed phase ordering. Dependencies here are structural (an assignment can't be
|
|
3
|
+
* created before both its endpoints exist; an entity can't be deleted while
|
|
4
|
+
* something still references it), not data-dependent, so a static table is
|
|
5
|
+
* sufficient - no per-run topological sort needed.
|
|
6
|
+
*
|
|
7
|
+
* Create/update phase (ascending): base entities first (tenants can be created
|
|
8
|
+
* with no dependencies; mapping rules/groups/roles likewise), then relationship
|
|
9
|
+
* assigns, then authorizations last since they reference the others by id.
|
|
10
|
+
*
|
|
11
|
+
* Delete/unassign phase (prune only): the reverse shape - authorizations first,
|
|
12
|
+
* then every relationship unassign, then base entities. This guarantees every
|
|
13
|
+
* edge referencing an entity is severed before the entity itself is deleted
|
|
14
|
+
* (see "Cascading deletes in prune mode" in the design plan) - entity-delete
|
|
15
|
+
* order among tenants/roles/groups/mapping-rules doesn't matter once every
|
|
16
|
+
* relationship touching them has already been unassigned.
|
|
17
|
+
*/
|
|
18
|
+
const PHASE = {
|
|
19
|
+
"create-tenant": 0,
|
|
20
|
+
"update-tenant": 0,
|
|
21
|
+
"create-mapping-rule": 1,
|
|
22
|
+
"update-mapping-rule": 1,
|
|
23
|
+
"create-group": 2,
|
|
24
|
+
"update-group": 2,
|
|
25
|
+
"create-role": 3,
|
|
26
|
+
"update-role": 3,
|
|
27
|
+
"assign-group-mapping-rule": 4,
|
|
28
|
+
"assign-group-user": 4,
|
|
29
|
+
"assign-group-client": 4,
|
|
30
|
+
"assign-role-mapping-rule": 5,
|
|
31
|
+
"assign-role-user": 5,
|
|
32
|
+
"assign-role-client": 5,
|
|
33
|
+
"assign-role-group": 6,
|
|
34
|
+
"assign-tenant-role": 7,
|
|
35
|
+
"assign-tenant-group": 8,
|
|
36
|
+
"assign-tenant-mapping-rule": 8,
|
|
37
|
+
"create-authorization": 9,
|
|
38
|
+
"update-authorization": 9,
|
|
39
|
+
"delete-authorization": 10,
|
|
40
|
+
"unassign-tenant-group": 11,
|
|
41
|
+
"unassign-tenant-mapping-rule": 11,
|
|
42
|
+
"unassign-tenant-role": 12,
|
|
43
|
+
"unassign-role-group": 13,
|
|
44
|
+
"unassign-role-mapping-rule": 14,
|
|
45
|
+
"unassign-role-user": 14,
|
|
46
|
+
"unassign-role-client": 14,
|
|
47
|
+
"unassign-group-mapping-rule": 15,
|
|
48
|
+
"unassign-group-user": 15,
|
|
49
|
+
"unassign-group-client": 15,
|
|
50
|
+
"delete-role": 16,
|
|
51
|
+
"delete-group": 16,
|
|
52
|
+
"delete-mapping-rule": 16,
|
|
53
|
+
"delete-tenant": 16,
|
|
54
|
+
};
|
|
55
|
+
export function sortActions(actions) {
|
|
56
|
+
return [...actions].sort((a, b) => PHASE[a.kind] - PHASE[b.kind]);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order.js","sourceRoot":"","sources":["../../src/reconcile/order.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,KAAK,GAA+B;IACxC,eAAe,EAAE,CAAC;IAClB,eAAe,EAAE,CAAC;IAClB,qBAAqB,EAAE,CAAC;IACxB,qBAAqB,EAAE,CAAC;IACxB,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE,CAAC;IACjB,aAAa,EAAE,CAAC;IAChB,aAAa,EAAE,CAAC;IAChB,2BAA2B,EAAE,CAAC;IAC9B,mBAAmB,EAAE,CAAC;IACtB,qBAAqB,EAAE,CAAC;IACxB,0BAA0B,EAAE,CAAC;IAC7B,kBAAkB,EAAE,CAAC;IACrB,oBAAoB,EAAE,CAAC;IACvB,mBAAmB,EAAE,CAAC;IACtB,oBAAoB,EAAE,CAAC;IACvB,qBAAqB,EAAE,CAAC;IACxB,4BAA4B,EAAE,CAAC;IAC/B,sBAAsB,EAAE,CAAC;IACzB,sBAAsB,EAAE,CAAC;IAEzB,sBAAsB,EAAE,EAAE;IAC1B,uBAAuB,EAAE,EAAE;IAC3B,8BAA8B,EAAE,EAAE;IAClC,sBAAsB,EAAE,EAAE;IAC1B,qBAAqB,EAAE,EAAE;IACzB,4BAA4B,EAAE,EAAE;IAChC,oBAAoB,EAAE,EAAE;IACxB,sBAAsB,EAAE,EAAE;IAC1B,6BAA6B,EAAE,EAAE;IACjC,qBAAqB,EAAE,EAAE;IACzB,uBAAuB,EAAE,EAAE;IAC3B,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,EAAE;IAClB,qBAAqB,EAAE,EAAE;IACzB,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,OAAwB;IAClD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC"}
|