@djangocfg/ext-base 1.0.1 → 1.0.3

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,72 @@
1
+ /**
2
+ * Extension Base configuration
3
+ */
4
+
5
+ import type { ExtensionMetadata } from './types';
6
+ import packageJson from '../package.json';
7
+
8
+ export const extensionConfig: ExtensionMetadata = {
9
+ name: 'base',
10
+ version: packageJson.version,
11
+ author: 'DjangoCFG Team',
12
+ displayName: 'Extension Base',
13
+ description: 'Base utilities and common code for building DjangoCFG extensions. Includes CLI tool for managing extensions.',
14
+ license: 'MIT',
15
+ githubUrl: 'https://github.com/markolofsen/django-cfg',
16
+ homepage: 'https://djangocfg.com',
17
+ keywords: ['base', 'utilities', 'cli', 'toolkit', 'helpers', 'hooks'],
18
+
19
+ // Marketplace metadata
20
+ category: 'utilities',
21
+ tags: ['base', 'utilities', 'cli', 'toolkit'],
22
+ features: [
23
+ 'Extension registration system',
24
+ 'React hooks for pagination and infinite scroll',
25
+ 'Environment utilities and helpers',
26
+ 'CLI tool for extension management',
27
+ 'Type-safe context helpers',
28
+ 'Logger utilities',
29
+ ],
30
+ npmUrl: `https://www.npmjs.com/package/${packageJson.name}`,
31
+ installCommand: `pnpm add ${packageJson.name}`,
32
+ packagePeerDependencies: packageJson.peerDependencies,
33
+ examples: [
34
+ {
35
+ title: 'Basic Extension Setup',
36
+ description: 'Initialize a new DjangoCFG extension',
37
+ code: `import { createExtension } from '@djangocfg/ext-base';
38
+
39
+ const myExtension = createExtension({
40
+ name: 'my-extension',
41
+ version: '1.0.0',
42
+ register: (app) => {
43
+ console.log('Extension registered!');
44
+ },
45
+ });
46
+
47
+ export default myExtension;`,
48
+ language: 'typescript',
49
+ },
50
+ {
51
+ title: 'Using Pagination Hook',
52
+ description: 'Implement infinite scroll with usePagination',
53
+ code: `import { usePagination } from '@djangocfg/ext-base';
54
+
55
+ function DataList() {
56
+ const { data, loading, hasMore, loadMore } = usePagination({
57
+ fetchFn: (page) => fetch(\`/api/data?page=\${page}\`),
58
+ pageSize: 20,
59
+ });
60
+
61
+ return (
62
+ <div>
63
+ {data.map(item => <div key={item.id}>{item.name}</div>)}
64
+ {hasMore && <button onClick={loadMore}>Load More</button>}
65
+ </div>
66
+ );
67
+ }`,
68
+ language: 'tsx',
69
+ },
70
+ ],
71
+ githubStars: 245,
72
+ };
@@ -10,6 +10,60 @@ export interface ExtensionContextOptions {
10
10
  revalidateIfStale?: boolean;
11
11
  }
12
12
 
