@likec4/leanix-bridge 1.53.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 +145 -0
- package/dist/index.d.mts +559 -0
- package/dist/index.mjs +1110 -0
- package/package.json +62 -0
- package/src/adr-generation.ts +105 -0
- package/src/contracts.ts +96 -0
- package/src/drawio-leanix-roundtrip.ts +51 -0
- package/src/drift-report.ts +61 -0
- package/src/fixture-model.ts +52 -0
- package/src/governance-checks.ts +103 -0
- package/src/impact-report.ts +38 -0
- package/src/index.ts +109 -0
- package/src/leanix-api-client.ts +138 -0
- package/src/leanix-graphql-operations.ts +160 -0
- package/src/leanix-inventory-snapshot.ts +263 -0
- package/src/mapping.ts +88 -0
- package/src/model-input.ts +36 -0
- package/src/reconcile.ts +227 -0
- package/src/report.ts +73 -0
- package/src/sync-to-leanix.ts +352 -0
- package/src/to-bridge-manifest.ts +85 -0
- package/src/to-leanix-inventory-dry-run.ts +105 -0
- package/src/validate.ts +106 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2026 Denis Davydkov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# @likec4/leanix-bridge
|
|
2
|
+
|
|
3
|
+
Bridge from the LikeC4 semantic model to LeanIX-shaped inventory artifacts. LikeC4 remains the canonical source of truth.
|
|
4
|
+
|
|
5
|
+
- **Dry-run**: identity manifest, LeanIX-shaped artifacts (fact sheets + relations), configurable mapping.
|
|
6
|
+
- **Sync plan** (optional): `planSyncToLeanix(dryRun, client)` queries LeanIX (read-only) and returns a plan artifact describing what would be created vs updated; use before live sync to review changes.
|
|
7
|
+
- **Live sync** (optional): `syncToLeanix(manifest, dryRun, client)` to create/update fact sheets and relations in the LeanIX API (auth, rate limiting, idempotency).
|
|
8
|
+
- **Draw.io ↔ LeanIX**: `manifestToDrawioLeanixMapping(manifest)` for round-trip mapping (likec4Id ↔ LeanIX fact sheet id) after sync.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
- **In scope**: identity manifest, dry-run, configurable mapping, **LeanIX API sync**, **Draw.io–LeanIX mapping**, **Phase 2 inbound** (inventory snapshot, reconciliation), **Phase 3** (impact analysis, drift detection, ADR generation, governance checks), tests.
|
|
13
|
+
- **Out of scope**: AI features, new top-level CLI namespaces.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### First-class CLI (recommended)
|
|
18
|
+
|
|
19
|
+
From the project root:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Generate bridge artifacts (manifest, leanix-dry-run.json, report) to out/bridge
|
|
23
|
+
likec4 gen leanix dry-run -o out/bridge
|
|
24
|
+
|
|
25
|
+
# Sync workflow: write artifacts and optional sync-plan (read-only when LEANIX_API_TOKEN is set)
|
|
26
|
+
likec4 sync leanix --dry-run -o out/bridge
|
|
27
|
+
|
|
28
|
+
# Live sync to LeanIX (requires LEANIX_API_TOKEN)
|
|
29
|
+
likec4 sync leanix --apply -o out/bridge
|
|
30
|
+
|
|
31
|
+
# Phase 2 inbound: fetch LeanIX inventory (read-only), then reconcile with manifest
|
|
32
|
+
# Fetch LeanIX inventory snapshot (read-only) to out/bridge
|
|
33
|
+
likec4 gen leanix inventory -o out/bridge
|
|
34
|
+
# Run reconciliation between manifest and LeanIX inventory, output to out/bridge
|
|
35
|
+
likec4 gen leanix reconcile -o out/bridge
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Export Draw.io with LeanIX profile (includes bridge-managed metadata for round-trip sync):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
likec4 export drawio --profile leanix -o ./diagrams
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The `--profile leanix` flag selects the LeanIX export profile so vertices and edges carry likec4Id, likec4ViewId, likec4RelationId, and bridgeManaged attributes for sync and round-trip.
|
|
45
|
+
|
|
46
|
+
### Custom generator (alternative)
|
|
47
|
+
|
|
48
|
+
You can still wire the bridge in your LikeC4 config:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// likec4.config.ts
|
|
52
|
+
import { defineConfig } from '@likec4/config'
|
|
53
|
+
import {
|
|
54
|
+
buildBridgeReport,
|
|
55
|
+
toBridgeManifest,
|
|
56
|
+
toLeanixInventoryDryRun,
|
|
57
|
+
} from '@likec4/leanix-bridge'
|
|
58
|
+
|
|
59
|
+
export default defineConfig({
|
|
60
|
+
name: 'my-project',
|
|
61
|
+
generators: {
|
|
62
|
+
'my-leanix': async ({ likec4model, ctx }) => {
|
|
63
|
+
const manifest = toBridgeManifest(likec4model, { mappingProfile: 'default' })
|
|
64
|
+
const dryRun = toLeanixInventoryDryRun(likec4model, { mappingProfile: 'default' })
|
|
65
|
+
const report = buildBridgeReport(manifest, dryRun)
|
|
66
|
+
|
|
67
|
+
await ctx.write({ path: ['out', 'bridge', 'manifest.json'], content: JSON.stringify(manifest, null, 2) })
|
|
68
|
+
await ctx.write({ path: ['out', 'bridge', 'leanix-dry-run.json'], content: JSON.stringify(dryRun, null, 2) })
|
|
69
|
+
await ctx.write({ path: ['out', 'bridge', 'report.json'], content: JSON.stringify(report, null, 2) })
|
|
70
|
+
|
|
71
|
+
// Phase 2 (programmatic): e.g. import { reconcileInventoryWithManifest } from '@likec4/leanix-bridge', then
|
|
72
|
+
// reconciliation = reconcileInventoryWithManifest(snapshot, manifest) and ctx.write(..., JSON.stringify(reconciliation, null, 2))
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Then run: `likec4 gen my-leanix`
|
|
79
|
+
|
|
80
|
+
### Optional: sync plan (review before sync)
|
|
81
|
+
|
|
82
|
+
Before pushing to LeanIX, you can produce a **sync plan** that queries LeanIX (read-only) to see what would be created vs updated:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { LeanixApiClient, planSyncToLeanix } from '@likec4/leanix-bridge'
|
|
86
|
+
|
|
87
|
+
const client = new LeanixApiClient({
|
|
88
|
+
apiToken: process.env.LEANIX_API_TOKEN!,
|
|
89
|
+
baseUrl: 'https://app.leanix.net',
|
|
90
|
+
requestDelayMs: 200,
|
|
91
|
+
})
|
|
92
|
+
const plan = await planSyncToLeanix(dryRun, client, { idempotent: true })
|
|
93
|
+
// plan.summary: { factSheetsToCreate, factSheetsToUpdate, relationsToCreate }
|
|
94
|
+
// plan.factSheetPlans: [{ likec4Id, name, type, action: 'create'|'update', existingFactSheetId? }]
|
|
95
|
+
// Write plan to out/bridge/sync-plan.json for review, then run sync
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Optional: sync to LeanIX API
|
|
99
|
+
|
|
100
|
+
After generating the dry-run artifacts (and optionally the sync plan), you can push them to LeanIX (requires an API token):
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { LeanixApiClient, syncToLeanix, manifestToDrawioLeanixMapping } from '@likec4/leanix-bridge'
|
|
104
|
+
|
|
105
|
+
const client = new LeanixApiClient({
|
|
106
|
+
apiToken: process.env.LEANIX_API_TOKEN!,
|
|
107
|
+
baseUrl: 'https://app.leanix.net',
|
|
108
|
+
requestDelayMs: 200,
|
|
109
|
+
})
|
|
110
|
+
const result = await syncToLeanix(manifest, dryRun, client, { idempotent: true })
|
|
111
|
+
// result.manifest has external.leanix.factSheetId per entity
|
|
112
|
+
const mapping = manifestToDrawioLeanixMapping(result.manifest)
|
|
113
|
+
// Use mapping.likec4IdToLeanixId for Draw.io round-trip
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## API
|
|
117
|
+
|
|
118
|
+
- **`toBridgeManifest(model, options?)`** – builds the identity manifest (canonical IDs + placeholder external IDs).
|
|
119
|
+
- **`toLeanixInventoryDryRun(model, options?)`** – builds LeanIX-shaped fact sheets and relations (no live IDs).
|
|
120
|
+
- **`buildBridgeReport(manifest, leanixDryRun)`** – builds a summary report with counts and artifact names.
|
|
121
|
+
- **`LeanixApiClient(config)`** – GraphQL client with Bearer auth and rate limiting (`apiToken`, `baseUrl?`, `requestDelayMs?`).
|
|
122
|
+
- **`planSyncToLeanix(leanixDryRun, client, options?)`** – queries LeanIX (read-only) and returns a **sync plan** (`SyncPlan`): per–fact sheet and per-relation actions (`create` / `update`), summary counts, and any query errors. Use before `syncToLeanix` to review what would change. Options: `idempotent?`, `generatedAt?`.
|
|
123
|
+
- **`syncToLeanix(manifest, leanixDryRun, client, options?)`** – syncs dry-run to LeanIX API; returns updated manifest with `external.leanix.factSheetId` and relation IDs. Options: `idempotent?`, `likec4IdAttribute?`.
|
|
124
|
+
- **`manifestToDrawioLeanixMapping(manifest)`** – returns `{ likec4IdToLeanixId, relationKeyToLeanixRelationId }` for Draw.io bridge-managed export or re-import from LeanIX.
|
|
125
|
+
- **`fetchLeanixInventorySnapshot(client, options?)`** – fetches a read-only snapshot of LeanIX fact sheets and relations (paginated); returns `LeanixInventorySnapshot`. Options: `likec4IdAttribute?`, `maxFactSheets?`, `generatedAt?`.
|
|
126
|
+
- **`reconcileInventoryWithManifest(snapshot, manifest, options?)`** – compares manifest to LeanIX snapshot; returns `ReconciliationResult` (matched, unmatchedInLikec4, unmatchedInLeanix, ambiguous). Optional `dryRun` improves matching.
|
|
127
|
+
- **`buildDriftReport(reconciliation)`** – builds a `DriftReport` from a `ReconciliationResult` (status, summary, description); accepts a single `ReconciliationResult` and returns `DriftReport`.
|
|
128
|
+
- **`impactReportFromSyncPlan(plan)`** – computes impact analysis from a sync plan; returns `ImpactReport` with affected entities and severity.
|
|
129
|
+
- **`generateAdrFromReconciliation(reconciliation, options?)`** – generates ADR-style markdown from a reconciliation result. **`generateAdrFromDriftReport(drift, options?)`** – generates ADR-style markdown from a drift report.
|
|
130
|
+
- **`runGovernanceChecks(reconciliation, options?)`** – runs configurable governance rules on a `ReconciliationResult`; accepts optional `GovernanceCheckOptions` and returns `GovernanceReport` with pass/fail and violation messages.
|
|
131
|
+
- **`isBridgeManifest(obj)`** / **`isLeanixInventorySnapshot(obj)`** – type guards for parsed JSON (e.g. from CLI artifact files).
|
|
132
|
+
|
|
133
|
+
Mapping is configurable via `options.mapping` (kinds → fact sheet types, relation kinds → relation types). LeanIX GraphQL schema varies by workspace; fact sheet types and relation types are meta-model specific.
|
|
134
|
+
|
|
135
|
+
## Contracts
|
|
136
|
+
|
|
137
|
+
- **canonicalId**: LikeC4 FQN (e.g. `cloud.backend.api`).
|
|
138
|
+
- **viewId**: LikeC4 view id (e.g. `index`, `landscape.overview`).
|
|
139
|
+
- **relationId** + **compositeKey**: `sourceFqn|targetFqn|relationId` for stable relation identity.
|
|
140
|
+
- **manifestVersion**, **generatedAt**, **bridgeVersion**, **mappingProfile**: manifest metadata.
|
|
141
|
+
|
|
142
|
+
## References
|
|
143
|
+
|
|
144
|
+
- [ADR-001: LeanIX bridge dry-run slice](../../docs/architecture-intelligence/adr-001-leanix-bridge-dry-run.md)
|
|
145
|
+
- [Implementation brief](../../docs/architecture-intelligence/implementation-brief.md)
|