@almadar/core 7.10.0 → 7.11.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.
@@ -1,8 +1,156 @@
1
- import { T as TraitEventContract, E as Entity, a as TraitEventListener, b as TraitConfig, c as EntityField, d as EntityPersistence, e as EntityRow, U as UseDeclaration, f as EntityRef, g as TraitRef, P as PageRef, O as OrbitalDefinition, h as OrbitalSchema, i as Trait, j as Page, k as PageRefObject, l as TraitReference } from './schema-VTi4U3sS.js';
1
+ import { U as UISlot, E as Effect, T as Trait, R as RenderUIEffect, a as TraitEventContract, b as Entity, c as TraitEventListener, d as TraitConfig, e as EntityField, f as EntityPersistence, g as EntityRow, h as UseDeclaration, i as EntityRef, j as TraitRef, P as PageRef, O as OrbitalDefinition, k as OrbitalSchema, l as Page, m as PageRefObject, n as TraitReference } from './schema-CSAEAlE6.js';
2
2
  import { S as SExpr } from './expression-eBO9-SQM.js';
3
- export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-UN56dMBD.js';
3
+ export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-B0k9Zoiw.js';
4
+ import { AnyPatternConfig } from '@almadar/patterns';
4
5
  import 'zod';
5
- import '@almadar/patterns';
6
+
7
+ /**
8
+ * Layout-Trait Builders
9
+ *
10
+ * Helpers for constructing the canonical inline LayoutTrait pattern that
11
+ * std layout-shell molecules (`std-filtered-list`, `std-master-detail-layout`,
12
+ * etc.) use to wrap a set of atom trait references in a `(render-ui main)`
13
+ * effect with `@trait.X` slot embeds.
14
+ *
15
+ * The canonical LayoutTrait is stateless: ONE state (`composing`, initial),
16
+ * ONE transition (`INIT` self-loop) carrying two effects — `(fetch Entity
17
+ * {emit: {success, failure}})` and `(render-ui "main" <pattern-tree>)`. Atoms
18
+ * embedded via `@trait.X` slot references react to the bus events the fetch
19
+ * emits; the LayoutTrait owns no further state.
20
+ *
21
+ * Usage from a std layout-shell molecule:
22
+ *
23
+ * ```ts
24
+ * import { makeSlot, makeLayoutTrait } from '@almadar/core/builders';
25
+ *
26
+ * const layout = makeLayoutTrait({
27
+ * name: 'DashboardLayout',
28
+ * linkedEntity: 'Metric',
29
+ * fetchEntity: 'Metric',
30
+ * loadedEvent: 'MetricLoaded',
31
+ * loadFailedEvent: 'MetricLoadFailed',
32
+ * renderUI: {
33
+ * type: 'stack',
34
+ * direction: 'vertical',
35
+ * children: [
36
+ * makeSlot('StatsRow'),
37
+ * makeSlot('ChartsRow'),
38
+ * makeSlot('FeedRow'),
39
+ * ],
40
+ * },
41
+ * });
42
+ * ```
43
+ *
44
+ * @packageDocumentation
45
+ */
46
+
47
+ /**
48
+ * Build a `@trait.<name>` slot reference string. Used as a child entry in a
49
+ * pattern tree to embed another trait's render-ui at that position. The
50
+ * runtime resolves `@trait.X` to the matching trait's render-ui inline.
51
+ *
52
+ * @example makeSlot('FilteredItemSearch') // "@trait.FilteredItemSearch"
53
+ */
54
+ declare function makeSlot(traitName: string): string;
55
+ /**
56
+ * Build a `(render-ui <slot> <root>)` effect tuple. Pattern-typed sugar over
57
+ * the raw `RenderUIEffect` literal so callers don't have to spell out the
58
+ * three-element tuple form.
59
+ *
60
+ * @param slot - Canonical UI slot name (`'main'`, `'header'`, etc. — see UI_SLOTS).
61
+ * @param root - The pattern config for this slot's content. Pass `null` to clear.
62
+ */
63
+ declare function makeRenderUI(slot: UISlot, root: AnyPatternConfig | null): RenderUIEffect;
64
+ /**
65
+ * Options for {@link makeLayoutTrait}.
66
+ */
67
+ interface MakeLayoutTraitOpts {
68
+ /** Trait name, e.g. `"DashboardGridLayout"`. */
69
+ name: string;
70
+ /** Entity this layout's emits/listens bind to. */
71
+ linkedEntity: string;
72
+ /** Optional human-readable description (carried through to `Trait.description`). */
73
+ description?: string;
74
+ /**
75
+ * Entity name to fetch on INIT. When set, a `(fetch <Entity> {emit:
76
+ * {success, failure}})` effect is prepended to the INIT transition. Omit
77
+ * for purely-presentational layouts that don't load data themselves.
78
+ */
79
+ fetchEntity?: string;
80
+ /**
81
+ * Event name emitted on successful fetch. Required when `fetchEntity` is
82
+ * set; the LayoutTrait declares this event in its `emits` and uses it as
83
+ * the `success` emit-name in the fetch effect.
84
+ * Convention: `"<Entity>Loaded"`.
85
+ */
86
+ loadedEvent?: string;
87
+ /**
88
+ * Event name emitted on fetch failure. Required when `fetchEntity` is
89
+ * set. Convention: `"<Entity>LoadFailed"`.
90
+ */
91
+ loadFailedEvent?: string;
92
+ /**
93
+ * Payload schema for the loaded event. Defaults to `[{ name: "data", type:
94
+ * "[<Entity>]" }]` when `fetchEntity` is set. Provide explicitly when the
95
+ * payload should carry additional fields.
96
+ */
97
+ loadedPayloadSchema?: Array<{
98
+ name: string;
99
+ type: string;
100
+ required?: boolean;
101
+ }>;
102
+ /**
103
+ * The pattern tree for the layout's main slot. Children may include
104
+ * `@trait.X` slot strings (built via {@link makeSlot}) interleaved with
105
+ * inline pattern configs (`{ type: 'stack', ... }`). The shape conforms to
106
+ * `AnyPatternConfig` from `@almadar/patterns`.
107
+ */
108
+ renderUI: AnyPatternConfig;
109
+ /**
110
+ * Override the slot the render-ui effect targets. Defaults to `'main'`.
111
+ * Specify when the layout shell should render into a sub-slot (rare).
112
+ */
113
+ slot?: UISlot;
114
+ /**
115
+ * Additional effects appended to the INIT transition AFTER the fetch +
116
+ * render-ui pair. Most layouts don't need this; provided for advanced
117
+ * cases (analytics emit, persistence seed, etc.).
118
+ */
119
+ extraEffects?: Effect[];
120
+ }
121
+ /**
122
+ * Build the canonical stateless LayoutTrait used by std layout-shell molecules.
123
+ *
124
+ * Result shape:
125
+ * - `category: 'interaction'`, `scope: 'instance'`
126
+ * - `linkedEntity` set per the option
127
+ * - `emits` declares the loaded + loadFailed events when `fetchEntity` is set
128
+ * - One state: `'composing'` (`isInitial: true`)
129
+ * - One transition: `composing → composing` on `INIT`, with effects:
130
+ * - (when `fetchEntity` set) `['fetch', '<Entity>', { emit: { success, failure } }]`
131
+ * - `['render-ui', slot, renderUI]`
132
+ * - …`extraEffects` if provided
133
+ *
134
+ * Atoms whose trait names appear as `@trait.<name>` strings inside `renderUI`
135
+ * get embedded by the runtime when the orbital instantiates. The LayoutTrait
136
+ * itself stays stateless — all reactive behaviour lives in the embedded atoms.
137
+ */
138
+ declare function makeLayoutTrait(opts: MakeLayoutTraitOpts): Trait;
139
+
140
+ /**
141
+ * Orbital Builders
142
+ *
143
+ * Pure functions for constructing and composing Orbitals.
144
+ * No new types. Everything uses existing core types:
145
+ * Entity, Trait, Page, OrbitalDefinition, OrbitalSchema.
146
+ *
147
+ * Three categories:
148
+ * 1. Builders: construct Entity, Page from common params
149
+ * 2. Utilities: ensureIdField, resolveDefaults
150
+ * 3. Composition: connect, compose, pipe
151
+ *
152
+ * @packageDocumentation
153
+ */
6
154
 
