@djangocfg/ext-base
Base utilities and common code for building DjangoCFG extensions.
Part of DjangoCFG — modern Django framework for production-ready SaaS applications.
What is this?
@djangocfg/ext-base provides the foundation for DjangoCFG extensions with:
- Extension registration system and metadata tracking
- React hooks for pagination, infinite scroll, and data fetching
- Environment utilities (isDevelopment, isProduction, isStaticBuild)
- Type-safe context helpers and logger utilities
- Auth integration and API factory
- CLI tool for managing extensions
Used internally by official extensions (newsletter, payments, support, leads, knowbase) and for building custom extensions.
Install
pnpm add @djangocfg/ext-base
CLI Usage
The package includes a CLI tool for creating new DjangoCFG extensions:
djangocfg-ext create
djangocfg-ext help
The CLI will guide you through creating a new extension with proper structure and configuration using the createExtensionConfig helper.
Quick Start
1. Create extension metadata
Use the createExtensionConfig helper to automatically pull data from package.json:
import { createExtensionConfig } from '@djangocfg/ext-base';
import packageJson from '../package.json';
export const extensionConfig = createExtensionConfig(packageJson, {
name: 'my-extension',
displayName: 'My Extension',
icon: 'Rocket',
category: 'utilities',
features: [
'Feature 1',
'Feature 2',
'Feature 3',
],
minVersion: '2.0.0',
examples: [
{
title: 'Basic Usage',
description: 'How to use this extension',
code: `import { MyComponent } from '@your-org/my-extension';`,
language: 'tsx',
},
],
});
This automatically imports from package.json:
- version
- author
- description
- license
- homepage
- githubUrl (from repository)
- keywords
- peerDependencies
2. Create extension provider
'use client';
import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
import { extensionConfig } from '../config';
export function MyExtensionProvider({ children }) {
return (
<ExtensionProvider metadata={extensionConfig}>
{children}
</ExtensionProvider>
);
}
3. Use in your app
import { MyExtensionProvider } from '@your-org/my-extension/hooks';
export default function RootLayout({ children }) {
return (
<MyExtensionProvider>
{children}
</MyExtensionProvider>
);
}
Core Features
Extension Config Helper
The createExtensionConfig helper creates a typed extension configuration by combining package.json data with manual metadata:
import { createExtensionConfig, type ExtensionConfigInput } from '@djangocfg/ext-base';
import packageJson from '../package.json';
export const extensionConfig = createExtensionConfig(packageJson, {
name: 'my-extension',
displayName: 'My Extension',
icon: 'Package',
category: 'utilities',
features: ['Feature list for marketplace'],
minVersion: '2.0.0',
githubStars: 100,
relatedExtensions: ['other-extension'],
examples: [
{
title: 'Example title',
description: 'Example description',
code: 'import { Component } from "@your-org/my-extension";',
language: 'tsx',
},
],
});
Automatically imported from package.json:
version - Package version
author - Author name (from string or object)
description - Package description
license - License type
homepage - Homepage URL
githubUrl - Repository URL
keywords - Keywords array
peerDependencies - Peer dependencies
Auto-generated:
npmUrl - npm package URL
installCommand - pnpm install command
tags - Same as keywords
Environment Configuration
import { isDevelopment, isProduction, isStaticBuild } from '@djangocfg/ext-base';
if (isDevelopment) {
console.log('Running in development mode');
}
API Factory
Create extension API instances with automatic configuration:
import { API } from './generated/ext_myextension';
import { createExtensionAPI } from '@djangocfg/ext-base/api';
export const apiMyExtension = createExtensionAPI(API);
import { usePagination, useInfinitePagination } from '@djangocfg/ext-base/hooks';
const { items, page, totalPages, goToPage, nextPage, prevPage } = usePagination({
keyPrefix: 'articles',
fetcher: async (page, pageSize) => {
const response = await api.articles.list({ page, page_size: pageSize });
return response.data;
},
pageSize: 20,
});
const { items, isLoading, hasMore, loadMore } = useInfinitePagination({
keyPrefix: 'articles',
fetcher: async (page, pageSize) => api.articles.list({ page, page_size: pageSize }).then(r => r.data),
pageSize: 20,
});
Type-Safe Context Creation
import { createExtensionContext } from '@djangocfg/ext-base/hooks';
interface MyContextValue {
data: any[];
refresh: () => void;
}
const { Provider, useContext: useMyContext } = createExtensionContext<MyContextValue>({
displayName: 'MyContext',
errorMessage: 'useMyContext must be used within MyProvider',
});
Logger
import { createExtensionLogger } from '@djangocfg/ext-base';
const logger = createExtensionLogger({ tag: 'my-extension' });
logger.info('Extension initialized');
logger.error('Operation failed', error);
logger.success('Completed!');
Auth Integration
import { useAuth } from '@djangocfg/ext-base/auth';
function MyComponent() {
const { user, isAuthenticated, login, logout } = useAuth();
return isAuthenticated ? (
<div>Welcome, {user?.email}</div>
) : (
<button onClick={login}>Login</button>
);
}
Package Exports
@djangocfg/ext-base | Server-safe exports (types, environment, API factory, logger, error handling) | Server & client components |
@djangocfg/ext-base/hooks | Client-only exports (ExtensionProvider, pagination hooks, context factory) | Client components only |
@djangocfg/ext-base/auth | Auth re-exports (useAuth, types) | Client components only |
@djangocfg/ext-base/api | API utilities (createExtensionAPI, getSharedAuthStorage) | Server & client components |
TypeScript Types
import type {
ExtensionMetadata,
ExtensionConfigInput,
ExtensionCategory,
ExtensionExample,
ExtensionProviderProps,
PaginatedResponse,
PaginationParams,
PaginationState,
InfinitePaginationReturn,
ExtensionLogger,
ExtensionError,
} from '@djangocfg/ext-base';
Best Practices
- Use
createExtensionConfig helper to maintain Single Source of Truth from package.json
- Always wrap your extension with
ExtensionProvider for proper registration
- Use Lucide icon names (not emoji) for
icon field
- Include comprehensive
features list for marketplace visibility
- Provide code
examples with proper syntax highlighting
- Use provided pagination hooks for consistent data fetching
- Use
createExtensionLogger with consistent tags for structured logging
- Separate client-only code using
/hooks entry point
License
MIT
Links