@almadar/core 2.14.3 → 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.
- package/dist/builders.d.ts +2 -2
- package/dist/builders.js +651 -66
- package/dist/builders.js.map +1 -1
- package/dist/{compose-behaviors-CQC8hsaL.d.ts → compose-behaviors-DQTTCmR2.d.ts} +1 -1
- package/dist/domain-language/index.d.ts +1 -1
- package/dist/domain-language/index.js +94 -6
- package/dist/domain-language/index.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +110 -7
- package/dist/index.js.map +1 -1
- package/dist/{schema-BFnZrBhm.d.ts → schema-CDA_dJjH.d.ts} +9393 -2822
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +94 -6
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -1
package/dist/builders.js
CHANGED
|
@@ -1,66 +1,181 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
// src/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
3
|
+
// src/types/orbital.ts
|
|
4
|
+
var FieldTypeSchema = z.enum([
|
|
5
|
+
"string",
|
|
6
|
+
"number",
|
|
7
|
+
"boolean",
|
|
8
|
+
"date",
|
|
9
|
+
"timestamp",
|
|
10
|
+
"datetime",
|
|
11
|
+
"array",
|
|
12
|
+
"object",
|
|
13
|
+
"enum",
|
|
14
|
+
"relation"
|
|
15
|
+
]);
|
|
16
|
+
var RelationCardinalitySchema = z.enum([
|
|
17
|
+
"one",
|
|
18
|
+
"many",
|
|
19
|
+
"one-to-many",
|
|
20
|
+
"many-to-one",
|
|
21
|
+
"many-to-many"
|
|
22
|
+
]);
|
|
23
|
+
var RelationConfigSchema = z.object({
|
|
24
|
+
entity: z.string().min(1, "Target entity is required"),
|
|
25
|
+
field: z.string().optional(),
|
|
26
|
+
cardinality: RelationCardinalitySchema.optional(),
|
|
27
|
+
onDelete: z.enum(["cascade", "nullify", "restrict"]).optional(),
|
|
28
|
+
// Legacy compatibility fields
|
|
29
|
+
foreignKey: z.string().optional(),
|
|
30
|
+
target: z.string().optional(),
|
|
31
|
+
type: RelationCardinalitySchema.optional()
|
|
32
|
+
}).transform((data) => {
|
|
33
|
+
const normalized = {
|
|
34
|
+
entity: data.entity || data.target || "",
|
|
35
|
+
cardinality: data.cardinality || data.type,
|
|
36
|
+
field: data.field,
|
|
37
|
+
onDelete: data.onDelete
|
|
38
|
+
};
|
|
39
|
+
return normalized;
|
|
40
|
+
});
|
|
41
|
+
var FieldFormatSchema = z.enum([
|
|
42
|
+
"email",
|
|
43
|
+
"url",
|
|
44
|
+
"phone",
|
|
45
|
+
"date",
|
|
46
|
+
"datetime",
|
|
47
|
+
"uuid"
|
|
48
|
+
]);
|
|
49
|
+
var EntityFieldSchema = z.lazy(
|
|
50
|
+
() => z.object({
|
|
51
|
+
name: z.string().min(1, "Field name is required"),
|
|
52
|
+
type: FieldTypeSchema,
|
|
53
|
+
required: z.boolean().optional(),
|
|
54
|
+
default: z.unknown().optional(),
|
|
55
|
+
values: z.array(z.string()).optional(),
|
|
56
|
+
enum: z.array(z.string()).optional(),
|
|
57
|
+
format: FieldFormatSchema.optional(),
|
|
58
|
+
min: z.number().optional(),
|
|
59
|
+
max: z.number().optional(),
|
|
60
|
+
items: EntityFieldSchema.optional(),
|
|
61
|
+
relation: RelationConfigSchema.optional()
|
|
62
|
+
}).refine(
|
|
63
|
+
(field) => field.type !== "relation" || field.relation !== void 0,
|
|
64
|
+
{ message: 'Relation config is required when type is "relation"', path: ["relation"] }
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
var ENTITY_ROLES = [
|
|
68
|
+
"player",
|
|
69
|
+
"enemy",
|
|
70
|
+
"npc",
|
|
71
|
+
"item",
|
|
72
|
+
"tile",
|
|
73
|
+
"projectile",
|
|
74
|
+
"effect",
|
|
75
|
+
"ui",
|
|
76
|
+
"decoration",
|
|
77
|
+
"vehicle"
|
|
78
|
+
];
|
|
79
|
+
var EntityRoleSchema = z.enum(ENTITY_ROLES);
|
|
80
|
+
var VISUAL_STYLES = ["pixel", "vector", "hd", "1-bit", "isometric"];
|
|
81
|
+
var VisualStyleSchema = z.enum(VISUAL_STYLES);
|
|
82
|
+
var GAME_TYPES = [
|
|
83
|
+
"platformer",
|
|
84
|
+
"roguelike",
|
|
85
|
+
"top-down",
|
|
86
|
+
"puzzle",
|
|
87
|
+
"racing",
|
|
88
|
+
"card",
|
|
89
|
+
"board",
|
|
90
|
+
"shooter",
|
|
91
|
+
"rpg"
|
|
92
|
+
];
|
|
93
|
+
var GameTypeSchema = z.enum(GAME_TYPES);
|
|
94
|
+
var AnimationDefSchema = z.object({
|
|
95
|
+
frames: z.union([z.array(z.number()), z.array(z.string())]),
|
|
96
|
+
fps: z.number().positive(),
|
|
97
|
+
loop: z.boolean()
|
|
98
|
+
});
|
|
99
|
+
var SemanticAssetRefSchema = z.object({
|
|
100
|
+
role: EntityRoleSchema,
|
|
101
|
+
category: z.string().min(1),
|
|
102
|
+
animations: z.array(z.string()).optional(),
|
|
103
|
+
style: VisualStyleSchema.optional(),
|
|
104
|
+
variant: z.string().optional()
|
|
105
|
+
});
|
|
106
|
+
z.object({
|
|
107
|
+
basePath: z.string(),
|
|
108
|
+
path: z.string(),
|
|
109
|
+
tiles: z.array(z.number()).optional(),
|
|
110
|
+
tileSize: z.number().positive().optional(),
|
|
111
|
+
files: z.array(z.string()).optional(),
|
|
112
|
+
animations: z.record(AnimationDefSchema).optional()
|
|
113
|
+
});
|
|
114
|
+
var AssetMappingSchema = z.object({
|
|
115
|
+
path: z.string(),
|
|
116
|
+
tiles: z.array(z.number()).optional(),
|
|
117
|
+
tileSize: z.number().positive().optional(),
|
|
118
|
+
files: z.array(z.string()).optional(),
|
|
119
|
+
animations: z.record(AnimationDefSchema).optional()
|
|
120
|
+
});
|
|
121
|
+
z.object({
|
|
122
|
+
gameType: GameTypeSchema,
|
|
123
|
+
style: VisualStyleSchema,
|
|
124
|
+
basePath: z.string(),
|
|
125
|
+
mappings: z.record(AssetMappingSchema)
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// src/types/entity.ts
|
|
129
|
+
var EntityPersistenceSchema = z.enum([
|
|
130
|
+
"persistent",
|
|
131
|
+
"runtime",
|
|
132
|
+
"singleton",
|
|
133
|
+
"instance",
|
|
134
|
+
"local"
|
|
135
|
+
]);
|
|
136
|
+
var OrbitalEntitySchema = z.object({
|
|
137
|
+
name: z.string().min(1, "Entity name is required"),
|
|
138
|
+
persistence: EntityPersistenceSchema.default("persistent"),
|
|
139
|
+
collection: z.string().optional(),
|
|
140
|
+
fields: z.array(EntityFieldSchema).min(1, "At least one field is required"),
|
|
141
|
+
instances: z.array(z.record(z.unknown())).optional(),
|
|
142
|
+
timestamps: z.boolean().optional(),
|
|
143
|
+
softDelete: z.boolean().optional(),
|
|
144
|
+
description: z.string().optional(),
|
|
145
|
+
visual_prompt: z.string().optional(),
|
|
146
|
+
assetRef: SemanticAssetRefSchema.optional()
|
|
147
|
+
});
|
|
148
|
+
var EntitySchema = OrbitalEntitySchema;
|
|
149
|
+
var ViewTypeSchema = z.enum([
|
|
150
|
+
"list",
|
|
151
|
+
"detail",
|
|
152
|
+
"create",
|
|
153
|
+
"edit",
|
|
154
|
+
"dashboard",
|
|
155
|
+
"custom"
|
|
156
|
+
]);
|
|
157
|
+
var PageTraitRefSchema = z.object({
|
|
158
|
+
ref: z.string().min(1, "Trait ref is required"),
|
|
159
|
+
linkedEntity: z.string().optional(),
|
|
160
|
+
config: z.record(z.unknown()).optional()
|
|
161
|
+
});
|
|
162
|
+
z.object({
|
|
163
|
+
name: z.string().min(1, "Page name is required"),
|
|
164
|
+
path: z.string().min(1, "Page path is required").startsWith("/", "Path must start with /"),
|
|
165
|
+
primaryEntity: z.string().min(1, "Primary entity is required"),
|
|
166
|
+
traits: z.array(PageTraitRefSchema).min(1, "Page must have at least one trait"),
|
|
167
|
+
title: z.string().optional()
|
|
168
|
+
}).strict();
|
|
169
|
+
var OrbitalPageSchema = z.object({
|
|
170
|
+
name: z.string().min(1, "Page name is required"),
|
|
171
|
+
path: z.string().min(1, "Page path is required").startsWith("/", "Path must start with /"),
|
|
172
|
+
viewType: ViewTypeSchema.optional(),
|
|
173
|
+
title: z.string().optional(),
|
|
174
|
+
primaryEntity: z.string().optional(),
|
|
175
|
+
traits: z.array(PageTraitRefSchema).optional(),
|
|
176
|
+
isInitial: z.boolean().optional()
|
|
177
|
+
}).strict();
|
|
178
|
+
var PageSchema = OrbitalPageSchema;
|
|
64
179
|
var UI_SLOTS = [
|
|
65
180
|
// App slots
|
|
66
181
|
"main",
|
|
@@ -244,9 +359,41 @@ var RequiredFieldSchema = z.object({
|
|
|
244
359
|
z.object({
|
|
245
360
|
ref: z.string().min(1),
|
|
246
361
|
linkedEntity: z.string().optional(),
|
|
362
|
+
name: 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(),
|
|
247
367
|
config: z.record(z.record(z.unknown())).optional(),
|
|
248
|
-
appliesTo: z.array(z.string()).optional()
|
|
249
|
-
|
|
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
|
+
);
|
|
250
397
|
var TraitSchema = z.object({
|
|
251
398
|
name: z.string().min(1),
|
|
252
399
|
description: z.string().optional(),
|
|
@@ -262,12 +409,20 @@ var TraitSchema = z.object({
|
|
|
262
409
|
listens: z.array(TraitEventListenerSchema).optional(),
|
|
263
410
|
ui: z.record(z.unknown()).optional()
|
|
264
411
|
});
|
|
265
|
-
z.union([
|
|
412
|
+
var TraitRefSchema = z.union([
|
|
266
413
|
z.string().min(1),
|
|
267
414
|
z.object({
|
|
268
415
|
ref: z.string().min(1),
|
|
269
416
|
config: z.record(z.unknown()).optional(),
|
|
270
|
-
linkedEntity: z.string().optional()
|
|
417
|
+
linkedEntity: z.string().optional(),
|
|
418
|
+
name: 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()
|
|
271
426
|
}),
|
|
272
427
|
TraitSchema
|
|
273
428
|
// Allow inline trait definitions
|
|
@@ -275,6 +430,426 @@ z.union([
|
|
|
275
430
|
function isInlineTrait(traitRef) {
|
|
276
431
|
return typeof traitRef === "object" && "name" in traitRef && !("ref" in traitRef);
|
|
277
432
|
}
|
|
433
|
+
z.enum([
|
|
434
|
+
"healthcare",
|
|
435
|
+
"education",
|
|
436
|
+
"finance",
|
|
437
|
+
"ecommerce",
|
|
438
|
+
"real-estate",
|
|
439
|
+
"logistics",
|
|
440
|
+
"hospitality",
|
|
441
|
+
"hr-management",
|
|
442
|
+
"project-management",
|
|
443
|
+
"social",
|
|
444
|
+
"content-management",
|
|
445
|
+
"iot",
|
|
446
|
+
"analytics",
|
|
447
|
+
"game",
|
|
448
|
+
"custom"
|
|
449
|
+
]);
|
|
450
|
+
var AGENT_DOMAIN_CATEGORIES = [
|
|
451
|
+
"game",
|
|
452
|
+
"business",
|
|
453
|
+
"dashboard",
|
|
454
|
+
"form",
|
|
455
|
+
"content",
|
|
456
|
+
"social",
|
|
457
|
+
"ecommerce",
|
|
458
|
+
"workflow"
|
|
459
|
+
];
|
|
460
|
+
var AgentDomainCategorySchema = z.enum([...AGENT_DOMAIN_CATEGORIES]);
|
|
461
|
+
z.enum([
|
|
462
|
+
"platformer",
|
|
463
|
+
"shooter",
|
|
464
|
+
"puzzle",
|
|
465
|
+
"rpg",
|
|
466
|
+
"board",
|
|
467
|
+
"racing",
|
|
468
|
+
"fighting",
|
|
469
|
+
"tower-defense",
|
|
470
|
+
"endless-runner",
|
|
471
|
+
"simulation",
|
|
472
|
+
"arcade",
|
|
473
|
+
"adventure"
|
|
474
|
+
]);
|
|
475
|
+
z.enum(["domain", "system"]);
|
|
476
|
+
z.enum([
|
|
477
|
+
"pending",
|
|
478
|
+
"active",
|
|
479
|
+
"completed",
|
|
480
|
+
"cancelled",
|
|
481
|
+
"error",
|
|
482
|
+
"suspended",
|
|
483
|
+
"blocked",
|
|
484
|
+
"domain_workflow",
|
|
485
|
+
"domain_status",
|
|
486
|
+
"system_loading",
|
|
487
|
+
"system_error",
|
|
488
|
+
"system_idle",
|
|
489
|
+
"system_editing",
|
|
490
|
+
"system_confirming"
|
|
491
|
+
]);
|
|
492
|
+
z.enum([
|
|
493
|
+
"domain_action",
|
|
494
|
+
"domain_trigger",
|
|
495
|
+
"system_crud",
|
|
496
|
+
"system_navigation",
|
|
497
|
+
"system_form",
|
|
498
|
+
"system_ui"
|
|
499
|
+
]);
|
|
500
|
+
z.enum([
|
|
501
|
+
"domain_core",
|
|
502
|
+
"domain_supporting",
|
|
503
|
+
"domain_reference",
|
|
504
|
+
"system_user",
|
|
505
|
+
"system_config",
|
|
506
|
+
"system_audit"
|
|
507
|
+
]);
|
|
508
|
+
var DomainVocabularySchema = z.record(z.string(), z.string()).optional();
|
|
509
|
+
var UserPersonaSchema = z.object({
|
|
510
|
+
name: z.string().min(1),
|
|
511
|
+
role: z.string().optional(),
|
|
512
|
+
device: z.enum(["mobile", "tablet", "desktop"]).optional()
|
|
513
|
+
});
|
|
514
|
+
var DomainContextSchema = z.object({
|
|
515
|
+
request: z.string().min(1, "Original request is required"),
|
|
516
|
+
requestFragment: z.string().optional(),
|
|
517
|
+
category: AgentDomainCategorySchema,
|
|
518
|
+
subDomain: z.string().optional(),
|
|
519
|
+
personas: z.array(UserPersonaSchema).optional(),
|
|
520
|
+
vocabulary: DomainVocabularySchema.optional()
|
|
521
|
+
});
|
|
522
|
+
var UXHintsSchema = z.object({
|
|
523
|
+
flowPattern: z.string().optional(),
|
|
524
|
+
listPattern: z.string().optional(),
|
|
525
|
+
formPattern: z.string().optional(),
|
|
526
|
+
detailPattern: z.string().optional(),
|
|
527
|
+
relatedLinks: z.array(z.lazy(() => RelatedLinkSchema)).optional()
|
|
528
|
+
});
|
|
529
|
+
var RelatedLinkSchema = z.object({
|
|
530
|
+
relation: z.string().min(1),
|
|
531
|
+
label: z.string().min(1),
|
|
532
|
+
targetView: z.enum(["list", "detail"]).optional()
|
|
533
|
+
});
|
|
534
|
+
var SuggestedGuardSchema = z.object({
|
|
535
|
+
id: z.string().min(1),
|
|
536
|
+
description: z.string().min(1),
|
|
537
|
+
appliesTo: z.array(z.string().min(1))
|
|
538
|
+
});
|
|
539
|
+
var DesignPreferencesSchema = z.object({
|
|
540
|
+
style: z.enum(["minimal", "modern", "playful", "data-driven", "immersive"]).optional(),
|
|
541
|
+
primaryColor: z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Must be valid hex color").optional(),
|
|
542
|
+
device: z.enum(["mobile", "tablet", "desktop", "all"]).optional(),
|
|
543
|
+
darkMode: z.boolean().optional(),
|
|
544
|
+
uxHints: UXHintsSchema.optional()
|
|
545
|
+
});
|
|
546
|
+
var ThemeTokensSchema = z.object({
|
|
547
|
+
colors: z.record(z.string(), z.string()).optional(),
|
|
548
|
+
radii: z.record(z.string(), z.string()).optional(),
|
|
549
|
+
spacing: z.record(z.string(), z.string()).optional(),
|
|
550
|
+
typography: z.record(z.string(), z.string()).optional(),
|
|
551
|
+
shadows: z.record(z.string(), z.string()).optional()
|
|
552
|
+
});
|
|
553
|
+
var ThemeVariantSchema = z.object({
|
|
554
|
+
colors: z.record(z.string(), z.string()).optional(),
|
|
555
|
+
radii: z.record(z.string(), z.string()).optional(),
|
|
556
|
+
spacing: z.record(z.string(), z.string()).optional(),
|
|
557
|
+
typography: z.record(z.string(), z.string()).optional(),
|
|
558
|
+
shadows: z.record(z.string(), z.string()).optional()
|
|
559
|
+
});
|
|
560
|
+
var ThemeDefinitionSchema = z.object({
|
|
561
|
+
name: z.string().min(1, "Theme name is required"),
|
|
562
|
+
tokens: ThemeTokensSchema,
|
|
563
|
+
variants: z.record(z.string(), ThemeVariantSchema).optional()
|
|
564
|
+
});
|
|
565
|
+
var ThemeRefStringSchema = z.string().regex(
|
|
566
|
+
/^[A-Z][a-zA-Z0-9]*\.theme$/,
|
|
567
|
+
'Theme reference must be in format "Alias.theme" (e.g., "Ocean.theme")'
|
|
568
|
+
);
|
|
569
|
+
var ThemeRefSchema = z.union([
|
|
570
|
+
ThemeDefinitionSchema,
|
|
571
|
+
ThemeRefStringSchema
|
|
572
|
+
]);
|
|
573
|
+
z.record(z.string(), z.record(z.string(), z.string())).optional();
|
|
574
|
+
var ALLOWED_CUSTOM_COMPONENTS = [
|
|
575
|
+
"div",
|
|
576
|
+
"span",
|
|
577
|
+
"button",
|
|
578
|
+
"a",
|
|
579
|
+
"p",
|
|
580
|
+
"h1",
|
|
581
|
+
"h2",
|
|
582
|
+
"h3",
|
|
583
|
+
"h4",
|
|
584
|
+
"h5",
|
|
585
|
+
"h6",
|
|
586
|
+
"header",
|
|
587
|
+
"footer",
|
|
588
|
+
"section",
|
|
589
|
+
"article",
|
|
590
|
+
"nav",
|
|
591
|
+
"main",
|
|
592
|
+
"aside",
|
|
593
|
+
"ul",
|
|
594
|
+
"ol",
|
|
595
|
+
"li",
|
|
596
|
+
"img",
|
|
597
|
+
"label",
|
|
598
|
+
"input",
|
|
599
|
+
"form"
|
|
600
|
+
];
|
|
601
|
+
var CustomPatternDefinitionSchema = z.object({
|
|
602
|
+
type: z.literal("custom"),
|
|
603
|
+
component: z.enum(ALLOWED_CUSTOM_COMPONENTS),
|
|
604
|
+
className: z.string(),
|
|
605
|
+
slots: z.array(z.string()).optional(),
|
|
606
|
+
props: z.array(z.string()).optional()
|
|
607
|
+
});
|
|
608
|
+
z.record(z.string(), CustomPatternDefinitionSchema).optional();
|
|
609
|
+
var SERVICE_TYPES = ["rest", "socket", "mcp"];
|
|
610
|
+
z.enum(SERVICE_TYPES);
|
|
611
|
+
var RestAuthConfigSchema = z.object({
|
|
612
|
+
type: z.enum(["api-key", "bearer", "basic", "oauth2"]),
|
|
613
|
+
keyName: z.string().optional(),
|
|
614
|
+
location: z.enum(["query", "header"]).optional(),
|
|
615
|
+
secretEnv: z.string().optional()
|
|
616
|
+
});
|
|
617
|
+
var RestServiceDefSchema = z.object({
|
|
618
|
+
name: z.string().min(1, "Service name is required"),
|
|
619
|
+
type: z.literal("rest"),
|
|
620
|
+
description: z.string().optional(),
|
|
621
|
+
baseUrl: z.string().url("Base URL must be a valid URL"),
|
|
622
|
+
headers: z.record(z.string()).optional(),
|
|
623
|
+
auth: RestAuthConfigSchema.optional(),
|
|
624
|
+
timeout: z.number().positive().optional()
|
|
625
|
+
});
|
|
626
|
+
var SocketEventsSchema = z.object({
|
|
627
|
+
inbound: z.array(z.string()),
|
|
628
|
+
outbound: z.array(z.string())
|
|
629
|
+
});
|
|
630
|
+
var SocketServiceDefSchema = z.object({
|
|
631
|
+
name: z.string().min(1, "Service name is required"),
|
|
632
|
+
type: z.literal("socket"),
|
|
633
|
+
description: z.string().optional(),
|
|
634
|
+
url: z.string().url("WebSocket URL must be valid"),
|
|
635
|
+
events: SocketEventsSchema,
|
|
636
|
+
reconnect: z.object({
|
|
637
|
+
enabled: z.boolean(),
|
|
638
|
+
maxAttempts: z.number().positive().optional(),
|
|
639
|
+
delayMs: z.number().positive().optional()
|
|
640
|
+
}).optional()
|
|
641
|
+
});
|
|
642
|
+
var McpServiceDefSchema = z.object({
|
|
643
|
+
name: z.string().min(1, "Service name is required"),
|
|
644
|
+
type: z.literal("mcp"),
|
|
645
|
+
description: z.string().optional(),
|
|
646
|
+
serverPath: z.string().min(1, "Server path is required"),
|
|
647
|
+
capabilities: z.array(z.string()).min(1, "At least one capability is required"),
|
|
648
|
+
env: z.record(z.string()).optional()
|
|
649
|
+
});
|
|
650
|
+
var ServiceDefinitionSchema = z.discriminatedUnion("type", [
|
|
651
|
+
RestServiceDefSchema,
|
|
652
|
+
SocketServiceDefSchema,
|
|
653
|
+
McpServiceDefSchema
|
|
654
|
+
]);
|
|
655
|
+
var ServiceRefStringSchema = z.string().regex(
|
|
656
|
+
/^[A-Z][a-zA-Z0-9]*\.services\.[a-zA-Z][a-zA-Z0-9]*$/,
|
|
657
|
+
'Service reference must be in format "Alias.services.ServiceName" (e.g., "Weather.services.openweather")'
|
|
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
|
+
});
|
|
667
|
+
var ServiceRefSchema = z.union([
|
|
668
|
+
ServiceDefinitionSchema,
|
|
669
|
+
ServiceRefObjectSchema,
|
|
670
|
+
ServiceRefStringSchema
|
|
671
|
+
]);
|
|
672
|
+
|
|
673
|
+
// src/types/orbital.ts
|
|
674
|
+
var UseDeclarationSchema = z.object({
|
|
675
|
+
from: z.string().min(1, "Import source is required"),
|
|
676
|
+
as: z.string().min(1, "Alias is required").regex(
|
|
677
|
+
/^[A-Z][a-zA-Z0-9]*$/,
|
|
678
|
+
'Alias must be PascalCase (e.g., "Health", "GameCore")'
|
|
679
|
+
)
|
|
680
|
+
});
|
|
681
|
+
function isEntityReference(entity) {
|
|
682
|
+
return typeof entity === "string";
|
|
683
|
+
}
|
|
684
|
+
function isEntityCall(entity) {
|
|
685
|
+
return typeof entity === "object" && entity !== null && "extends" in entity;
|
|
686
|
+
}
|
|
687
|
+
var EntityRefStringSchema = z.string().regex(
|
|
688
|
+
/^[A-Z][a-zA-Z0-9]*\.entity$/,
|
|
689
|
+
'Entity reference must be in format "Alias.entity" (e.g., "Goblin.entity")'
|
|
690
|
+
);
|
|
691
|
+
var EntityCallSchema = z.object({
|
|
692
|
+
extends: z.string().regex(
|
|
693
|
+
/^[A-Z][a-zA-Z0-9]*\.entity$/,
|
|
694
|
+
'EntityCall "extends" must be in format "Alias.entity"'
|
|
695
|
+
),
|
|
696
|
+
name: z.string().optional(),
|
|
697
|
+
fields: z.array(EntityFieldSchema).optional(),
|
|
698
|
+
persistence: EntityPersistenceSchema.optional(),
|
|
699
|
+
collection: z.string().optional()
|
|
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
|
+
);
|
|
715
|
+
var EntityRefSchema = z.union([
|
|
716
|
+
EntitySchema,
|
|
717
|
+
EntityRefStringSchema,
|
|
718
|
+
EntityCallSchema
|
|
719
|
+
]);
|
|
720
|
+
var PageRefStringSchema = z.string().regex(
|
|
721
|
+
/^[A-Z][a-zA-Z0-9]*\.pages\.[A-Z][a-zA-Z0-9]*$/,
|
|
722
|
+
'Page reference must be in format "Alias.pages.PageName" (e.g., "User.pages.Profile")'
|
|
723
|
+
);
|
|
724
|
+
var PageRefObjectSchema = z.object({
|
|
725
|
+
ref: PageRefStringSchema,
|
|
726
|
+
path: z.string().startsWith("/").optional(),
|
|
727
|
+
linkedEntity: z.string().optional(),
|
|
728
|
+
traits: z.array(TraitRefSchema).optional()
|
|
729
|
+
});
|
|
730
|
+
var PageRefSchema = z.union([
|
|
731
|
+
PageSchema,
|
|
732
|
+
PageRefStringSchema,
|
|
733
|
+
PageRefObjectSchema
|
|
734
|
+
]);
|
|
735
|
+
z.string().regex(
|
|
736
|
+
/^([A-Z][a-zA-Z0-9]*\.traits\.)?[A-Z][a-zA-Z0-9]*$/,
|
|
737
|
+
'Trait reference must be "TraitName" or "Alias.traits.TraitName"'
|
|
738
|
+
);
|
|
739
|
+
function parseEntityRef(ref) {
|
|
740
|
+
const match = ref.match(/^([A-Z][a-zA-Z0-9]*)\.entity$/);
|
|
741
|
+
if (!match) return null;
|
|
742
|
+
return { alias: match[1] };
|
|
743
|
+
}
|
|
744
|
+
z.object({
|
|
745
|
+
event: z.string().min(1),
|
|
746
|
+
triggers: z.string().min(1),
|
|
747
|
+
guard: z.string().optional()
|
|
748
|
+
});
|
|
749
|
+
var EventSourceSchema = z.object({
|
|
750
|
+
trait: z.string().min(1),
|
|
751
|
+
transition: z.string().optional(),
|
|
752
|
+
tick: z.string().optional()
|
|
753
|
+
});
|
|
754
|
+
var ComputedEventContractSchema = z.object({
|
|
755
|
+
event: z.string().min(1),
|
|
756
|
+
originalEvent: z.string().min(1),
|
|
757
|
+
source: EventSourceSchema,
|
|
758
|
+
description: z.string().optional(),
|
|
759
|
+
payload: z.array(EventPayloadFieldSchema).optional()
|
|
760
|
+
});
|
|
761
|
+
var ComputedEventListenerSchema = z.object({
|
|
762
|
+
event: z.string().min(1),
|
|
763
|
+
source: EventSourceSchema,
|
|
764
|
+
triggers: z.string().min(1),
|
|
765
|
+
guard: ExpressionSchema.optional(),
|
|
766
|
+
payloadMapping: z.record(z.string()).optional()
|
|
767
|
+
});
|
|
768
|
+
z.object({
|
|
769
|
+
name: z.string().min(1, "Orbital name is required"),
|
|
770
|
+
description: z.string().optional(),
|
|
771
|
+
visual_prompt: z.string().optional(),
|
|
772
|
+
// Import system
|
|
773
|
+
uses: z.array(UseDeclarationSchema).optional(),
|
|
774
|
+
// Theme & Services
|
|
775
|
+
theme: ThemeRefSchema.optional(),
|
|
776
|
+
services: z.array(ServiceRefSchema).optional(),
|
|
777
|
+
// Components (inline or reference)
|
|
778
|
+
entity: EntityRefSchema,
|
|
779
|
+
traits: z.array(TraitRefSchema),
|
|
780
|
+
pages: z.array(PageRefSchema),
|
|
781
|
+
// Event interface (trait-centric model) - computed by resolver
|
|
782
|
+
emits: z.array(ComputedEventContractSchema).optional(),
|
|
783
|
+
listens: z.array(ComputedEventListenerSchema).optional(),
|
|
784
|
+
// Filter for exposed events (trait-centric model)
|
|
785
|
+
exposes: z.array(z.string()).optional(),
|
|
786
|
+
// Context fields - persisted throughout orbital lifecycle
|
|
787
|
+
domainContext: DomainContextSchema.optional(),
|
|
788
|
+
design: DesignPreferencesSchema.optional(),
|
|
789
|
+
suggestedGuards: z.array(SuggestedGuardSchema).optional()
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// src/builders/layout-strategy.ts
|
|
793
|
+
function hasSequentialChain(wiring) {
|
|
794
|
+
if (wiring.length < 2) {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
798
|
+
const allTargets = /* @__PURE__ */ new Set();
|
|
799
|
+
for (const entry of wiring) {
|
|
800
|
+
let targets = adjacency.get(entry.from);
|
|
801
|
+
if (!targets) {
|
|
802
|
+
targets = /* @__PURE__ */ new Set();
|
|
803
|
+
adjacency.set(entry.from, targets);
|
|
804
|
+
}
|
|
805
|
+
targets.add(entry.to);
|
|
806
|
+
allTargets.add(entry.to);
|
|
807
|
+
}
|
|
808
|
+
const roots = [];
|
|
809
|
+
for (const from of adjacency.keys()) {
|
|
810
|
+
if (!allTargets.has(from)) {
|
|
811
|
+
roots.push(from);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
const starts = roots.length > 0 ? roots : [...adjacency.keys()];
|
|
815
|
+
for (const start of starts) {
|
|
816
|
+
let current = start;
|
|
817
|
+
let length = 1;
|
|
818
|
+
const visited = /* @__PURE__ */ new Set([current]);
|
|
819
|
+
while (true) {
|
|
820
|
+
const nexts = adjacency.get(current);
|
|
821
|
+
if (!nexts || nexts.size === 0) break;
|
|
822
|
+
let advanced = false;
|
|
823
|
+
for (const next of nexts) {
|
|
824
|
+
if (!visited.has(next)) {
|
|
825
|
+
visited.add(next);
|
|
826
|
+
current = next;
|
|
827
|
+
length++;
|
|
828
|
+
advanced = true;
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
if (!advanced) break;
|
|
833
|
+
}
|
|
834
|
+
if (length >= 3) {
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
function detectLayoutStrategy(orbitals, eventWiring) {
|
|
841
|
+
if (eventWiring && eventWiring.length > 0 && hasSequentialChain(eventWiring)) {
|
|
842
|
+
return "wizard-flow";
|
|
843
|
+
}
|
|
844
|
+
const count = orbitals.length;
|
|
845
|
+
if (count <= 1) {
|
|
846
|
+
return "single";
|
|
847
|
+
}
|
|
848
|
+
if (count <= 4) {
|
|
849
|
+
return "tabs";
|
|
850
|
+
}
|
|
851
|
+
return "sidebar";
|
|
852
|
+
}
|
|
278
853
|
|
|
279
854
|
// src/builders/event-wiring.ts
|
|
280
855
|
function findInlineTrait(orbitals, name) {
|
|
@@ -420,6 +995,16 @@ function ensureIdField(fields) {
|
|
|
420
995
|
function plural(name) {
|
|
421
996
|
return name + "s";
|
|
422
997
|
}
|
|
998
|
+
function resolveEntityNameForBuilder(ref) {
|
|
999
|
+
if (isEntityReference(ref)) {
|
|
1000
|
+
return parseEntityRef(ref)?.alias ?? ref;
|
|
1001
|
+
}
|
|
1002
|
+
if (isEntityCall(ref)) {
|
|
1003
|
+
if (ref.name) return ref.name;
|
|
1004
|
+
return parseEntityRef(ref.extends)?.alias ?? ref.extends;
|
|
1005
|
+
}
|
|
1006
|
+
return ref.name;
|
|
1007
|
+
}
|
|
423
1008
|
function makeEntity(opts) {
|
|
424
1009
|
const fields = ensureIdField(opts.fields);
|
|
425
1010
|
const persistence = opts.persistence ?? "runtime";
|
|
@@ -552,7 +1137,7 @@ function pipe(orbitals, events, appName) {
|
|
|
552
1137
|
}
|
|
553
1138
|
}
|
|
554
1139
|
const pages = cloned.map((o, i) => {
|
|
555
|
-
const entityName =
|
|
1140
|
+
const entityName = resolveEntityNameForBuilder(o.entity);
|
|
556
1141
|
const traitNames = o.traits.map((t) => t.name);
|
|
557
1142
|
return {
|
|
558
1143
|
name: `${entityName}Page`,
|