@kosdev-code/kos-ui-plugin 2.1.18 → 2.1.19

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 (58) hide show
  1. package/documentation-generator-CAlVz5vA.cjs +266 -0
  2. package/documentation-generator-CAlVz5vA.cjs.map +1 -0
  3. package/documentation-generator-Di4c9D9P.js +2337 -0
  4. package/documentation-generator-Di4c9D9P.js.map +1 -0
  5. package/index.cjs +69 -69
  6. package/index.cjs.map +1 -1
  7. package/index.d.ts +1 -0
  8. package/index.d.ts.map +1 -1
  9. package/index.js +817 -753
  10. package/index.js.map +1 -1
  11. package/lib/components/dynamic-component/dynamic-component.d.ts +69 -0
  12. package/lib/components/dynamic-component/dynamic-component.d.ts.map +1 -1
  13. package/lib/contexts/index.d.ts +1 -0
  14. package/lib/contexts/index.d.ts.map +1 -1
  15. package/lib/contexts/plugins-provider/plugins-provider.d.ts.map +1 -1
  16. package/lib/contexts/reactive-extension-registry-context.d.ts +10 -0
  17. package/lib/contexts/reactive-extension-registry-context.d.ts.map +1 -0
  18. package/lib/hooks/index.d.ts +4 -2
  19. package/lib/hooks/index.d.ts.map +1 -1
  20. package/lib/hooks/use-dynamic-component.d.ts +12 -1
  21. package/lib/hooks/use-dynamic-component.d.ts.map +1 -1
  22. package/lib/hooks/use-extension-point.d.ts +95 -0
  23. package/lib/hooks/use-extension-point.d.ts.map +1 -0
  24. package/lib/hooks/use-reactive-extension-registry.d.ts +20 -0
  25. package/lib/hooks/use-reactive-extension-registry.d.ts.map +1 -0
  26. package/lib/hooks/use-typed-extensions.d.ts.map +1 -1
  27. package/lib/utils/contribution-registry.d.ts +170 -0
  28. package/lib/utils/contribution-registry.d.ts.map +1 -0
  29. package/lib/utils/extension-points/extension-point-registry.d.ts.map +1 -1
  30. package/lib/utils/extension-points/extension-point-schemas.d.ts +4 -4
  31. package/lib/utils/index.d.ts +3 -0
  32. package/lib/utils/index.d.ts.map +1 -1
  33. package/lib/utils/plugin-system/plugin-extension-manager.d.ts.map +1 -1
  34. package/lib/utils/processors/initialize-plugins.d.ts.map +1 -1
  35. package/lib/utils/reactive-extension-registry.d.ts +140 -0
  36. package/lib/utils/reactive-extension-registry.d.ts.map +1 -0
  37. package/lib/webpack/index.d.ts +2 -0
  38. package/lib/webpack/index.d.ts.map +1 -1
  39. package/lib/webpack/with-plugin-dev-aggregator.d.ts +94 -0
  40. package/lib/webpack/with-plugin-dev-aggregator.d.ts.map +1 -0
  41. package/lib/webpack/with-plugin-dev-server.d.ts +113 -0
  42. package/lib/webpack/with-plugin-dev-server.d.ts.map +1 -0
  43. package/package.json +2 -2
  44. package/types/contribution-enablement.d.ts +293 -0
  45. package/types/contribution-enablement.d.ts.map +1 -0
  46. package/types/plugins.d.ts +8 -0
  47. package/utils.cjs +1 -1
  48. package/utils.cjs.map +1 -1
  49. package/utils.js +29 -291
  50. package/utils.js.map +1 -1
  51. package/webpack.cjs +3 -12
  52. package/webpack.cjs.map +1 -1
  53. package/webpack.js +455 -727
  54. package/webpack.js.map +1 -1
  55. package/documentation-generator-DFaIDo0E.cjs +0 -266
  56. package/documentation-generator-DFaIDo0E.cjs.map +0 -1
  57. package/documentation-generator-auruIa_o.js +0 -1560
  58. package/documentation-generator-auruIa_o.js.map +0 -1
