@djangocfg/ext-base 1.0.3 → 1.0.4

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 (40) hide show
  1. package/README.md +134 -8
  2. package/dist/api.cjs +40 -0
  3. package/dist/api.d.cts +35 -0
  4. package/dist/api.d.ts +35 -0
  5. package/dist/api.js +2 -0
  6. package/dist/auth.cjs +10 -0
  7. package/dist/auth.d.cts +1 -0
  8. package/dist/auth.d.ts +1 -0
  9. package/dist/auth.js +2 -0
  10. package/dist/chunk-3RG5ZIWI.js +8 -0
  11. package/dist/chunk-UXTBBEO5.js +237 -0
  12. package/dist/chunk-VJEGYVBV.js +140 -0
  13. package/dist/cli.mjs +530 -0
  14. package/dist/hooks.cjs +437 -0
  15. package/dist/hooks.d.cts +97 -0
  16. package/dist/hooks.d.ts +97 -0
  17. package/dist/hooks.js +95 -0
  18. package/dist/index.cjs +345 -0
  19. package/dist/index.d.cts +363 -0
  20. package/dist/index.d.ts +363 -0
  21. package/dist/index.js +3 -0
  22. package/package.json +3 -1
  23. package/src/cli/index.ts +281 -15
  24. package/src/context/ExtensionProvider.tsx +67 -4
  25. package/src/extensionConfig.ts +77 -28
  26. package/templates/extension-template/README.md.template +30 -0
  27. package/templates/extension-template/package.json.template +2 -1
  28. package/templates/extension-template/playground/.gitignore.template +34 -0
  29. package/templates/extension-template/playground/CLAUDE.md +35 -0
  30. package/templates/extension-template/playground/README.md.template +76 -0
  31. package/templates/extension-template/playground/app/globals.css.template +19 -0
  32. package/templates/extension-template/playground/app/layout.tsx.template +30 -0
  33. package/templates/extension-template/playground/app/page.tsx.template +44 -0
  34. package/templates/extension-template/playground/next.config.ts.template +62 -0
  35. package/templates/extension-template/playground/package.json.template +33 -0
  36. package/templates/extension-template/playground/tsconfig.json.template +27 -0
  37. package/templates/extension-template/src/contexts/__PROVIDER_NAME__Context.tsx +1 -1
  38. package/templates/extension-template/src/contexts/__PROVIDER_NAME__ExtensionProvider.tsx +1 -0
  39. package/templates/extension-template/src/index.ts +12 -4
  40. package/templates/extension-template/src/utils/withSmartProvider.tsx +70 -0
package/README.md CHANGED
@@ -39,6 +39,15 @@ The package includes a CLI tool for creating new DjangoCFG extensions:
39
39
  # Create a new extension with interactive wizard
40
40
  djangocfg-ext create
41
41
 
42
+ # Quick test extension (auto-cleanup + unique name)
43
+ djangocfg-ext test
44
+
45
+ # List all extensions in workspace
46
+ djangocfg-ext list
47
+
48
+ # Show extension info
49
+ djangocfg-ext info <extension-name>
50
+
42
51
  # Show help
43
52
  djangocfg-ext help
44
53
  ```
@@ -50,6 +59,9 @@ The CLI will guide you through creating a new extension with proper structure an
50
59
  - Automatic npm registry validation to prevent duplicate package names
51
60
  - Support for both scoped (`@my-org/my-extension`) and unscoped (`my-extension`) package names
52
61
  - Template generation with proper placeholder replacement
62
+ - **Playground environment** with Next.js 15 for rapid development
63
+ - Auto-dependency installation and type checking
64
+ - Smart workspace detection for monorepos
53
65
 
54
66
  ## Quick Start
55
67
 
@@ -115,7 +127,7 @@ export function MyExtensionProvider({ children }) {
115
127
  ### 3. Use in your app
116
128
 
117
129
  ```typescript
118
- import { MyExtensionProvider } from '@your-org/my-extension/hooks';
130
+ import { MyExtensionProvider } from '@your-org/my-extension';
119
131
 
