rust-kgdb 0.6.80 → 0.6.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ================================================================================
4
+ * RpcFederationProxy: Federated SQL Demo
5
+ * Cross-Database Queries via WASM RPC Proxy
6
+ * ================================================================================
7
+ *
8
+ * This demo showcases RpcFederationProxy from the rust-kgdb SDK:
9
+ * - Query across KGDB + Snowflake + BigQuery in single SQL statement
10
+ * - 7 Semantic UDFs (similar_to, neighbors, entity_type, etc.)
11
+ * - 9 Table Functions (graph_search, pagerank, vector_search, etc.)
12
+ * - Capability-based security with WasmSandbox
13
+ * - Full provenance tracking with audit log
14
+ *
15
+ * Architecture:
16
+ * - TypeScript SDK: Thin RPC proxy layer
17
+ * - Rust Core: Heavy lifting (DataFusion, Arrow, Vortex, HDRF partitioning)
18
+ *
19
+ * Run: node examples/rpc-federation-sql-demo.js
20
+ *
21
+ * @requires HyperFederate server running at http://localhost:30180
22
+ */
23
+
24
+ const {
25
+ RpcFederationProxy,
26
+ FEDERATION_TOOLS,
27
+ GraphDB,
28
+ WasmSandbox,
29
+ ProofDAG
30
+ } = require('../index.js')
31
+
32
+ // ================================================================================
33
+ // DEMO: Federated SQL Queries
34
+ // ================================================================================
35
+
36
+ async function runDemo() {
37
+ console.log('╔══════════════════════════════════════════════════════════════════════╗')
38
+ console.log('║ RpcFederationProxy: Federated SQL Demo ║')
39
+ console.log('║ Cross-Database Queries via WASM RPC Proxy ║')
40
+ console.log('╚══════════════════════════════════════════════════════════════════════╝\n')
41
+
42
+ // Create RpcFederationProxy with custom config
43
+ const federation = new RpcFederationProxy({
44
+ endpoint: process.env.HYPERFEDERATE_URL || 'http://localhost:30180',
45
+ timeout: 30000,
46
+ identityId: 'demo-user-001',
47
+ // WasmSandbox provides capability-based security
48
+ sandbox: new WasmSandbox({
49
+ capabilities: ['ReadKG', 'ExecuteTool', 'Federation'],
50
+ fuelLimit: 100000
51
+ })
52
+ })
53
+
54
+ console.log(`Federation Endpoint: ${federation.endpoint}`)
55
+ console.log(`Session ID: ${federation.sessionId}`)
56
+ console.log(`Identity ID: ${federation.identityId}`)
57
+ console.log(`Initial Fuel: ${federation.getFuelRemaining()}`)
58
+ console.log()
59
+
60
+ // ============================================================================
61
+ // 1. List available federation tools
62
+ // ============================================================================
63
+ console.log('1. Available Federation Tools (Category Theory: Typed Morphisms)')
64
+ console.log('═'.repeat(70))
65
+ for (const [name, tool] of Object.entries(FEDERATION_TOOLS)) {
66
+ console.log(` ${name}`)
67
+ console.log(` Input: ${tool.input}`)
68
+ console.log(` Output: ${tool.output}`)
69
+ console.log(` Domain: ${tool.domain}`)
70
+ console.log()
71
+ }
72
+
73
+ // ============================================================================
74
+ // 2. Simple SQL query
75
+ // ============================================================================
76
+ console.log('2. Simple SQL Query')
77
+ console.log('═'.repeat(70))
78
+ try {
79
+ const simpleResult = await federation.query('SELECT 1 + 2 as result, NOW() as timestamp')
80
+ console.log(` Columns: ${simpleResult.columns.join(', ')}`)
81
+ console.log(` Rows: ${JSON.stringify(simpleResult.rows, null, 2)}`)
82
+ console.log(` Duration: ${simpleResult.duration}ms`)
83
+ console.log()
84
+ } catch (error) {
85
+ console.log(` [Skipped - Server not running: ${error.message}]`)
86
+ console.log()
87
+ }
88
+
89
+ // ============================================================================
90
+ // 3. KGDB + Snowflake Federation Query
91
+ // ============================================================================
92
+ console.log('3. KGDB + Snowflake Federation Query')
93
+ console.log('═'.repeat(70))
94
+ const kgSfQuery = `
95
+ -- Federation: KGDB (Knowledge Graph) + Snowflake (TPC-H)
96
+ WITH kg_entities AS (
97
+ SELECT * FROM graph_search('
98
+ PREFIX finance: <https://gonnect.ai/domains/finance#>
99
+ PREFIX tpch: <https://gonnect.ai/tpch#>
100
+ SELECT ?person ?custKey WHERE {
101
+ ?person a finance:Person ;
102
+ tpch:custKey ?custKey .
103
+ } LIMIT 10
104
+ ')
105
+ )
106
+ SELECT
107
+ kg.person AS kg_entity,
108
+ kg.custKey,
109
+ sf.C_NAME,
110
+ sf.C_ACCTBAL
111
+ FROM kg_entities kg
112
+ JOIN snowflake_tpch.CUSTOMER sf
113
+ ON CAST(kg.custKey AS INTEGER) = sf.C_CUSTKEY
114
+ LIMIT 10
115
+ `
116
+ console.log(` Query:\n${kgSfQuery.trim().split('\n').map(l => ' ' + l).join('\n')}`)
117
+ console.log()
118
+ try {
119
+ const result = await federation.query(kgSfQuery)
120
+ console.log(` Result: ${result.rowCount} rows in ${result.duration}ms`)
121
+ console.log(` Sources: ${result.metadata.sources?.join(', ')}`)
122
+ console.log()
123
+ } catch (error) {
124
+ console.log(` [Demo mode - Server not running]`)
125
+ console.log()
126
+ }
127
+
128
+ // ============================================================================
129
+ // 4. Three-Way Federation: KGDB + Snowflake + BigQuery
130
+ // ============================================================================
131
+ console.log('4. Three-Way Federation: KGDB + Snowflake + BigQuery')
132
+ console.log('═'.repeat(70))
133
+ const threeWayQuery = `
134
+ -- Three-way federation: KGDB + Snowflake + BigQuery
135
+ WITH
136
+ kg_risk AS (
137
+ SELECT * FROM graph_search('
138
+ PREFIX finance: <https://gonnect.ai/domains/finance#>
139
+ PREFIX tpch: <https://gonnect.ai/tpch#>
140
+ SELECT ?person ?custKey ?riskScore WHERE {
141
+ ?risk finance:assessedFor ?person ;
142
+ finance:riskScore ?riskScore .
143
+ ?person tpch:custKey ?custKey .
144
+ FILTER(?riskScore > 0.7)
145
+ } LIMIT 5
146
+ ')
147
+ ),
148
+ sf_cust AS (
149
+ SELECT C_CUSTKEY, C_NAME, C_ACCTBAL
150
+ FROM snowflake_tpch.CUSTOMER
151
+ LIMIT 100
152
+ )
153
+ SELECT
154
+ kg.person AS kg_entity,
155
+ kg.riskScore,
156
+ sf.C_NAME,
157
+ sf.C_ACCTBAL,
158
+ bq.name AS popular_name,
159
+ bq.number AS birth_count
160
+ FROM kg_risk kg
161
+ JOIN sf_cust sf ON CAST(kg.custKey AS INTEGER) = sf.C_CUSTKEY
162
+ LEFT JOIN bigquery_public.usa_1910_current bq
163
+ ON LOWER(SPLIT_PART(sf.C_NAME, ' ', 1)) = LOWER(bq.name)
164
+ WHERE bq.year = 2000
165
+ LIMIT 10
166
+ `
167
+ console.log(` Query: Three-way federation across KGDB + Snowflake + BigQuery`)
168
+ console.log()
169
+
170
+ // ============================================================================
171
+ // 5. Semantic UDF Examples (7 AI-Powered Functions)
172
+ // ============================================================================
173
+ console.log('5. Semantic UDFs (7 AI-Powered Functions)')
174
+ console.log('═'.repeat(70))
175
+ const udfs = [
176
+ { name: 'similar_to', example: "similar_to('<http://ex.org/Entity1>', 0.7)" },
177
+ { name: 'text_search', example: "text_search('high risk fraud', 5)" },
178
+ { name: 'neighbors', example: "neighbors('<http://ex.org/Entity1>', 2)" },
179
+ { name: 'graph_pattern', example: "graph_pattern('<http://ex.org/Entity1>', NULL, NULL)" },
180
+ { name: 'sparql_query', example: "sparql_query('SELECT ?s WHERE { ?s a <http://ex.org/Person> }')" },
181
+ { name: 'entity_type', example: "entity_type('<http://ex.org/Entity1>')" },
182
+ { name: 'entity_properties', example: "entity_properties('<http://ex.org/Entity1>')" }
183
+ ]
184
+ for (const udf of udfs) {
185
+ console.log(` ${udf.name}`)
186
+ console.log(` Example: SELECT ${udf.example}`)
187
+ console.log()
188
+ }
189
+
190
+ // ============================================================================
191
+ // 6. Table Functions (9 Graph Analytics)
192
+ // ============================================================================
193
+ console.log('6. Table Functions (9 Graph Analytics)')
194
+ console.log('═'.repeat(70))
195
+ const tableFunctions = [
196
+ { name: 'graph_search', desc: 'SPARQL → SQL bridge' },
197
+ { name: 'vector_search', desc: 'Semantic similarity search' },
198
+ { name: 'pagerank', desc: 'PageRank centrality' },
199
+ { name: 'connected_components', desc: 'Community detection' },
200
+ { name: 'shortest_paths', desc: 'Path finding' },
201
+ { name: 'triangle_count', desc: 'Graph density measure' },
202
+ { name: 'label_propagation', desc: 'Community detection' },
203
+ { name: 'datalog_reason', desc: 'Datalog inference' },
204
+ { name: 'motif_search', desc: 'Graph pattern matching' }
205
+ ]
206
+ for (const fn of tableFunctions) {
207
+ console.log(` ${fn.name.padEnd(25)} - ${fn.desc}`)
208
+ }
209
+ console.log()
210
+
211
+ // ============================================================================
212
+ // 7. Audit Log (Provenance Tracking)
213
+ // ============================================================================
214
+ console.log('7. Audit Log (Provenance Tracking - Proof Theory)')
215
+ console.log('═'.repeat(70))
216
+ const auditLog = federation.getAuditLog()
217
+ console.log(` Total entries: ${auditLog.length}`)
218
+ for (const entry of auditLog.slice(0, 3)) {
219
+ console.log(` - Action: ${entry.action}`)
220
+ console.log(` Duration: ${entry.duration}ms`)
221
+ console.log(` Rows: ${entry.rows}`)
222
+ console.log(` Timestamp: ${entry.timestamp}`)
223
+ console.log()
224
+ }
225
+
226
+ // ============================================================================
227
+ // 8. ProofDAG with Federation Evidence
228
+ // ============================================================================
229
+ console.log('8. ProofDAG with Federation Evidence')
230
+ console.log('═'.repeat(70))
231
+ const proof = new ProofDAG('High-risk customers identified across 3 data sources')
232
+
233
+ // Add federation evidence to the proof
234
+ const fedNode = proof.addFederationEvidence(
235
+ proof.rootId,
236
+ threeWayQuery,
237
+ ['kgdb', 'snowflake', 'bigquery'],
238
+ 42, // rowCount
239
+ 890, // duration
240
+ { planHash: 'abc123', cached: false }
241
+ )
242
+ console.log(` Root claim: ${proof.rootClaim}`)
243
+ console.log(` Proof hash: ${proof.computeHash()}`)
244
+ console.log(` Verification: ${JSON.stringify(proof.verify())}`)
245
+ console.log()
246
+
247
+ // ============================================================================
248
+ // Summary
249
+ // ============================================================================
250
+ console.log('╔══════════════════════════════════════════════════════════════════════╗')
251
+ console.log('║ Demo Complete! ║')
252
+ console.log('╚══════════════════════════════════════════════════════════════════════╝')
253
+ console.log(`
254
+ Key Capabilities Demonstrated:
255
+ - RpcFederationProxy: Thin SDK proxy to Rust HyperFederate server
256
+ - Cross-Database SQL: KGDB + Snowflake + BigQuery in single query
257
+ - 7 Semantic UDFs: AI-powered functions in SQL context
258
+ - 9 Table Functions: Graph analytics via SQL
259
+ - WasmSandbox: Capability-based security with fuel metering
260
+ - ProofDAG: Full provenance tracking (W3C PROV compatible)
261
+
262
+ Architecture Principle:
263
+ - Heavy lifting in Rust core (DataFusion, Arrow, Vortex, HDRF)
264
+ - TypeScript SDK is thin RPC proxy layer
265
+ - Category Theory: Tools as typed morphisms (Input → Output)
266
+ - Proof Theory: Every answer has verifiable reasoning chain
267
+
268
+ Fuel Remaining: ${federation.getFuelRemaining()}
269
+ `)
270
+ }
271
+
272
+ // Run the demo
273
+ runDemo().catch(console.error)
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ================================================================================
4
+ * RpcFederationProxy: Virtual Tables Demo
5
+ * Session-Bound Query Result Materialization
6
+ * ================================================================================
7
+ *
8
+ * Virtual Tables in HyperFederate:
9
+ * - Session-bound materialization of federation query results
10
+ * - Stored as RDF triples in KGDB (self-describing)
11
+ * - Access control via shared_with and shared_with_groups
12
+ * - Refresh policies: on_demand, ttl, on_source_change
13
+ * - No ETL required - real-time query materialization
14
+ *
15
+ * Architecture:
16
+ * - Heavy lifting in Rust core (DataFusion, Arrow, KGDB storage)
17
+ * - TypeScript SDK provides thin RPC proxy layer
18
+ *
19
+ * Run: node examples/rpc-virtual-tables-demo.js
20
+ *
21
+ * @requires HyperFederate server running at http://localhost:30180
22
+ */
23
+
24
+ const {
25
+ RpcFederationProxy,
26
+ WasmSandbox,
27
+ ProofDAG
28
+ } = require('../index.js')
29
+
30
+ // ================================================================================
31
+ // DEMO: Virtual Tables
32
+ // ================================================================================
33
+
34
+ async function runDemo() {
35
+ console.log('╔══════════════════════════════════════════════════════════════════════╗')
36
+ console.log('║ RpcFederationProxy: Virtual Tables Demo ║')
37
+ console.log('║ Session-Bound Query Result Materialization ║')
38
+ console.log('╚══════════════════════════════════════════════════════════════════════╝\n')
39
+
40
+ // Create RpcFederationProxy
41
+ const federation = new RpcFederationProxy({
42
+ endpoint: process.env.HYPERFEDERATE_URL || 'http://localhost:30180',
43
+ identityId: 'risk-analyst-001'
44
+ })
45
+
46
+ console.log(`Federation Endpoint: ${federation.endpoint}`)
47
+ console.log(`Session ID: ${federation.sessionId}`)
48
+ console.log(`Identity ID: ${federation.identityId}`)
49
+ console.log()
50
+
51
+ // ============================================================================
52
+ // 1. Create Virtual Table from Federation Query
53
+ // ============================================================================
54
+ console.log('1. Create Virtual Table from Federation Query')
55
+ console.log('═'.repeat(70))
56
+
57
+ const createVtQuery = `
58
+ -- High-risk customers: KGDB risk scores + Snowflake account data
59
+ SELECT
60
+ kg.person AS kg_entity,
61
+ kg.riskScore AS risk_level,
62
+ entity_type(kg.person) AS entity_types,
63
+ sf.C_NAME AS customer_name,
64
+ sf.C_ACCTBAL AS account_balance,
65
+ sf.C_MKTSEGMENT AS market_segment
66
+ FROM graph_search('
67
+ PREFIX finance: <https://gonnect.ai/domains/finance#>
68
+ PREFIX tpch: <https://gonnect.ai/tpch#>
69
+ SELECT ?person ?riskScore ?custKey WHERE {
70
+ ?risk finance:assessedFor ?person ;
71
+ finance:riskScore ?riskScore .
72
+ ?person tpch:custKey ?custKey .
73
+ FILTER(?riskScore > 0.7)
74
+ }
75
+ ') kg
76
+ JOIN snowflake_tpch.CUSTOMER sf
77
+ ON CAST(kg.custKey AS INTEGER) = sf.C_CUSTKEY
78
+ WHERE sf.C_ACCTBAL > 50000
79
+ `
80
+
81
+ console.log(' SQL Query:')
82
+ console.log(createVtQuery.trim().split('\n').map(l => ' ' + l).join('\n'))
83
+ console.log()
84
+
85
+ try {
86
+ const vt = await federation.createVirtualTable('high_risk_customers', createVtQuery, {
87
+ refreshPolicy: 'on_demand',
88
+ ttlSeconds: 3600,
89
+ sharedWith: ['risk-analyst-002', 'compliance-officer-001'],
90
+ sharedWithGroups: ['team-risk-analytics', 'team-compliance']
91
+ })
92
+
93
+ console.log(' Virtual Table Created:')
94
+ console.log(` ID: ${vt.id}`)
95
+ console.log(` Name: ${vt.name}`)
96
+ console.log(` URI: ${vt.uri}`)
97
+ console.log(` Columns: ${vt.columns.join(', ')}`)
98
+ console.log(` Row Count: ${vt.rowCount}`)
99
+ console.log(` Refresh Policy: ${vt.refreshPolicy}`)
100
+ console.log(` Created At: ${vt.createdAt}`)
101
+ console.log()
102
+ } catch (error) {
103
+ console.log(` [Demo mode - Server not running]`)
104
+ console.log(` Virtual table would be created with:`)
105
+ console.log(` Name: high_risk_customers`)
106
+ console.log(` Refresh Policy: on_demand`)
107
+ console.log(` TTL: 3600 seconds`)
108
+ console.log(` Shared With: risk-analyst-002, compliance-officer-001`)
109
+ console.log(` Shared Groups: team-risk-analytics, team-compliance`)
110
+ console.log()
111
+ }
112
+
113
+ // ============================================================================
114
+ // 2. Query Virtual Table (No Re-execution)
115
+ // ============================================================================
116
+ console.log('2. Query Virtual Table (Materialized Results)')
117
+ console.log('═'.repeat(70))
118
+ console.log(' Virtual tables are materialized - no query re-execution needed.')
119
+ console.log()
120
+ console.log(' Query: SELECT * FROM virtual.high_risk_customers WHERE account_balance > 100000')
121
+ console.log()
122
+
123
+ try {
124
+ const result = await federation.queryVirtualTable('high_risk_customers', 'account_balance > 100000')
125
+ console.log(` Result: ${result.rowCount} rows in ${result.duration}ms`)
126
+ console.log(` (Materialized data, not re-executed)`)
127
+ console.log()
128
+ } catch (error) {
129
+ console.log(` [Demo mode - Would query materialized virtual table]`)
130
+ console.log()
131
+ }
132
+
133
+ // ============================================================================
134
+ // 3. Virtual Table Use Cases
135
+ // ============================================================================
136
+ console.log('3. Virtual Table Use Cases')
137
+ console.log('═'.repeat(70))
138
+ const useCases = [
139
+ {
140
+ name: 'Risk Dashboard',
141
+ query: `CREATE VIRTUAL TABLE risk_dashboard AS
142
+ SELECT entity, risk_score, neighbors(entity, 1) AS network
143
+ FROM high_risk_customers`,
144
+ refresh: 'ttl (5 min)',
145
+ shared: 'team-risk-analytics'
146
+ },
147
+ {
148
+ name: 'Compliance Audit',
149
+ query: `CREATE VIRTUAL TABLE compliance_audit AS
150
+ SELECT entity, risk_score, entity_properties(entity) AS all_props
151
+ FROM high_risk_customers WHERE risk_score > 0.9`,
152
+ refresh: 'on_source_change',
153
+ shared: 'compliance-officers'
154
+ },
155
+ {
156
+ name: 'Customer 360',
157
+ query: `CREATE VIRTUAL TABLE customer_360 AS
158
+ SELECT kg.*, sf.*, bq.name_popularity
159
+ FROM graph_search(...) kg
160
+ JOIN snowflake.CUSTOMER sf ON ...
161
+ LEFT JOIN bigquery.usa_names bq ON ...`,
162
+ refresh: 'on_demand',
163
+ shared: 'team-customer-success'
164
+ }
165
+ ]
166
+
167
+ for (const useCase of useCases) {
168
+ console.log(` ${useCase.name}`)
169
+ console.log(` Refresh: ${useCase.refresh}`)
170
+ console.log(` Shared With: ${useCase.shared}`)
171
+ console.log()
172
+ }
173
+
174
+ // ============================================================================
175
+ // 4. Access Control Model
176
+ // ============================================================================
177
+ console.log('4. Access Control Model')
178
+ console.log('═'.repeat(70))
179
+ console.log(`
180
+ Virtual tables support fine-grained access control:
181
+
182
+ ┌─────────────────────────────────────────────────────────────────────┐
183
+ │ Virtual Table: high_risk_customers │
184
+ │ Owner: risk-analyst-001 (creator) │
185
+ ├─────────────────────────────────────────────────────────────────────┤
186
+ │ shared_with (individuals): │
187
+ │ - risk-analyst-002 [Full access] │
188
+ │ - compliance-officer-001 [Full access] │
189
+ │ │
190
+ │ shared_with_groups (teams): │
191
+ │ - team-risk-analytics [All members have access] │
192
+ │ - team-compliance [All members have access] │
193
+ └─────────────────────────────────────────────────────────────────────┘
194
+
195
+ Access check: has_access(identity_id, groups) → boolean
196
+ `)
197
+
198
+ // ============================================================================
199
+ // 5. RDF Storage (Self-Describing)
200
+ // ============================================================================
201
+ console.log('5. Virtual Table RDF Storage (Self-Describing)')
202
+ console.log('═'.repeat(70))
203
+ console.log(`
204
+ Virtual tables are stored as RDF triples in KGDB:
205
+
206
+ <urn:hyperfederate:vt:${federation.sessionId}:high_risk_customers>
207
+ a hf:VirtualTable ;
208
+ hf:name "high_risk_customers" ;
209
+ hf:sessionId "${federation.sessionId}" ;
210
+ hf:ownerId "${federation.identityId}" ;
211
+ hf:query "SELECT kg.person, kg.riskScore..." ;
212
+ hf:refreshPolicy "on_demand" ;
213
+ hf:rowCount "42"^^xsd:integer ;
214
+ hf:createdAt "2024-12-21T12:00:00Z"^^xsd:dateTime ;
215
+ hf:sourceLineage "kgdb", "snowflake" ;
216
+ hf:sharedWith "risk-analyst-002", "compliance-officer-001" ;
217
+ hf:sharedWithGroups "team-risk-analytics", "team-compliance" .
218
+
219
+ This makes virtual tables queryable via SPARQL!
220
+ `)
221
+
222
+ // ============================================================================
223
+ // 6. ProofDAG Integration
224
+ // ============================================================================
225
+ console.log('6. ProofDAG Integration (Provenance Tracking)')
226
+ console.log('═'.repeat(70))
227
+
228
+ const proof = new ProofDAG('Risk analysis for high-value customers')
229
+
230
+ // Add virtual table creation as evidence
231
+ const vtNode = proof.addVirtualTableEvidence(
232
+ proof.rootId,
233
+ 'high_risk_customers',
234
+ createVtQuery,
235
+ 42 // rowCount
236
+ )
237
+
238
+ console.log(` Root claim: ${proof.rootClaim}`)
239
+ console.log(` Evidence type: virtual_table`)
240
+ console.log(` Proof hash: ${proof.computeHash()}`)
241
+ console.log()
242
+
243
+ // ============================================================================
244
+ // Summary
245
+ // ============================================================================
246
+ console.log('╔══════════════════════════════════════════════════════════════════════╗')
247
+ console.log('║ Demo Complete! ║')
248
+ console.log('╚══════════════════════════════════════════════════════════════════════╝')
249
+ console.log(`
250
+ Virtual Table Benefits:
251
+ - No ETL Pipeline: Real-time query materialization
252
+ - Session Isolation: Each user sees only their tables
253
+ - Access Control: Fine-grained sharing via identities/groups
254
+ - Self-Describing: Stored as RDF, queryable via SPARQL
255
+ - Refresh Policies: on_demand, ttl, on_source_change
256
+ - Provenance: Full lineage tracking via ProofDAG
257
+
258
+ Architecture Principle:
259
+ - Materialization logic in Rust core (DataFusion + KGDB)
260
+ - TypeScript SDK provides thin RPC proxy layer
261
+ - Heavy computation happens server-side
262
+
263
+ Audit Log Entries: ${federation.getAuditLog().length}
264
+ `)
265
+ }
266
+
267
+ // Run the demo
268
+ runDemo().catch(console.error)