@@ -0,0 +1,140 @@
1
+ import { PluginExtension, PluginExtensionsType } from '../../types/plugins';
2
+
3
+ /**
4
+ * Event emitted when extension point changes
5
+ */
6
+ export interface ExtensionPointChangeEvent {
7
+ extensionPoint: string;
8
+ changeType: "contribution-enabled" | "contribution-disabled" | "best-changed";
9
+ affectedContribution: string;
10
+ newBest?: string;
11
+ timestamp: number;
12
+ }
13
+ /**
14
+ * Reactive extension registry that monitors contribution state
15
+ *
16
+ * Bridges the gap between ContributionRegistry (state management) and
17
+ * React components by providing filtered extension lists and change notifications.
18
+ *
19
+ * This registry:
20
+ * - Filters extensions based on enabled state
21
+ * - Subscribes to ContributionRegistry for state changes
22
+ * - Emits ExtensionPointChangeEvent when contributions change
23
+ * - Manages extension point-scoped subscriptions
24
+ * - Handles cleanup to prevent memory leaks
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const registry = new ReactiveExtensionRegistry(extensions);
29
+ *
30
+ * // Get only enabled extensions
31
+ * const enabledExtensions = registry.getExtensions('ddk.settings.view');
32
+ *
33
+ * // Subscribe to changes
34
+ * const unsubscribe = registry.subscribe('ddk.settings.view', (event) => {
35
+ * console.log('Extension point changed:', event);
36
+ * });
37
+ *
38
+ * // Cleanup when done
39
+ * registry.destroy();
40
+ * ```
41
+ */
42
+ export declare class ReactiveExtensionRegistry {
43
+ /**
44
+ * Reference to all plugin extensions (unfiltered)
45
+ */
46
+ private extensions;
47
+ /**
48
+ * Map of extension point to listeners
49
+ * Each extension point can have multiple components listening for changes
50
+ */
51
+ private listeners;
52
+ /**
53
+ * Unsubscribe function for ContributionRegistry subscription
54
+ * Used during cleanup to remove listener
55
+ */
56
+ private contributionUnsubscribe;
57
+ constructor(extensions: PluginExtensionsType);
58
+ /**
59
+ * Get extensions for an extension point (filtered by enabled state)
60
+ *
61
+ * By default, only returns enabled contributions. Use `includeDisabled: true`
62
+ * to get all contributions regardless of state.
63
+ *
64
+ * @param extensionPoint - Extension point identifier
65
+ * @param includeDisabled - If true, include disabled contributions (default: false)
66
+ * @returns Record of extension ID to extension object
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * // Get only enabled settings extensions
71
+ * const enabled = registry.getExtensions('ddk.settings.view');
72
+ *
73
+ * // Get all settings extensions (including disabled)
74
+ * const all = registry.getExtensions('ddk.settings.view', true);
75
+ * ```
76
+ */
77
+ getExtensions(extensionPoint: string, includeDisabled?: boolean): Record<string, PluginExtension>;
78
+ /**
79
+ * Subscribe to changes for a specific extension point
80
+ *
81
+ * Registers a listener that will be called whenever contributions for
82
+ * the specified extension point change state (enabled/disabled) or when
83
+ * the best contribution for that point changes.
84
+ *
85
+ * @param extensionPoint - Extension point identifier to monitor
86
+ * @param listener - Callback function to handle change events
87
+ * @returns Unsubscribe function to stop receiving events
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const unsubscribe = registry.subscribe('ddk.settings.view', (event) => {
92
+ * if (event.changeType === 'best-changed') {
93
+ * console.log('New best contribution:', event.newBest);
94
+ * }
95
+ * });
96
+ *
97
+ * // Later...
98
+ * unsubscribe();
99
+ * ```
100
+ */
101
+ subscribe(extensionPoint: string, listener: (event: ExtensionPointChangeEvent) => void): () => void;
102
+ /**
103
+ * Internal: Subscribe to contribution state changes
104
+ *
105
+ * Sets up subscription to ContributionRegistry to receive notifications
106
+ * when any contribution's enabled state changes. Routes these events to
107
+ * extension point-specific listeners.
108
+ *
109
+ * @private
110
+ */
111
+ private subscribeToContributionChanges;
112
+ /**
113
+ * Internal: Handle contribution state change
114
+ *
115
+ * Called when ContributionRegistry emits a state change event.
116
+ * Determines if the "best" contribution has changed and emits
117
+ * ExtensionPointChangeEvent to all listeners for that extension point.
118
+ *
119
+ * @param event - Contribution state change event from ContributionRegistry
120
+ * @private
121
+ */
122
+ private handleContributionChange;
123
+ /**
124
+ * Cleanup subscriptions and listeners
125
+ *
126
+ * Call this when the registry is no longer needed to prevent memory leaks.
127
+ * Typically called when the PluginsProvider is unmounted.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * useEffect(() => {
132
+ * const registry = new ReactiveExtensionRegistry(extensions);
133
+ * // Use registry...
134
+ * return () => registry.destroy();
135
+ * }, []);
136
+ * ```
137
+ */
138
+ destroy(): void;
139
+ }
140
+ //# sourceMappingURL=reactive-extension-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactive-extension-registry.d.ts","sourceRoot":"","sources":["../../../../../../packages/sdk/kos-ui-plugin/src/lib/utils/reactive-extension-registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAI7B;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,sBAAsB,GAAG,uBAAuB,GAAG,cAAc,CAAC;IAC9E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,yBAAyB;IACpC;;OAEG;IACH,OAAO,CAAC,UAAU,CAAuB;IAEzC;;;OAGG;IACH,OAAO,CAAC,SAAS,CAGf;IAEF;;;OAGG;IACH,OAAO,CAAC,uBAAuB,CAA6B;gBAEhD,UAAU,EAAE,oBAAoB;IAM5C;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CACX,cAAc,EAAE,MAAM,EACtB,eAAe,UAAQ,GACtB,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;IAgBlC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,SAAS,CACP,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,GACnD,MAAM,IAAI;IAuBb;;;;;;;;OAQG;IACH,OAAO,CAAC,8BAA8B;IAMtC;;;;;;;;;OASG;IACH,OAAO,CAAC,wBAAwB;IA6ChC;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,IAAI;CAQhB"}
@@ -1,2 +1,4 @@
1
1
  export * from './with-kos-config';