13
+ /**
14
+ * Extension category types
15
+ */
16
+ export type ExtensionCategory =
17
+ | 'forms' // Forms, CRM, Lead Management
18
+ | 'payments' // Payment Processing, Billing
19
+ | 'content' // Content Management, Marketing
20
+ | 'support' // Support, Helpdesk, Tickets
21
+ | 'utilities' // Tools, Base, Infrastructure
22
+ | 'analytics' // Analytics, Tracking, Monitoring
23
+ | 'security' // Security, Authentication, Authorization
24
+ | 'integration' // Third-party Integrations
25
+ | 'other'; // Other/Uncategorized
26
+
27
+ /**
28
+ * Extension categories with display names for CLI and UI
29
+ */
30
+ export const EXTENSION_CATEGORIES: Array<{ title: string; value: ExtensionCategory }> = [
31
+ { title: 'Forms', value: 'forms' },
32
+ { title: 'Payments', value: 'payments' },
33
+ { title: 'Content', value: 'content' },
34
+ { title: 'Support', value: 'support' },
35
+ { title: 'Utilities', value: 'utilities' },
36
+ { title: 'Analytics', value: 'analytics' },
37
+ { title: 'Security', value: 'security' },
38
+ { title: 'Integration', value: 'integration' },
39
+ { title: 'Other', value: 'other' },
40
+ ];
41
+
42
+ /**
43
+ * Code example for extension documentation
44
+ */
45
+ export interface ExtensionExample {
46
+ /**
47
+ * Example title
48
+ */
49
+ title: string;
50
+
51
+ /**
52
+ * Example description
53
+ */
54
+ description?: string;
55
+
56
+ /**
57
+ * Code snippet
58
+ */
59
+ code: string;
60
+
61
+ /**
62
+ * Programming language for syntax highlighting
63
+ */
64
+ language: string;
65
+ }
66
+
13
67
  export interface ExtensionMetadata {
14
68
  /**
15
69
  * Unique extension name (e.g., 'newsletter', 'payments')
@@ -58,21 +112,94 @@ export interface ExtensionMetadata {
58
112
  keywords?: string[];
59
113
 
60
114
  /**
61
- * Extension icon URL or emoji
62
- * @example '📧' or 'https://example.com/icon.png'
115
+ * Minimum required DjangoCFG version
116
+ */
117
+ minVersion?: string;
118
+
119
+ // ─────────────────────────────────────────────────────────────────────────
120
+ // Marketplace-specific fields
121
+ // ─────────────────────────────────────────────────────────────────────────
122
+
123
+ /**
124
+ * Extension category for marketplace organization
63
125
  */
64
- icon?: string;
126
+ category?: ExtensionCategory;
65
127
 
66
128
  /**
67
- * List of extension dependencies
68
- * @example ['payments', 'auth']
129
+ * Tags for search and filtering
69
130
  */
70
- dependencies?: string[];
131
+ tags?: string[];
71
132
 
72
133
  /**
73
- * Minimum required DjangoCFG version
134
+ * List of key features
74
135
  */
75
- minVersion?: string;
136
+ features?: string[];
137
+
138
+ /**
139
+ * npm package URL
140
+ * @example 'https://www.npmjs.com/package/@djangocfg/ext-newsletter'
141
+ */
142
+ npmUrl?: string;
143
+
144
+ /**
145
+ * Marketplace-safe ID (package name with @ and / replaced by -)
146
+ * @example '@djangocfg/ext-newsletter' -> 'djangocfg-ext-newsletter'
147
+ */
148
+ marketplaceId?: string;
149
+
150
+ /**
151
+ * Marketplace URL
152
+ * @example 'https://hub.djangocfg.com/extensions/djangocfg-ext-newsletter'
153
+ */
154
+ marketplaceUrl?: string;
155
+
156
+ /**
157
+ * Installation command
158
+ * @example 'pnpm add @djangocfg/ext-newsletter'
159
+ */
160
+ installCommand?: string;
161
+
162
+ /**
163
+ * Download URL for npm tarball
164
+ * @example 'https://registry.npmjs.org/@djangocfg/ext-newsletter/-/ext-newsletter-1.0.0.tgz'
165
+ */
166
+ downloadUrl?: string;
167
+
168
+ /**
169
+ * Code examples for documentation
170
+ */
171
+ examples?: ExtensionExample[];
172
+
173
+ /**
174
+ * npm package dependencies
175
+ */
176
+ packageDependencies?: Record<string, string>;
177
+
178
+ /**
179
+ * npm peer dependencies
180
+ */
181
+ packagePeerDependencies?: Record<string, string>;
182
+
183
+ /**
184
+ * npm dev dependencies
185
+ */
186
+ packageDevDependencies?: Record<string, string>;
187
+
188
+ /**
189
+ * README content in markdown
190
+ */
191
+ readme?: string;
192
+
193
+ /**
194
+ * Preview image URL (1200x630 recommended)
195
+ * @example 'https://unpkg.com/@djangocfg/ext-leads@latest/preview.svg'
196
+ */
197
+ preview?: string;
198
+
199
+ /**
200
+ * GitHub stars count
201
+ */
202
+ githubStars?: number;
76
203
  }
77
204
 