7
155
  /**
8
156
  * Ensure the fields array has an `id` field. Prepends one if missing.
@@ -67,6 +215,46 @@ interface MakeTraitRefOpts {
67
215
  /** Call-site config overrides. Matches {@link TraitReference.config}. */
68
216
  config?: TraitConfig;
69
217
  }
218
+ /**
219
+ * Typed-narrowing variant of {@link MakeTraitRefOpts} for callers that know
220
+ * the imported atom's overridable surfaces — its event-key set, listen-key
221
+ * set, and config shape. Generated std factories use this variant so an LLM
222
+ * tool consumer (orbital-agent) sees the closed event-name set and the
223
+ * config field schema instead of the un-narrowed `Record<string, string>` /
224
+ * `TraitConfig` defaults.
225
+ *
226
+ * Type parameters:
227
+ * - `EventKey` — string union of the atom's emit event names. Narrows the
228
+ * `events` rename map's keys to legal originals only.
229
+ * - `ConfigShape` — typed shape of the trait's `config { ... }` block (literal
230
+ * unions intact). Narrows the `config` override to the atom's actual fields.
231
+ * - `ListenKey` — string union of the atom's listen-key contract. Narrows
232
+ * each listens entry's `event` against the atom's real subscription set.
233
+ *
234
+ * Runtime behavior is unchanged — {@link makeTraitRef} accepts both the
235
+ * narrow and wide forms via the standard structural-typing rules. This is
236
+ * a type-level narrowing only; widening at the call boundary is intentional.
237
+ */
238
+ interface MakeTraitRefOptsTyped<EventKey extends string = string, ConfigShape extends TraitConfig = Record<string, never>, ListenKey extends string = string> extends Omit<MakeTraitRefOpts, 'events' | 'effects' | 'listens' | 'config'> {
239
+ /** Per-key rename map, narrowed to the atom's actual event keys. */
240
+ events?: Partial<Record<EventKey, string>>;
241
+ /**
242
+ * Per-event SExpression effect replacement. Keys are POST-rename event
243
+ * names so they're caller-defined (no narrowing here); values stay typed
244
+ * as `SExpr[]`.
245
+ */
246
+ effects?: Partial<Record<string, SExpr[]>>;
247
+ /**
248
+ * Replace the imported trait's `listens` array entirely. Each entry's
249
+ * `event` field is narrowed to {@link ListenKey} where the atom's
250
+ * subscription set is fixed; otherwise this widens to plain string.
251
+ */
252
+ listens?: Array<TraitEventListener & {
253
+ event?: ListenKey;
254
+ }>;
255
+ /** Typed call-site config overrides — narrowed to {@link ConfigShape}. */
256
+ config?: ConfigShape;
257
+ }
70
258
  /**
71
259
  * Build a {@link TraitReference} from options.
72
260
  *
@@ -93,6 +281,21 @@ interface MakePageRefOpts {
93
281
  /** Replace the page's trait list. */
