@object-ui/core 17.1.0 → 17.2.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.
@@ -5,6 +5,7 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
+ import type { ActionInput as SpecActionInput } from '@objectstack/spec/ui';
8
9
  import { ExpressionEvaluator } from '../evaluator/ExpressionEvaluator';
9
10
  import { type UndoableOperation } from './UndoManager';
10
11
  export interface ActionResult {
@@ -65,7 +66,12 @@ export interface ActionDef {
65
66
  /** Action type identifier — a `RunnableActionType` (the spec's six plus the
66
67
  * `navigation` alias of `url`) or a custom type with a registered handler. */
67
68
  type?: string;
68
- /** Legacy action type field */
69
+ /**
70
+ * Legacy action type field.
71
+ *
72
+ * @deprecated objectui dialect — use the spec spelling `type`. Both are read,
73
+ * `type` first (objectstack#4075 step 2).
74
+ */
69
75
  actionType?: string;
70
76
  /** Action name (from UIActionSchema) */
71
77
  name?: string;
@@ -84,13 +90,36 @@ export interface ActionDef {
84
90
  condition?: string;
85
91
  /** Disabled expression — if truthy, skip action */
86
92
  disabled?: string | boolean;
87
- /** API endpoint (string URL or complex config) */
93
+ /**
94
+ * API endpoint (string URL or complex config).
95
+ *
96
+ * @deprecated objectui dialect — the spec spells an `api` action's endpoint
97
+ * `target` (with the verb in `method`). `executeAPI` resolves
98
+ * `api || endpoint || target`, so `target` alone is sufficient. The
99
+ * `ApiConfig` object form has no spec counterpart and is objectui-only
100
+ * (objectstack#4075 step 2).
101
+ */
88
102
  api?: string | ApiConfig;
89
- /** API endpoint URL (spec v2.0.1 alias) */
103
+ /**
104
+ * API endpoint URL.
105
+ *
106
+ * @deprecated objectui dialect — this was the "spec v2.0.1 alias", but spec 17
107
+ * spells it `target`. `executeAPI` resolves `api || endpoint || target`
108
+ * (objectstack#4075 step 2).
109
+ */
90
110
  endpoint?: string;
91
111
  /** HTTP method */
92
112
  method?: string;
93
- /** Navigation target */
113
+ /**
114
+ * Navigation target — a nested envelope carrying the `navigation` alias's own
115
+ * spelling (`to` / `external` / `newTab` / `replace`).
116
+ *
117
+ * @deprecated objectui dialect — the spec has no nested navigation envelope;
118
+ * it spells a navigation action `{ type: 'url', target, openIn }`.
119
+ * `executeNavigation` reads `navigate.to || navigate.target || navigate.redirect`,
120
+ * falling back to the same keys on the action itself, so a flat `target` works
121
+ * today (objectstack#4075 step 2).
122
+ */
94
123
  navigate?: any;
95
124
  /** onClick callback (legacy) */
96
125
  onClick?: () => void | Promise<void>;
@@ -177,10 +206,82 @@ export interface ActionDef {
177
206
  * must perform all auth/authz itself (e.g. the cloud `/sso-open` endpoint,
178
207
  * which re-runs every check the POST half would have done). */
179
208
  newTabUrl?: string;
209
+ /** Where this action renders (`record_header`, `list_toolbar`, …). Read by
210
+ * `ActionEngine.registerActions` to seed the location filter. */
211
+ locations?: SpecActionInput['locations'];
212
+ /**
213
+ * Visibility predicate, evaluated against the runner's context.
214
+ *
215
+ * The `boolean` arm is objectui's own, deliberately wider than the spec:
216
+ * `ActionSchema.visible` admits only a CEL string or a `{ dialect, source }`
217
+ * envelope, while `ActionEngine.getActionsForLocation` also honours a literal
218
+ * `visible: true` / `false` (pinned by `ActionEngine.visibility.test.ts`).
219
+ * Declared rather than left to the index signature so the tolerance is
220
+ * auditable instead of invisible — but it IS a dialect, and objectstack#4075
221
+ * step 3 has to decide whether the spec adopts the boolean or objectui drops
222
+ * it. Do not widen this further.
223
+ */
224
+ visible?: SpecActionInput['visible'] | boolean;
225
+ /** System permissions the caller must ALL hold for the action to be offered
226
+ * (ADR-0066 D4 UI half — the server enforces the source of truth). */
227
+ requiredPermissions?: SpecActionInput['requiredPermissions'];
228
+ /** Icon name for the rendered control. */
229
+ icon?: SpecActionInput['icon'];
230
+ /** Visual emphasis of the rendered control (`primary`, `danger`, …). */
231
+ variant?: SpecActionInput['variant'];
232
+ /** Sort weight among sibling actions. */
233
+ order?: SpecActionInput['order'];
234
+ /** Which renderer surfaces the action (`action:button`, `action:menu`, …). */
235
+ component?: SpecActionInput['component'];
236
+ /** Object this action is declared against. */
237
+ objectName?: SpecActionInput['objectName'];
238
+ /** AI affordance metadata (tool exposure, prompts). */
239
+ ai?: SpecActionInput['ai'];
240
+ /** Accessibility overrides for the rendered control. */
241
+ aria?: SpecActionInput['aria'];
242
+ /** Extra properties merged into the request body alongside the collected params. */
243
+ bodyExtra?: SpecActionInput['bodyExtra'];
244
+ /** How collected params are shaped into the request body (`flat` or nested). */
245
+ bodyShape?: SpecActionInput['bodyShape'];
246
+ /** Execution mode of the action. */
247
+ mode?: SpecActionInput['mode'];
248
+ /** Field on the record supplying the record id sent to the endpoint. */
249
+ recordIdField?: SpecActionInput['recordIdField'];
250
+ /** Request-parameter name carrying the record id. */
251
+ recordIdParam?: SpecActionInput['recordIdParam'];
252
+ /** Auth/tenancy feature the action requires before it is offered. */
253
+ requiresFeature?: SpecActionInput['requiresFeature'];
254
+ /**
255
+ * @deprecated Retired in `@objectstack/spec` 17 as a `retiredKey()` tombstone —
256
+ * authoring it is a hard parse rejection, so this resolves to `undefined` and
257
+ * assigning a value is a compile error. A HOST may still pass a shortcut
258
+ * explicitly via `ActionEngine.registerAction(action, { shortcut })`; it is
259
+ * only no longer sourced from authored metadata. No replacement key.
260
+ */
261
+ shortcut?: SpecActionInput['shortcut'];
262
+ /**
263
+ * @deprecated Retired in `@objectstack/spec` 17 as a `retiredKey()` tombstone —
264
+ * authoring it is a hard parse rejection, so this resolves to `undefined` and
265
+ * assigning a value is a compile error. Use the list view's `bulkActions` /
266
+ * `bulkActionDefs` instead; `ActionEngine.registerAction(action, { bulkEnabled })`
267
+ * remains available to a HOST passing it explicitly.
268
+ */
269
+ bulkEnabled?: SpecActionInput['bulkEnabled'];
180
270
  /** Any additional properties */
181
271
  [key: string]: any;
182
272
  }
183
- export type ActionHandler = (action: ActionDef, context: ActionContext) => Promise<ActionResult> | ActionResult;
273
+ /**
274
+ * A handler registered with {@link ActionRunner} — the client-side action
275
+ * dispatch seam: given an authored `ActionDef` and the invocation context,
276
+ * produce an `ActionResult`.
277
+ *
278
+ * NOT the spec's `ActionHandler` (`@objectstack/spec/ui`), whose name this type
279
+ * carried until objectstack#4115. That one is the SERVER-side objectql action
280
+ * handler — a different calling convention entirely (`(ctx) => unknown`, with
281
+ * validated params and a trusted engine facade on `ctx`) and a different
282
+ * execution site.
283
+ */
284
+ export type ActionRunnerHandler = (action: ActionDef, context: ActionContext) => Promise<ActionResult> | ActionResult;
184
285
  /**
185
286
  * Confirmation handler — replaces window.confirm.
186
287
  * Consumers can provide an async implementation (e.g., Shadcn AlertDialog).
@@ -353,7 +454,7 @@ export declare class ActionRunner {
353
454
  * values the user must copy now (2FA codes, OAuth client_secret).
354
455
  */
355
456
  setResultDialogHandler(handler: ResultDialogHandler): void;
356
- registerHandler(actionName: string, handler: ActionHandler): void;
457
+ registerHandler(actionName: string, handler: ActionRunnerHandler): void;
357
458
  unregisterHandler(actionName: string): void;
358
459
  /**
359
460
  * Register a named script handler. When a `script` action's
@@ -361,7 +462,7 @@ export declare class ActionRunner {
361
462
  * instead of the expression evaluator. Lets dashboards/views wire
362
463
  * symbolic action names (e.g. 'export_dashboard_pdf') to JS callbacks.
363
464
  */
364
- registerScript(scriptName: string, handler: ActionHandler): void;
465
+ registerScript(scriptName: string, handler: ActionRunnerHandler): void;
365
466
  unregisterScript(scriptName: string): void;
366
467
  execute(action: ActionDef): Promise<ActionResult>;
367
468
  /**
@@ -467,9 +568,15 @@ export declare class ActionRunner {
467
568
  * fragment.
468
569
  *
469
570
  * `ctx.origin`, `ctx.user.*`, `ctx.org.*`, `ctx.recordId` are surfaced
470
- * implicitly from the runner's ActionContext + window. Consumers can
471
- * extend by stuffing extra keys under `context.ctx = {...}` before
472
- * calling `runner.execute()`.
571
+ * implicitly from the runner's ActionContext + window, and
572
+ * `ctx.selection.ids` / `ctx.selection.count` reflect the grid's current
573
+ * checkbox selection (`context.selectedRecords`) — `${ctx.selection.ids}`
574
+ * comma-joins the ids via the standard `String(array)` behaviour, so a
575
+ * list_toolbar url/api action can carry the selection without any bulk
576
+ * plumbing (objectui#3139). In an aggregate bulk dispatch,
577
+ * `${param._selectedIds}` interpolates the same ids from the injected
578
+ * param. Consumers can extend by stuffing extra keys under
579
+ * `context.ctx = {...}` before calling `runner.execute()`.
473
580
  */
474
581
  private interpolateTarget;
475
582
  /**
@@ -802,9 +802,15 @@ export class ActionRunner {
802
802
  * fragment.
803
803
  *
804
804
  * `ctx.origin`, `ctx.user.*`, `ctx.org.*`, `ctx.recordId` are surfaced
805
- * implicitly from the runner's ActionContext + window. Consumers can
806
- * extend by stuffing extra keys under `context.ctx = {...}` before
807
- * calling `runner.execute()`.
805
+ * implicitly from the runner's ActionContext + window, and
806
+ * `ctx.selection.ids` / `ctx.selection.count` reflect the grid's current
807
+ * checkbox selection (`context.selectedRecords`) — `${ctx.selection.ids}`
808
+ * comma-joins the ids via the standard `String(array)` behaviour, so a
809
+ * list_toolbar url/api action can carry the selection without any bulk
810
+ * plumbing (objectui#3139). In an aggregate bulk dispatch,
811
+ * `${param._selectedIds}` interpolates the same ids from the injected
812
+ * param. Consumers can extend by stuffing extra keys under
813
+ * `context.ctx = {...}` before calling `runner.execute()`.
808
814
  */
809
815
  interpolateTarget(target, action) {
810
816
  if (typeof target !== 'string' || target.indexOf('${') === -1)
@@ -839,6 +845,22 @@ export class ActionRunner {
839
845
  user: this.context.user ?? {},
840
846
  org: this.context.org ?? this.context.organization ?? {},
841
847
  recordId: this.context.record?.id ?? this.context.recordId,
848
+ // Current list selection (published by the grid as `selectedRecords`).
849
+ // `${ctx.selection.ids}` in a url/api target comma-joins the ids —
850
+ // String(array) — giving toolbar actions selection access without any
851
+ // bulk-executor involvement (objectui#3139). Empty when nothing is
852
+ // selected, so authors can treat "" as "no selection".
853
+ selection: {
854
+ ids: Array.isArray(this.context.selectedRecords)
855
+ ? this.context.selectedRecords
856
+ .map((r) => r?.id)
857
+ .filter((v) => v != null)
858
+ .map(String)
859
+ : [],
860
+ count: Array.isArray(this.context.selectedRecords)
861
+ ? this.context.selectedRecords.length
862
+ : 0,
863
+ },
842
864
  };
843
865
  if (this.context.ctx && typeof this.context.ctx === 'object') {
844
866
  Object.assign(ctx, this.context.ctx);
@@ -32,25 +32,42 @@
32
32
  * interface it mirrors would be the same "declared ≠ enforced" trap this whole
33
33
  * thread is about.
34
34
  *
35
- * ── What the inventory found, i.e. step 2's worklist ─────────────────────────
36
- * `ActionDef` declares 34 keys, the spec's `ActionSchema` declares 36, and they
37
- * overlap on 17. The two halves of the difference are different problems:
35
+ * ── What the inventory found, and what step 2 did with it ────────────────────
36
+ * Step 1 found `ActionDef` declaring 34 keys against the spec `ActionSchema`'s
37
+ * 36, overlapping on 17. The two halves of the difference were different
38
+ * problems, and step 2 (objectstack#4075) treated them differently:
38
39
  *
39
40
  * 18 keys the SPEC owns that `ActionDef` never declared — `ai`, `aria`,
40
41
  * `bodyExtra`, `bodyShape`, `bulkEnabled`, `component`, `icon`, `locations`,
41
42
  * `mode`, `objectName`, `order`, `recordIdField`, `recordIdParam`,
42
43
  * `requiredPermissions`, `requiresFeature`, `shortcut`, `variant`, `visible`.
43
- * These are authored today and reach readers through the index signature.
44
- * `ActionEngine` reads two of them (`visible` at the location filter, `locations`
45
- * at registration) through an `as any` cast — a cast that exists ONLY because the
46
- * field is undeclared, and that goes away when step 2 promotes them.
44
+ * These are authored today and used to reach readers through the index
45
+ * signature. **Step 2 promoted all 18 to explicit optional fields**, typed by
46
+ * DERIVATION from `@objectstack/spec`'s `ActionInput` rather than by hand-copied
47
+ * shapes. The `as any` casts `ActionEngine` needed to read `visible`,
48
+ * `locations` and `requiredPermissions` are gone with them — those casts existed
49
+ * only because the fields were undeclared.
50
+ *
51
+ * Two of the 18 landed as `undefined` rather than as usable types, which is the
52
+ * correct outcome: spec 17 retired `shortcut` and `bulkEnabled` as `retiredKey()`
53
+ * tombstones (`z.never()`), so deriving turns "authoring this is a parse
54
+ * rejection" into a compile error at no cost. Hand-copying would have quietly
55
+ * re-legitimized two dead keys — which is why the types are derived.
47
56
  *
48
57
  * 17 keys `ActionDef` declares that the spec does not own — `actionType`, `api`,
49
58
  * `chain`, `chainMode`, `close`, `condition`, `confirm`, `endpoint`, `modal`,
50
59
  * `navigate`, `onClick`, `onFailure`, `onSuccess`, `redirect`, `reload`, `toast`,
51
- * `actionParams`. Several are already marked legacy at their declaration. These
52
- * are objectui's own dialect and need the #4115 treatment: kept and documented as
53
- * deliberate, or retired — but not silently carried.
60
+ * `actionParams`. Step 2 marked `@deprecated`, with the spec spelling to use
61
+ * instead, ONLY the four the runner itself proves are aliases: `actionType` (→
62
+ * `type`), `api` and `endpoint` (→ `target`; `executeAPI` resolves
63
+ * `api || endpoint || target`), and `navigate` (→ flat `target`/`openIn`;
64
+ * `executeNavigation` already falls back to them). The rest are runner mechanics
65
+ * with no spec counterpart — chaining, toasts, post-execution reload/close — and
66
+ * deprecating them toward a spelling that does not exist would be worse than
67
+ * leaving them declared.
68
+ *
69
+ * Step 3 remains: remove the index signature, at which point `tsc` catches both
70
+ * typos and retired keys and the dev-mode warning below can retire with it.
54
71
  */
55
72
  /**
56
73
  * Every property `ActionDef` declares, in declaration order.
@@ -59,7 +76,7 @@
59
76
  * `keyof ActionDef` cannot substitute for this list: the index signature widens
60
77
  * it to `string | number`, which is precisely the problem being worked around.
61
78
  */
62
- export declare const ACTION_DEF_KEYS: readonly ["type", "actionType", "name", "label", "confirmText", "confirm", "condition", "disabled", "api", "endpoint", "method", "navigate", "onClick", "reload", "close", "redirect", "toast", "successMessage", "errorMessage", "refreshAfter", "undoable", "params", "actionParams", "resultDialog", "target", "body", "openIn", "modal", "chain", "chainMode", "onSuccess", "onFailure", "opensInNewTab", "newTabUrl"];
79
+ export declare const ACTION_DEF_KEYS: readonly ["type", "actionType", "name", "label", "confirmText", "confirm", "condition", "disabled", "api", "endpoint", "method", "navigate", "onClick", "reload", "close", "redirect", "toast", "successMessage", "errorMessage", "refreshAfter", "undoable", "params", "actionParams", "resultDialog", "target", "body", "openIn", "modal", "chain", "chainMode", "onSuccess", "onFailure", "opensInNewTab", "newTabUrl", "locations", "visible", "requiredPermissions", "icon", "variant", "order", "component", "objectName", "ai", "aria", "bodyExtra", "bodyShape", "mode", "recordIdField", "recordIdParam", "requiresFeature", "shortcut", "bulkEnabled"];
63
80
  /**
64
81
  * Every property `@objectstack/spec`'s `ActionSchema` declares.
65
82
  *
@@ -32,25 +32,42 @@
32
32
  * interface it mirrors would be the same "declared ≠ enforced" trap this whole
33
33
  * thread is about.
34
34
  *
35
- * ── What the inventory found, i.e. step 2's worklist ─────────────────────────
36
- * `ActionDef` declares 34 keys, the spec's `ActionSchema` declares 36, and they
37
- * overlap on 17. The two halves of the difference are different problems:
35
+ * ── What the inventory found, and what step 2 did with it ────────────────────
36
+ * Step 1 found `ActionDef` declaring 34 keys against the spec `ActionSchema`'s
37
+ * 36, overlapping on 17. The two halves of the difference were different
38
+ * problems, and step 2 (objectstack#4075) treated them differently:
38
39
  *
39
40
  * 18 keys the SPEC owns that `ActionDef` never declared — `ai`, `aria`,
40
41
  * `bodyExtra`, `bodyShape`, `bulkEnabled`, `component`, `icon`, `locations`,
41
42
  * `mode`, `objectName`, `order`, `recordIdField`, `recordIdParam`,
42
43
  * `requiredPermissions`, `requiresFeature`, `shortcut`, `variant`, `visible`.
43
- * These are authored today and reach readers through the index signature.
44
- * `ActionEngine` reads two of them (`visible` at the location filter, `locations`
45
- * at registration) through an `as any` cast — a cast that exists ONLY because the
46
- * field is undeclared, and that goes away when step 2 promotes them.
44
+ * These are authored today and used to reach readers through the index
45
+ * signature. **Step 2 promoted all 18 to explicit optional fields**, typed by
46
+ * DERIVATION from `@objectstack/spec`'s `ActionInput` rather than by hand-copied
47
+ * shapes. The `as any` casts `ActionEngine` needed to read `visible`,
48
+ * `locations` and `requiredPermissions` are gone with them — those casts existed
49
+ * only because the fields were undeclared.
50
+ *
51
+ * Two of the 18 landed as `undefined` rather than as usable types, which is the
52
+ * correct outcome: spec 17 retired `shortcut` and `bulkEnabled` as `retiredKey()`
53
+ * tombstones (`z.never()`), so deriving turns "authoring this is a parse
54
+ * rejection" into a compile error at no cost. Hand-copying would have quietly
55
+ * re-legitimized two dead keys — which is why the types are derived.
47
56
  *
48
57
  * 17 keys `ActionDef` declares that the spec does not own — `actionType`, `api`,
49
58
  * `chain`, `chainMode`, `close`, `condition`, `confirm`, `endpoint`, `modal`,
50
59
  * `navigate`, `onClick`, `onFailure`, `onSuccess`, `redirect`, `reload`, `toast`,
51
- * `actionParams`. Several are already marked legacy at their declaration. These
52
- * are objectui's own dialect and need the #4115 treatment: kept and documented as
53
- * deliberate, or retired — but not silently carried.
60
+ * `actionParams`. Step 2 marked `@deprecated`, with the spec spelling to use
61
+ * instead, ONLY the four the runner itself proves are aliases: `actionType` (→
62
+ * `type`), `api` and `endpoint` (→ `target`; `executeAPI` resolves
63
+ * `api || endpoint || target`), and `navigate` (→ flat `target`/`openIn`;
64
+ * `executeNavigation` already falls back to them). The rest are runner mechanics
65
+ * with no spec counterpart — chaining, toasts, post-execution reload/close — and
66
+ * deprecating them toward a spelling that does not exist would be worse than
67
+ * leaving them declared.
68
+ *
69
+ * Step 3 remains: remove the index signature, at which point `tsc` catches both
70
+ * typos and retired keys and the dev-mode warning below can retire with it.
54
71
  */
55
72
  /**
56
73
  * Every property `ActionDef` declares, in declaration order.
@@ -94,6 +111,29 @@ export const ACTION_DEF_KEYS = [
94
111
  'onFailure',
95
112
  'opensInNewTab',
96
113
  'newTabUrl',
114
+ // Promoted out of the index signature by objectstack#4075 step 2 — the 18 keys
115
+ // the spec owns that `ActionDef` had never declared. Their types are derived
116
+ // from `@objectstack/spec`'s `ActionInput`, so this list is the only
117
+ // hand-maintained half, and `actionKeys.pin.test.ts` re-derives it from the
118
+ // interface's AST.
119
+ 'locations',
120
+ 'visible',
121
+ 'requiredPermissions',
122
+ 'icon',
123
+ 'variant',
124
+ 'order',
125
+ 'component',
126
+ 'objectName',
127
+ 'ai',
128
+ 'aria',
129
+ 'bodyExtra',
130
+ 'bodyShape',
131
+ 'mode',
132
+ 'recordIdField',
133
+ 'recordIdParam',
134
+ 'requiresFeature',
135
+ 'shortcut',
136
+ 'bulkEnabled',
97
137
  ];
98
138
  /**
99
139
  * Every property `@objectstack/spec`'s `ActionSchema` declares.
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * ObjectUI - Query AST Builder
3
- * Phase 3.3: QuerySchema AST implementation
3
+ * Phase 3.3: DriverQueryConfig AST implementation
4
4
  * ObjectStack Spec v2.0.1: Window functions support
5
5
  */
6
- import type { QueryAST, QuerySchema } from '@object-ui/types';
6
+ import type { SqlQueryAST, DriverQueryConfig } from '@object-ui/types';
7
7
  /**
8
- * Query AST Builder - Converts QuerySchema to AST
8
+ * Query AST Builder - Converts DriverQueryConfig to AST
9
9
  */
10
10
  export declare class QueryASTBuilder {
11
- build(query: QuerySchema): QueryAST;
11
+ build(query: DriverQueryConfig): SqlQueryAST;
12
12
  private buildSelect;
13
13
  private buildFrom;
14
14
  private buildWhere;
@@ -26,7 +26,7 @@ export declare class QueryASTBuilder {
26
26
  * Build window function node (ObjectStack Spec v2.0.1)
27
27
  */
28
28
  private buildWindow;
29
- optimize(ast: QueryAST): QueryAST;
29
+ optimize(ast: SqlQueryAST): SqlQueryAST;
30
30
  }
31
31
  export declare const defaultQueryASTBuilder: QueryASTBuilder;
32
- export declare function buildQueryAST(query: QuerySchema): QueryAST;
32
+ export declare function buildQueryAST(query: DriverQueryConfig): SqlQueryAST;
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * ObjectUI - Query AST Builder
3
- * Phase 3.3: QuerySchema AST implementation
3
+ * Phase 3.3: DriverQueryConfig AST implementation
4
4
  * ObjectStack Spec v2.0.1: Window functions support
5
5
  */
6
6
  /**
7
- * Query AST Builder - Converts QuerySchema to AST
7
+ * Query AST Builder - Converts DriverQueryConfig to AST
8
8
  */
9
9
  export class QueryASTBuilder {
10
10
  build(query) {
@@ -7,7 +7,17 @@
7
7
  */
8
8
  import type { Registry } from './Registry.js';
9
9
  import type { PluginScope, PluginScopeConfig, AppMetadataPlugin, AppPluginContext } from '@object-ui/types';
10
- export interface PluginDefinition {
10
+ /**
11
+ * A plugin for objectui's component REGISTRY: it declares its name/version and
12
+ * a `register(registry | scope)` callback that contributes renderers.
13
+ *
14
+ * NOT the spec's `PluginDefinition` (`@objectstack/spec/kernel`), whose name
15
+ * this interface carried until objectstack#4115. That one is the platform
16
+ * PACKAGE manifest — `{ id?, type?, slug?, staticPath?, version?, author?,
17
+ * homepage?, onInstall?, onEnable?, … }` — a marketplace/install-time document
18
+ * with no `register` seam, and it shares no required member with this type.
19
+ */
20
+ export interface RegistryPluginDefinition {
11
21
  name: string;
12
22
  version: string;
13
23
  dependencies?: string[];
@@ -28,7 +38,7 @@ export declare class PluginSystem {
28
38
  * @param useScope Whether to use scoped loading (default: true for better isolation)
29
39
  * @throws Error if dependencies are missing
30
40
  */
31
- loadPlugin(plugin: PluginDefinition, registry: Registry, useScope?: boolean): Promise<void>;
41
+ loadPlugin(plugin: RegistryPluginDefinition, registry: Registry, useScope?: boolean): Promise<void>;
32
42
  /**
33
43
  * Unload a plugin from the system
34
44
  * @param name The name of the plugin to unload
@@ -52,7 +62,7 @@ export declare class PluginSystem {
52
62
  * @param name The name of the plugin
53
63
  * @returns The plugin definition or undefined
54
64
  */
55
- getPlugin(name: string): PluginDefinition | undefined;
65
+ getPlugin(name: string): RegistryPluginDefinition | undefined;
56
66
  /**
57
67
  * Get all loaded plugin names
58
68
  * @returns Array of loaded plugin names
@@ -62,11 +72,11 @@ export declare class PluginSystem {
62
72
  * Get all plugin definitions
63
73
  * @returns Array of all plugin definitions
64
74
  */
65
- getAllPlugins(): PluginDefinition[];
75
+ getAllPlugins(): RegistryPluginDefinition[];
66
76
  /**
67
77
  * Install an AppMetadataPlugin at runtime.
68
78
  *
69
- * Wraps the plugin as a PluginDefinition, calls its `init()` and `start()`
79
+ * Wraps the plugin as a RegistryPluginDefinition, calls its `init()` and `start()`
70
80
  * lifecycle hooks, and loads it into the system.
71
81
  *
72
82
  * @param plugin - An AppMetadataPlugin instance
@@ -142,7 +142,7 @@ export class PluginSystem {
142
142
  /**
143
143
  * Install an AppMetadataPlugin at runtime.
144
144
  *
145
- * Wraps the plugin as a PluginDefinition, calls its `init()` and `start()`
145
+ * Wraps the plugin as a RegistryPluginDefinition, calls its `init()` and `start()`
146
146
  * lifecycle hooks, and loads it into the system.
147
147
  *
148
148
  * @param plugin - An AppMetadataPlugin instance
@@ -9,12 +9,12 @@
9
9
  * WidgetRegistry - Runtime widget management with auto-discovery.
10
10
  *
11
11
  * Provides registration, loading, and lookup of runtime widgets
12
- * described by WidgetManifest objects. Widgets can be loaded from
12
+ * described by RuntimeWidgetManifest objects. Widgets can be loaded from
13
13
  * ES module URLs, provided inline, or resolved from the component registry.
14
14
  *
15
15
  * @module
16
16
  */
17
- import type { WidgetManifest, ResolvedWidget, WidgetRegistryListener } from '@object-ui/types';
17
+ import type { RuntimeWidgetManifest, ResolvedWidget, WidgetRegistryListener } from '@object-ui/types';
18
18
  import type { Registry } from './Registry.js';
19
19
  /**
20
20
  * Options for creating a WidgetRegistry instance.
@@ -54,11 +54,11 @@ export declare class WidgetRegistry {
54
54
  * Register a widget manifest.
55
55
  * Does not load the widget; call `load()` to resolve it.
56
56
  */
57
- register(manifest: WidgetManifest): void;
57
+ register(manifest: RuntimeWidgetManifest): void;
58
58
  /**
59
59
  * Register multiple widget manifests at once.
60
60
  */
61
- registerAll(manifests: WidgetManifest[]): void;
61
+ registerAll(manifests: RuntimeWidgetManifest[]): void;
62
62
  /**
63
63
  * Unregister a widget by name.
64
64
  */
@@ -66,15 +66,15 @@ export declare class WidgetRegistry {
66
66
  /**
67
67
  * Get a widget manifest by name.
68
68
  */
69
- getManifest(name: string): WidgetManifest | undefined;
69
+ getManifest(name: string): RuntimeWidgetManifest | undefined;
70
70
  /**
71
71
  * Get all registered widget manifests.
72
72
  */
73
- getAllManifests(): WidgetManifest[];
73
+ getAllManifests(): RuntimeWidgetManifest[];
74
74
  /**
75
75
  * Get manifests filtered by category.
76
76
  */
77
- getByCategory(category: string): WidgetManifest[];
77
+ getByCategory(category: string): RuntimeWidgetManifest[];
78
78
  /**
79
79
  * Check if a widget is registered.
80
80
  */
@@ -244,7 +244,7 @@ export class WidgetRegistry {
244
244
  // source.url is only known at runtime.
245
245
  //
246
246
  // Security: Widget URLs must be from trusted sources only. Never pass
247
- // user-supplied URLs directly to WidgetManifest. URLs should be validated
247
+ // user-supplied URLs directly to RuntimeWidgetManifest. URLs should be validated
248
248
  // and controlled by the application developer.
249
249
  //
250
250
  // CSP Consideration: If your application uses strict Content Security Policy,
@@ -19,14 +19,20 @@
19
19
  * `large` is the unconditional base; `medium`/`small`/`xsmall` are `max-width`
20
20
  * overrides.
21
21
  */
22
- export type StyleMap = Record<string, string | number>;
23
- export interface ResponsiveStyles {
24
- /** Unconditional base (desktop-first). */
25
- large?: StyleMap;
26
- medium?: StyleMap;
27
- small?: StyleMap;
28
- xsmall?: StyleMap;
29
- }
22
+ import type { ResponsiveStyles } from '@objectstack/spec/ui';
23
+ /**
24
+ * `StyleMap` / `ResponsiveStyles` are **owned by the spec** (ADR-0065,
25
+ * `@objectstack/spec/ui`) and re-exported here, not re-declared.
26
+ *
27
+ * They used to be hand-written copies under the spec's own names. Both were
28
+ * member-for-member identical to the spec's at the time of the burn-down
29
+ * (objectstack#4115), which is exactly what makes a copy dangerous: it passes
30
+ * every structural comparison right up until the spec adds a breakpoint or
31
+ * widens a value type, and the doc comment above claims spec canonicity the
32
+ * whole time. Binding the names to the spec at compile time is the only form
33
+ * that cannot drift.
34
+ */
35
+ export type { StyleMap, ResponsiveStyles } from '@objectstack/spec/ui';
30
36
  /** max-width breakpoints (px), mirroring Builder.io's default device sizes. */
31
37
  export declare const STYLE_BREAKPOINTS: Record<'medium' | 'small' | 'xsmall', number>;
32
38
  /** True when a node actually carries responsive styles worth compiling. */
@@ -26,14 +26,26 @@ export interface ChartResultField {
26
26
  label?: string;
27
27
  format?: string;
28
28
  }
29
- export interface ChartSeries {
29
+ /**
30
+ * One renderer-internal series binding produced by {@link buildChartSeries}:
31
+ * WHICH result-set column to draw and what to call it.
32
+ *
33
+ * NOT the spec's `ChartSeries` (`@objectstack/spec/ui`), which this type was
34
+ * named after until objectstack#4115. That one is the AUTHORED dataset-binding
35
+ * descriptor — `{ name, label?, type?, color?, stack?, yAxis, variant?,
36
+ * dashArray?, opacity? }`, where `name` is a measure and no `data` is carried.
37
+ * A third shape, `ChartDataSeries` in `@object-ui/types` (renamed in the same
38
+ * burn-down), is the inline static-data series of an SDUI `ChartSchema` node.
39
+ * Three different concepts; this is the one the chart renderers consume.
40
+ */
41
+ export interface ChartSeriesBinding {
30
42
  dataKey: string;
31
43
  label: string;
32
44
  }
33
45
  export interface ChartSeriesResult {
34
46
  data: Array<Record<string, unknown>>;
35
47
  xAxisKey: string | undefined;
36
- series: ChartSeries[];
48
+ series: ChartSeriesBinding[];
37
49
  }
38
50
  export declare function buildChartSeries(rows: Array<Record<string, unknown>> | null | undefined, dimensions: string[] | null | undefined, values: string[] | null | undefined, fields?: ChartResultField[] | null): ChartSeriesResult;
39
51
  /**
@@ -78,6 +78,15 @@ export declare function dashboardFilterVariableDefs(defs: DashboardFilterDef[]):
78
78
  * Build the operator shape (the value side of a `FilterCondition` entry) for
79
79
  * one filter's current value. Returns `undefined` when the value imposes no
80
80
  * constraint. The caller keys the result by the bound field name.
81
+ *
82
+ * A `date`/`dateRange` value is held to three spellings (#3151): a known
83
+ * preset name → range bounds; a date-macro token or ISO date → equality on
84
+ * that day; **anything else → skipped with a console warning**, never
85
+ * silently downgraded to an equality nothing can match. That last branch is
86
+ * the same strictness `buildWidgetScopedFilter` applies to a default binding
87
+ * on an unknown field name, for the same reason: a query the backend answers
88
+ * `200 OK` with zero rows is indistinguishable from "this range has no data",
89
+ * so the typo has to be said out loud somewhere.
81
90
  */
82
91
  export declare function buildFilterCondition(def: DashboardFilterDef, value: unknown): Record<string, unknown> | unknown | undefined;
83
92
  /**