@object-ui/core 0.5.0 → 2.0.0

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 (85) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +11 -0
  3. package/dist/actions/ActionRunner.d.ts +228 -4
  4. package/dist/actions/ActionRunner.js +397 -45
  5. package/dist/actions/TransactionManager.d.ts +193 -0
  6. package/dist/actions/TransactionManager.js +410 -0
  7. package/dist/actions/index.d.ts +1 -0
  8. package/dist/actions/index.js +1 -0
  9. package/dist/adapters/ApiDataSource.d.ts +69 -0
  10. package/dist/adapters/ApiDataSource.js +293 -0
  11. package/dist/adapters/ValueDataSource.d.ts +55 -0
  12. package/dist/adapters/ValueDataSource.js +287 -0
  13. package/dist/adapters/index.d.ts +3 -0
  14. package/dist/adapters/index.js +5 -2
  15. package/dist/adapters/resolveDataSource.d.ts +40 -0
  16. package/dist/adapters/resolveDataSource.js +59 -0
  17. package/dist/data-scope/DataScopeManager.d.ts +127 -0
  18. package/dist/data-scope/DataScopeManager.js +229 -0
  19. package/dist/data-scope/index.d.ts +10 -0
  20. package/dist/data-scope/index.js +10 -0
  21. package/dist/evaluator/ExpressionEvaluator.d.ts +11 -1
  22. package/dist/evaluator/ExpressionEvaluator.js +32 -8
  23. package/dist/evaluator/FormulaFunctions.d.ts +58 -0
  24. package/dist/evaluator/FormulaFunctions.js +350 -0
  25. package/dist/evaluator/index.d.ts +1 -0
  26. package/dist/evaluator/index.js +1 -0
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.js +4 -2
  29. package/dist/query/query-ast.d.ts +2 -2
  30. package/dist/query/query-ast.js +3 -3
  31. package/dist/registry/Registry.d.ts +10 -0
  32. package/dist/registry/Registry.js +2 -1
  33. package/dist/registry/WidgetRegistry.d.ts +120 -0
  34. package/dist/registry/WidgetRegistry.js +275 -0
  35. package/dist/theme/ThemeEngine.d.ts +82 -0
  36. package/dist/theme/ThemeEngine.js +400 -0
  37. package/dist/theme/index.d.ts +8 -0
  38. package/dist/theme/index.js +8 -0
  39. package/dist/validation/index.d.ts +1 -1
  40. package/dist/validation/index.js +1 -1
  41. package/dist/validation/validation-engine.d.ts +19 -1
  42. package/dist/validation/validation-engine.js +67 -2
  43. package/dist/validation/validators/index.d.ts +1 -1
  44. package/dist/validation/validators/index.js +1 -1
  45. package/dist/validation/validators/object-validation-engine.d.ts +2 -2
  46. package/dist/validation/validators/object-validation-engine.js +1 -1
  47. package/package.json +4 -3
  48. package/src/actions/ActionRunner.ts +577 -55
  49. package/src/actions/TransactionManager.ts +521 -0
  50. package/src/actions/__tests__/ActionRunner.params.test.ts +134 -0
  51. package/src/actions/__tests__/ActionRunner.test.ts +711 -0
  52. package/src/actions/__tests__/TransactionManager.test.ts +447 -0
  53. package/src/actions/index.ts +1 -0
  54. package/src/adapters/ApiDataSource.ts +349 -0
  55. package/src/adapters/ValueDataSource.ts +332 -0
  56. package/src/adapters/__tests__/ApiDataSource.test.ts +418 -0
  57. package/src/adapters/__tests__/ValueDataSource.test.ts +325 -0
  58. package/src/adapters/__tests__/resolveDataSource.test.ts +144 -0
  59. package/src/adapters/index.ts +6 -1
  60. package/src/adapters/resolveDataSource.ts +79 -0
  61. package/src/builder/__tests__/schema-builder.test.ts +235 -0
  62. package/src/data-scope/DataScopeManager.ts +269 -0
  63. package/src/data-scope/__tests__/DataScopeManager.test.ts +211 -0
  64. package/src/data-scope/index.ts +16 -0
  65. package/src/evaluator/ExpressionEvaluator.ts +34 -8
  66. package/src/evaluator/FormulaFunctions.ts +398 -0
  67. package/src/evaluator/__tests__/ExpressionContext.test.ts +110 -0
  68. package/src/evaluator/__tests__/FormulaFunctions.test.ts +447 -0
  69. package/src/evaluator/index.ts +1 -0
  70. package/src/index.ts +4 -3
  71. package/src/query/__tests__/window-functions.test.ts +1 -1
  72. package/src/query/query-ast.ts +3 -3
  73. package/src/registry/Registry.ts +12 -1
  74. package/src/registry/WidgetRegistry.ts +316 -0
  75. package/src/registry/__tests__/WidgetRegistry.test.ts +321 -0
  76. package/src/theme/ThemeEngine.ts +452 -0
  77. package/src/theme/__tests__/ThemeEngine.test.ts +606 -0
  78. package/src/theme/index.ts +22 -0
  79. package/src/validation/__tests__/object-validation-engine.test.ts +1 -1
  80. package/src/validation/__tests__/schema-validator.test.ts +118 -0
  81. package/src/validation/index.ts +1 -1
  82. package/src/validation/validation-engine.ts +61 -2
  83. package/src/validation/validators/index.ts +1 -1
  84. package/src/validation/validators/object-validation-engine.ts +2 -2
  85. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,350 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * Registry of built-in formula functions
