@almadar/core 3.0.0 → 4.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.
@@ -1,5 +1,5 @@
1
- import { T as TraitEventContract, E as EntityField, a as EntityPersistence, b as EntityRow, O as OrbitalDefinition, c as OrbitalSchema, d as Trait, e as Entity, P as Page } from './schema-COvHzxfu.js';
2
- 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-tUJ7EcaX.js';
1
+ import { T as TraitEventContract, E as EntityField, a as EntityPersistence, b as EntityRow, O as OrbitalDefinition, c as OrbitalSchema, d as Trait, e as Entity, P as Page } from './schema-CDA_dJjH.js';
2
+ 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-DQTTCmR2.js';
3
3
  import 'zod';
4
4
  import '@almadar/patterns';
5
5
 
package/dist/builders.js CHANGED
@@ -360,10 +360,40 @@ z.object({
360
360
  ref: z.string().min(1),
361
361
  linkedEntity: z.string().optional(),
362
362
  name: z.string().optional(),
363
- events: z.record(z.string(), z.string()).optional(),
363
+ events: z.record(
364
+ z.string().min(1, "events key (atom event name) must be non-empty"),
365
+ z.string().min(1, "events value (caller event name) must be non-empty")
366
+ ).optional(),
364
367
  config: z.record(z.record(z.unknown())).optional(),
365
- appliesTo: z.array(z.string()).optional()
366
- });
368
+ appliesTo: z.array(z.string()).optional(),
369
+ // Phase F.7: zod accepts an array (the inliner validates element
370
+ // shape). The full ListenDefinition shape isn't recursively encoded
371
+ // here because TraitReference is the call-site form — listen entries
372
+ // pasted in are already-resolved structured definitions, not nested
373
+ // overrides.
374
+ listens: z.array(z.unknown()).optional(),
375
+ emitsScope: z.enum(["internal", "external"]).optional(),
376
+ // Phase F.8: per-transition effects override. The keys are event
377
+ // names (the transition triggers AFTER renames). Values are arrays
378
+ // of SExpression-shaped data; the inliner validates the SExpression
379
+ // shape during application, so the schema accepts loose `unknown[]`.
380
+ effects: z.record(
381
+ z.string().min(1, "effects override key (event name) must be non-empty"),
382
+ z.array(z.unknown())
383
+ ).optional()
384
+ }).refine(
385
+ (ref) => {
386
+ if (!ref.events) return true;
387
+ for (const [from, to] of Object.entries(ref.events)) {
388
+ if (from.length === 0 || to.length === 0) return false;
389
+ }
390
+ return true;
391
+ },
392
+ {
393
+ message: 'TraitReference "events" entries must have non-empty atom and caller event names',
394
+ path: ["events"]
395
+ }
396
+ );
367
397
  var TraitSchema = z.object({
368
398
  name: z.string().min(1),
369
399
  description: z.string().optional(),
@@ -386,7 +416,13 @@ var TraitRefSchema = z.union([
386
416
  config: z.record(z.unknown()).optional(),
387
417
  linkedEntity: z.string().optional(),
388
418
  name: z.string().optional(),
389
- events: z.record(z.string(), z.string()).optional()
419
+ // Phase F.4: same non-empty refine as TraitReferenceSchema.events.
420
+ // Both schemas accept the same call-site argument shape, so the
421
+ // validators should agree.
422
+ events: z.record(
423
+ z.string().min(1, "events key (atom event name) must be non-empty"),
424
+ z.string().min(1, "events value (caller event name) must be non-empty")
425
+ ).optional()
390
426
  }),
391
427
  TraitSchema
392
428
  // Allow inline trait definitions
@@ -620,8 +656,17 @@ var ServiceRefStringSchema = z.string().regex(
620
656
  /^[A-Z][a-zA-Z0-9]*\.services\.[a-zA-Z][a-zA-Z0-9]*$/,
621
657
  'Service reference must be in format "Alias.services.ServiceName" (e.g., "Weather.services.openweather")'
622
658
  );
659
+ var ServiceRefObjectSchema = z.object({
660
+ ref: ServiceRefStringSchema,
661
+ description: z.string().optional(),
662
+ baseUrl: z.string().url("baseUrl override must be a valid URL").optional(),
663
+ headers: z.record(z.string()).optional(),
664
+ url: z.string().url("url override must be a valid URL").optional(),
665
+ serverPath: z.string().optional()
666
+ });
623
667
  var ServiceRefSchema = z.union([
624
668
  ServiceDefinitionSchema,
669
+ ServiceRefObjectSchema,
625
670
  ServiceRefStringSchema
626
671
  ]);
627
672
 
@@ -652,7 +697,21 @@ var EntityCallSchema = z.object({
652
697
  fields: z.array(EntityFieldSchema).optional(),
653
698
  persistence: EntityPersistenceSchema.optional(),
654
699
  collection: z.string().optional()
655
- });
700
+ }).refine(
701
+ (call) => {
702
+ if (!call.fields) return true;
703
+ const seen = /* @__PURE__ */ new Set();
704
+ for (const field of call.fields) {
705
+ if (seen.has(field.name)) return false;
706
+ seen.add(field.name);
707
+ }
708
+ return true;
709
+ },
710
+ {
711
+ message: 'EntityCall "fields" override list must not contain duplicate field names',
712
+ path: ["fields"]
713
+ }
714
+ );
656
715
  var EntityRefSchema = z.union([
657
716
  EntitySchema,
658
717
  EntityRefStringSchema,