120
132
  export default function RootLayout({ children }) {
121
133
  return (
@@ -126,6 +138,94 @@ export default function RootLayout({ children }) {
126
138
  }
127
139
  ```
128
140
 
141
+ ## Development Workflow
142
+
143
+ Every extension created with the CLI includes a **playground** - a Next.js 15 development environment for rapid testing and iteration.
144
+
145
+ ### Starting the Playground
146
+
147
+ ```bash
148
+ cd your-extension
149
+ pnpm dev:playground
150
+ ```
151
+
152
+ This command:
153
+ 1. ✅ Automatically builds your extension
154
+ 2. ✅ Starts Next.js dev server on port 3333
155
+ 3. ✅ Opens browser automatically
156
+ 4. ✅ Hot-reloads on source changes
157
+
158
+ ### Playground Features
159
+
160
+ - **Next.js 15 App Router** with React 19
161
+ - **Tailwind CSS v4** pre-configured
162
+ - **BaseApp** wrapper with theme, auth, and SWR
163
+ - **Auto-build** extension before starting (via `predev` script)
164
+ - **Auto-open browser** when dev server is ready
165
+ - **Hot reload** for instant feedback
166
+
167
+ ### Building for Production
168
+
169
+ ```bash
170
+ # Build extension
171
+ pnpm build
172
+
173
+ # Build playground
174
+ pnpm build:playground
175
+
176
+ # Type check
177
+ pnpm check
178
+ ```
179
+
180
+ ## Smart Provider Pattern
181
+
182
+ Extensions support a **Smart Provider Pattern** that allows components to work both standalone and with manual provider wrapping.
183
+
184
+ ### Using withSmartProvider
185
+
186
+ Create self-contained components that automatically wrap themselves with the provider when needed:
187
+
188
+ ```typescript
189
+ import { withSmartProvider } from '@your-org/my-extension';
190
+
191
+ // Your component
192
+ function MyComponent() {
193
+ const { data } = useMyExtension();
194
+ return <div>{data}</div>;
195
+ }
196
+
197
+ // Wrap with smart provider
198
+ export const MySmartComponent = withSmartProvider(MyComponent);
199
+ ```
200
+
201
+ **Usage:**
202
+
203
+ ```typescript
204
+ // Works standalone (auto-wrapped)
205
+ <MySmartComponent />
206
+
207
+ // Also works with manual provider (shares context)
208
+ <MyExtensionProvider>
209
+ <MySmartComponent />
210
+ <MySmartComponent />
211
+ </MyExtensionProvider>
212
+ ```
213
+
214
+ **Benefits:**
215
+ - ✅ Components work out-of-the-box without provider boilerplate
216
+ - ✅ Multiple components can still share context when manually wrapped
217
+ - ✅ Best of both worlds - simplicity and flexibility
218
+
219
+ **When to use:**
220
+ - Library components that should "just work"
221
+ - Components that might be used in isolation
222
+ - Reducing boilerplate for simple use cases
223
+
224
+ **When to use manual provider:**
225
+ - Multiple components need to share state
226
+ - Performance optimization (single provider instance)
227
+ - Explicit context boundaries
228
+
129
229
  ## Core Features
130
230
 
131
231
  ### Extension Config Helper
@@ -279,8 +379,17 @@ function MyComponent() {
279
379
  | `@djangocfg/ext-base/api` | API utilities (createExtensionAPI, getSharedAuthStorage) | Server & client components |
280
380
 
281
381
  **For your own extensions:**
282
- - Use `@your-org/ext-name/config` to import extension metadata without loading React components (server-safe)
283
- - This is the recommended way to import `extensionConfig` in server components and build tools
382
+
383
+ Extension templates automatically export:
384
+ - `extensionConfig` - Extension metadata
385
+ - `[Name]Provider` - Main provider component (wraps ExtensionProvider)
386
+ - `use[Name]` - Context hook (required provider)
387
+ - `use[Name]Optional` - Context hook (optional provider)
388
+ - `withSmartProvider` - HOC for self-contained components
389
+
390
+ **Server-safe imports:**
391
+ - Use `@your-org/ext-name/config` to import extension metadata without loading React components
392
+ - This is recommended for server components and build tools
284
393
 
285
394
  ## Extension Categories
286
395
 
@@ -342,17 +451,34 @@ import type {
342
451
 
343
452
  ## Best Practices
344
453
 
454
+ ### Configuration & Metadata
345
455
  - Use `createExtensionConfig` helper to maintain Single Source of Truth from package.json
346
- - Always wrap your extension with `ExtensionProvider` for proper registration
347
456
  - Use Lucide icon names (not emoji) for `icon` field
348
- - **Include a `preview.png` file** in your extension root (1200x630px recommended) - it will be automatically served via unpkg
349
457
  - Include comprehensive `features` list for marketplace visibility
350
458
  - Provide code `examples` with proper syntax highlighting
351
- - Use provided pagination hooks for consistent data fetching
352
- - Use `createExtensionLogger` with consistent tags for structured logging
353
- - Separate client-only code using `/hooks` entry point
459
+ - **Include a `preview.png` file** in your extension root (1200x630px recommended)
354
460
  - List `preview.png` in your package.json `files` array for npm publication
355
461
 
462
+ ### Development
463
+ - Use the **playground** for rapid development (`pnpm dev:playground`)
464
+ - Test your components in isolation before integrating
465
+ - Run type checks before building (`pnpm check`)
466
+ - Use `createExtensionLogger` with consistent tags for structured logging
467
+
468
+ ### Architecture
469
+ - Always wrap your extension with `ExtensionProvider` for proper registration
470
+ - Export main provider as `[Name]Provider` (not `[Name]ExtensionProvider`)
471
+ - Use `withSmartProvider` for components that should work standalone
472
+ - Prefer manual provider wrapping when components need shared state
473
+ - Use provided pagination hooks for consistent data fetching
474
+ - Separate client-only code appropriately
475
+
476
+ ### Publishing
477
+ - Test with `pnpm build` before publishing
478
+ - Verify preview image is accessible via unpkg
479
+ - Ensure all peer dependencies are correctly listed
480
+ - Include clear usage examples in README
481
+
356
482
  ## License
357
483
 
358
484
  MIT
package/dist/api.cjs ADDED
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
10
+ // src/config.ts
11
+ process.env.NODE_ENV === "development";
12
+ process.env.NODE_ENV === "production";
13
+ var isStaticBuild = process.env.STATIC_BUILD === "true";
14
+ function getApiUrl() {
15
+ return process.env.NEXT_PUBLIC_API_URL || "/api";
16
+ }
17
+
18
+ // src/api/createExtensionAPI.ts
19
+ function createExtensionAPI(APIClass) {
20
+ let storage;
21
+ try {
22
+ const { api: accountsApi } = __require("@djangocfg/api");
23
+ storage = accountsApi._storage;
24
+ } catch (error) {
25
+ storage = void 0;
26
+ }
27
+ const apiUrl = isStaticBuild ? "" : getApiUrl();
28
+ return new APIClass(apiUrl, storage ? { storage } : void 0);
29
+ }
30
+ function getSharedAuthStorage() {
31
+ try {
32
+ const { api: accountsApi } = __require("@djangocfg/api");
33
+ return accountsApi._storage;
34
+ } catch (error) {
35
+ return void 0;
36
+ }
37
+ }
38
+
39
+ exports.createExtensionAPI = createExtensionAPI;
40
+ exports.getSharedAuthStorage = getSharedAuthStorage;
package/dist/api.d.cts ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Factory for creating extension API instances
3
+ *
4
+ * Provides consistent API setup across all extensions with shared authentication
5
+ */
6
+ /**
7
+ * Creates an extension API instance with shared authentication storage
8
+ *
9
+ * @param APIClass - The generated API class from your extension
10
+ * @returns Configured API instance with shared auth storage
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // In your extension's api/index.ts
15
+ * import { API } from './generated/ext_newsletter';
16
+ * import { createExtensionAPI } from '@djangocfg/ext-base/api';
17
+ *
18
+ * export const apiNewsletter = createExtensionAPI(API);
19
+ * ```
20
+ */
21
+ declare function createExtensionAPI<T>(APIClass: new (url: string, options?: any) => T): T;
22
+ /**
23
+ * Get shared authentication storage from accounts API
24
+ *
25
+ * @returns Storage instance or undefined if not available
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const storage = getSharedAuthStorage();
30
+ * const api = new API(apiUrl, { storage });
31
+ * ```
32
+ */
33
+ declare function getSharedAuthStorage(): any | undefined;
34
+
35
+ export { createExtensionAPI, getSharedAuthStorage };
package/dist/api.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Factory for creating extension API instances
3
+ *
4
+ * Provides consistent API setup across all extensions with shared authentication
5
+ */
6
+ /**
7
+ * Creates an extension API instance with shared authentication storage
8
+ *
9
+ * @param APIClass - The generated API class from your extension
10
+ * @returns Configured API instance with shared auth storage
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // In your extension's api/index.ts
15
+ * import { API } from './generated/ext_newsletter';
16
+ * import { createExtensionAPI } from '@djangocfg/ext-base/api';
17
+ *
18
+ * export const apiNewsletter = createExtensionAPI(API);
19
+ * ```
20
+ */
21
+ declare function createExtensionAPI<T>(APIClass: new (url: string, options?: any) => T): T;
22
+ /**
23
+ * Get shared authentication storage from accounts API
24
+ *
25
+ * @returns Storage instance or undefined if not available
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const storage = getSharedAuthStorage();
30
+ * const api = new API(apiUrl, { storage });
31
+ * ```
32
+ */
33
+ declare function getSharedAuthStorage(): any | undefined;
34
+
35
+ export { createExtensionAPI, getSharedAuthStorage };
package/dist/api.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createExtensionAPI, getSharedAuthStorage } from './chunk-VJEGYVBV.js';
2
+ import './chunk-3RG5ZIWI.js';
package/dist/auth.cjs ADDED
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ var auth = require('@djangocfg/api/auth');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "useAuth", {
8
+ enumerable: true,
9
+ get: function () { return auth.useAuth; }
10
+ });
@@ -0,0 +1 @@
1
+ export { AuthContextType, UserProfile, useAuth } from '@djangocfg/api/auth';
package/dist/auth.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { AuthContextType, UserProfile, useAuth } from '@djangocfg/api/auth';
package/dist/auth.js ADDED
@@ -0,0 +1,2 @@
1
+ import './chunk-3RG5ZIWI.js';
2
+ export { useAuth } from '@djangocfg/api/auth';
@@ -0,0 +1,8 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export { __require };
@@ -0,0 +1,237 @@
1
+ import { package_default } from './chunk-VJEGYVBV.js';
2
+ import { createConsola } from 'consola';
3
+
4
+ // src/types/context.ts
5
+ var EXTENSION_CATEGORIES = [
6
+ { title: "Forms", value: "forms" },
7
+ { title: "Payments", value: "payments" },
8
+ { title: "Content", value: "content" },
9
+ { title: "Support", value: "support" },
10
+ { title: "Utilities", value: "utilities" },
11
+ { title: "Analytics", value: "analytics" },
12
+ { title: "Security", value: "security" },
13
+ { title: "Integration", value: "integration" },
14
+ { title: "Other", value: "other" }
15
+ ];
16
+
17
+ // src/utils/createExtensionConfig.ts
18
+ function replaceWorkspaceDeps(deps) {
19
+ if (!deps) return void 0;
20
+ const result = {};
21
+ for (const [key, value] of Object.entries(deps)) {
22
+ result[key] = value === "workspace:*" ? "latest" : value;
23
+ }
24
+ return result;
25
+ }
26
+ function createExtensionConfig(packageJson, config) {
27
+ const author = typeof packageJson.author === "string" ? packageJson.author : packageJson.author?.name || "Unknown";
28
+ const githubUrl = typeof packageJson.repository === "string" ? packageJson.repository : packageJson.repository?.url;
29
+ const packageNameWithoutScope = packageJson.name.split("/").pop() || packageJson.name;
30
+ const downloadUrl = `https://registry.npmjs.org/${packageJson.name}/-/${packageNameWithoutScope}-${packageJson.version}.tgz`;
31
+ const marketplaceId = packageJson.name.replace("@", "").replace("/", "-");
32
+ return {
33
+ // From package.json
34
+ name: config.name,
35
+ version: packageJson.version,
36
+ author,
37
+ description: packageJson.description,
38
+ keywords: packageJson.keywords,
39
+ license: packageJson.license,
40
+ homepage: packageJson.homepage,
41
+ githubUrl,
42
+ packageDependencies: replaceWorkspaceDeps(packageJson.dependencies),
43
+ packagePeerDependencies: replaceWorkspaceDeps(packageJson.peerDependencies),
44
+ packageDevDependencies: replaceWorkspaceDeps(packageJson.devDependencies),
45
+ // From manual config
46
+ displayName: config.displayName,
47
+ category: config.category,
48
+ features: config.features,
49
+ examples: config.examples,
50
+ minVersion: config.minVersion,
51
+ githubStars: config.githubStars,
52
+ // Auto-generated
53
+ npmUrl: `https://www.npmjs.com/package/${packageJson.name}`,
54
+ marketplaceId,
55
+ // Only generate marketplace URL for official @djangocfg extensions
56
+ marketplaceUrl: packageJson.name.startsWith("@djangocfg/ext-") ? `https://hub.djangocfg.com/extensions/${marketplaceId}` : void 0,
57
+ installCommand: `pnpm add ${packageJson.name}`,
58
+ downloadUrl,
59
+ tags: packageJson.keywords,
60
+ preview: `https://unpkg.com/${packageJson.name}@latest/preview.png`
61
+ };
62
+ }
63
+
64
+ // src/extensionConfig.ts
65
+ var extensionConfig = createExtensionConfig(package_default, {
66
+ name: "base",
67
+ displayName: "Extension Base",
68
+ category: "utilities",
69
+ features: [
70
+ "CLI for creating extensions",
71
+ "Next.js 15 playground for rapid development",
72
+ "Smart Provider Pattern for flexible component usage",
73
+ "Extension context and provider system",
74
+ "Pagination hooks (standard & infinite scroll)",
75
+ "API client utilities with auth integration",
76
+ "Type-safe context creation helpers",
77
+ "Logging system with structured output",
78
+ "Environment detection (dev, prod, static)",
79
+ "TypeScript types and utilities"
80
+ ],
81
+ minVersion: "2.0.0",
82
+ examples: [
83
+ {
84
+ title: "Create Extension with CLI",
85
+ description: "Interactive wizard with playground environment",
86
+ code: `# Create extension with interactive wizard
87
+ pnpm dlx @djangocfg/ext-base create
88
+
89
+ # Quick test extension (auto-cleanup)
90
+ pnpm dlx @djangocfg/ext-base test
91
+
92
+ # List all extensions
93
+ pnpm dlx @djangocfg/ext-base list`,
94
+ language: "bash"
95
+ },
96
+ {
97
+ title: "Development with Playground",
98
+ description: "Start Next.js playground for rapid testing",
99
+ code: `cd your-extension
100
+
101
+ # Start playground (auto-builds extension + opens browser)
102
+ pnpm dev:playground
103
+
104
+ # Build for production
105
+ pnpm build
106
+
107
+ # Type check
108
+ pnpm check`,
109
+ language: "bash"
110
+ },
111
+ {
112
+ title: "Smart Provider Pattern",
113
+ description: "Components that work standalone or with shared context",
114
+ code: `import { withSmartProvider } from '@your-org/my-extension';
115
+
116
+ // Your component
117
+ function MyComponent() {
118
+ const { data } = useMyExtension();
119
+ return <div>{data}</div>;
120
+ }
121
+
122
+ // Wrap with smart provider
123
+ export const MySmartComponent = withSmartProvider(MyComponent);
124
+
125
+ // Usage 1: Standalone (auto-wrapped)
126
+ <MySmartComponent />
127
+
128
+ // Usage 2: Manual provider (shared context)
129
+ <MyExtensionProvider>
130
+ <MySmartComponent />
131
+ <MySmartComponent />
132
+ </MyExtensionProvider>`,
133
+ language: "tsx"
134
+ },
135
+ {
136
+ title: "Extension Provider",
137
+ description: "Register and wrap your extension",
138
+ code: `import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
139
+ import { extensionConfig } from './config';
140
+
141
+ export function MyExtensionProvider({ children }) {
142
+ return (
143
+ <ExtensionProvider metadata={extensionConfig}>
144
+ {children}
145
+ </ExtensionProvider>
146
+ );
147
+ }`,
148
+ language: "tsx"
149
+ },
150
+ {
151
+ title: "Pagination Hooks",
152
+ description: "Built-in hooks for standard and infinite scroll",
153
+ code: `import { usePagination, useInfinitePagination } from '@djangocfg/ext-base/hooks';
154
+
155
+ // Standard pagination
156
+ const { items, page, totalPages, nextPage, prevPage } = usePagination({
157
+ keyPrefix: 'articles',
158
+ fetcher: async (page, pageSize) => api.articles.list({ page, page_size: pageSize }),
159
+ pageSize: 20,
160
+ });
161
+
162
+ // Infinite scroll
163
+ const { items, isLoading, hasMore, loadMore } = useInfinitePagination({
164
+ keyPrefix: 'articles',
165
+ fetcher: async (page, pageSize) => api.articles.list({ page, page_size: pageSize }),
166
+ pageSize: 20,
167
+ });`,
168
+ language: "tsx"
169
+ }
170
+ ]
171
+ });
172
+
173
+ // src/utils/errors.ts
174
+ function isExtensionError(error) {
175
+ return typeof error === "object" && error !== null && "message" in error && "timestamp" in error;
176
+ }
177
+ function createExtensionError(error, code, details) {
178
+ const message = error instanceof Error ? error.message : String(error);
179
+ return {
180
+ message,
181
+ code,
182
+ details,
183
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
184
+ };
185
+ }
186
+ function formatErrorMessage(error) {
187
+ if (isExtensionError(error)) {
188
+ return error.code ? `[${error.code}] ${error.message}` : error.message;
189
+ }
190
+ if (error instanceof Error) {
191
+ return error.message;
192
+ }
193
+ return String(error);
194
+ }
195
+ function handleExtensionError(error, logger, callback) {
196
+ const extensionError = isExtensionError(error) ? error : createExtensionError(error);
197
+ if (logger) {
198
+ logger.error("Extension error:", extensionError);
199
+ }
200
+ if (callback) {
201
+ callback(extensionError);
202
+ }
203
+ }
204
+ var isDevelopment = process.env.NODE_ENV === "development";
205
+ var LEVEL_MAP = {
206
+ debug: 4,
207
+ info: 3,
208
+ warn: 2,
209
+ error: 1
210
+ };
211
+ function createExtensionLogger(options) {
212
+ const { tag, level = "info", enabled = true } = options;
213
+ if (!enabled) {
214
+ const noop = () => {
215
+ };
216
+ return {
217
+ info: noop,
218
+ warn: noop,
219
+ error: noop,
220
+ debug: noop,
221
+ success: noop
222
+ };
223
+ }
224
+ const logLevel = isDevelopment ? LEVEL_MAP[level] : LEVEL_MAP.error;
225
+ const consola = createConsola({
226
+ level: logLevel
227
+ }).withTag(tag);
228
+ return {
229
+ info: (...args) => consola.info(...args),
230
+ warn: (...args) => consola.warn(...args),
231
+ error: (...args) => consola.error(...args),
232
+ debug: (...args) => consola.debug(...args),
233
+ success: (...args) => consola.success(...args)
234
+ };
235
+ }
236
+
237
+ export { EXTENSION_CATEGORIES, createExtensionConfig, createExtensionError, createExtensionLogger, extensionConfig, formatErrorMessage, handleExtensionError, isExtensionError };