94
282
  traits?: TraitRef[];
95
283
  }
284
+ /**
285
+ * Typed-narrowing variant of {@link MakePageRefOpts}. Narrows the `traits`
286
+ * override array's entries to the orbital's known trait-name union — so the
287
+ * agent can't pass a trait name that doesn't exist on the page's owning
288
+ * orbital. Generated std page-helpers use this variant to surface the
289
+ * trait set in the tool schema; un-narrowed call sites stay compatible.
290
+ *
291
+ * Type parameter:
292
+ * - `TraitName` — string union of trait names the page may reference.
293
+ */
294
+ interface MakePageRefOptsTyped<TraitName extends string = string> extends Omit<MakePageRefOpts, 'traits'> {
295
+ traits?: Array<{
296
+ ref: TraitName;
297
+ } | TraitRef>;
298
+ }
96
299
  /**
97
300
  * Build a {@link PageRefObject} from options. Pass-through factory — omits
98
301
  * optional keys that are `undefined`.
@@ -225,4 +428,4 @@ declare function compose(orbitals: (OrbitalDefinition | OrbitalSchema)[], pages:
225
428
  */
226
429
  declare function pipe(orbitals: (OrbitalDefinition | OrbitalSchema)[], events: TraitEventContract[], appName?: string): OrbitalSchema;
227
430
 
228
- export { type ComposeConnection, type ComposePage, type MakeAtomOrbitalOpts, type MakeAtomOrbitalTraitOverrides, type MakeEntityOpts, type MakeOrbitalWithUsesOpts, type MakePageOpts, type MakePageRefOpts, type MakeTraitRefOpts, compose, connect, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeSchema, makeTraitRef, mergeOrbitals, pipe, plural, wire };
431
+ export { type ComposeConnection, type ComposePage, type MakeAtomOrbitalOpts, type MakeAtomOrbitalTraitOverrides, type MakeEntityOpts, type MakeLayoutTraitOpts, type MakeOrbitalWithUsesOpts, type MakePageOpts, type MakePageRefOpts, type MakePageRefOptsTyped, type MakeTraitRefOpts, type MakeTraitRefOptsTyped, compose, connect, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeLayoutTrait, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeRenderUI, makeSchema, makeSlot, makeTraitRef, mergeOrbitals, pipe, plural, wire };
package/dist/builders.js CHANGED
@@ -1090,6 +1090,83 @@ function composeBehaviors(input) {
1090
1090
  };
