@fjell/registry 4.4.6 → 4.4.9
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/README.md +81 -4
- package/dist/Registry.cjs +20 -1
- package/dist/Registry.js +20 -1
- package/dist/RegistryHub.cjs +17 -1
- package/dist/RegistryHub.js +17 -1
- package/dist/index.cjs +35 -0
- package/dist/index.cjs.map +1 -1
- package/dist/types.d.ts +15 -0
- package/docs/README.md +74 -0
- package/docs/index.html +17 -0
- package/docs/memory-data/scaling-10-instances.json +206 -206
- package/docs/memory-data/scaling-100-instances.json +206 -206
- package/docs/memory-data/scaling-1000-instances.json +108 -108
- package/docs/memory-data/scaling-10000-instances.json +49 -49
- package/docs/memory-data/scaling-20-instances.json +208 -208
- package/docs/memory-data/scaling-200-instances.json +201 -201
- package/docs/memory-data/scaling-2000-instances.json +107 -107
- package/docs/memory-data/scaling-50-instances.json +206 -206
- package/docs/memory-data/scaling-500-instances.json +108 -108
- package/docs/memory-data/scaling-5000-instances.json +49 -49
- package/docs/memory-overhead.svg +17 -17
- package/docs/memory.md +111 -111
- package/docs/package.json +35 -0
- package/docs/public/README.md +623 -0
- package/docs/public/TIMING_NODE_OPTIMIZATION.md +207 -0
- package/docs/public/examples/coordinates-example.ts +253 -0
- package/docs/public/examples/multi-level-keys.ts +374 -0
- package/docs/public/examples/registry-hub-coordinates-example.ts +370 -0
- package/docs/public/examples/registry-hub-types.ts +437 -0
- package/docs/public/examples/simple-example.ts +250 -0
- package/docs/public/examples-README.md +222 -0
- package/docs/public/fjell-icon.svg +1 -0
- package/docs/public/icon.png +0 -0
- package/docs/public/icon2.png +0 -0
- package/docs/public/memory-overhead.svg +120 -0
- package/docs/public/memory.md +430 -0
- package/docs/public/pano.png +0 -0
- package/docs/public/pano2.png +0 -0
- package/docs/public/timing-range.svg +176 -0
- package/docs/public/timing.md +483 -0
- package/docs/src/App.css +1175 -0
- package/docs/src/App.test.tsx +50 -0
- package/docs/src/App.tsx +583 -0
- package/docs/src/index.css +40 -0
- package/docs/src/main.tsx +10 -0
- package/docs/src/test/setup.ts +1 -0
- package/docs/timing-range.svg +41 -41
- package/docs/timing.md +101 -101
- package/docs/tsconfig.node.json +13 -0
- package/docs/vitest.config.ts +14 -0
- package/examples/README.md +35 -0
- package/examples/coordinates-example.ts +253 -0
- package/examples/registry-hub-coordinates-example.ts +370 -0
- package/package.json +2 -2
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react'
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import App from './App'
|
|
4
|
+
|
|
5
|
+
// Mock fetch
|
|
6
|
+
const mockFetch = vi.fn()
|
|
7
|
+
global.fetch = mockFetch
|
|
8
|
+
|
|
9
|
+
describe('App', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
mockFetch.mockClear()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('renders the main title', () => {
|
|
15
|
+
mockFetch.mockResolvedValueOnce({
|
|
16
|
+
text: () => Promise.resolve('# Test README\n\nThis is a test.')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
render(<App />)
|
|
20
|
+
|
|
21
|
+
expect(screen.getByText('🏔️ Fjell Registry')).toBeInTheDocument()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('renders the subtitle', () => {
|
|
25
|
+
mockFetch.mockResolvedValueOnce({
|
|
26
|
+
text: () => Promise.resolve('# Test README\n\nThis is a test.')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
render(<App />)
|
|
30
|
+
|
|
31
|
+
expect(screen.getByText('Common Registry for Fjell - A powerful TypeScript registry system')).toBeInTheDocument()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('shows loading state initially', () => {
|
|
35
|
+
mockFetch.mockImplementationOnce(() => new Promise(() => { })) // Never resolves
|
|
36
|
+
|
|
37
|
+
render(<App />)
|
|
38
|
+
|
|
39
|
+
expect(screen.getByText('Loading documentation...')).toBeInTheDocument()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('shows error message when fetch fails', async () => {
|
|
43
|
+
mockFetch.mockRejectedValueOnce(new Error('Failed to fetch'))
|
|
44
|
+
|
|
45
|
+
render(<App />)
|
|
46
|
+
|
|
47
|
+
// Wait for the error state
|
|
48
|
+
await screen.findByText(/Error loading documentation/)
|
|
49
|
+
})
|
|
50
|
+
})
|
package/docs/src/App.tsx
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import ReactMarkdown from 'react-markdown'
|
|
3
|
+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
|
|
4
|
+
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'
|
|
5
|
+
import remarkGfm from 'remark-gfm'
|
|
6
|
+
import './App.css'
|
|
7
|
+
|
|
8
|
+
interface DocumentSection {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
subtitle: string;
|
|
12
|
+
file: string;
|
|
13
|
+
content?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const documentSections: DocumentSection[] = [
|
|
17
|
+
{ id: 'overview', title: 'Foundation', subtitle: 'Core concepts & philosophy', file: '/README.md' },
|
|
18
|
+
{ id: 'getting-started', title: 'Getting Started', subtitle: 'Your first steps with Fjell', file: '/fjell-registry/examples-README.md' },
|
|
19
|
+
{ id: 'examples', title: 'Examples', subtitle: 'Code examples & usage patterns', file: '/fjell-registry/examples-README.md' },
|
|
20
|
+
{ id: 'performance', title: 'Performance', subtitle: 'Memory, timing & optimization', file: '/memory.md' }
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const App: React.FC = () => {
|
|
24
|
+
const [currentSection, setCurrentSection] = useState('overview')
|
|
25
|
+
const [documents, setDocuments] = useState<{ [key: string]: string }>({})
|
|
26
|
+
const [loading, setLoading] = useState(true)
|
|
27
|
+
const [sidebarOpen, setSidebarOpen] = useState(false)
|
|
28
|
+
const [fullscreenImage, setFullscreenImage] = useState<string | null>(null)
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const loadDocuments = async () => {
|
|
32
|
+
const loadedDocs: { [key: string]: string } = {}
|
|
33
|
+
|
|
34
|
+
for (const section of documentSections) {
|
|
35
|
+
try {
|
|
36
|
+
const response = await fetch(section.file)
|
|
37
|
+
|
|
38
|
+
if (response.ok) {
|
|
39
|
+
loadedDocs[section.id] = await response.text()
|
|
40
|
+
} else {
|
|
41
|
+
// Fallback content for missing files
|
|
42
|
+
loadedDocs[section.id] = getFallbackContent(section.id)
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`Error loading ${section.file}:`, error)
|
|
46
|
+
loadedDocs[section.id] = getFallbackContent(section.id)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setDocuments(loadedDocs)
|
|
51
|
+
setLoading(false)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
loadDocuments()
|
|
55
|
+
}, [])
|
|
56
|
+
|
|
57
|
+
const getFallbackContent = (sectionId: string): string => {
|
|
58
|
+
switch (sectionId) {
|
|
59
|
+
case 'overview':
|
|
60
|
+
return `# Fjell Registry
|
|
61
|
+
|
|
62
|
+
A comprehensive service location and registry system for the Fjell ecosystem.
|
|
63
|
+
The Registry provides a centralized way to register, scope, and retrieve service
|
|
64
|
+
instances based on type hierarchies and contextual scopes.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
\`\`\`bash
|
|
69
|
+
npm install @fjell/registry
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
## Quick Start
|
|
73
|
+
|
|
74
|
+
\`\`\`typescript
|
|
75
|
+
import { createRegistry, createCoordinate } from '@fjell/registry'
|
|
76
|
+
|
|
77
|
+
// Create a registry with mandatory type identifier
|
|
78
|
+
const registry = createRegistry('services')
|
|
79
|
+
|
|
80
|
+
// Create a coordinate with Key Type Array and scopes
|
|
81
|
+
const userCoordinate = createCoordinate(['User'], ['firestore'])
|
|
82
|
+
const userInstance = registry.createInstance(userCoordinate, () => new UserService())
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
## Core Concepts
|
|
86
|
+
|
|
87
|
+
- **Registry**: Central service locator with mandatory type identifier
|
|
88
|
+
- **Coordinate**: Unique service identifier using Key Type Arrays and scopes
|
|
89
|
+
- **Instance**: Registered service with its coordinate and registry reference
|
|
90
|
+
- **Scopes**: Context qualifiers enabling multiple implementations`
|
|
91
|
+
|
|
92
|
+
case 'getting-started':
|
|
93
|
+
return `# Getting Started
|
|
94
|
+
|
|
95
|
+
## Basic Usage
|
|
96
|
+
|
|
97
|
+
\`\`\`typescript
|
|
98
|
+
import { createRegistry, createCoordinate } from '@fjell/registry'
|
|
99
|
+
|
|
100
|
+
// Create a registry with type identifier
|
|
101
|
+
const registry = createRegistry('services')
|
|
102
|
+
|
|
103
|
+
// Register a service with coordinate
|
|
104
|
+
const coordinate = createCoordinate(['User'], ['firestore'])
|
|
105
|
+
const instance = registry.createInstance(coordinate, () => new UserService())
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
## Key Concepts
|
|
109
|
+
|
|
110
|
+
- **Coordinates**: Use Key Type Arrays like \`['User', 'Profile']\` for hierarchical types
|
|
111
|
+
- **Scopes**: Context qualifiers like \`['firestore']\`, \`['postgresql']\` for multiple implementations
|
|
112
|
+
- **Registries**: Each has a mandatory type identifier for organization
|
|
113
|
+
|
|
114
|
+
## Examples
|
|
115
|
+
|
|
116
|
+
Check the examples directory for detailed usage patterns with different key structures and scope configurations.`
|
|
117
|
+
|
|
118
|
+
case 'examples':
|
|
119
|
+
return `# Registry Examples
|
|
120
|
+
|
|
121
|
+
This directory contains examples demonstrating how to use the Registry with different key patterns and configurations.
|
|
122
|
+
|
|
123
|
+
*Note: This content should be loaded from examples/README.md. If you're seeing this, there may be an issue with file loading.*
|
|
124
|
+
|
|
125
|
+
## Examples Available
|
|
126
|
+
|
|
127
|
+
- **simple-example.ts**: Basic usage without complexity
|
|
128
|
+
- **multi-level-keys.ts**: Advanced hierarchical patterns
|
|
129
|
+
- **registry-hub-types.ts**: Enterprise service organization
|
|
130
|
+
- **coordinates-example.ts**: Service introspection patterns
|
|
131
|
+
- **registry-hub-coordinates-example.ts**: Cross-registry discovery`
|
|
132
|
+
|
|
133
|
+
case 'performance':
|
|
134
|
+
return `# Performance Guide
|
|
135
|
+
|
|
136
|
+
Comprehensive performance analysis and optimization strategies for Fjell Registry.
|
|
137
|
+
|
|
138
|
+
## Memory Efficiency
|
|
139
|
+
|
|
140
|
+
The registry system is designed for memory efficiency with minimal overhead per registered instance and coordinate.
|
|
141
|
+
|
|
142
|
+
### Key Features
|
|
143
|
+
- Lightweight coordinate system using arrays
|
|
144
|
+
- Efficient instance tree organization
|
|
145
|
+
- Minimal memory footprint per service registration
|
|
146
|
+
|
|
147
|
+
### Memory Benchmarks
|
|
148
|
+
Performance metrics and memory usage patterns show efficient scaling with large numbers of registered services.
|
|
149
|
+
|
|
150
|
+
## Timing Performance
|
|
151
|
+
|
|
152
|
+
Performance benchmarks for Fjell Registry service location operations.
|
|
153
|
+
|
|
154
|
+
### Core Operations
|
|
155
|
+
- **Instance creation**: Fast atomic registration with coordinates
|
|
156
|
+
- **Registry lookup**: Efficient retrieval by Key Type Arrays and scopes
|
|
157
|
+
- **Coordinate resolution**: Quick scope-based service discovery
|
|
158
|
+
- **Tree traversal**: Optimized instance tree navigation
|
|
159
|
+
|
|
160
|
+
### Timing Benchmarks
|
|
161
|
+
- Instance registration: < 1ms per service
|
|
162
|
+
- Coordinate-based lookup: < 0.1ms average
|
|
163
|
+
- Scope resolution: < 0.5ms for complex hierarchies
|
|
164
|
+
- Memory allocation: Minimal per registered instance
|
|
165
|
+
|
|
166
|
+
## Production Optimization
|
|
167
|
+
|
|
168
|
+
Best practices for optimizing Fjell Registry performance in production environments.
|
|
169
|
+
|
|
170
|
+
### Registry Organization
|
|
171
|
+
- Use specific type identifiers for different service categories
|
|
172
|
+
- Group related services in dedicated registries
|
|
173
|
+
- Leverage scopes for environment-specific implementations
|
|
174
|
+
|
|
175
|
+
### Performance Tips
|
|
176
|
+
- Design efficient Key Type Array hierarchies
|
|
177
|
+
- Minimize scope complexity where possible
|
|
178
|
+
- Use appropriate registry types for service organization
|
|
179
|
+
- Consider coordinate caching for frequently accessed services
|
|
180
|
+
|
|
181
|
+
### Production Settings
|
|
182
|
+
Recommended Node.js heap size settings and monitoring approaches for large-scale registry usage.`
|
|
183
|
+
|
|
184
|
+
default:
|
|
185
|
+
return `# ${sectionId}\n\nDocumentation section not found.`
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const currentContent = documents[currentSection] || ''
|
|
190
|
+
const currentSectionData = documentSections.find(s => s.id === currentSection)
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div className="app">
|
|
194
|
+
<header className="header">
|
|
195
|
+
<div className="header-container">
|
|
196
|
+
<div className="brand">
|
|
197
|
+
<h1 className="brand-title">
|
|
198
|
+
<span className="brand-fjell">Fjell</span>
|
|
199
|
+
<span className="brand-registry">Registry</span>
|
|
200
|
+
</h1>
|
|
201
|
+
<p className="brand-tagline">
|
|
202
|
+
Service location that
|
|
203
|
+
<span className="gradient-text"> weaves through the mist</span>
|
|
204
|
+
</p>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<div className="header-actions">
|
|
208
|
+
<a
|
|
209
|
+
href="https://github.com/getfjell/fjell-registry"
|
|
210
|
+
target="_blank"
|
|
211
|
+
rel="noopener noreferrer"
|
|
212
|
+
className="header-link"
|
|
213
|
+
>
|
|
214
|
+
<span>View Source</span>
|
|
215
|
+
</a>
|
|
216
|
+
<a
|
|
217
|
+
href="https://www.npmjs.com/package/@fjell/registry"
|
|
218
|
+
target="_blank"
|
|
219
|
+
rel="noopener noreferrer"
|
|
220
|
+
className="header-link"
|
|
221
|
+
>
|
|
222
|
+
<span>Install Package</span>
|
|
223
|
+
</a>
|
|
224
|
+
<button
|
|
225
|
+
className="menu-toggle"
|
|
226
|
+
onClick={() => setSidebarOpen(!sidebarOpen)}
|
|
227
|
+
>
|
|
228
|
+
<span className="menu-line"></span>
|
|
229
|
+
<span className="menu-line"></span>
|
|
230
|
+
<span className="menu-line"></span>
|
|
231
|
+
</button>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
</header>
|
|
235
|
+
|
|
236
|
+
<div className="layout">
|
|
237
|
+
<nav className={`sidebar ${sidebarOpen ? 'sidebar-open' : ''}`}>
|
|
238
|
+
<div className="nav-content">
|
|
239
|
+
<div className="nav-header">
|
|
240
|
+
<h3 className="nav-title">Explore</h3>
|
|
241
|
+
<p className="nav-subtitle">Navigate through concepts</p>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<div className="nav-sections">
|
|
245
|
+
{documentSections.map((section) => (
|
|
246
|
+
<button
|
|
247
|
+
key={section.id}
|
|
248
|
+
className={`nav-item ${currentSection === section.id ? 'active' : ''}`}
|
|
249
|
+
onClick={() => {
|
|
250
|
+
setCurrentSection(section.id)
|
|
251
|
+
setSidebarOpen(false)
|
|
252
|
+
}}
|
|
253
|
+
>
|
|
254
|
+
<div className="nav-item-content">
|
|
255
|
+
<div className="nav-item-title">{section.title}</div>
|
|
256
|
+
<div className="nav-item-subtitle">{section.subtitle}</div>
|
|
257
|
+
</div>
|
|
258
|
+
</button>
|
|
259
|
+
))}
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
{/* Artistic Logo Placement */}
|
|
263
|
+
<img
|
|
264
|
+
src="/fjell-registry/icon.png"
|
|
265
|
+
alt="Fjell Registry"
|
|
266
|
+
className="fjell-logo"
|
|
267
|
+
title="Fjell Registry - Service location that weaves through the mist"
|
|
268
|
+
onError={(e) => {
|
|
269
|
+
console.log('Icon failed to load, trying alternative path');
|
|
270
|
+
e.currentTarget.src = '/icon.png';
|
|
271
|
+
}}
|
|
272
|
+
onLoad={() => console.log('Fjell logo loaded successfully')}
|
|
273
|
+
/>
|
|
274
|
+
</div>
|
|
275
|
+
</nav>
|
|
276
|
+
|
|
277
|
+
<main className="main">
|
|
278
|
+
<div className="content-container">
|
|
279
|
+
{loading ? (
|
|
280
|
+
<div className="loading">
|
|
281
|
+
<div className="loading-animation">
|
|
282
|
+
<div className="loading-dot"></div>
|
|
283
|
+
<div className="loading-dot"></div>
|
|
284
|
+
<div className="loading-dot"></div>
|
|
285
|
+
</div>
|
|
286
|
+
<p className="loading-text">Awakening the Registry</p>
|
|
287
|
+
</div>
|
|
288
|
+
) : (
|
|
289
|
+
<div className="content-wrapper">
|
|
290
|
+
<div className="content-header">
|
|
291
|
+
<div className="breadcrumb">
|
|
292
|
+
<span className="breadcrumb-home">Fjell Registry</span>
|
|
293
|
+
<span className="breadcrumb-separator">›</span>
|
|
294
|
+
<span className="breadcrumb-current">{currentSectionData?.title}</span>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
|
|
298
|
+
<div className="section-header">
|
|
299
|
+
<h1 className="content-title">
|
|
300
|
+
{currentSectionData?.title}
|
|
301
|
+
</h1>
|
|
302
|
+
<p className="content-subtitle">
|
|
303
|
+
{currentSectionData?.subtitle}
|
|
304
|
+
</p>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div className="content">
|
|
308
|
+
{currentSection === 'examples' ? (
|
|
309
|
+
<div className="examples-content">
|
|
310
|
+
<ReactMarkdown
|
|
311
|
+
remarkPlugins={[remarkGfm]}
|
|
312
|
+
components={{
|
|
313
|
+
code({ className, children, ...props }: any) {
|
|
314
|
+
const match = /language-(\w+)/.exec(className || '')
|
|
315
|
+
return !props.inline && match ? (
|
|
316
|
+
<SyntaxHighlighter
|
|
317
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
318
|
+
language={match[1]}
|
|
319
|
+
PreTag="div"
|
|
320
|
+
{...props}
|
|
321
|
+
>
|
|
322
|
+
{String(children).replace(/\n$/, '')}
|
|
323
|
+
</SyntaxHighlighter>
|
|
324
|
+
) : (
|
|
325
|
+
<code className={className} {...props}>
|
|
326
|
+
{children}
|
|
327
|
+
</code>
|
|
328
|
+
)
|
|
329
|
+
},
|
|
330
|
+
h1({ children }) {
|
|
331
|
+
return <h1 className="content-h1">{children}</h1>
|
|
332
|
+
},
|
|
333
|
+
h2({ children }) {
|
|
334
|
+
return <h2 className="content-h2">{children}</h2>
|
|
335
|
+
},
|
|
336
|
+
h3({ children }) {
|
|
337
|
+
return <h3 className="content-h3">{children}</h3>
|
|
338
|
+
}
|
|
339
|
+
}}
|
|
340
|
+
>
|
|
341
|
+
{currentContent}
|
|
342
|
+
</ReactMarkdown>
|
|
343
|
+
|
|
344
|
+
<div className="examples-grid">
|
|
345
|
+
<div className="example-card">
|
|
346
|
+
<h3>🟢 Simple Example</h3>
|
|
347
|
+
<p>Perfect for beginners! Basic dependency injection without complexity.</p>
|
|
348
|
+
<details>
|
|
349
|
+
<summary>View Code</summary>
|
|
350
|
+
<div className="example-code-block">
|
|
351
|
+
<SyntaxHighlighter
|
|
352
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
353
|
+
language="bash"
|
|
354
|
+
PreTag="div"
|
|
355
|
+
>
|
|
356
|
+
npx tsx examples/simple-example.ts
|
|
357
|
+
</SyntaxHighlighter>
|
|
358
|
+
</div>
|
|
359
|
+
</details>
|
|
360
|
+
</div>
|
|
361
|
+
|
|
362
|
+
<div className="example-card">
|
|
363
|
+
<h3>🔶 Multi-Level Keys</h3>
|
|
364
|
+
<p>Advanced usage with scopes and hierarchical key type arrays.</p>
|
|
365
|
+
<details>
|
|
366
|
+
<summary>View Code</summary>
|
|
367
|
+
<div className="example-code-block">
|
|
368
|
+
<SyntaxHighlighter
|
|
369
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
370
|
+
language="bash"
|
|
371
|
+
PreTag="div"
|
|
372
|
+
>
|
|
373
|
+
npx tsx examples/multi-level-keys.ts
|
|
374
|
+
</SyntaxHighlighter>
|
|
375
|
+
</div>
|
|
376
|
+
</details>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
<div className="example-card">
|
|
380
|
+
<h3>🏗️ Registry Hub</h3>
|
|
381
|
+
<p>Enterprise architecture with organized service categories.</p>
|
|
382
|
+
<details>
|
|
383
|
+
<summary>View Code</summary>
|
|
384
|
+
<div className="example-code-block">
|
|
385
|
+
<SyntaxHighlighter
|
|
386
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
387
|
+
language="bash"
|
|
388
|
+
PreTag="div"
|
|
389
|
+
>
|
|
390
|
+
npx tsx examples/registry-hub-types.ts
|
|
391
|
+
</SyntaxHighlighter>
|
|
392
|
+
</div>
|
|
393
|
+
</details>
|
|
394
|
+
</div>
|
|
395
|
+
|
|
396
|
+
<div className="example-card">
|
|
397
|
+
<h3>🔍 Coordinate Discovery</h3>
|
|
398
|
+
<p>Service introspection and discovery patterns.</p>
|
|
399
|
+
<details>
|
|
400
|
+
<summary>View Code</summary>
|
|
401
|
+
<div className="example-code-block">
|
|
402
|
+
<SyntaxHighlighter
|
|
403
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
404
|
+
language="bash"
|
|
405
|
+
PreTag="div"
|
|
406
|
+
>
|
|
407
|
+
npx tsx examples/coordinates-example.ts
|
|
408
|
+
</SyntaxHighlighter>
|
|
409
|
+
</div>
|
|
410
|
+
</details>
|
|
411
|
+
</div>
|
|
412
|
+
|
|
413
|
+
<div className="example-card">
|
|
414
|
+
<h3>🌐 Hub Coordinates</h3>
|
|
415
|
+
<p>Cross-registry coordinate discovery for enterprise apps.</p>
|
|
416
|
+
<details>
|
|
417
|
+
<summary>View Code</summary>
|
|
418
|
+
<div className="example-code-block">
|
|
419
|
+
<SyntaxHighlighter
|
|
420
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
421
|
+
language="bash"
|
|
422
|
+
PreTag="div"
|
|
423
|
+
>
|
|
424
|
+
npx tsx examples/registry-hub-coordinates-example.ts
|
|
425
|
+
</SyntaxHighlighter>
|
|
426
|
+
</div>
|
|
427
|
+
</details>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
</div>
|
|
431
|
+
) : currentSection === 'performance' ? (
|
|
432
|
+
<div className="performance-content">
|
|
433
|
+
<ReactMarkdown
|
|
434
|
+
remarkPlugins={[remarkGfm]}
|
|
435
|
+
components={{
|
|
436
|
+
code({ className, children, ...props }: any) {
|
|
437
|
+
const match = /language-(\w+)/.exec(className || '')
|
|
438
|
+
return !props.inline && match ? (
|
|
439
|
+
<SyntaxHighlighter
|
|
440
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
441
|
+
language={match[1]}
|
|
442
|
+
PreTag="div"
|
|
443
|
+
{...props}
|
|
444
|
+
>
|
|
445
|
+
{String(children).replace(/\n$/, '')}
|
|
446
|
+
</SyntaxHighlighter>
|
|
447
|
+
) : (
|
|
448
|
+
<code className={className} {...props}>
|
|
449
|
+
{children}
|
|
450
|
+
</code>
|
|
451
|
+
)
|
|
452
|
+
},
|
|
453
|
+
h1({ children }) {
|
|
454
|
+
return <h1 className="content-h1">{children}</h1>
|
|
455
|
+
},
|
|
456
|
+
h2({ children }) {
|
|
457
|
+
return <h2 className="content-h2">{children}</h2>
|
|
458
|
+
},
|
|
459
|
+
h3({ children }) {
|
|
460
|
+
return <h3 className="content-h3">{children}</h3>
|
|
461
|
+
}
|
|
462
|
+
}}
|
|
463
|
+
>
|
|
464
|
+
{currentContent}
|
|
465
|
+
</ReactMarkdown>
|
|
466
|
+
<div className="performance-charts">
|
|
467
|
+
<div className="svg-display">
|
|
468
|
+
<h3>Memory Overhead Analysis</h3>
|
|
469
|
+
<img
|
|
470
|
+
src="/fjell-registry/memory-overhead.svg"
|
|
471
|
+
alt="Memory Overhead Chart"
|
|
472
|
+
className="performance-chart clickable-chart"
|
|
473
|
+
onClick={() => setFullscreenImage('/fjell-registry/memory-overhead.svg')}
|
|
474
|
+
title="Click to view full screen"
|
|
475
|
+
/>
|
|
476
|
+
</div>
|
|
477
|
+
<div className="svg-display">
|
|
478
|
+
<h3>Timing Performance Analysis</h3>
|
|
479
|
+
<img
|
|
480
|
+
src="/fjell-registry/timing-range.svg"
|
|
481
|
+
alt="Timing Performance Chart"
|
|
482
|
+
className="performance-chart clickable-chart"
|
|
483
|
+
onClick={() => setFullscreenImage('/fjell-registry/timing-range.svg')}
|
|
484
|
+
title="Click to view full screen"
|
|
485
|
+
/>
|
|
486
|
+
</div>
|
|
487
|
+
</div>
|
|
488
|
+
</div>
|
|
489
|
+
) : (
|
|
490
|
+
<ReactMarkdown
|
|
491
|
+
remarkPlugins={[remarkGfm]}
|
|
492
|
+
components={{
|
|
493
|
+
code({ className, children, ...props }: any) {
|
|
494
|
+
const match = /language-(\w+)/.exec(className || '')
|
|
495
|
+
return !props.inline && match ? (
|
|
496
|
+
<SyntaxHighlighter
|
|
497
|
+
style={oneDark as { [key: string]: React.CSSProperties }}
|
|
498
|
+
language={match[1]}
|
|
499
|
+
PreTag="div"
|
|
500
|
+
{...props}
|
|
501
|
+
>
|
|
502
|
+
{String(children).replace(/\n$/, '')}
|
|
503
|
+
</SyntaxHighlighter>
|
|
504
|
+
) : (
|
|
505
|
+
<code className={className} {...props}>
|
|
506
|
+
{children}
|
|
507
|
+
</code>
|
|
508
|
+
)
|
|
509
|
+
},
|
|
510
|
+
h1({ children }) {
|
|
511
|
+
return <h1 className="content-h1">{children}</h1>
|
|
512
|
+
},
|
|
513
|
+
h2({ children }) {
|
|
514
|
+
return <h2 className="content-h2">{children}</h2>
|
|
515
|
+
},
|
|
516
|
+
h3({ children }) {
|
|
517
|
+
return <h3 className="content-h3">{children}</h3>
|
|
518
|
+
}
|
|
519
|
+
}}
|
|
520
|
+
>
|
|
521
|
+
{currentContent}
|
|
522
|
+
</ReactMarkdown>
|
|
523
|
+
)}
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
<div className="content-navigation">
|
|
527
|
+
{documentSections.map((section) => {
|
|
528
|
+
if (section.id === currentSection) return null
|
|
529
|
+
return (
|
|
530
|
+
<button
|
|
531
|
+
key={section.id}
|
|
532
|
+
className="nav-suggestion"
|
|
533
|
+
onClick={() => setCurrentSection(section.id)}
|
|
534
|
+
>
|
|
535
|
+
<span className="nav-suggestion-label">Next</span>
|
|
536
|
+
<span className="nav-suggestion-title">{section.title}</span>
|
|
537
|
+
</button>
|
|
538
|
+
)
|
|
539
|
+
}).filter(Boolean).slice(0, 1)}
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
)}
|
|
543
|
+
</div>
|
|
544
|
+
</main>
|
|
545
|
+
</div>
|
|
546
|
+
|
|
547
|
+
<footer className="footer">
|
|
548
|
+
<div className="footer-container">
|
|
549
|
+
<div className="footer-content">
|
|
550
|
+
<p className="footer-text">
|
|
551
|
+
Crafted with intention for the Fjell ecosystem
|
|
552
|
+
</p>
|
|
553
|
+
<p className="footer-license">
|
|
554
|
+
Licensed under Apache-2.0 • 2024
|
|
555
|
+
</p>
|
|
556
|
+
</div>
|
|
557
|
+
</div>
|
|
558
|
+
</footer>
|
|
559
|
+
|
|
560
|
+
{/* Fullscreen Image Modal */}
|
|
561
|
+
{fullscreenImage && (
|
|
562
|
+
<div className="fullscreen-modal" onClick={() => setFullscreenImage(null)}>
|
|
563
|
+
<div className="fullscreen-content">
|
|
564
|
+
<img
|
|
565
|
+
src={fullscreenImage}
|
|
566
|
+
alt="Performance Chart"
|
|
567
|
+
className="fullscreen-image"
|
|
568
|
+
/>
|
|
569
|
+
<button
|
|
570
|
+
className="close-button"
|
|
571
|
+
onClick={() => setFullscreenImage(null)}
|
|
572
|
+
aria-label="Close fullscreen view"
|
|
573
|
+
>
|
|
574
|
+
×
|
|
575
|
+
</button>
|
|
576
|
+
</div>
|
|
577
|
+
</div>
|
|
578
|
+
)}
|
|
579
|
+
</div>
|
|
580
|
+
)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export default App
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--fjell-blue: #2563eb;
|
|
3
|
+
--fjell-blue-light: #3b82f6;
|
|
4
|
+
--fjell-gray: #374151;
|
|
5
|
+
--fjell-gray-light: #6b7280;
|
|
6
|
+
--fjell-background: #f9fafb;
|
|
7
|
+
--fjell-border: #e5e7eb;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
* {
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
margin: 0;
|
|
16
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
17
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
18
|
+
sans-serif;
|
|
19
|
+
-webkit-font-smoothing: antialiased;
|
|
20
|
+
-moz-osx-font-smoothing: grayscale;
|
|
21
|
+
color: var(--fjell-gray);
|
|
22
|
+
background-color: var(--fjell-background);
|
|
23
|
+
line-height: 1.6;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
code {
|
|
27
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
28
|
+
background-color: #f1f5f9;
|
|
29
|
+
padding: 0.125rem 0.25rem;
|
|
30
|
+
border-radius: 0.25rem;
|
|
31
|
+
font-size: 0.875em;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pre code {
|
|
35
|
+
display: block;
|
|
36
|
+
padding: 1rem;
|
|
37
|
+
overflow-x: auto;
|
|
38
|
+
border-radius: 0.5rem;
|
|
39
|
+
background-color: #1e293b !important;
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|