@lumina-study/block-store
v0.1.2
Published
Redux Toolkit store for managing lumina.json configurations from GitHub and GitLab repositories
Maintainers
Readme
@lumina-study/block-store
A Redux Toolkit store for managing lumina.json files from GitHub and GitLab repositories. Block types are defined by @lumina-study/block-schema (single source of truth).
Features
- 🔄 Redux Toolkit Integration: Modern Redux state management with built-in best practices
- 📋 Block Schema Compliance: Uses
@lumina-study/block-schemaas the single source of truth for block types - 🌐 Multi-Provider Support: Fetch lumina.json files from GitHub and GitLab repositories
- 📦 TypeScript First: Full TypeScript support with comprehensive type definitions
- 🔍 Commit Tracking: Automatically tracks the commit SHA for each lumina.json source
- ✨ Simple API: Easy-to-use actions and selectors for managing sources and accessing blocks
- 🧪 Well Tested: 24 tests passing with comprehensive coverage
What is lumina.json?
A lumina.json file contains an array of blocks following the @lumina-study/block-schema specification. This package manages the retrieval and storage of these files from Git repositories.
Installation
npm install @lumina-study/block-store
# or
pnpm add @lumina-study/block-store
# or
yarn add @lumina-study/block-storeQuick Start
1. Create the Store
import { createBlockStore } from '@lumina-study/block-store'
const store = createBlockStore()2. Add a lumina.json Source
import { addLuminaJson } from '@lumina-study/block-store'
// Fetch from GitHub
await store.dispatch(
addLuminaJson({
provider: 'github',
organization: 'luminastudy',
repository: 'my-project',
token: 'optional-github-token', // For private repos
})
)
// Fetch from GitLab
await store.dispatch(
addLuminaJson({
provider: 'gitlab',
organization: 'my-group',
repository: 'my-project',
token: 'optional-gitlab-token', // For private repos
})
)3. Access Data
import {
selectAllSources,
selectAllBlocks,
selectBlockById,
selectBlocksFromSource,
} from '@lumina-study/block-store'
// Get all lumina.json sources
const sources = selectAllSources(store.getState())
// Get all blocks from all sources (flattened)
const allBlocks = selectAllBlocks(store.getState())
// Get a specific block by ID across all sources
const block = selectBlockById('block-uuid')(store.getState())
// Get blocks from a specific source
const sourceBlocks = selectBlocksFromSource('github:luminastudy:my-project')(
store.getState()
)API Reference
Store Factory
createBlockStore()
Creates and configures a Redux store for managing lumina.json sources.
import { createBlockStore } from '@lumina-study/block-store'
const store = createBlockStore()Returns: BlockStore - Configured Redux store
Actions
addLuminaJson(params: AddLuminaJsonParams)
Async thunk that fetches a lumina.json file from a Git provider and adds it to the store.
Parameters:
interface AddLuminaJsonParams {
provider: 'github' | 'gitlab'
organization: string // Organization or user name
repository: string // Repository name
token?: string // Optional auth token for private repos
}Example:
import { addLuminaJson } from '@lumina-study/block-store'
await store.dispatch(
addLuminaJson({
provider: 'github',
organization: 'luminastudy',
repository: 'block-store',
})
)Behavior:
- Fetches
lumina.jsonfrom the repository root - Validates that the file contains a
blocksarray - Stores the source with provider, org, repo, commitSha, and content
- Tracks when the source was added
removeLuminaJson(key: string)
Removes a lumina.json source from the store by its key.
Example:
import { removeLuminaJson } from '@lumina-study/block-store'
store.dispatch(removeLuminaJson('github:luminastudy:block-store'))clearSources()
Clears all lumina.json sources from the store.
import { clearSources } from '@lumina-study/block-store'
store.dispatch(clearSources())clearError()
Clears any error state.
import { clearError } from '@lumina-study/block-store'
store.dispatch(clearError())Selectors
selectAllSources(state)
Returns all lumina.json sources as an array.
import { selectAllSources } from '@lumina-study/block-store'
const sources = selectAllSources(store.getState())
// Returns: LuminaJsonSource[]Returns:
interface LuminaJsonSource {
provider: 'github' | 'gitlab'
organization: string
repository: string
commitSha: string
luminaJson: LuminaJson // Contains blocks array
addedAt: string // ISO timestamp
}selectSourceByKey(key)(state)
Returns a specific source by its key.
import { selectSourceByKey } from '@lumina-study/block-store'
const source = selectSourceByKey('github:luminastudy:my-project')(
store.getState()
)Key Format: "provider:organization:repository"
selectSourcesByProvider(provider)(state)
Returns all sources for a specific Git provider.
import { selectSourcesByProvider } from '@lumina-study/block-store'
const githubSources = selectSourcesByProvider('github')(store.getState())
const gitlabSources = selectSourcesByProvider('gitlab')(store.getState())selectAllBlocks(state)
Returns all blocks from all sources (flattened).
import { selectAllBlocks } from '@lumina-study/block-store'
const allBlocks = selectAllBlocks(store.getState())
// Returns: Block[]Returns:
interface Block {
id: string // UUID
title: {
he_text: string
en_text: string
}
prerequisites: string[] // Array of block IDs
parents: string[] // Array of block IDs
[key: string]: unknown // Additional properties
}selectBlocksFromSource(sourceKey)(state)
Returns blocks from a specific source.
import { selectBlocksFromSource } from '@lumina-study/block-store'
const blocks = selectBlocksFromSource('github:luminastudy:my-project')(
store.getState()
)selectBlockById(blockId)(state)
Finds a block by ID across all sources.
import { selectBlockById } from '@lumina-study/block-store'
const block = selectBlockById('550e8400-e29b-41d4-a716-446655440000')(
store.getState()
)
// Returns: Block | undefinedselectLoading(state)
Returns the loading state.
import { selectLoading } from '@lumina-study/block-store'
const isLoading = selectLoading(store.getState())
// Returns: booleanselectError(state)
Returns the current error message, if any.
import { selectError } from '@lumina-study/block-store'
const error = selectError(store.getState())
// Returns: string | nullTypes
All TypeScript types are exported for use in your application:
import type {
// Core types
GitProvider,
Block,
LuminaJson,
LuminaJsonSource,
// State types
BlockStoreState,
// Parameter types
AddLuminaJsonParams,
// Store types
BlockStore,
RootState,
AppDispatch,
} from '@lumina-study/block-store'Utilities
generateSourceKey(provider, organization, repository)
Generates a unique key for a lumina.json source.
import { generateSourceKey } from '@lumina-study/block-store'
const key = generateSourceKey('github', 'luminastudy', 'block-store')
// Returns: "github:luminastudy:block-store"parseSourceKey(key)
Parses a source key into its components.
import { parseSourceKey } from '@lumina-study/block-store'
const { provider, organization, repository } = parseSourceKey(
'github:luminastudy:block-store'
)Services (Advanced)
For advanced use cases, you can access the underlying services directly:
import {
fetchLuminaJsonFromGitHub,
fetchLuminaJsonFromGitLab,
} from '@lumina-study/block-store'
// Fetch directly without Redux
const { luminaJson, commitSha } = await fetchLuminaJsonFromGitHub(
'luminastudy',
'my-project'
)Integration with React
import { Provider, useDispatch, useSelector } from 'react-redux'
import {
createBlockStore,
addLuminaJson,
selectAllSources,
selectAllBlocks,
selectBlockById,
} from '@lumina-study/block-store'
import type { AppDispatch } from '@lumina-study/block-store'
const store = createBlockStore()
function App() {
return (
<Provider store={store}>
<LuminaJsonManager />
</Provider>
)
}
function LuminaJsonManager() {
const dispatch = useDispatch<AppDispatch>()
const sources = useSelector(selectAllSources)
const allBlocks = useSelector(selectAllBlocks)
const handleAddSource = () => {
dispatch(
addLuminaJson({
provider: 'github',
organization: 'luminastudy',
repository: 'my-project',
})
)
}
return (
<div>
<button onClick={handleAddSource}>Add Source</button>
<h2>Sources ({sources.length})</h2>
<ul>
{sources.map(source => (
<li key={`${source.provider}:${source.organization}:${source.repository}`}>
{source.organization}/{source.repository}
({source.luminaJson.blocks.length} blocks, SHA: {source.commitSha.substring(0, 7)})
</li>
))}
</ul>
<h2>All Blocks ({allBlocks.length})</h2>
<ul>
{allBlocks.map(block => (
<li key={block.id}>
{block.title.en_text} / {block.title.he_text}
</li>
))}
</ul>
</div>
)
}Data Structure
State Shape
{
luminaJson: {
sources: {
"github:luminastudy:my-project": {
provider: "github",
organization: "luminastudy",
repository: "my-project",
commitSha: "abc123...",
luminaJson: {
blocks: [
{
id: "550e8400-e29b-41d4-a716-446655440000",
title: {
he_text: "בלוק לדוגמה",
en_text: "Example Block"
},
prerequisites: [],
parents: []
}
]
},
addedAt: "2024-01-01T00:00:00.000Z"
}
},
loading: false,
error: null
}
}lumina.json File Format
{
"blocks": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": {
"he_text": "בלוק לדוגמה",
"en_text": "Example Block"
},
"prerequisites": ["another-block-uuid"],
"parents": ["parent-block-uuid"]
}
]
}Error Handling
The store handles errors gracefully and stores them in the state:
import {
selectError,
selectLoading,
clearError,
} from '@lumina-study/block-store'
const error = selectError(store.getState())
const loading = selectLoading(store.getState())
if (loading) {
console.log('Loading...')
} else if (error) {
console.error('Error:', error)
// Clear the error
store.dispatch(clearError())
}Block Schema
Blocks follow the @lumina-study/block-schema specification (v0.1):
- id: Unique identifier (UUID format)
- title: Object with
he_text(Hebrew) anden_text(English) - prerequisites: Array of prerequisite block IDs (UUIDs)
- parents: Array of parent block IDs (UUIDs)
- Additional custom properties are allowed
Development
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Build
pnpm build
# Lint
pnpm lint
# Format
pnpm formatContributing
See CONTRIBUTING.md for contribution guidelines.
License
MIT © Lumina Study
Related Packages
@lumina-study/block-schema- JSON Schema for Lumina Study block objects (single source of truth)
