@djangocfg/ext-base 1.0.0 → 1.0.2

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.
Files changed (41) hide show
  1. package/README.md +140 -176
  2. package/package.json +28 -12
  3. package/preview.png +0 -0
  4. package/src/cli/index.ts +274 -0
  5. package/src/config.ts +17 -0
  6. package/src/index.ts +2 -1
  7. package/src/metadata.ts +73 -0
  8. package/src/types/context.ts +124 -3
  9. package/src/utils/createExtensionConfig.ts +139 -0
  10. package/src/utils/index.ts +5 -0
  11. package/templates/extension-template/README.md.template +62 -0
  12. package/templates/extension-template/package.json.template +73 -0
  13. package/templates/extension-template/preview.png +0 -0
  14. package/templates/extension-template/src/components/.gitkeep +0 -0
  15. package/templates/extension-template/src/config.ts +35 -0
  16. package/templates/extension-template/src/contexts/__PROVIDER_NAME__Context.tsx +41 -0
  17. package/templates/extension-template/src/contexts/__PROVIDER_NAME__ExtensionProvider.tsx +36 -0
  18. package/templates/extension-template/src/hooks/index.ts +27 -0
  19. package/templates/extension-template/src/index.ts +17 -0
  20. package/templates/extension-template/src/types.ts +7 -0
  21. package/templates/extension-template/tsconfig.json +8 -0
  22. package/templates/extension-template/tsup.config.ts +26 -0
  23. package/dist/api.cjs +0 -41
  24. package/dist/api.d.cts +0 -35
  25. package/dist/api.d.ts +0 -35
  26. package/dist/api.js +0 -2
  27. package/dist/auth.cjs +0 -10
  28. package/dist/auth.d.cts +0 -1
  29. package/dist/auth.d.ts +0 -1
  30. package/dist/auth.js +0 -2
  31. package/dist/chunk-3RG5ZIWI.js +0 -8
  32. package/dist/chunk-MECBWZG4.js +0 -44
  33. package/dist/chunk-YQGNYUBX.js +0 -67
  34. package/dist/hooks.cjs +0 -190
  35. package/dist/hooks.d.cts +0 -96
  36. package/dist/hooks.d.ts +0 -96
  37. package/dist/hooks.js +0 -65
  38. package/dist/index.cjs +0 -131
  39. package/dist/index.d.cts +0 -246
  40. package/dist/index.d.ts +0 -246
  41. package/dist/index.js +0 -3