10
+ */
11
+ export class FormulaFunctions {
12
+ constructor() {
13
+ Object.defineProperty(this, "functions", {
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true,
17
+ value: new Map()
18
+ });
19
+ this.registerDefaults();
20
+ }
21
+ /**
22
+ * Register a custom formula function
23
+ */
24
+ register(name, fn) {
25
+ this.functions.set(name.toUpperCase(), fn);
26
+ }
27
+ /**
28
+ * Get a formula function by name
29
+ */
30
+ get(name) {
31
+ return this.functions.get(name.toUpperCase());
32
+ }
33
+ /**
34
+ * Check if a function is registered
35
+ */
36
+ has(name) {
37
+ return this.functions.has(name.toUpperCase());
38
+ }
39
+ /**
40
+ * Get all registered function names
41
+ */
42
+ getNames() {
43
+ return Array.from(this.functions.keys());
44
+ }
45
+ /**
46
+ * Get all functions as a plain object (for injection into expression context)
47
+ */
48
+ toObject() {
49
+ const result = {};
50
+ for (const [name, fn] of this.functions) {
51
+ result[name] = fn;
52
+ }
53
+ return result;
54
+ }
55
+ /**
56
+ * Register all default built-in functions
57
+ */
58
+ registerDefaults() {
59
+ this.registerAggregationFunctions();
60
+ this.registerDateFunctions();
61
+ this.registerLogicFunctions();
62
+ this.registerStringFunctions();
63
+ this.registerStringSearchFunctions();
64
+ this.registerStatisticalFunctions();
65
+ }
66
+ // ==========================================================================
67
+ // Aggregation Functions
68
+ // ==========================================================================
69
+ registerAggregationFunctions() {
70
+ this.register('SUM', (...args) => {
71
+ const values = flattenNumericArgs(args);
72
+ return values.reduce((sum, v) => sum + v, 0);
73
+ });
74
+ this.register('AVG', (...args) => {
75
+ const values = flattenNumericArgs(args);
76
+ if (values.length === 0)
77
+ return 0;
78
+ return values.reduce((sum, v) => sum + v, 0) / values.length;
79
+ });
80
+ this.register('COUNT', (...args) => {
81
+ const values = flattenArgs(args);
82
+ return values.filter(v => v != null).length;
83
+ });
84
+ this.register('MIN', (...args) => {
85
+ const values = flattenNumericArgs(args);
86
+ if (values.length === 0)
87
+ return 0;
88
+ return Math.min(...values);
89
+ });
90
+ this.register('MAX', (...args) => {
91
+ const values = flattenNumericArgs(args);
92
+ if (values.length === 0)
93
+ return 0;
94
+ return Math.max(...values);
95
+ });
96
+ }
97
+ // ==========================================================================
98
+ // Date Functions
99
+ // ==========================================================================
100
+ registerDateFunctions() {
101
+ this.register('TODAY', () => {
102
+ const now = new Date();
103
+ return now.toISOString().split('T')[0];
104
+ });
105
+ this.register('NOW', () => {
106
+ return new Date().toISOString();
107
+ });
108
+ this.register('DATEADD', (dateStr, amount, unit) => {
109
+ const date = new Date(dateStr);
110
+ if (isNaN(date.getTime())) {
111
+ throw new Error(`DATEADD: Invalid date "${dateStr}"`);
112
+ }
113
+ const normalizedUnit = String(unit).toLowerCase();
114
+ switch (normalizedUnit) {
115
+ case 'day':
116
+ case 'days':
117
+ date.setDate(date.getDate() + amount);
118
+ break;
119
+ case 'month':
120
+ case 'months':
121
+ date.setMonth(date.getMonth() + amount);
122
+ break;
123
+ case 'year':
124
+ case 'years':
125
+ date.setFullYear(date.getFullYear() + amount);
126
+ break;
127
+ case 'hour':
128
+ case 'hours':
129
+ date.setHours(date.getHours() + amount);
130
+ break;
131
+ case 'minute':
132
+ case 'minutes':
133
+ date.setMinutes(date.getMinutes() + amount);
134
+ break;
135
+ default:
136
+ throw new Error(`DATEADD: Unsupported unit "${unit}"`);
137
+ }
138
+ return date.toISOString();
139
+ });
140
+ this.register('DATEDIFF', (dateStr1, dateStr2, unit) => {
141
+ const date1 = new Date(dateStr1);
142
+ const date2 = new Date(dateStr2);
143
+ if (isNaN(date1.getTime())) {
144
+ throw new Error(`DATEDIFF: Invalid date "${dateStr1}"`);
145
+ }
146
+ if (isNaN(date2.getTime())) {
147
+ throw new Error(`DATEDIFF: Invalid date "${dateStr2}"`);
148
+ }
149
+ const diffMs = date2.getTime() - date1.getTime();
150
+ const normalizedUnit = String(unit).toLowerCase();
151
+ switch (normalizedUnit) {
152
+ case 'day':
153
+ case 'days':
154
+ return Math.floor(diffMs / (1000 * 60 * 60 * 24));
155
+ case 'month':
156
+ case 'months':
157
+ return (date2.getFullYear() - date1.getFullYear()) * 12 + (date2.getMonth() - date1.getMonth());
158
+ case 'year':
159
+ case 'years':
160
+ return date2.getFullYear() - date1.getFullYear();
161
+ case 'hour':
162
+ case 'hours':
163
+ return Math.floor(diffMs / (1000 * 60 * 60));
164
+ case 'minute':
165
+ case 'minutes':
166
+ return Math.floor(diffMs / (1000 * 60));
167
+ default:
168
+ throw new Error(`DATEDIFF: Unsupported unit "${unit}"`);
169
+ }
170
+ });
171
+ this.register('DATEFORMAT', (dateStr, format) => {
172
+ const date = new Date(dateStr);
173
+ if (isNaN(date.getTime())) {
174
+ throw new Error(`DATEFORMAT: Invalid date "${dateStr}"`);
175
+ }
176
+ const pad = (n, len = 2) => String(n).padStart(len, '0');
177
+ return format
178
+ .replace('YYYY', String(date.getFullYear()))
179
+ .replace('YY', String(date.getFullYear()).slice(-2))
180
+ .replace('MM', pad(date.getMonth() + 1))
181
+ .replace('DD', pad(date.getDate()))
182
+ .replace('HH', pad(date.getHours()))
183
+ .replace('mm', pad(date.getMinutes()))
184
+ .replace('ss', pad(date.getSeconds()));
185
+ });
186
+ }
187
+ // ==========================================================================
188
+ // Logic Functions
189
+ // ==========================================================================
190
+ registerLogicFunctions() {
191
+ this.register('IF', (condition, trueValue, falseValue) => {
192
+ return condition ? trueValue : falseValue;
193
+ });
194
+ this.register('AND', (...args) => {
195
+ return args.every(Boolean);
196
+ });
197
+ this.register('OR', (...args) => {
198
+ return args.some(Boolean);
199
+ });
200
+ this.register('NOT', (value) => {
201
+ return !value;
202
+ });
203
+ this.register('SWITCH', (expr, ...cases) => {
204
+ // SWITCH(expr, val1, result1, val2, result2, ..., defaultResult)
205
+ for (let i = 0; i < cases.length - 1; i += 2) {
206
+ if (expr === cases[i]) {
207
+ return cases[i + 1];
208
+ }
209
+ }
210
+ // Return default value if odd number of case args
211
+ if (cases.length % 2 === 1) {
212
+ return cases[cases.length - 1];
213
+ }
214
+ return undefined;
215
+ });
216
+ }
217
+ // ==========================================================================
218
+ // String Functions
219
+ // ==========================================================================
220
+ registerStringFunctions() {
221
+ this.register('CONCAT', (...args) => {
222
+ return args.map(a => String(a ?? '')).join('');
223
+ });
224
+ this.register('LEFT', (text, count) => {
225
+ return String(text ?? '').substring(0, count);
226
+ });
227
+ this.register('RIGHT', (text, count) => {
228
+ const str = String(text ?? '');
229
+ return str.substring(Math.max(0, str.length - count));
230
+ });
231
+ this.register('TRIM', (text) => {
232
+ return String(text ?? '').trim();
233
+ });
234
+ this.register('UPPER', (text) => {
235
+ return String(text ?? '').toUpperCase();
236
+ });
237
+ this.register('LOWER', (text) => {
238
+ return String(text ?? '').toLowerCase();
239
+ });
240
+ }
241
+ // ==========================================================================
242
+ // String Search Functions
243
+ // ==========================================================================
244
+ registerStringSearchFunctions() {
245
+ this.register('FIND', (search, text, startPos) => {
246
+ const str = String(text ?? '');
247
+ const idx = str.indexOf(String(search ?? ''), startPos ?? 0);
248
+ return idx;
249
+ });
250
+ this.register('REPLACE', (text, search, replacement) => {
251
+ const str = String(text ?? '');
252
+ return str.split(String(search ?? '')).join(String(replacement ?? ''));
253
+ });
254
+ this.register('SUBSTRING', (text, start, length) => {
255
+ const str = String(text ?? '');
256
+ if (length !== undefined) {
257
+ return str.substring(start, start + length);
258
+ }
259
+ return str.substring(start);
260
+ });
261
+ this.register('REGEX', (text, pattern, flags) => {
262
+ const str = String(text ?? '');
263
+ const regex = new RegExp(pattern, flags);
264
+ return regex.test(str);
265
+ });
266
+ this.register('LEN', (text) => {
267
+ return String(text ?? '').length;
268
+ });
269
+ }
270
+ // ==========================================================================
271
+ // Statistical Functions
272
+ // ==========================================================================
273
+ registerStatisticalFunctions() {
274
+ this.register('MEDIAN', (...args) => {
275
+ const values = flattenNumericArgs(args).sort((a, b) => a - b);
276
+ if (values.length === 0)
277
+ return 0;
278
+ const mid = Math.floor(values.length / 2);
279
+ return values.length % 2 !== 0
280
+ ? values[mid]
281
+ : (values[mid - 1] + values[mid]) / 2;
282
+ });
283
+ this.register('STDEV', (...args) => {
284
+ const values = flattenNumericArgs(args);
285
+ if (values.length < 2)
286
+ return 0;
287
+ const mean = values.reduce((sum, v) => sum + v, 0) / values.length;
288
+ const squaredDiffs = values.map(v => (v - mean) ** 2);
289
+ const variance = squaredDiffs.reduce((sum, v) => sum + v, 0) / (values.length - 1);
290
+ return Math.sqrt(variance);
291
+ });
292
+ this.register('VARIANCE', (...args) => {
293
+ const values = flattenNumericArgs(args);
294
+ if (values.length < 2)
295
+ return 0;
296
+ const mean = values.reduce((sum, v) => sum + v, 0) / values.length;
297
+ const squaredDiffs = values.map(v => (v - mean) ** 2);
298
+ return squaredDiffs.reduce((sum, v) => sum + v, 0) / (values.length - 1);
299
+ });
300
+ this.register('PERCENTILE', (percentile, ...args) => {
301
+ const values = flattenNumericArgs(args).sort((a, b) => a - b);
302
+ if (values.length === 0)
303
+ return 0;
304
+ const p = Math.max(0, Math.min(100, percentile)) / 100;
305
+ const index = p * (values.length - 1);
306
+ const lower = Math.floor(index);
307
+ const upper = Math.ceil(index);
308
+ if (lower === upper)
309
+ return values[lower];
310
+ const fraction = index - lower;
311
+ return values[lower] + fraction * (values[upper] - values[lower]);
312
+ });
313
+ }
314
+ }
315
+ // ==========================================================================
316
+ // Helpers
317
+ // ==========================================================================
318
+ /**
319
+ * Flatten nested arrays and extract numeric values
320
+ */
321
+ function flattenNumericArgs(args) {
322
+ const result = [];
323
+ for (const arg of args) {
324
+ if (Array.isArray(arg)) {
325
+ result.push(...flattenNumericArgs(arg));
326
+ }
327
+ else {
328
+ const num = Number(arg);
329
+ if (!isNaN(num)) {
330
+ result.push(num);
331
+ }
332
+ }
333
+ }
334
+ return result;
335
+ }
336
+ /**
337
+ * Flatten nested arrays
338
+ */
339
+ function flattenArgs(args) {
340
+ const result = [];
341
+ for (const arg of args) {
342
+ if (Array.isArray(arg)) {
343
+ result.push(...flattenArgs(arg));
344
+ }
345
+ else {
346
+ result.push(arg);
347
+ }
348
+ }
349
+ return result;
350
+ }
@@ -8,3 +8,4 @@
8
8
  export * from './ExpressionContext.js';