1091
1091
  }
1092
1092
 
1093
+ // src/builders/layout-trait.ts
1094
+ function makeSlot(traitName) {
1095
+ return `@trait.${traitName}`;
1096
+ }
1097
+ function makeRenderUI(slot, root) {
1098
+ return root === null ? ["render-ui", slot, null] : ["render-ui", slot, root];
1099
+ }
1100
+ function makeLayoutTrait(opts) {
1101
+ const slot = opts.slot ?? "main";
1102
+ const effects = [];
1103
+ const emits = [];
1104
+ const eventDefs = [
1105
+ { key: "INIT", name: "Initialize" }
1106
+ ];
1107
+ if (opts.fetchEntity) {
1108
+ if (!opts.loadedEvent || !opts.loadFailedEvent) {
1109
+ throw new Error(
1110
+ `makeLayoutTrait: fetchEntity '${opts.fetchEntity}' set but loadedEvent / loadFailedEvent are required`
1111
+ );
1112
+ }
1113
+ const payloadSchema = opts.loadedPayloadSchema ?? [{ name: "data", type: `[${opts.fetchEntity}]` }];
1114
+ emits.push(
1115
+ { event: opts.loadedEvent, scope: "internal", payloadSchema },
1116
+ {
1117
+ event: opts.loadFailedEvent,
1118
+ scope: "internal",
1119
+ payloadSchema: [
1120
+ { name: "error", type: "string" },
1121
+ { name: "code", type: "string" }
1122
+ ]
1123
+ }
1124
+ );
1125
+ eventDefs.push(
1126
+ { key: opts.loadedEvent, name: `${opts.fetchEntity} loaded`, payloadSchema },
1127
+ {
1128
+ key: opts.loadFailedEvent,
1129
+ name: `${opts.fetchEntity} load failed`,
1130
+ payloadSchema: [
1131
+ { name: "error", type: "string" },
1132
+ { name: "code", type: "string" }
1133
+ ]
1134
+ }
1135
+ );
1136
+ const fetchFx = [
1137
+ "fetch",
1138
+ opts.fetchEntity,
1139
+ { emit: { success: opts.loadedEvent, failure: opts.loadFailedEvent } }
1140
+ ];
1141
+ effects.push(fetchFx);
1142
+ }
1143
+ effects.push(makeRenderUI(slot, opts.renderUI));
1144
+ if (opts.extraEffects && opts.extraEffects.length > 0) {
1145
+ effects.push(...opts.extraEffects);
1146
+ }
1147
+ const trait = {
1148
+ name: opts.name,
1149
+ ...opts.description ? { description: opts.description } : {},
1150
+ category: "interaction",
1151
+ linkedEntity: opts.linkedEntity,
1152
+ scope: "instance",
1153
+ ...emits.length > 0 ? { emits } : {},
1154
+ stateMachine: {
1155
+ states: [{ name: "composing", isInitial: true }],
1156
+ events: eventDefs,
1157
+ transitions: [
1158
+ {
1159
+ from: "composing",
1160
+ to: "composing",
1161
+ event: "INIT",
1162
+ effects
1163
+ }
1164
+ ]
1165
+ }
1166
+ };
1167
+ return trait;
1168
+ }
1169
+
1093
1170
  // src/builders.ts
1094
1171
  function ensureIdField(fields) {
1095
1172
  if (!fields || fields.length === 0) return [{ name: "id", type: "string", required: true }];
@@ -1336,6 +1413,6 @@ function pipe(orbitals, events, appName) {
1336
1413
  };
1337
1414
  }
1338
1415
 
1339
- export { applyEventWiring, compose, composeBehaviors, connect, detectLayoutStrategy, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeSchema, makeTraitRef, mergeOrbitals, pipe, plural, wire };
1416
+ export { applyEventWiring, compose, composeBehaviors, connect, detectLayoutStrategy, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeLayoutTrait, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeRenderUI, makeSchema, makeSlot, makeTraitRef, mergeOrbitals, pipe, plural, wire };
1340
1417
  //# sourceMappingURL=builders.js.map
1341
1418
  //# sourceMappingURL=builders.js.map