package/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ <div align="center">
2
+
3
+ ![DjangoCFG Extension Preview](https://unpkg.com/@djangocfg/ext-base@latest/preview.png)
4
+
5
+ </div>
6
+
1
7
  # @djangocfg/ext-base
2
8
 
3
9
  Base utilities and common code for building DjangoCFG extensions.
@@ -6,17 +12,16 @@ Base utilities and common code for building DjangoCFG extensions.
6
12
 
7
13
  ## What is this?
8
14
 
9
- `@djangocfg/ext-base` is a foundation library for DjangoCFG extensions. It provides:
15
+ `@djangocfg/ext-base` provides the foundation for DjangoCFG extensions with:
10
16
 
11
- - **Extension registration system** - automatic extension metadata tracking
12
- - **Common React hooks** - pagination, infinite scroll, data fetching patterns
13
- - **Environment utilities** - isDevelopment, isProduction, isStaticBuild helpers
14
- - **Type-safe context helpers** - factory functions for creating contexts
15
- - **Logger utilities** - structured logging with tags
16
- - **Auth integration** - convenient re-exports of useAuth
17
- - **TypeScript types** - shared types for all extensions
17
+ - Extension registration system and metadata tracking
18
+ - React hooks for pagination, infinite scroll, and data fetching
19
+ - Environment utilities (isDevelopment, isProduction, isStaticBuild)
20
+ - Type-safe context helpers and logger utilities
21
+ - Auth integration and API factory
22
+ - **CLI tool** for managing extensions
18
23
 
19
- This package is used internally by all official DjangoCFG extensions (newsletter, payments, support, leads, knowbase) and can be used to build your own custom extensions.
24
+ Used internally by official extensions (newsletter, payments, support, leads, knowbase) and for building custom extensions.
20
25
 
21
26
  ## Install
22
27
 
@@ -24,27 +29,64 @@ This package is used internally by all official DjangoCFG extensions (newsletter
24
29
  pnpm add @djangocfg/ext-base
25
30
  ```
26
31
 
32
+ ## CLI Usage
33
+
34
+ The package includes a CLI tool for creating new DjangoCFG extensions:
35
+
36
+ ```bash
37
+ # Create a new extension with interactive wizard
38
+ djangocfg-ext create
39
+
40
+ # Show help
41
+ djangocfg-ext help
42
+ ```
43
+
44
+ The CLI will guide you through creating a new extension with proper structure and configuration using the `createExtensionConfig` helper.
45
+
27
46
  ## Quick Start
28
47
 
29
48
  ### 1. Create extension metadata
30
49
 
50
+ Use the `createExtensionConfig` helper to automatically pull data from package.json:
51
+
31
52
  ```typescript
32
53
  // src/config.ts
33
- import type { ExtensionMetadata } from '@djangocfg/ext-base';
54
+ import { createExtensionConfig } from '@djangocfg/ext-base';
55
+ import packageJson from '../package.json';
34
56
 
35
- export const extensionConfig: ExtensionMetadata = {
57
+ export const extensionConfig = createExtensionConfig(packageJson, {
36
58
  name: 'my-extension',
37
- version: '1.0.0',
38
- author: 'Your Name',
39
59
  displayName: 'My Extension',
40
- description: 'Amazing extension functionality',
41
- icon: '🚀',
42
- license: 'MIT',
43
- keywords: ['extension', 'feature'],
44
- };
60
+ icon: 'Rocket', // Lucide icon name
61
+ category: 'utilities',
62
+ features: [
63
+ 'Feature 1',
64
+ 'Feature 2',
65
+ 'Feature 3',
66
+ ],
67
+ minVersion: '2.0.0',
68
+ examples: [
69
+ {
70
+ title: 'Basic Usage',
71
+ description: 'How to use this extension',
72
+ code: `import { MyComponent } from '@your-org/my-extension';`,
73
+ language: 'tsx',
74
+ },
75
+ ],
76
+ });
45
77
  ```
46
78
 
47
- ### 2. Create your extension provider
79
+ This automatically imports from package.json:
80
+ - version
81
+ - author
82
+ - description
83
+ - license
84
+ - homepage
85
+ - githubUrl (from repository)
86
+ - keywords
87
+ - peerDependencies
88
+
89
+ ### 2. Create extension provider
48
90
 
49
91
  ```typescript
50
92
  // src/contexts/MyExtensionProvider.tsx
@@ -56,7 +98,6 @@ import { extensionConfig } from '../config';
56
98
  export function MyExtensionProvider({ children }) {
57
99
  return (
58
100
  <ExtensionProvider metadata={extensionConfig}>
59
- {/* Your extension contexts here */}
60
101
  {children}
61
102
  </ExtensionProvider>
62
103
  );
@@ -77,60 +118,73 @@ export default function RootLayout({ children }) {
77
118
  }
78
119
  ```
79
120
 
80
- The extension will automatically register itself and log in development mode:
81
- ```
82
- [ext-base] Extension registered: My Extension v1.0.0
83
- ```
84
-
85
121
  ## Core Features
86
122
 
87
- ### Environment Configuration
123
+ ### Extension Config Helper
88
124
 
89
- ```typescript
90
- import { isDevelopment, isProduction, isStaticBuild, isClient, isServer } from '@djangocfg/ext-base';
125
+ The `createExtensionConfig` helper creates a typed extension configuration by combining package.json data with manual metadata:
91
126
 
92
- if (isDevelopment) {
93
- console.log('Running in development mode');
94
- }
127
+ ```typescript
128
+ import { createExtensionConfig, type ExtensionConfigInput } from '@djangocfg/ext-base';
129
+ import packageJson from '../package.json';
95
130
 
96
- if (isStaticBuild) {
97
- // Special handling for Next.js static export
98
- }
131
+ export const extensionConfig = createExtensionConfig(packageJson, {
132
+ // Required fields
133
+ name: 'my-extension',
134
+ displayName: 'My Extension',
135
+ icon: 'Package', // Lucide icon name
136
+ category: 'utilities', // 'forms' | 'payments' | 'content' | 'support' | 'utilities' | 'analytics' | 'security' | 'integration' | 'other'
137
+ features: ['Feature list for marketplace'],
138
+
139
+ // Optional fields
140
+ minVersion: '2.0.0',
141
+ githubStars: 100,
142
+ relatedExtensions: ['other-extension'],
143
+ examples: [
144
+ {
145
+ title: 'Example title',
146
+ description: 'Example description',
147
+ code: 'import { Component } from "@your-org/my-extension";',
148
+ language: 'tsx',
149
+ },
150
+ ],
151
+ });
99
152
  ```
100
153
 
101
- ### API Factory
154
+ **Automatically imported from package.json:**
155
+ - `version` - Package version
156
+ - `author` - Author name (from string or object)
157
+ - `description` - Package description
158
+ - `license` - License type
159
+ - `homepage` - Homepage URL
160
+ - `githubUrl` - Repository URL
161
+ - `keywords` - Keywords array
162
+ - `peerDependencies` - Peer dependencies
163
+
164
+ **Auto-generated:**
165
+ - `npmUrl` - npm package URL
166
+ - `installCommand` - pnpm install command
167
+ - `tags` - Same as keywords
102
168
 
103
- Create extension API instances with shared authentication in one line:
169
+ ### Environment Configuration
104
170
 
105
171
  ```typescript
106
- // src/api/index.ts
107
- import { API } from './generated/ext_myextension';
108
- import { createExtensionAPI } from '@djangocfg/ext-base/api';
172
+ import { isDevelopment, isProduction, isStaticBuild } from '@djangocfg/ext-base';
109
173
 
110
- // That's it! All configuration is handled automatically:
111
- // - API URL from environment
112
- // - Static build detection
113
- // - Shared authentication storage from @djangocfg/api
114
- export const apiMyExtension = createExtensionAPI(API);
174
+ if (isDevelopment) {
175
+ console.log('Running in development mode');
176
+ }
115
177
  ```
116
178
 
117
- **Before (manual setup):**
118
- ```typescript
119
- import { API } from './generated/ext_myextension';
120
- import { api as accountsApi } from '@djangocfg/api';
121
-
122
- const isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === 'true';
123
- const apiUrl = isStaticBuild ? '' : process.env.NEXT_PUBLIC_API_URL || '';
124
- const storage = (accountsApi as any)._storage;
179
+ ### API Factory
125
180
 
126
- export const apiMyExtension = new API(apiUrl, { storage });
127
- ```
181
+ Create extension API instances with automatic configuration:
128
182
 
129
- **After (with factory):**
130
183
  ```typescript
131
184
  import { API } from './generated/ext_myextension';
132
185
  import { createExtensionAPI } from '@djangocfg/ext-base/api';
133
186
 
187
+ // Handles API URL, static build detection, and shared auth automatically
134
188
  export const apiMyExtension = createExtensionAPI(API);
135
189
  ```
136
190
 
@@ -140,23 +194,19 @@ export const apiMyExtension = createExtensionAPI(API);
140
194
  import { usePagination, useInfinitePagination } from '@djangocfg/ext-base/hooks';
141
195
 
142
196
  // Standard pagination
143
- const { items, page, pageSize, totalPages, goToPage, nextPage, prevPage } = usePagination({
197
+ const { items, page, totalPages, goToPage, nextPage, prevPage } = usePagination({
144
198
  keyPrefix: 'articles',
145
199
  fetcher: async (page, pageSize) => {
146
200
  const response = await api.articles.list({ page, page_size: pageSize });
147
201
  return response.data;
148
202
  },
149
- initialPage: 1,
150
203
  pageSize: 20,
151
204
  });
152
205
 
153
206
  // Infinite scroll
154
207
  const { items, isLoading, hasMore, loadMore } = useInfinitePagination({
155
208
  keyPrefix: 'articles',
156
- fetcher: async (page, pageSize) => {
157
- const response = await api.articles.list({ page, page_size: pageSize });
158
- return response.data;
159
- },
209
+ fetcher: async (page, pageSize) => api.articles.list({ page, page_size: pageSize }).then(r => r.data),
160
210
  pageSize: 20,
161
211
  });
162
212
  ```
@@ -175,12 +225,6 @@ const { Provider, useContext: useMyContext } = createExtensionContext<MyContextV
175
225
  displayName: 'MyContext',
176
226
  errorMessage: 'useMyContext must be used within MyProvider',
177
227
  });
178
-
179
- // In components
180
- export function MyComponent() {
181
- const { data, refresh } = useMyContext();
182
- return <div>{data.length} items</div>;
183
- }
184
228
  ```
185
229
 
186
230
  ### Logger
@@ -188,14 +232,11 @@ export function MyComponent() {
188
232
  ```typescript
189
233
  import { createExtensionLogger } from '@djangocfg/ext-base';
190
234
 
191
- const logger = createExtensionLogger({
192
- tag: 'my-extension',
193
- level: 'info',
194
- });
235
+ const logger = createExtensionLogger({ tag: 'my-extension' });
195
236
 
196
237
  logger.info('Extension initialized');
197
- logger.error('Something went wrong', error);
198
- logger.success('Operation completed!');
238
+ logger.error('Operation failed', error);
239
+ logger.success('Completed!');
199
240
  ```
200
241
 
201
242
  ### Auth Integration
@@ -206,62 +247,34 @@ import { useAuth } from '@djangocfg/ext-base/auth';
206
247
  function MyComponent() {
207
248
  const { user, isAuthenticated, login, logout } = useAuth();
208
249
 
209
- if (!isAuthenticated) {
210
- return <button onClick={login}>Login</button>;
211
- }
212
-
213
- return <div>Welcome, {user?.email}</div>;
214
- }
215
- ```
216
-
217
- ### Error Handling
218
-
219
- ```typescript
220
- import { handleError, formatError } from '@djangocfg/ext-base';
221
-
222
- try {
223
- await someOperation();
224
- } catch (error) {
225
- handleError(error, (formattedError) => {
226
- logger.error('Operation failed:', formattedError);
227
- });
250
+ return isAuthenticated ? (
251
+ <div>Welcome, {user?.email}</div>
252
+ ) : (
253
+ <button onClick={login}>Login</button>
254
+ );
228
255
  }
229
256
  ```
230
257
 
231
258
  ## Package Exports
232
259
 
233
- ### Main entry (`@djangocfg/ext-base`)
234
- Server-safe exports - can be used in both client and server components:
235
- - All TypeScript types
236
- - Environment configuration (isDevelopment, isProduction, etc.)
237
- - API factory (createExtensionAPI)
238
- - Logger utilities
239
- - Error handling utilities
240
-
241
- ### Hooks entry (`@djangocfg/ext-base/hooks`)
242
- Client-only exports:
243
- - `ExtensionProvider` - main provider component
244
- - `usePagination` - standard pagination hook
245
- - `useInfinitePagination` - infinite scroll hook
246
- - `createExtensionContext` - context factory
247
-
248
- ### Auth entry (`@djangocfg/ext-base/auth`)
249
- Auth re-exports:
250
- - `useAuth` - authentication hook
251
- - `UserProfile` type
252
- - `AuthContextType` type
253
-
254
- ### API entry (`@djangocfg/ext-base/api`)
255
- API utilities:
256
- - `createExtensionAPI` - API instance factory
257
- - `getSharedAuthStorage` - Get shared auth storage
260
+ | Export | Description | Usage |
261
+ |--------|-------------|-------|
262
+ | `@djangocfg/ext-base` | Server-safe exports (types, environment, API factory, logger, error handling) | Server & client components |
263
+ | `@djangocfg/ext-base/hooks` | Client-only exports (ExtensionProvider, pagination hooks, context factory) | Client components only |
264
+ | `@djangocfg/ext-base/auth` | Auth re-exports (useAuth, types) | Client components only |
265
+ | `@djangocfg/ext-base/api` | API utilities (createExtensionAPI, getSharedAuthStorage) | Server & client components |
258
266
 
259
267
  ## TypeScript Types
260
268
 
261
269
  ```typescript
262
270
  import type {
263
- // Extension metadata
271
+ // Extension configuration
264
272
  ExtensionMetadata,
273
+ ExtensionConfigInput,
274
+ ExtensionCategory,
275
+ ExtensionExample,
276
+
277
+ // Provider
265
278
  ExtensionProviderProps,
266
279
 
267
280
  // Pagination
@@ -270,71 +283,22 @@ import type {
270
283
  PaginationState,
271
284
  InfinitePaginationReturn,
272
285
 
273
- // Logger
286
+ // Utilities
274
287
  ExtensionLogger,
275
- LoggerOptions,
276
-
277
- // Errors
278
288
  ExtensionError,
279
- ErrorHandler,
280
-
281
- // Context
282
- ExtensionContextOptions,
283
289
  } from '@djangocfg/ext-base';
284
290
  ```
285
291
 
286
- ## Example: Complete Extension
287
-
288
- ```typescript
289
- // config.ts
290
- export const extensionConfig: ExtensionMetadata = {
291
- name: 'blog',
292
- version: '1.0.0',
293
- author: 'Your Company',
294
- displayName: 'Blog',
295
- description: 'Blog management system',
296
- icon: '📝',
297
- keywords: ['blog', 'articles'],
298
- };
299
-
300
- // contexts/BlogProvider.tsx
301
- 'use client';
302
-
303
- import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
304
- import { useInfinitePagination } from '@djangocfg/ext-base/hooks';
305
- import { createExtensionLogger } from '@djangocfg/ext-base';
306
- import { extensionConfig } from '../config';
307
-
308
- const logger = createExtensionLogger({ tag: 'blog' });
309
-
310
- export function BlogProvider({ children }) {
311
- const { items, loadMore, hasMore } = useInfinitePagination({
312
- keyPrefix: 'blog-articles',
313
- fetcher: async (page, pageSize) => {
314
- const response = await api.articles.list({ page, page_size: pageSize });
315
- return response.data;
316
- },
317
- });
318
-
319
- logger.info('Blog provider initialized with', items.length, 'articles');
320
-
321
- return (
322
- <ExtensionProvider metadata={extensionConfig}>
323
- {/* Your contexts here */}
324
- {children}
325
- </ExtensionProvider>
326
- );
327
- }
328
- ```
329
-
330
292
  ## Best Practices
331
293
 
332
- 1. **Always use ExtensionProvider** - Wrap your extension with it for proper registration
333
- 2. **Define metadata** - Create a `config.ts` file with complete metadata
334
- 3. **Use provided hooks** - Leverage `usePagination` and `useInfinitePagination`
335
- 4. **Structured logging** - Use `createExtensionLogger` with consistent tags
336
- 5. **Type safety** - Import types from `@djangocfg/ext-base`
337
- 6. **Separate entry points** - Use `/hooks` for client code, main entry for server-safe code
294
+ - Use `createExtensionConfig` helper to maintain Single Source of Truth from package.json
295
+ - Always wrap your extension with `ExtensionProvider` for proper registration
296
+ - Use Lucide icon names (not emoji) for `icon` field
297
+ - Include comprehensive `features` list for marketplace visibility
298
+ - Provide code `examples` with proper syntax highlighting
299
+ - Use provided pagination hooks for consistent data fetching
300
+ - Use `createExtensionLogger` with consistent tags for structured logging
301
+ - Separate client-only code using `/hooks` entry point
338
302
 
339
303
  ## License
340
304
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ext-base",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Base utilities and common code for DjangoCFG extensions",
5
5
  "keywords": [
6
6
  "django",
@@ -27,54 +27,70 @@
27
27
  "license": "MIT",
28
28
  "type": "module",
29
29
  "main": "./dist/index.cjs",
30
- "module": "./dist/index.mjs",
30
+ "module": "./dist/index.js",
31
31
  "types": "./dist/index.d.ts",
32
32
  "exports": {
33
33
  ".": {
34
34
  "types": "./dist/index.d.ts",
35
- "import": "./dist/index.mjs",
35
+ "import": "./dist/index.js",
36
36
  "require": "./dist/index.cjs"
37
37
  },
38
38
  "./hooks": {
39
39
  "types": "./dist/hooks.d.ts",
40
- "import": "./dist/hooks.mjs",
40
+ "import": "./dist/hooks.js",
41
41
  "require": "./dist/hooks.cjs"
42
42
  },
43
43
  "./auth": {
44
44
  "types": "./dist/auth.d.ts",
45
- "import": "./dist/auth.mjs",
45
+ "import": "./dist/auth.js",
46
46
  "require": "./dist/auth.cjs"
47
47
  },
48
48
  "./api": {
49
49
  "types": "./dist/api.d.ts",
50
- "import": "./dist/api.mjs",
50
+ "import": "./dist/api.js",
51
51
  "require": "./dist/api.cjs"
52
52
  }
53
53
  },
54
54
  "files": [
55
55
  "dist",
56
- "src"
56
+ "src",
57
+ "preview.png",
58
+ "templates"
57
59
  ],
60
+ "bin": {
61
+ "djangocfg-ext": "./dist/cli.mjs"
62
+ },
58
63
  "scripts": {
59
64
  "build": "tsup",
60
65
  "dev": "tsup --watch",
61
- "check": "tsc --noEmit"
66
+ "check": "tsc --noEmit",
67
+ "cli": "tsx src/cli/index.ts",
68
+ "cli:help": "tsx src/cli/index.ts --help",
69
+ "cli:list": "tsx src/cli/index.ts list",
70
+ "cli:info": "tsx src/cli/index.ts info"
62
71
  },
63
72
  "peerDependencies": {
64
- "@djangocfg/api": "^2.1.14",
73
+ "@djangocfg/api": "^2.1.15",
65
74
  "consola": "^3.4.2",
66
75
  "react": "^18 || ^19",
67
76
  "react-dom": "^18 || ^19",
68
77
  "swr": "^2.3.7"
69
78
  },
79
+ "dependencies": {
80
+ "chalk": "^5.3.0",
81
+ "consola": "^3.4.2",
82
+ "picocolors": "^1.1.1",
83
+ "prompts": "^2.4.2"
84
+ },
70
85
  "devDependencies": {
71
- "@djangocfg/api": "^2.1.14",
72
- "@djangocfg/typescript-config": "^2.1.14",
86
+ "@djangocfg/api": "^2.1.15",
87
+ "@djangocfg/typescript-config": "^2.1.15",
73
88
  "@types/node": "^24.7.2",
89
+ "@types/prompts": "^2.4.9",
74
90
  "@types/react": "^19.0.0",
75
- "consola": "^3.4.2",
76
91
  "swr": "^2.3.7",
77
92
  "tsup": "^8.5.0",
93
+ "tsx": "^4.19.2",
78
94
  "typescript": "^5.9.3"
79
95
  }
80
96
  }
package/preview.png ADDED
Binary file