9
9
  export * from './ExpressionEvaluator.js';
10
10
  export * from './ExpressionCache.js';
11
+ export * from './FormulaFunctions.js';
@@ -8,3 +8,4 @@
8
8
  export * from './ExpressionContext.js';
9
9
  export * from './ExpressionEvaluator.js';
10
10
  export * from './ExpressionCache.js';
11
+ export * from './FormulaFunctions.js';
package/dist/index.d.ts CHANGED
@@ -9,9 +9,13 @@ export type { SchemaNode, ComponentRendererProps } from './types/index.js';
9
9
  export * from './registry/Registry.js';
10
10
  export * from './registry/PluginSystem.js';
11
11
  export * from './registry/PluginScopeImpl.js';
12
+ export * from './registry/WidgetRegistry.js';
12
13
  export * from './validation/index.js';
13
14
  export * from './builder/schema-builder.js';
14
15
  export * from './utils/filter-converter.js';
15
16
  export * from './evaluator/index.js';
16
17
  export * from './actions/index.js';
17
18
  export * from './query/index.js';
19
+ export * from './adapters/index.js';
20
+ export * from './theme/index.js';
21
+ export * from './data-scope/index.js';
package/dist/index.js CHANGED
@@ -8,11 +8,13 @@
8
8
  export * from './registry/Registry.js';