2
+ export * from './with-plugin-dev-server';
3
+ export * from './with-plugin-dev-aggregator';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/sdk/kos-ui-plugin/src/lib/webpack/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/sdk/kos-ui-plugin/src/lib/webpack/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Multi-Plugin Development Mode Aggregation Middleware
3
+ *
4
+ * This webpack composable aggregates metadata from multiple plugin dev servers
5
+ * running on different ports, combining them into a single response at the
6
+ * `/api/kos/ui/plugins/contexts` endpoint.
7
+ *
8
+ * This allows a host app to load multiple plugins simultaneously during development.
9
+ */
10
+ export interface PluginDevAggregatorOptions {
11
+ /**
12
+ * List of plugin dev server URLs to aggregate.
13
+ * Example: ['http://localhost:4201', 'http://localhost:4202']
14
+ */
15
+ pluginServers: string[];
16
+ /**
17
+ * Include the host app's own .kos.json plugin definitions.
18
+ * Default: true
19
+ */
20
+ includeHostPlugins?: boolean;
21
+ /**
22
+ * Path to the host app's .kos.json file.
23
+ * Default: './.kos.json'
24
+ */
25
+ kosJsonPath?: string;
26
+ /**
27
+ * Merge backend plugins with local dev plugins.
28
+ * When true, fetches plugins from backend and overlays local dev plugins on top.
29
+ * Local dev plugins get overrides pointing to dev servers.
30
+ * Backend plugins use their original URLs (no overrides).
31
+ *
32
+ * This is useful for third-party developers who want to:
33
+ * - Run against a production DDK backend
34
+ * - Load DDK base plugins from the backend
35
+ * - Develop their own custom plugins locally
36
+ *
37
+ * Default: false (local-only mode)
38
+ */
39
+ mergeWithBackend?: boolean;
40
+ /**
41
+ * Fallback to backend if no local plugin servers are available.
42
+ * Default: true
43
+ */
44
+ fallbackToBackend?: boolean;
45
+ /**
46
+ * Backend URL to fallback to when no plugin servers available.
47
+ * Default: 'http://localhost:8081'
48
+ */
49
+ backendUrl?: string;
50
+ /**
51
+ * Enable verbose logging for debugging.
52
+ * Default: false
53
+ */
54
+ verbose?: boolean;
55
+ }
56
+ /**
57
+ * Webpack plugin composable that aggregates multiple plugin dev servers.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * // Host app webpack.config.ts
62
+ * import { withPluginDevAggregator } from '@kosdev-code/kos-ui-plugin/webpack';
63
+ *
64
+ * export default composePlugins(
65
+ * withNx(),
66
+ * withReact({}),
67
+ * withPluginDevAggregator({
68
+ * pluginServers: [
69
+ * 'http://localhost:4201', // beverage-pour
70
+ * 'http://localhost:4202' // kos-ddk-standard-plugin
71
+ * ]
72
+ * })
73
+ * );
74
+ * ```
75
+ *
76
+ * @example With environment variables
77
+ * ```typescript
78
+ * const pluginServers = [
79
+ * process.env.PLUGIN_A_DEV === 'true' && 'http://localhost:4201',
80
+ * process.env.PLUGIN_B_DEV === 'true' && 'http://localhost:4202',
81
+ * ].filter(Boolean);
82
+ *
83
+ * export default composePlugins(
84
+ * withNx(),
85
+ * withReact({}),
86
+ * withPluginDevAggregator({
87
+ * pluginServers,
88
+ * fallbackToBackend: pluginServers.length === 0
89
+ * })
90
+ * );
91
+ * ```
92
+ */
93
+ export declare const withPluginDevAggregator: (options: PluginDevAggregatorOptions) => (config: any, context: any) => any;
94
+ //# sourceMappingURL=with-plugin-dev-aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-plugin-dev-aggregator.d.ts","sourceRoot":"","sources":["../../../../../../packages/sdk/kos-ui-plugin/src/lib/webpack/with-plugin-dev-aggregator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,uBAAuB,YACzB,0BAA0B,cAYnB,GAAG,WAAW,GAAG,QA8VlC,CAAC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Configuration options for plugin development server middleware
3
+ */
4
+ export interface PluginDevServerOptions {
5
+ /**
6
+ * Path to .kos.json file, relative to project root.
7
+ * Default: '.kos.json'
8
+ */
9
+ kosJsonPath?: string;
10
+ /**
11
+ * Project root directory. Used to resolve kosJsonPath.
12
+ * Default: process.cwd()
13
+ */
14
+ projectRoot?: string;
15
+ /**
16
+ * Default plugin context if not specified in .kos.json test section.
17
+ * Default: 'kosdev.ddk'
18
+ */
19
+ defaultContext?: string;
20
+ /**
21
+ * Enable verbose logging for debugging.
22
+ * Default: false
23
+ */
24
+ verbose?: boolean;
25
+ }
26
+ /**
27
+ * Webpack plugin composable that adds plugin development server middleware.
28
+ *
29
+ * This middleware serves the `/api/kos/ui/plugins/contexts` endpoint, mimicking
30
+ * the backend KOS plugin API response format. It enables local plugin development
31
+ * without requiring backend deployment.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // webpack.config.ts
36
+ * import { withKosConfig, withPluginDevServer } from '@kosdev-code/kos-ui-plugin/webpack';
37
+ * import { composePlugins, withNx } from '@nx/webpack';
38
+ *
39
+ * export default composePlugins(
40
+ * withNx(),
41
+ * withReact({}),
42
+ * withKosConfig(webpack),
43
+ * withPluginDevServer() // ← Add plugin dev server
44
+ * );
45
+ * ```
46
+ *
47
+ * @example With options
48
+ * ```typescript
49
+ * export default composePlugins(
50
+ * withNx(),
51
+ * withReact({}),
52
+ * withKosConfig(webpack),
53
+ * withPluginDevServer({
54
+ * kosJsonPath: '.kos.json',
55
+ * defaultContext: 'kosdev.ddk',
56
+ * verbose: true
57
+ * })
58
+ * );
59
+ * ```
60
+ *
61
+ * ## .kos.json Structure
62
+ *
63
+ * The middleware reads two sections from .kos.json:
64
+ *
65
+ * ```json
66
+ * {
67
+ * "kos": {
68
+ * "ui": {
69
+ * "plugin": {
70
+ * "id": "MyPlugin",
71
+ * "extensions": [...],
72
+ * "contributes": {...}
73
+ * }
74
+ * }
75
+ * },
76
+ * "test": {
77
+ * "plugin": {
78
+ * "context": "kosdev.ddk"
79
+ * }
80
+ * }
81
+ * }
82
+ * ```
83
+ *
84
+ * - `kos.ui.plugin`: Production plugin descriptor (becomes API `descriptor`)
85
+ * - `test.plugin.context`: Development plugin context/group name
86
+ *
87
+ * ## Response Format
88
+ *
89
+ * The middleware returns the same format as the backend `/api/kos/ui/plugins/contexts`:
90
+ *
91
+ * ```json
92
+ * {
93
+ * "status": 200,
94
+ * "version": {"major": 1, "minor": 0},
95
+ * "data": [
96
+ * {
97
+ * "name": "kosdev.ddk",
98
+ * "plugins": [
99
+ * {
100
+ * "descriptor": { ... },
101
+ * "id": "uuid-v4",
102
+ * "path": "/"
103
+ * }
104
+ * ]
105
+ * }
106
+ * ]
107
+ * }
108
+ * ```
109
+ *
110
+ * @param options - Configuration options
111
+ */
112
+ export declare const withPluginDevServer: (options?: PluginDevServerOptions) => (config: any, context: any) => any;
113
+ //# sourceMappingURL=with-plugin-dev-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-plugin-dev-server.d.ts","sourceRoot":"","sources":["../../../../../../packages/sdk/kos-ui-plugin/src/lib/webpack/with-plugin-dev-server.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AACH,eAAO,MAAM,mBAAmB,aAAa,sBAAsB,cAQjD,GAAG,WAAW,GAAG,QAuJlC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kosdev-code/kos-ui-plugin",
3
- "version": "2.1.18",
3
+ "version": "2.1.19",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "kos": {
23
23
  "build": {
24
- "gitHash": "a67b416c6600353f7483b900351970722d3e3282"
24
+ "gitHash": "6a8e249e4d22e16b7c678edf286c58258f65b6db"
25
25
  }
26
26
  },