78
205
  export interface ExtensionProviderProps {
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Helper to create extension configuration from package.json
3
+ */
4
+
5
+ import type { ExtensionMetadata } from '../types';
6
+
7
+ /**
8
+ * Package.json structure
9
+ */
10
+ interface PackageJson {
11
+ name: string;
12
+ version: string;
13
+ description?: string;
14
+ keywords?: string[];
15
+ author?: string | { name: string; email?: string; url?: string };
16
+ license?: string;
17
+ homepage?: string;
18
+ repository?: string | { type: string; url: string; directory?: string };
19
+ dependencies?: Record<string, string>;
20
+ peerDependencies?: Record<string, string>;
21
+ devDependencies?: Record<string, string>;
22
+ }
23
+
24
+ /**
25
+ * Manual metadata fields that must be provided
26
+ */
27
+ export interface ExtensionConfigInput {
28
+ /**
29
+ * Extension short name (e.g., 'leads', 'payments')
30
+ */
31
+ name: string;
32
+
33
+ /**
34
+ * Display name for marketplace
35
+ */
36
+ displayName: string;
37
+
38
+ /**
39
+ * Extension category
40
+ */
41
+ category: ExtensionMetadata['category'];
42
+
43
+ /**
44
+ * Key features list
45
+ */
46
+ features: string[];
47
+
48
+ /**
49
+ * Code examples (optional)
50
+ */
51
+ examples?: ExtensionMetadata['examples'];
52
+
53
+ /**
54
+ * Minimum required DjangoCFG version (optional)
55
+ */
56
+ minVersion?: string;
57
+
58
+ /**
59
+ * GitHub stars count (optional)
60
+ */
61
+ githubStars?: number;
62
+ }
63
+
64
+ /**
65
+ * Create extension configuration from package.json + manual metadata
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * import packageJson from '../package.json';
70
+ * import { createExtensionConfig } from '@djangocfg/ext-base';
71
+ *
72
+ * export const extensionConfig = createExtensionConfig(packageJson, {
73
+ * name: 'leads',
74
+ * displayName: 'Leads & Forms',
75
+ * icon: 'FileText',
76
+ * category: 'forms',
77
+ * features: [
78
+ * 'Contact form components',
79
+ * 'Lead tracking',
80
+ * ],
81
+ * });
82
+ * ```
83
+ */
84
+ /**
85
+ * Replace workspace:* with latest in dependencies
86
+ */
87
+ function replaceWorkspaceDeps(deps?: Record<string, string>): Record<string, string> | undefined {
88
+ if (!deps) return undefined;
89
+
90
+ const result: Record<string, string> = {};
91
+ for (const [key, value] of Object.entries(deps)) {
92
+ result[key] = value === 'workspace:*' ? 'latest' : value;
93
+ }
94
+ return result;
95
+ }
96
+
97
+ export function createExtensionConfig(
98
+ packageJson: PackageJson,
99
+ config: ExtensionConfigInput
100
+ ): ExtensionMetadata {
101
+ // Extract author name
102
+ const author = typeof packageJson.author === 'string'
103
+ ? packageJson.author
104
+ : packageJson.author?.name || 'Unknown';
105
+
106
+ // Extract repository URL
107
+ const githubUrl = typeof packageJson.repository === 'string'
108
+ ? packageJson.repository
109
+ : packageJson.repository?.url;
110
+
111
+ // Generate npm tarball download URL
112
+ // Format: https://registry.npmjs.org/{package}/-/{name-without-scope}-{version}.tgz
113
+ const packageNameWithoutScope = packageJson.name.split('/').pop() || packageJson.name;
114
+ const downloadUrl = `https://registry.npmjs.org/${packageJson.name}/-/${packageNameWithoutScope}-${packageJson.version}.tgz`;
115
+
116
+ // Generate marketplace-safe ID (replace @ and / with -)
117
+ // @djangocfg/ext-newsletter -> djangocfg-ext-newsletter
118
+ // somepackage -> somepackage
119
+ const marketplaceId = packageJson.name.replace('@', '').replace('/', '-');
120
+
121
+ return {
122
+ // From package.json
123
+ name: config.name,
124
+ version: packageJson.version,
125
+ author,
126
+ description: packageJson.description,
127
+ keywords: packageJson.keywords,
128
+ license: packageJson.license,
129
+ homepage: packageJson.homepage,
130
+ githubUrl,
131
+ packageDependencies: replaceWorkspaceDeps(packageJson.dependencies),
132
+ packagePeerDependencies: replaceWorkspaceDeps(packageJson.peerDependencies),
133
+ packageDevDependencies: replaceWorkspaceDeps(packageJson.devDependencies),
134
+
135
+ // From manual config
136
+ displayName: config.displayName,
137
+ category: config.category,
138
+ features: config.features,
139
+ examples: config.examples,
140
+ minVersion: config.minVersion,
141
+ githubStars: config.githubStars,
142
+
143
+ // Auto-generated
144
+ npmUrl: `https://www.npmjs.com/package/${packageJson.name}`,
145
+ marketplaceId,
146
+ // Only generate marketplace URL for official @djangocfg extensions
147
+ marketplaceUrl: packageJson.name.startsWith('@djangocfg/ext-')
148
+ ? `https://hub.djangocfg.com/extensions/${marketplaceId}`
149
+ : undefined,
150
+ installCommand: `pnpm add ${packageJson.name}`,
151
+ downloadUrl,
152
+ tags: packageJson.keywords,
153
+ preview: `https://unpkg.com/${packageJson.name}@latest/preview.png`,
154
+ };
155
+ }
@@ -8,3 +8,8 @@ export {
8
8
  formatErrorMessage,
9
9
  handleExtensionError,
10
10
  } from './errors';
11
+
12
+ export {
13
+ createExtensionConfig,
14
+ type ExtensionConfigInput,
15
+ } from './createExtensionConfig';
@@ -0,0 +1,64 @@
1
+ <div align="center">
2
+
3
+ ![DjangoCFG Extension Preview](https://unpkg.com/__PACKAGE_NAME__@latest/preview.png)
4
+
5
+ __MARKETPLACE_LINK__
6
+
7
+ </div>
8
+
9
+ # __PACKAGE_NAME__
10
+
11
+ __DESCRIPTION__
12
+
13
+ **Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
14
+
15
+ ## Features
16
+
17
+ - Feature 1
18
+ - Feature 2
19
+ - Feature 3
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pnpm add __PACKAGE_NAME__
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Provider Setup
30
+
31
+ ```typescript
32
+ import { __PROVIDER_NAME__ExtensionProvider } from '__PACKAGE_NAME__/hooks';
33
+
34
+ export default function RootLayout({ children }) {
35
+ return (
36
+ <__PROVIDER_NAME__ExtensionProvider>
37
+ {children}
38
+ </__PROVIDER_NAME__ExtensionProvider>
39
+ );
40
+ }
41
+ ```
42
+
43
+ ### Using Hooks
44
+
45
+ ```typescript
46
+ 'use client';
47
+
48
+ import { use__PROVIDER_NAME__ } from '__PACKAGE_NAME__/hooks';
49
+
50
+ export function MyComponent() {
51
+ const context = use__PROVIDER_NAME__();
52
+
53
+ return <div>Your component</div>;
54
+ }
55
+ ```
56
+
57
+ ## License
58
+
59
+ MIT
60
+
61
+ ## Links
62
+
63
+ - [DjangoCFG Documentation](https://djangocfg.com)
64
+ - [GitHub](https://github.com/markolofsen/django-cfg)
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "__PACKAGE_NAME__",
3
+ "version": "1.0.0",
4
+ "description": "__DESCRIPTION__",
5
+ "keywords": [
6
+ "django",
7
+ "djangocfg",
8
+ "extension",
9
+ "__NAME__",
10
+ "typescript",
11
+ "react"
12
+ ],
13
+ "author": {
14
+ "name": "DjangoCFG",
15
+ "url": "https://djangocfg.com"
16
+ },
17
+ "homepage": "https://hub.djangocfg.com/extensions/__MARKETPLACE_ID__",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/markolofsen/django-cfg.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/markolofsen/django-cfg/issues"
24
+ },
25
+ "license": "MIT",
26
+ "type": "module",
27
+ "main": "./dist/index.cjs",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.js",
34
+ "require": "./dist/index.cjs"
35
+ },
36
+ "./hooks": {
37
+ "types": "./dist/hooks.d.ts",
38
+ "import": "./dist/hooks.js",
39
+ "require": "./dist/hooks.cjs"
40
+ },
41
+ "./config": {
42
+ "types": "./dist/config.d.ts",
43
+ "import": "./dist/config.js",
44
+ "require": "./dist/config.cjs"
45
+ }
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "src",
50
+ "preview.png"
51
+ ],
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "dev": "tsup --watch",
55
+ "check": "tsc --noEmit"
56
+ },
57
+ "peerDependencies": {
58
+ "@djangocfg/api": "latest",
59
+ "@djangocfg/ext-base": "latest",
60
+ "@djangocfg/ui-core": "latest",
61
+ "@djangocfg/ui-nextjs": "latest",
62
+ "consola": "^3.4.2",
63
+ "lucide-react": "^0.545.0",
64
+ "next": "^15.5.7",
65
+ "react": "^18 || ^19",
66
+ "react-dom": "^18 || ^19",
67
+ "swr": "^2.3.7"
68
+ },
69
+ "devDependencies": {
70
+ "@djangocfg/api": "latest",
71
+ "@djangocfg/ext-base": "latest",
72
+ "@djangocfg/typescript-config": "latest",
73
+ "@types/node": "^24.7.2",
74
+ "@types/react": "^19.0.0",
75
+ "consola": "^3.4.2",
76
+ "swr": "^2.3.7",
77
+ "tsup": "^8.5.0",
78
+ "typescript": "^5.9.3"
79
+ }
80
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * __DISPLAY_NAME__ extension configuration
3
+ */
4
+
5
+ import { createExtensionConfig } from '@djangocfg/ext-base';
6
+ import packageJson from '../package.json';
7
+
8
+ export const extensionConfig = createExtensionConfig(packageJson, {
9
+ name: '__NAME__',
10
+ displayName: '__DISPLAY_NAME__',
11
+ category: '__CATEGORY__',
12
+ features: [
13
+ 'Feature 1',
14
+ 'Feature 2',
15
+ 'Feature 3',
16
+ ],
17
+ minVersion: '2.0.0',
18
+ examples: [
19
+ {
20
+ title: 'Basic Usage',
21
+ description: 'How to use this extension',
22
+ code: `import { __PROVIDER_NAME__ExtensionProvider } from '__PACKAGE_NAME__/hooks';
23
+
24
+ export default function RootLayout({ children }) {
25
+ return (
26
+ <__PROVIDER_NAME__ExtensionProvider>
27
+ {children}
28
+ </__PROVIDER_NAME__ExtensionProvider>
29
+ );
30
+ }`,
31
+ language: 'tsx',
32
+ },
33
+ ],
34
+ });
@@ -0,0 +1,41 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Main __DISPLAY_NAME__ Context
5
+ */
6
+
7
+ import { createContext, useContext, type ReactNode } from 'react';
8
+
9
+ interface __PROVIDER_NAME__ContextValue {
10
+ // Add your context values here
11
+ }
12
+
13
+ const __PROVIDER_NAME__Context = createContext<__PROVIDER_NAME__ContextValue | undefined>(undefined);
14
+
15
+ export interface __PROVIDER_NAME__ProviderProps {
16
+ children: ReactNode;
17
+ }
18
+
19
+ export function __PROVIDER_NAME__Provider({ children }: __PROVIDER_NAME__ProviderProps) {
20
+ const value: __PROVIDER_NAME__ContextValue = {
21
+ // Implement your context logic here
22
+ };
23
+
24
+ return (
25
+ <__PROVIDER_NAME__Context.Provider value={value}>
26
+ {children}
27
+ </__PROVIDER_NAME__Context.Provider>
28
+ );
29
+ }
30
+
31
+ export function use__PROVIDER_NAME__() {
32
+ const context = useContext(__PROVIDER_NAME__Context);
33
+ if (context === undefined) {
34
+ throw new Error('use__PROVIDER_NAME__ must be used within __PROVIDER_NAME__Provider');
35
+ }
36
+ return context;
37
+ }
38
+
39
+ export function use__PROVIDER_NAME__Optional() {
40
+ return useContext(__PROVIDER_NAME__Context);
41
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Main __DISPLAY_NAME__ Extension Provider
3
+ *
4
+ * Wraps all contexts with ExtensionProvider for proper registration
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import type { ReactNode } from 'react';
10
+ import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
11
+ import { extensionConfig } from '../config';
12
+ import { __PROVIDER_NAME__Provider } from './__PROVIDER_NAME__Context';
13
+
14
+ interface __PROVIDER_NAME__ExtensionProviderProps {
15
+ children: ReactNode;
16
+ }
17
+
18
+ /**
19
+ * Main provider for __DISPLAY_NAME__ extension
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * <__PROVIDER_NAME__ExtensionProvider>
24
+ * <YourApp />
25
+ * </__PROVIDER_NAME__ExtensionProvider>
26
+ * ```
27
+ */
28
+ export function __PROVIDER_NAME__ExtensionProvider({ children }: __PROVIDER_NAME__ExtensionProviderProps) {
29
+ return (
30
+ <ExtensionProvider metadata={extensionConfig}>
31
+ <__PROVIDER_NAME__Provider>
32
+ {children}
33
+ </__PROVIDER_NAME__Provider>
34
+ </ExtensionProvider>
35
+ );
36
+ }
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * __PACKAGE_NAME__/hooks
5
+ * React hooks and client-only components
6
+ *
7
+ * This entry point includes React components, hooks, and SWR functionality.
8
+ * NOT safe for Server Components.
9
+ */
10
+
11
+ // ============================================================================
12
+ // Re-export everything from main entry (types, constants)
13
+ // ============================================================================
14
+ export * from '../index';
15
+
16
+ // ============================================================================
17
+ // Contexts & Hooks
18
+ // ============================================================================
19
+ export {
20
+ __PROVIDER_NAME__ExtensionProvider,
21
+ } from '../contexts/__PROVIDER_NAME__ExtensionProvider';
22
+
23
+ export {
24
+ __PROVIDER_NAME__Provider,
25
+ use__PROVIDER_NAME__,
26
+ use__PROVIDER_NAME__Optional,
27
+ } from '../contexts/__PROVIDER_NAME__Context';