9
9
  export * from './registry/PluginSystem.js';
10
10
  export * from './registry/PluginScopeImpl.js';
11
+ export * from './registry/WidgetRegistry.js';
11
12
  export * from './validation/index.js';
12
13
  export * from './builder/schema-builder.js';
13
14
  export * from './utils/filter-converter.js';
14
15
  export * from './evaluator/index.js';
15
16
  export * from './actions/index.js';
16
17
  export * from './query/index.js';
17
- // export * from './data-scope'; // TODO
18
- // export * from './validators'; // TODO
18
+ export * from './adapters/index.js';
19
+ export * from './theme/index.js';
20
+ export * from './data-scope/index.js';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ObjectUI - Query AST Builder
3
3
  * Phase 3.3: QuerySchema AST implementation
4
- * ObjectStack Spec v0.7.1: Window functions support
4
+ * ObjectStack Spec v2.0.1: Window functions support
5
5
  */
6
6
  import type { QueryAST, QuerySchema } from '@object-ui/types';
7
7
  /**
@@ -23,7 +23,7 @@ export declare class QueryASTBuilder {
23
23
  private buildLiteral;
24
24
  private buildAggregation;
25
25
  /**
26
- * Build window function node (ObjectStack Spec v0.7.1)
26
+ * Build window function node (ObjectStack Spec v2.0.1)
27
27
  */
