@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/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@likec4/leanix-bridge",
3
+ "version": "1.53.0",
4
+ "license": "MIT",
5
+ "bugs": "https://github.com/likec4/likec4/issues",
6
+ "homepage": "https://likec4.dev",
7
+ "author": "Denis Davydkov <denis@davydkov.com>",
8
+ "description": "Bridge from LikeC4 semantic model to LeanIX-shaped inventory artifacts (supports optional live sync or dry-run modes)",
9
+ "files": [
10
+ "dist",
11
+ "src",
12
+ "**/package.json",
13
+ "!**/__*/**",
14
+ "!**/*.spec.*",
15
+ "!**/*.snap",
16
+ "!**/*.map"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/likec4/likec4.git",
21
+ "directory": "packages/leanix-bridge"
22
+ },
23
+ "type": "module",
24
+ "sideEffects": false,
25
+ "exports": {
26
+ ".": {
27
+ "sources": "./src/index.ts",
28
+ "default": {
29
+ "types": "./dist/index.d.mts",
30
+ "import": "./dist/index.mjs",
31
+ "default": "./dist/index.mjs"
32
+ }
33
+ }
34
+ },
35
+ "publishConfig": {
36
+ "registry": "https://registry.npmjs.org",
37
+ "access": "public"
38
+ },
39
+ "dependencies": {
40
+ "remeda": "^2.33.6",
41
+ "@likec4/core": "1.53.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "~22.19.15",
45
+ "typescript": "5.9.3",
46
+ "obuild": "0.4.31",
47
+ "vitest": "4.1.0",
48
+ "@likec4/devops": "1.42.0",
49
+ "@likec4/tsconfig": "1.53.0"
50
+ },
51
+ "scripts": {
52
+ "typecheck": "tsc -b --verbose",
53
+ "build": "obuild",
54
+ "lint": "oxlint --type-aware",
55
+ "clean": "likec4ops clean",
56
+ "pack": "pnpm pack",
57
+ "test": "vitest run --no-isolate",
58
+ "test:watch": "vitest"
59
+ },
60
+ "types": "dist/index.d.mts",
61
+ "module": "dist/index.mjs"
62
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Phase 3: Generate an Architecture Decision Record (ADR) from reconciliation and/or impact.
3
+ * Output is markdown; no DSL generation.
4
+ */
5
+
6
+ import type { DriftReport } from './drift-report'
7
+ import type { ImpactReport } from './impact-report'
8
+ import type { ReconciliationResult } from './reconcile'
9
+
10
+ /** Returns date part YYYY-MM-DD from ISO timestamp (G25, G5). Handles short strings defensively. */
11
+ function formatIsoDateString(iso: string): string {
12
+ if (typeof iso !== 'string' || iso.length < 10) return iso
13
+ return iso.slice(0, 10)
14
+ }
15
+
16
+ /** Shared ADR header lines (title, status, date). Reduces duplication between ADR generators. */
17
+ function buildAdrHeader(title: string, status: string, dateIso: string): string[] {
18
+ return [
19
+ `# ${title}`,
20
+ '',
21
+ `- Status: ${status}`,
22
+ `- Date: ${formatIsoDateString(dateIso)}`,
23
+ '',
24
+ ]
25
+ }
26
+
27
+ /** Options for ADR generation (title, status, optional impact report). */
28
+ export interface AdrGenerationOptions {
29
+ title?: string
30
+ /** ADR status line. Default: "Proposed". */
31
+ status?: string
32
+ /** Optional impact report to include. */
33
+ impact?: ImpactReport
34
+ }
35
+
36
+ /**
37
+ * Generates a short ADR-style markdown document from a reconciliation result (and optional impact).
38
+ * Use for governance or audit trail; does not modify any data.
39
+ */
40
+ export function generateAdrFromReconciliation(
41
+ reconciliation: ReconciliationResult,
42
+ options: AdrGenerationOptions = {},
43
+ ): string {
44
+ const title = options.title ?? 'LeanIX inventory reconciliation'
45
+ const status = options.status ?? 'Proposed'
46
+ const impact = options.impact
47
+ const lines: string[] = [
48
+ ...buildAdrHeader(title, status, reconciliation.generatedAt),
49
+ '## Context',
50
+ '',
51
+ `Reconciliation of LikeC4 manifest (project: ${reconciliation.manifestProjectId}) with LeanIX inventory snapshot (${
52
+ formatIsoDateString(reconciliation.snapshotGeneratedAt)
53
+ }).`,
54
+ '',
55
+ '## Result',
56
+ '',
57
+ `- Matched: ${reconciliation.summary.matched}`,
58
+ `- Unmatched in LikeC4: ${reconciliation.summary.unmatchedInLikec4}`,
59
+ `- Unmatched in LeanIX: ${reconciliation.summary.unmatchedInLeanix}`,
60
+ `- Ambiguous: ${reconciliation.summary.ambiguous}`,
61
+ '',
62
+ ]
63
+ if (impact) {
64
+ lines.push('## Impact (if sync applied)', '', impact.impactSummary, '', '')
65
+ }
66
+ lines.push(
67
+ '## Decision',
68
+ '',
69
+ 'LikeC4 remains the single source of truth; LeanIX is an adapter. No DSL is auto-generated from LeanIX.',
70
+ '',
71
+ )
72
+ return lines.join('\n')
73
+ }
74
+
75
+ /** Options for ADR generation from a drift report (subset of AdrGenerationOptions). */
76
+ export type DriftAdrGenerationOptions = Pick<AdrGenerationOptions, 'title' | 'status'>
77
+
78
+ /**
79
+ * Generates a short ADR-style markdown from a drift report.
80
+ */
81
+ export function generateAdrFromDriftReport(
82
+ drift: DriftReport,
83
+ options: DriftAdrGenerationOptions = {},
84
+ ): string {
85
+ const title = options.title ?? 'LeanIX drift report'
86
+ const status = options.status ?? 'Proposed'
87
+ return [
88
+ ...buildAdrHeader(title, status, drift.generatedAt),
89
+ '## Drift status',
90
+ '',
91
+ drift.description,
92
+ '',
93
+ '## Summary',
94
+ '',
95
+ `- Matched: ${drift.summary.matched}`,
96
+ `- Unmatched in LikeC4: ${drift.summary.unmatchedInLikec4}`,
97
+ `- Unmatched in LeanIX: ${drift.summary.unmatchedInLeanix}`,
98
+ `- Ambiguous: ${drift.summary.ambiguous}`,
99
+ '',
100
+ '## Decision',
101
+ '',
102
+ 'Review drift findings and determine whether synchronization or manual remediation is required.',
103
+ '',
104
+ ].join('\n')
105
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Canonical bridge contracts for LikeC4 ↔ LeanIX interoperability.
3
+ * LikeC4 remains the semantic source of truth; external IDs are provider-scoped.
4
+ * Uses readFileSync (not require) so when bundled into likec4 CLI the bundler
5
+ * does not emit require('../package.json') which fails in the tarball layout.
6
+ */
7
+
8
+ import { readFileSync } from 'node:fs'
9
+ import { dirname, join } from 'node:path'
10
+ import { fileURLToPath } from 'node:url'
11
+
12
+ const _dir = dirname(fileURLToPath(import.meta.url))
13
+ function readVersion(): string {
14
+ try {
15
+ const pkg = JSON.parse(readFileSync(join(_dir, '..', 'package.json'), 'utf8')) as { version?: string }
16
+ return pkg.version ?? '0.1.0'
17
+ } catch {
18
+ const pkg = JSON.parse(readFileSync(join(_dir, '..', '..', 'package.json'), 'utf8')) as { version?: string }
19
+ return pkg.version ?? '0.1.0'
20
+ }
21
+ }
22
+ /** Single source of truth: must match package.json version. */
23
+ export const BRIDGE_VERSION: string = readVersion()
24
+
25
+ /** Semantic anchor: LikeC4 FQN (e.g. cloud.backend.api) */
26
+ export type CanonicalId = string
27
+
28
+ /** Provider-scoped external identifier (e.g. LeanIX factSheetId) */
29
+ export type ExternalId = string
30
+
31
+ /** LikeC4 view id (e.g. index, saas, landscape.overview) */
32
+ export type ViewId = string
33
+
34
+ /** LikeC4 relation id; for composite key use sourceFqn|targetFqn|relationId */
35
+ export type RelationId = string
36
+
37
+ /** Version of the manifest schema */
38
+ export type ManifestVersion = string
39
+
40
+ /** ISO timestamp when the artifact was generated */
41
+ export type GeneratedAt = string
42
+
43
+ /** Version of the bridge that produced the artifact */
44
+ export type BridgeVersion = string
45
+
46
+ /** Name or id of the mapping profile used */
47
+ export type MappingProfile = string
48
+
49
+ /** Provider name (e.g. leanix, drawio) */
50
+ export type Provider = string
51
+
52
+ /** External IDs for a single provider (e.g. factSheetId, externalId). */
53
+ export interface ProviderExternalIds {
54
+ factSheetId?: string
55
+ externalId?: string
56
+ [key: string]: string | undefined
57
+ }
58
+
59
+ /** Entity entry in the manifest: canonical id + optional external IDs per provider. */
60
+ export interface ManifestEntity {
61
+ canonicalId: CanonicalId
62
+ external?: Partial<Record<Provider, ProviderExternalIds>>
63
+ }
64
+
65
+ /** View entry in the manifest (viewId + optional provider external ids). */
66
+ export interface ManifestView {
67
+ viewId: ViewId
68
+ external?: Partial<Record<Provider, Record<string, string>>>
69
+ }
70
+
71
+ /** Relation entry: composite key and optional external relation id per provider. */
72
+ export interface ManifestRelation {
73
+ relationId: RelationId
74
+ sourceFqn: CanonicalId
75
+ targetFqn: CanonicalId
76
+ compositeKey: string
77
+ external?: Partial<Record<Provider, { relationId?: string; [key: string]: string | undefined }>>
78
+ }
79
+
80
+ /** Identity manifest: canonical IDs and provider-scoped external IDs */
81
+ export interface BridgeManifest {
82
+ manifestVersion: ManifestVersion
83
+ generatedAt: GeneratedAt
84
+ bridgeVersion: BridgeVersion
85
+ mappingProfile: MappingProfile
86
+ projectId: string
87
+ entities: Record<CanonicalId, ManifestEntity>
88
+ views: Record<ViewId, ManifestView>
89
+ relations: ManifestRelation[]
90
+ }
91
+
92
+ /** Manifest schema version (semantic; must match parser). */
93
+ export const BRIDGE_MANIFEST_VERSION = '1.0'
94
+
95
+ /** Provider identifier for LeanIX (single source of truth for external.leanix). */
96
+ export const LEANIX_PROVIDER = 'leanix' as const
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Draw.io ↔ LeanIX round-trip: mapping between bridge manifest (with LeanIX external IDs)
3
+ * and diagram identity (likec4Id, likec4RelationId).
4
+ * Use after syncToLeanix to get a mapping for re-export or for annotating diagrams.
5
+ */
6
+
7
+ import { type BridgeManifest, type CanonicalId, LEANIX_PROVIDER } from './contracts'
8
+
9
+ /** Mapping from LikeC4 canonical id to LeanIX identity (fact sheet id or externalId for Draw.io cells or export). */
10
+ export interface DrawioLeanixMapping {
11
+ likec4IdToLeanixId: Record<CanonicalId, string>
12
+ /** Composite key (sourceFqn|targetFqn|relationId) -> LeanIX relation id. */
13
+ relationKeyToLeanixRelationId: Record<string, string>
14
+ }
15
+
16
+ /**
17
+ * Collects likec4Id → LeanIX identity (factSheetId or externalId) from manifest entities that have LeanIX external.
18
+ * Single responsibility: one level of abstraction for entity extraction.
19
+ */
20
+ function collectLikec4IdToLeanixId(manifest: BridgeManifest): Record<CanonicalId, string> {
21
+ const out: Record<CanonicalId, string> = {}
22
+ for (const [canonicalId, entity] of Object.entries(manifest.entities)) {
23
+ const leanixId = entity.external?.[LEANIX_PROVIDER]?.factSheetId ?? entity.external?.[LEANIX_PROVIDER]?.externalId
24
+ if (leanixId) out[canonicalId] = leanixId
25
+ }
26
+ return out
27
+ }
28
+
29
+ /**
30
+ * Collects compositeKey → LeanIX relationId from manifest relations that have LeanIX external.
31
+ * Single responsibility: one level of abstraction for relation extraction.
32
+ */
33
+ function collectRelationKeyToLeanixRelationId(manifest: BridgeManifest): Record<string, string> {
34
+ const out: Record<string, string> = {}
35
+ for (const rel of manifest.relations) {
36
+ const leanixRelId = rel.external?.[LEANIX_PROVIDER]?.relationId
37
+ if (leanixRelId) out[rel.compositeKey] = leanixRelId
38
+ }
39
+ return out
40
+ }
41
+
42
+ /**
43
+ * Builds a mapping from manifest (after sync) for use in Draw.io bridge-managed export
44
+ * or when re-importing from LeanIX. Elements can store leanixFactSheetId in style for round-trip.
45
+ */
46
+ export function manifestToDrawioLeanixMapping(manifest: BridgeManifest): DrawioLeanixMapping {
47
+ return {
48
+ likec4IdToLeanixId: collectLikec4IdToLeanixId(manifest),
49
+ relationKeyToLeanixRelationId: collectRelationKeyToLeanixRelationId(manifest),
50
+ }
51
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Phase 3: Drift detection from reconciliation result.
3
+ * Produces a structured drift report (in sync, LikeC4 ahead, LeanIX ahead, or diverged).
4
+ */
5
+
6
+ import type { ReconciliationResult } from './reconcile'
7
+
8
+ /** Drift status: in_sync, likec4_ahead, leanix_ahead, or diverged. */
9
+ export type DriftStatus = 'in_sync' | 'likec4_ahead' | 'leanix_ahead' | 'diverged'
10
+
11
+ /** Drift report (status, summary, description). */
12
+ export interface DriftReport {
13
+ generatedAt: string
14
+ manifestProjectId: string
15
+ snapshotGeneratedAt: string
16
+ status: DriftStatus
17
+ summary: ReconciliationResult['summary']
18
+ /** Short human-readable drift description. */
19
+ description: string
20
+ }
21
+
22
+ /**
23
+ * Builds a drift report from a reconciliation result.
24
+ * In_sync: all matched, no unmatched, no ambiguous. Likec4_ahead: only unmatched in LikeC4. Leanix_ahead: only unmatched in LeanIX. Diverged: mixed or ambiguous.
25
+ */
26
+ export function buildDriftReport(reconciliation: ReconciliationResult): DriftReport {
27
+ const { summary } = reconciliation
28
+ const hasUnmatchedLikec4 = summary.unmatchedInLikec4 > 0
29
+ const hasUnmatchedLeanix = summary.unmatchedInLeanix > 0
30
+ const hasAmbiguous = summary.ambiguous > 0
31
+
32
+ let status: DriftStatus
33
+ let description: string
34
+ switch (true) {
35
+ case hasAmbiguous || (hasUnmatchedLikec4 && hasUnmatchedLeanix):
36
+ status = 'diverged'
37
+ description =
38
+ `${summary.ambiguous} ambiguous; ${summary.unmatchedInLikec4} only in LikeC4, ${summary.unmatchedInLeanix} only in LeanIX`
39
+ break
40
+ case hasUnmatchedLikec4 && !hasUnmatchedLeanix:
41
+ status = 'likec4_ahead'
42
+ description = `${summary.unmatchedInLikec4} element(s) in LikeC4 not yet in LeanIX`
43
+ break
44
+ case hasUnmatchedLeanix && !hasUnmatchedLikec4:
45
+ status = 'leanix_ahead'
46
+ description = `${summary.unmatchedInLeanix} fact sheet(s) in LeanIX not in LikeC4`
47
+ break
48
+ default:
49
+ status = 'in_sync'
50
+ description = `${summary.matched} matched; no drift`
51
+ }
52
+
53
+ return {
54
+ generatedAt: reconciliation.generatedAt,
55
+ manifestProjectId: reconciliation.manifestProjectId,
56
+ snapshotGeneratedAt: reconciliation.snapshotGeneratedAt,
57
+ status,
58
+ summary: reconciliation.summary,
59
+ description,
60
+ }
61
+ }
@@ -0,0 +1,52 @@
1
+ import type { BridgeModelInput } from './model-input'
2
+
3
+ /** Minimal in-memory model for tests */
4
+ export function createFixtureModel(overrides: Partial<{
5
+ projectId: string
6
+ elements: Array<
7
+ {
8
+ id: string
9
+ kind: string
10
+ title: string
11
+ tags?: string[]
12
+ technology?: string | null
13
+ metadata?: Record<string, unknown>
14
+ }
15
+ >
16
+ relations: Array<{ id: string; source: string; target: string; kind?: string | null; title?: string | null }>
17
+ views: Array<{ id: string }>
18
+ }> = {}): BridgeModelInput {
19
+ const projectId = overrides.projectId ?? 'test-project'
20
+ const elements = overrides.elements ?? [
21
+ { id: 'cloud', kind: 'system', title: 'Cloud', tags: [], metadata: {} },
22
+ { id: 'cloud.backend', kind: 'container', title: 'Backend', tags: [], metadata: {} },
23
+ { id: 'cloud.backend.api', kind: 'component', title: 'API', tags: ['core'], technology: 'Node', metadata: {} },
24
+ ]
25
+ const relations = overrides.relations ?? [
26
+ { id: 'r1', source: 'cloud', target: 'cloud.backend', kind: 'contains', title: null },
27
+ { id: 'r2', source: 'cloud.backend', target: 'cloud.backend.api', kind: 'contains', title: null },
28
+ ]
29
+ const views = overrides.views ?? [{ id: 'index' }, { id: 'landscape' }]
30
+
31
+ return {
32
+ projectId,
33
+ elements: () =>
34
+ elements.map(e => ({
35
+ id: e.id,
36
+ kind: e.kind,
37
+ title: e.title,
38
+ tags: e.tags ?? [],
39
+ technology: e.technology ?? null,
40
+ getMetadata: () => e.metadata ?? {},
41
+ })),
42
+ relationships: () =>
43
+ relations.map(r => ({
44
+ id: r.id,
45
+ source: { id: r.source },
46
+ target: { id: r.target },
47
+ kind: r.kind ?? null,
48
+ title: r.title ?? null,
49
+ })),
50
+ views: () => views.map(v => ({ id: v.id })),
51
+ }
52
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Phase 3: Governance checks on reconciliation result.
3
+ * Configurable rules (no ambiguous, all LikeC4 matched, no orphans in LeanIX); returns pass/fail per check.
4
+ */
5
+
6
+ import type { ReconciliationResult } from './reconcile'
7
+
8
+ /** Single governance check result (id, name, passed, optional message). */
9
+ export interface GovernanceCheckResult {
10
+ id: string
11
+ name: string
12
+ passed: boolean
13
+ message?: string
14
+ }
15
+
16
+ export interface GovernanceReport {
17
+ passed: boolean
18
+ generatedAt: string
19
+ checks: GovernanceCheckResult[]
20
+ }
21
+
22
+ /** Options for runGovernanceChecks (noAmbiguous, allLikec4Matched, noOrphanInLeanix). */
23
+ export interface GovernanceCheckOptions {
24
+ /** Fail if any ambiguous matches. Default: true. */
25
+ noAmbiguous?: boolean
26
+ /** Fail if any LikeC4 entity has no match in LeanIX. Default: false. */
27
+ allLikec4Matched?: boolean
28
+ /** Fail if any LeanIX fact sheet has no match in LikeC4. Default: false. */
29
+ noOrphanInLeanix?: boolean
30
+ }
31
+
32
+ const DEFAULT_OPTIONS: Required<GovernanceCheckOptions> = {
33
+ noAmbiguous: true,
34
+ allLikec4Matched: false,
35
+ noOrphanInLeanix: false,
36
+ }
37
+
38
+ /** Builds a single check result (G5: reduce duplication). */
39
+ function buildCheck(
40
+ id: string,
41
+ name: string,
42
+ passed: boolean,
43
+ failedMessage?: string,
44
+ ): GovernanceCheckResult {
45
+ const result: GovernanceCheckResult = { id, name, passed }
46
+ if (!passed && failedMessage !== undefined) {
47
+ result.message = failedMessage
48
+ }
49
+ return result
50
+ }
51
+
52
+ /**
53
+ * Runs governance checks on a reconciliation result.
54
+ * Returns a report with one entry per check; overall passed iff all checks pass.
55
+ */
56
+ export function runGovernanceChecks(
57
+ reconciliation: ReconciliationResult,
58
+ options: GovernanceCheckOptions = {},
59
+ ): GovernanceReport {
60
+ const opts = { ...DEFAULT_OPTIONS, ...options }
61
+ const checks: GovernanceCheckResult[] = []
62
+ const { summary } = reconciliation
63
+
64
+ if (opts.noAmbiguous) {
65
+ checks.push(
66
+ buildCheck(
67
+ 'noAmbiguous',
68
+ 'No ambiguous matches',
69
+ summary.ambiguous === 0,
70
+ `${summary.ambiguous} ambiguous match(es)`,
71
+ ),
72
+ )
73
+ }
74
+
75
+ if (opts.allLikec4Matched) {
76
+ checks.push(
77
+ buildCheck(
78
+ 'allLikec4Matched',
79
+ 'All LikeC4 elements matched in LeanIX',
80
+ summary.unmatchedInLikec4 === 0,
81
+ `${summary.unmatchedInLikec4} unmatched in LikeC4`,
82
+ ),
83
+ )
84
+ }
85
+
86
+ if (opts.noOrphanInLeanix) {
87
+ checks.push(
88
+ buildCheck(
89
+ 'noOrphanInLeanix',
90
+ 'No LeanIX fact sheets without LikeC4 match',
91
+ summary.unmatchedInLeanix === 0,
92
+ `${summary.unmatchedInLeanix} unmatched in LeanIX`,
93
+ ),
94
+ )
95
+ }
96
+
97
+ const passed = checks.every(c => c.passed)
98
+ return {
99
+ passed,
100
+ generatedAt: new Date().toISOString(),
101
+ checks,
102
+ }
103
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Phase 3: Impact analysis from a sync plan.
3
+ * Produces a structured report of what would change if the plan were applied (no writes).
4
+ */
5
+
6
+ import type { SyncPlan, SyncPlanSummary } from './sync-to-leanix'
7
+
8
+ /** Impact report from a sync plan (summary counts and human-readable impact summary). */
9
+ export interface ImpactReport {
10
+ generatedAt: string
11
+ projectId: string
12
+ mappingProfile: string
13
+ summary: SyncPlanSummary
14
+ /** Human-readable one-line impact summary. */
15
+ impactSummary: string
16
+ hasErrors: boolean
17
+ }
18
+
19
+ /**
20
+ * Builds an impact report from a sync plan (read-only).
21
+ * Use before applying sync to understand what would be created/updated.
22
+ */
23
+ export function impactReportFromSyncPlan(plan: SyncPlan): ImpactReport {
24
+ const { summary, errors } = plan
25
+ const parts: string[] = []
26
+ if (summary.factSheetsToCreate > 0) parts.push(`${summary.factSheetsToCreate} fact sheet(s) to create`)
27
+ if (summary.factSheetsToUpdate > 0) parts.push(`${summary.factSheetsToUpdate} fact sheet(s) to update`)
28
+ if (summary.relationsToCreate > 0) parts.push(`${summary.relationsToCreate} relation(s) to create`)
29
+ const impactSummary = parts.length > 0 ? parts.join('; ') : 'No changes'
30
+ return {
31
+ generatedAt: plan.generatedAt,
32
+ projectId: plan.projectId,
33
+ mappingProfile: plan.mappingProfile,
34
+ summary,
35
+ impactSummary: errors.length > 0 ? `${impactSummary} (${errors.length} plan error(s))` : impactSummary,
36
+ hasErrors: errors.length > 0,
37
+ }
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @likec4/leanix-bridge
3
+ *
4
+ * Bridge from LikeC4 semantic model to LeanIX-shaped inventory artifacts.
5
+ * Supports dry-run artifacts, optional LeanIX API sync (LeanixApiClient, syncToLeanix),
6
+ * and Draw.io round-trip helpers (manifestToDrawioLeanixMapping). LikeC4 remains canonical.
7
+ */
8
+
9
+ export {
10
+ BRIDGE_MANIFEST_VERSION,
11
+ BRIDGE_VERSION,
12
+ LEANIX_PROVIDER,
13
+ } from './contracts'
14
+ export type {
15
+ BridgeManifest,
16
+ BridgeVersion,
17
+ CanonicalId,
18
+ ExternalId,
19
+ GeneratedAt,
20
+ ManifestEntity,
21
+ ManifestRelation,
22
+ ManifestVersion,
23
+ ManifestView,
24
+ MappingProfile,
25
+ Provider,
26
+ ProviderExternalIds,
27
+ RelationId as BridgeRelationId,
28
+ ViewId as BridgeViewId,
29
+ } from './contracts'
30
+
31
+ export {
32
+ DEFAULT_LEANIX_MAPPING,
33
+ FALLBACK_FACT_SHEET_TYPE,
34
+ FALLBACK_RELATION_TYPE,
35
+ getFactSheetType,
36
+ getRelationType,
37
+ mergeWithDefault,
38
+ } from './mapping'
39
+ export type { LeanixMappingConfig } from './mapping'
40
+
41
+ export type { BridgeElementLike, BridgeModelInput, BridgeRelationLike, BridgeViewLike } from './model-input'
42
+
43
+ export { toBridgeManifest } from './to-bridge-manifest'
44
+ export type { ToBridgeManifestOptions } from './to-bridge-manifest'
45
+
46
+ export { toLeanixInventoryDryRun } from './to-leanix-inventory-dry-run'
47
+ export type {
48
+ LeanixFactSheetDryRun,
49
+ LeanixInventoryDryRun,
50
+ LeanixRelationDryRun,
51
+ ToLeanixInventoryDryRunOptions,
52
+ } from './to-leanix-inventory-dry-run'
53
+
54
+ export { buildBridgeReport } from './report'
55
+ export type { BridgeReport } from './report'
56
+
57
+ export { LeanixApiClient } from './leanix-api-client'
58
+ export type { GraphQLResponse, LeanixApiClientConfig } from './leanix-api-client'
59
+ export { LeanixApiError } from './leanix-api-client'
60
+
61
+ export { planSyncToLeanix, syncToLeanix } from './sync-to-leanix'
62
+ export type {
63
+ PlanSyncToLeanixOptions,
64
+ SyncPlan,
65
+ SyncPlanFactSheetEntry,
66
+ SyncPlanRelationEntry,
67
+ SyncPlanSummary,
68
+ SyncToLeanixOptions,
69
+ SyncToLeanixResult,
70
+ } from './sync-to-leanix'
71
+
72
+ export { manifestToDrawioLeanixMapping } from './drawio-leanix-roundtrip'
73
+ export type { DrawioLeanixMapping } from './drawio-leanix-roundtrip'
74
+
75
+ export { fetchLeanixInventorySnapshot } from './leanix-inventory-snapshot'
76
+ export type {
77
+ FetchLeanixInventorySnapshotOptions,
78
+ LeanixFactSheetSnapshotItem,
79
+ LeanixInventorySnapshot,
80
+ LeanixRelationSnapshotItem,
81
+ } from './leanix-inventory-snapshot'
82
+
83
+ export { reconcileInventoryWithManifest } from './reconcile'
84
+ export type {
85
+ AmbiguousMatch,
86
+ MatchedPair,
87
+ ReconcileOptions,
88
+ ReconciliationResult,
89
+ UnmatchedInLeanix,
90
+ UnmatchedInLikec4,
91
+ } from './reconcile'
92
+
93
+ export { impactReportFromSyncPlan } from './impact-report'
94
+ export type { ImpactReport } from './impact-report'
95
+
96
+ export { buildDriftReport } from './drift-report'
97
+ export type { DriftReport, DriftStatus } from './drift-report'
98
+
99
+ export { generateAdrFromDriftReport, generateAdrFromReconciliation } from './adr-generation'
100
+ export type { AdrGenerationOptions, DriftAdrGenerationOptions } from './adr-generation'
101
+
102
+ export { runGovernanceChecks } from './governance-checks'
103
+ export type {
104
+ GovernanceCheckOptions,
105
+ GovernanceCheckResult,
106
+ GovernanceReport,
107
+ } from './governance-checks'
108
+
109
+ export { isBridgeManifest, isLeanixInventorySnapshot } from './validate'