27
27
  "publishConfig": {
@@ -0,0 +1,293 @@
1
+ import { BaseContribution, PluginExtensionsType, ProcessedContributions } from './plugins';
2
+
3
+ /**
4
+ * Enhanced contribution interface with runtime enablement state
5
+ *
6
+ * Extends BaseContribution with fields that enable dynamic runtime control
7
+ * over contribution visibility and availability. This allows plugins to
8
+ * respond to events (feature flags, device state, etc.) and update which
9
+ * contributions are visible to the plugin system.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const contribution: DynamicContribution = {
14
+ * id: 'advanced-settings',
15
+ * remote: 'settingsPlugin',
16
+ * sectionId: 'settings',
17
+ * enabled: true,
18
+ * enabledCondition: (context) => {
19
+ * return context.context?.userRole === 'admin';
20
+ * }
21
+ * };
22
+ * ```
23
+ */
24
+ export interface DynamicContribution extends BaseContribution {
25
+ /**
26
+ * Whether this contribution is currently enabled
27
+ *
28
+ * When false, the contribution will be filtered out by resolveBestExtension
29
+ * and will not be visible to DynamicComponent or other plugin consumers.
30
+ *
31
+ * @default true
32
+ */
33
+ enabled: boolean;
34
+ /**
35
+ * Optional reason for disabled state
36
+ *
37
+ * Useful for debugging, logging, and displaying to users why a contribution
38
+ * is unavailable. Should be a human-readable string.
39
+ *
40
+ * @example "Feature flag 'advanced-mode' is disabled"
41
+ * @example "User lacks premium license"
42
+ * @example "Device mode: basic"
43
+ */
44
+ disabledReason?: string;
45
+ /**
46
+ * Optional timestamp when enabled state last changed
47
+ *
48
+ * Unix timestamp (milliseconds) of the last state transition.
49
+ * Useful for debugging, auditing, and temporal queries.
50
+ *
51
+ * @example Date.now() // 1705780800000
52
+ */
53
+ lastStateChange?: number;
54
+ /**
55
+ * Optional conditional enablement function
56
+ *
57
+ * Evaluated when contribution is accessed via isEnabled().
58
+ * Allows for dynamic enablement based on runtime context.
59
+ *
60
+ * If provided, this function is called in addition to checking the
61
+ * `enabled` boolean field. Both must be true for the contribution
62
+ * to be considered enabled.
63
+ *
64
+ * @param context - Current runtime context including extensions, contributions, and custom data
65
+ * @returns true if contribution should be enabled, false otherwise
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * enabledCondition: (context) => {
70
+ * const licenseModel = context.context?.licenseModel;
71
+ * return licenseModel?.hasPremiumLicense === true;
72
+ * }
73
+ * ```
74
+ */
75
+ enabledCondition?: (context: EnablementContext) => boolean;
76
+ }
77
+ /**
78
+ * Context provided to enablement condition functions
79
+ *
80
+ * Provides runtime information that enablement conditions can use to
81
+ * determine whether a contribution should be enabled. This includes
82
+ * the current plugin system state and custom application data.
83
+ */
84
+ export interface EnablementContext {
85
+ /**
86
+ * Current extensions state
87
+ *
88
+ * The full PluginExtensionsType object representing all registered
89
+ * extension points and their contributions.
90
+ */
91
+ extensions: PluginExtensionsType;
92
+ /**
93
+ * Current contributions state
94
+ *
95
+ * Processed contributions including experiences and other contribution types.
96
+ */
97
+ contributions: ProcessedContributions;
98
+ /**
99
+ * Custom context data
100
+ *
101
+ * Application-specific context that can be used in enablement conditions.
102
+ * For example, user model, license model, device state, etc.
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * {
107
+ * userModel: { role: 'admin', id: '123' },
108
+ * licenseModel: { hasPremiumLicense: true },
109
+ * deviceState: { mode: 'advanced' }
110
+ * }
111
+ * ```
112
+ */
113
+ context?: Record<string, any>;
114
+ }
115
+ /**
116
+ * Event emitted when a contribution's enabled state changes
117
+ *
118
+ * This event is emitted by ContributionRegistry whenever setEnabled()
119
+ * or batchUpdate() changes a contribution's state. Listeners can subscribe
120
+ * to these events to react to enablement changes.
121
+ */
122
+ export interface ContributionStateChangeEvent {
123
+ /**
124
+ * Unique identifier of the contribution that changed
125
+ */
126
+ contributionId: string;
127
+ /**
128
+ * Extension point this contribution belongs to
129
+ *
130
+ * @example "ddk.features"
131
+ * @example "ddk.settings.view"
132
+ */
133
+ extensionPoint: string;
134
+ /**
135
+ * New enabled state (true = enabled, false = disabled)
136
+ */
137
+ enabled: boolean;
138
+ /**
139
+ * Previous enabled state before this change
140
+ */
141
+ previousState: boolean;
142
+ /**
143
+ * Optional reason for the state change
144
+ *
145
+ * @example "Feature flag 'advanced-mode' changed to enabled"
146
+ * @example "App unloaded"
147
+ */
148
+ reason?: string;
149
+ /**
150
+ * Unix timestamp (milliseconds) when this change occurred
151
+ */
152
+ timestamp: number;
153
+ }
154
+ /**
155
+ * Centralized contribution enablement registry interface
156
+ *
157
+ * The ContributionRegistry manages the enabled/disabled state of all
158
+ * contributions in the plugin system. It provides methods to:
159
+ * - Update contribution state
160
+ * - Query contribution state
161
+ * - Subscribe to state changes
162
+ * - Perform batch atomic updates
163
+ *
164
+ * This is the primary API for implementing dynamic contribution enablement.
165
+ */
166
+ export interface IContributionRegistry {
167
+ /**
168
+ * Set enabled state for a contribution
169
+ *
170
+ * Updates the contribution's enabled state and emits a
171
+ * ContributionStateChangeEvent to all subscribers.
172
+ *
173
+ * @param contributionId - Unique identifier of the contribution
174
+ * @param enabled - New enabled state (true = enabled, false = disabled)
175
+ * @param reason - Optional human-readable reason for the change
176
+ *
177
+ * @throws Error if contribution does not exist
178
+ *
179
+ * @example
180
+ * ```typescript
181
+ * ContributionRegistry.setEnabled(
182
+ * 'advanced-settings',
183
+ * false,
184
+ * 'Device mode changed to basic'
185
+ * );
186
+ * ```
187
+ */
188
+ setEnabled(contributionId: string, enabled: boolean, reason?: string): void;
189
+ /**
190
+ * Get enabled state for a contribution
191
+ *
192
+ * Checks both the enabled boolean field and evaluates any
193
+ * enabledCondition function if present. Returns true only if
194
+ * both checks pass.
195
+ *
196
+ * @param contributionId - Unique identifier of the contribution
197
+ * @returns true if contribution is enabled, false otherwise
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * if (ContributionRegistry.isEnabled('advanced-settings')) {
202
+ * // Show advanced settings UI
203
+ * }
204
+ * ```
205
+ */
206
+ isEnabled(contributionId: string): boolean;
207
+ /**
208
+ * Subscribe to all contribution state changes
209
+ *
210
+ * Registers a listener that will be called whenever any contribution's
211
+ * enabled state changes. The listener receives a ContributionStateChangeEvent.
212
+ *
213
+ * @param listener - Callback function to handle state change events
214
+ * @returns Unsubscribe function to stop receiving events
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * const unsubscribe = ContributionRegistry.subscribe((event) => {
219
+ * console.log(`${event.contributionId} ${event.enabled ? 'enabled' : 'disabled'}`);
220
+ * });
221
+ *
222
+ * // Later: stop listening
223
+ * unsubscribe();
224
+ * ```
225
+ */
226
+ subscribe(listener: (event: ContributionStateChangeEvent) => void): () => void;
227
+ /**
228
+ * Subscribe to changes for a specific extension point
229
+ *
230
+ * Like subscribe(), but only emits events for contributions
231
+ * belonging to the specified extension point.
232
+ *
233
+ * @param extensionPoint - Extension point identifier to monitor
234
+ * @param listener - Callback function to handle state change events
235
+ * @returns Unsubscribe function to stop receiving events
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * const unsubscribe = ContributionRegistry.subscribeToExtensionPoint(
240
+ * 'ddk.settings.view',
241
+ * (event) => {
242
+ * console.log(`Settings contribution changed: ${event.contributionId}`);
243
+ * }
244
+ * );
245
+ * ```
246
+ */
247
+ subscribeToExtensionPoint(extensionPoint: string, listener: (event: ContributionStateChangeEvent) => void): () => void;
248
+ /**
249
+ * Batch update multiple contributions atomically
250
+ *
251
+ * Updates multiple contribution states in a single atomic operation.
252
+ * All updates succeed or all fail together. Emits one event per
253
+ * contribution that changed state.
254
+ *
255
+ * @param updates - Array of contribution updates to apply
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * // Disable all advanced features at once
260
+ * ContributionRegistry.batchUpdate([
261
+ * { contributionId: 'advanced-settings', enabled: false, reason: 'Basic mode' },
262
+ * { contributionId: 'diagnostics', enabled: false, reason: 'Basic mode' },
263
+ * { contributionId: 'dev-tools', enabled: false, reason: 'Basic mode' }
264
+ * ]);
265
+ * ```
266
+ */
267
+ batchUpdate(updates: Array<{
268
+ contributionId: string;
269
+ enabled: boolean;
270
+ reason?: string;
271
+ }>): void;
272
+ /**
273
+ * Get all contributions for an extension point
274
+ *
275
+ * Returns an array of DynamicContribution objects for the specified
276
+ * extension point. By default, only returns enabled contributions.
277
+ *
278
+ * @param extensionPoint - Extension point identifier
279
+ * @param includeDisabled - If true, include disabled contributions in results
280
+ * @returns Array of contributions for the extension point
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * // Get only enabled settings contributions
285
+ * const enabledSettings = ContributionRegistry.getContributions('ddk.settings.view');
286
+ *
287
+ * // Get all settings contributions (including disabled)
288
+ * const allSettings = ContributionRegistry.getContributions('ddk.settings.view', true);
289
+ * ```
290
+ */
291
+ getContributions(extensionPoint: string, includeDisabled?: boolean): DynamicContribution[];
292
+ }
293
+ //# sourceMappingURL=contribution-enablement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contribution-enablement.d.ts","sourceRoot":"","sources":["../../../../../packages/sdk/kos-ui-plugin/src/types/contribution-enablement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC;CAC5D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,UAAU,EAAE,oBAAoB,CAAC;IAEjC;;;;OAIG;IACH,aAAa,EAAE,sBAAsB,CAAC;IAEtC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5E;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3C;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CACP,QAAQ,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI,GACtD,MAAM,IAAI,CAAC;IAEd;;;;;;;;;;;;;;;;;;;OAmBG;IACH,yBAAyB,CACvB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI,GACtD,MAAM,IAAI,CAAC;IAEd;;;;;;;;;;;;;;;;;;OAkBG;IACH,WAAW,CACT,OAAO,EAAE,KAAK,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;QACvB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC,GACD,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;OAkBG;IACH,gBAAgB,CACd,cAAc,EAAE,MAAM,EACtB,eAAe,CAAC,EAAE,OAAO,GACxB,mBAAmB,EAAE,CAAC;CAC1B"}