28
28
  private buildWindow;
29
29
  optimize(ast: QueryAST): QueryAST;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ObjectUI - Query AST Builder
3
3
  * Phase 3.3: QuerySchema AST implementation
4
- * ObjectStack Spec v0.7.1: Window functions support
4
+ * ObjectStack Spec v2.0.1: Window functions support
5
5
  */
6
6
  /**
7
7
  * Query AST Builder - Converts QuerySchema to AST
@@ -44,7 +44,7 @@ export class QueryASTBuilder {
44
44
  if (query.aggregations && query.aggregations.length > 0) {
45
45
  fields.push(...query.aggregations.map(agg => this.buildAggregation(agg)));
46
46
  }
47
- // Add window functions (ObjectStack Spec v0.7.1)
47
+ // Add window functions (ObjectStack Spec v2.0.1)
48
48
  if (query.windows && query.windows.length > 0) {
49
49
  fields.push(...query.windows.map(win => this.buildWindow(win)));
50
50
  }
@@ -227,7 +227,7 @@ export class QueryASTBuilder {
227
227
  };
228
228
  }
229
229
  /**
230
- * Build window function node (ObjectStack Spec v0.7.1)
230
+ * Build window function node (ObjectStack Spec v2.0.1)
231
231
  */
232
232
  buildWindow(config) {
233
233
  const node = {
@@ -26,6 +26,16 @@ export type ComponentMeta = {
26
26
  icon?: string;
27
27
  category?: string;
28
28
  namespace?: string;
29
+ /**
30
+ * When true, prevents the component from being registered with a non-namespaced fallback.
31
+ * Use this when a component should only be accessible via its full namespaced key.
32
+ * This avoids conflicts with other components that share the same base name.
33
+ *
34
+ * @example
35
+ * // Register as 'view:form' only, don't overwrite 'form'
36
+ * registry.register('form', FormView, { namespace: 'view', skipFallback: true });
37
+ */
38
+ skipFallback?: boolean;
29
39
  inputs?: ComponentInput[];
30
40
  defaultProps?: Record<string, any>;
31
41
  defaultChildren?: SchemaNode[];
@@ -51,7 +51,8 @@ export class Registry {
51
51
  // This allows "button" to work even when registered as "ui:button"
52
52
  // Note: If multiple namespaced components share the same short name,
53
53
  // the last registration wins for non-namespaced lookups
54
- if (meta?.namespace) {
54
+ // Skip this if skipFallback is true to avoid overwriting other components
55
+ if (meta?.namespace && !meta?.skipFallback) {
55
56
  this.components.set(type, {
56
57
  type: fullType, // Keep reference to namespaced type
57
58
  component,
@@ -0,0 +1,120 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * WidgetRegistry - Runtime widget management with auto-discovery.
10
+ *
11
+ * Provides registration, loading, and lookup of runtime widgets
12
+ * described by WidgetManifest objects. Widgets can be loaded from
13
+ * ES module URLs, provided inline, or resolved from the component registry.
14
+ *
15
+ * @module
16
+ */
17
+ import type { WidgetManifest, ResolvedWidget, WidgetRegistryListener } from '@object-ui/types';
18
+ import type { Registry } from './Registry.js';
19
+ /**
20
+ * Options for creating a WidgetRegistry instance.
21
+ */
22
+ export interface WidgetRegistryOptions {
23
+ /**
24
+ * Component registry to sync loaded widgets into.
25
+ * When a widget is loaded, its component is also registered here.
26
+ */
27
+ componentRegistry?: Registry;
28
+ }
29
+ /**
30
+ * WidgetRegistry manages runtime-loadable widgets described by manifests.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const widgets = new WidgetRegistry({ componentRegistry: registry });
35
+ *
36
+ * widgets.register({
37
+ * name: 'custom-chart',
38
+ * version: '1.0.0',
39
+ * type: 'chart',
40
+ * label: 'Custom Chart',
41
+ * source: { type: 'module', url: '/widgets/chart.js' },
42
+ * });
43
+ *
44
+ * const resolved = await widgets.load('custom-chart');
45
+ * ```
46
+ */
47
+ export declare class WidgetRegistry {
48
+ private manifests;
49
+ private resolved;
50
+ private listeners;
51
+ private componentRegistry?;
52
+ constructor(options?: WidgetRegistryOptions);
53
+ /**
54
+ * Register a widget manifest.
55
+ * Does not load the widget; call `load()` to resolve it.
56
+ */
57
+ register(manifest: WidgetManifest): void;
58
+ /**
59
+ * Register multiple widget manifests at once.
60
+ */
61
+ registerAll(manifests: WidgetManifest[]): void;
62
+ /**
63
+ * Unregister a widget by name.
64
+ */
65
+ unregister(name: string): boolean;
66
+ /**
67
+ * Get a widget manifest by name.
68
+ */
69
+ getManifest(name: string): WidgetManifest | undefined;
70
+ /**
71
+ * Get all registered widget manifests.
72
+ */
73
+ getAllManifests(): WidgetManifest[];
74
+ /**
75
+ * Get manifests filtered by category.
76
+ */
77
+ getByCategory(category: string): WidgetManifest[];
78
+ /**
79
+ * Check if a widget is registered.
80
+ */
81
+ has(name: string): boolean;
82
+ /**
83
+ * Check if a widget has been loaded (resolved).
84
+ */
85
+ isLoaded(name: string): boolean;
86
+ /**
87
+ * Load (resolve) a widget by name.
88
+ * If already loaded, returns the cached resolved widget.
89
+ *
90
+ * @throws Error if the widget is not registered or fails to load.
91
+ */
92
+ load(name: string): Promise<ResolvedWidget>;
93
+ /**
94
+ * Load all registered widgets.
95
+ * Returns an array of results (settled promises).
96
+ */
97
+ loadAll(): Promise<Array<{
98
+ name: string;
99
+ result: ResolvedWidget | Error;
100
+ }>>;
101
+ /**
102
+ * Subscribe to widget registry events.
103
+ * @returns Unsubscribe function.
104
+ */
105
+ on(listener: WidgetRegistryListener): () => void;
106
+ /**
107
+ * Clear all registered and loaded widgets.
108
+ */
109
+ clear(): void;
110
+ /**
111
+ * Get registry statistics.
112
+ */
113
+ getStats(): {
114
+ registered: number;
115
+ loaded: number;
116
+ categories: string[];
117
+ };
118
+ private resolveComponent;
119
+ private emit;
120
+ }