eventmodeler 0.6.7 → 0.6.9
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/index.js +160 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2576,6 +2576,33 @@ function getEntry(doc, scope, id) {
|
|
|
2576
2576
|
return;
|
|
2577
2577
|
return entry instanceof Y4.AbstractType ? entry.toJSON() : entry;
|
|
2578
2578
|
}
|
|
2579
|
+
// ../packages/canvas-model/src/dimensions.ts
|
|
2580
|
+
var ELEMENT_DIMENSIONS = {
|
|
2581
|
+
commandSticky: { width: 160, height: 100 },
|
|
2582
|
+
eventSticky: { width: 160, height: 100 },
|
|
2583
|
+
readModelSticky: { width: 160, height: 100 },
|
|
2584
|
+
screen: { width: 180, height: 120 },
|
|
2585
|
+
processor: { width: 120, height: 120 },
|
|
2586
|
+
slice: { width: 300, height: 200 },
|
|
2587
|
+
aggregate: { width: 300, height: 200 },
|
|
2588
|
+
actor: { width: 300, height: 200 },
|
|
2589
|
+
chapter: { width: 800, height: 1200 },
|
|
2590
|
+
note: { width: 200, height: 150 },
|
|
2591
|
+
externalEvent: { width: 160, height: 100 },
|
|
2592
|
+
context: { width: 300, height: 200 },
|
|
2593
|
+
swimLane: { width: 300, height: 200 }
|
|
2594
|
+
};
|
|
2595
|
+
var FIXED_SIZE_SCOPE_DIMENSIONS = {
|
|
2596
|
+
commands: ELEMENT_DIMENSIONS.commandSticky,
|
|
2597
|
+
events: ELEMENT_DIMENSIONS.eventSticky,
|
|
2598
|
+
readModels: ELEMENT_DIMENSIONS.readModelSticky,
|
|
2599
|
+
screens: ELEMENT_DIMENSIONS.screen,
|
|
2600
|
+
processors: ELEMENT_DIMENSIONS.processor,
|
|
2601
|
+
externalEvents: ELEMENT_DIMENSIONS.externalEvent
|
|
2602
|
+
};
|
|
2603
|
+
function canonicalSizeForScope(scope) {
|
|
2604
|
+
return FIXED_SIZE_SCOPE_DIMENSIONS[scope];
|
|
2605
|
+
}
|
|
2579
2606
|
// ../packages/canvas-model/src/actions.ts
|
|
2580
2607
|
import * as Y5 from "yjs";
|
|
2581
2608
|
// ../packages/canvas-model/src/containment.ts
|
|
@@ -2705,7 +2732,7 @@ var FieldTypeSchema = z.enum([
|
|
|
2705
2732
|
"Custom"
|
|
2706
2733
|
]);
|
|
2707
2734
|
var FieldBase = z.object({
|
|
2708
|
-
id: z.string().uuid().
|
|
2735
|
+
id: z.string().uuid().default(() => crypto.randomUUID()),
|
|
2709
2736
|
name: z.string().min(1),
|
|
2710
2737
|
fieldType: FieldTypeSchema,
|
|
2711
2738
|
isList: z.boolean().optional(),
|
|
@@ -2742,12 +2769,22 @@ var NoteSchema = Box.extend({
|
|
|
2742
2769
|
title: z.string().min(1),
|
|
2743
2770
|
description: z.string().optional()
|
|
2744
2771
|
});
|
|
2772
|
+
var ExcalidrawElementSchema = z.object({
|
|
2773
|
+
id: z.string().min(1),
|
|
2774
|
+
type: z.string().min(1),
|
|
2775
|
+
version: z.number().int().optional(),
|
|
2776
|
+
isDeleted: z.boolean().optional()
|
|
2777
|
+
}).passthrough();
|
|
2778
|
+
var DesignSchema = z.array(ExcalidrawElementSchema);
|
|
2745
2779
|
var canonicalSticky = (idKey) => NamedBox.extend({
|
|
2746
2780
|
[idKey]: z.string().uuid().optional(),
|
|
2747
2781
|
modelId: z.string().uuid().optional(),
|
|
2748
2782
|
fields: z.array(FieldSchema).optional(),
|
|
2749
2783
|
isLinkedCopy: z.literal(false).optional()
|
|
2750
2784
|
});
|
|
2785
|
+
var canonicalScreen = canonicalSticky("screenId").extend({
|
|
2786
|
+
design: DesignSchema.optional()
|
|
2787
|
+
});
|
|
2751
2788
|
var linkedCopySticky = (idKey, originalIdKey) => Box.extend({
|
|
2752
2789
|
[idKey]: z.string().uuid().optional(),
|
|
2753
2790
|
modelId: z.string().uuid().optional(),
|
|
@@ -2766,7 +2803,7 @@ var stickyVariants = {
|
|
|
2766
2803
|
linkedCopy: linkedCopySticky("readModelStickyId", "originalReadModelStickyId")
|
|
2767
2804
|
},
|
|
2768
2805
|
screens: {
|
|
2769
|
-
canonical:
|
|
2806
|
+
canonical: canonicalScreen,
|
|
2770
2807
|
linkedCopy: linkedCopySticky("screenId", "originalScreenId")
|
|
2771
2808
|
},
|
|
2772
2809
|
processors: {
|
|
@@ -2783,6 +2820,41 @@ var ReadModelSchema = z.union([stickyVariants.readModels.canonical, stickyVarian
|
|
|
2783
2820
|
var ScreenSchema = z.union([stickyVariants.screens.canonical, stickyVariants.screens.linkedCopy]);
|
|
2784
2821
|
var ProcessorSchema = z.union([stickyVariants.processors.canonical, stickyVariants.processors.linkedCopy]);
|
|
2785
2822
|
var ExternalEventSchema = z.union([stickyVariants.externalEvents.canonical, stickyVariants.externalEvents.linkedCopy]);
|
|
2823
|
+
var FlowTypeSchema = z.enum([
|
|
2824
|
+
"CommandToEvent",
|
|
2825
|
+
"EventToReadModel",
|
|
2826
|
+
"ReadModelToScreen",
|
|
2827
|
+
"ReadModelToProcessor",
|
|
2828
|
+
"ScreenToCommand",
|
|
2829
|
+
"ProcessorToCommand",
|
|
2830
|
+
"CommandToExternalEvent",
|
|
2831
|
+
"ExternalEventToProcessor"
|
|
2832
|
+
]);
|
|
2833
|
+
var FlowHandleSchema = z.enum([
|
|
2834
|
+
"top-source",
|
|
2835
|
+
"right-source",
|
|
2836
|
+
"bottom-source",
|
|
2837
|
+
"left-source",
|
|
2838
|
+
"top-target",
|
|
2839
|
+
"right-target",
|
|
2840
|
+
"bottom-target",
|
|
2841
|
+
"left-target"
|
|
2842
|
+
]);
|
|
2843
|
+
var FlowMappingSchema = z.object({
|
|
2844
|
+
mappingId: z.string().uuid().optional(),
|
|
2845
|
+
sourceFieldId: z.string().uuid(),
|
|
2846
|
+
targetFieldId: z.string().uuid()
|
|
2847
|
+
});
|
|
2848
|
+
var FlowSchema = z.object({
|
|
2849
|
+
flowId: z.string().uuid().optional(),
|
|
2850
|
+
modelId: z.string().uuid().optional(),
|
|
2851
|
+
flowType: FlowTypeSchema,
|
|
2852
|
+
sourceId: z.string().uuid(),
|
|
2853
|
+
targetId: z.string().uuid(),
|
|
2854
|
+
sourceHandle: FlowHandleSchema.optional(),
|
|
2855
|
+
targetHandle: FlowHandleSchema.optional(),
|
|
2856
|
+
mappings: z.array(FlowMappingSchema).optional()
|
|
2857
|
+
});
|
|
2786
2858
|
var SCOPE_SCHEMAS = {
|
|
2787
2859
|
commands: CommandSchema,
|
|
2788
2860
|
events: EventSchema,
|
|
@@ -2796,7 +2868,8 @@ var SCOPE_SCHEMAS = {
|
|
|
2796
2868
|
chapters: ChapterSchema,
|
|
2797
2869
|
contexts: ContextSchema,
|
|
2798
2870
|
swimLanes: SwimLaneSchema,
|
|
2799
|
-
notes: NoteSchema
|
|
2871
|
+
notes: NoteSchema,
|
|
2872
|
+
flows: FlowSchema
|
|
2800
2873
|
};
|
|
2801
2874
|
function validateEntry(scope, data) {
|
|
2802
2875
|
const schema = pickSchema(scope, data);
|
|
@@ -2975,7 +3048,19 @@ var ELEMENT_VIEW = `ElementView:
|
|
|
2975
3048
|
"x": 0, "y": 0, "width": 0, "height": 0,
|
|
2976
3049
|
"fields": [FieldView, ...],
|
|
2977
3050
|
"linkedCopy": false,
|
|
2978
|
-
"originalId": "<uuid>"
|
|
3051
|
+
"originalId": "<uuid>", // only when linkedCopy = true
|
|
3052
|
+
"design": [ExcalidrawElement, ...]
|
|
3053
|
+
// screens only; omitted when empty/absent
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
ExcalidrawElement (passthrough — Excalidraw owns the full shape):
|
|
3057
|
+
{
|
|
3058
|
+
"id": "<element-id>", // required
|
|
3059
|
+
"type": "rectangle" | "ellipse" | "diamond" | "arrow"
|
|
3060
|
+
| "line" | "freedraw" | "text" | "image" | "frame" | ...,
|
|
3061
|
+
"version": 1, // optional
|
|
3062
|
+
"isDeleted": false, // optional
|
|
3063
|
+
... // any extra Excalidraw props pass through
|
|
2979
3064
|
}`;
|
|
2980
3065
|
var SLICE_VIEW = `SliceView:
|
|
2981
3066
|
{
|
|
@@ -3318,6 +3403,9 @@ function buildElementView(e) {
|
|
|
3318
3403
|
if (originalId)
|
|
3319
3404
|
view.originalId = originalId;
|
|
3320
3405
|
}
|
|
3406
|
+
if (e.scope === "screens" && Array.isArray(e.design) && e.design.length > 0) {
|
|
3407
|
+
view.design = e.design;
|
|
3408
|
+
}
|
|
3321
3409
|
return view;
|
|
3322
3410
|
}
|
|
3323
3411
|
function buildSliceView(doc, slice) {
|
|
@@ -3427,6 +3515,9 @@ function buildShowElementView(doc, scope2, element) {
|
|
|
3427
3515
|
if (element.isLinkedCopy && originalKey) {
|
|
3428
3516
|
view.originalId = read(element, originalKey);
|
|
3429
3517
|
}
|
|
3518
|
+
if (scope2 === "screens" && Array.isArray(element.design) && element.design.length > 0) {
|
|
3519
|
+
view.design = element.design;
|
|
3520
|
+
}
|
|
3430
3521
|
view.copies = copies.map((c) => ({
|
|
3431
3522
|
copyId: read(c, ID_KEY[scope2]),
|
|
3432
3523
|
x: c.x,
|
|
@@ -3587,7 +3678,8 @@ var TYPES = [
|
|
|
3587
3678
|
{ type: "chapter", scope: "chapters", idKey: "chapterId", nameKey: "name" },
|
|
3588
3679
|
{ type: "context", scope: "contexts", idKey: "contextId", nameKey: "name" },
|
|
3589
3680
|
{ type: "swim-lane", scope: "swimLanes", idKey: "swimLaneId", nameKey: "name" },
|
|
3590
|
-
{ type: "note", scope: "notes", idKey: "noteId", nameKey: "title" }
|
|
3681
|
+
{ type: "note", scope: "notes", idKey: "noteId", nameKey: "title" },
|
|
3682
|
+
{ type: "flow", scope: "flows", idKey: "flowId", nameKey: "name", nameless: true }
|
|
3591
3683
|
];
|
|
3592
3684
|
var ALIAS_TO_CANONICAL = {
|
|
3593
3685
|
command: "command",
|
|
@@ -3625,7 +3717,9 @@ var ALIAS_TO_CANONICAL = {
|
|
|
3625
3717
|
swimLane: "swim-lane",
|
|
3626
3718
|
swimLanes: "swim-lane",
|
|
3627
3719
|
note: "note",
|
|
3628
|
-
notes: "note"
|
|
3720
|
+
notes: "note",
|
|
3721
|
+
flow: "flow",
|
|
3722
|
+
flows: "flow"
|
|
3629
3723
|
};
|
|
3630
3724
|
function resolveType(alias) {
|
|
3631
3725
|
const canonical = ALIAS_TO_CANONICAL[alias];
|
|
@@ -3637,6 +3731,22 @@ function knownTypeAliases() {
|
|
|
3637
3731
|
return TYPES.map((t) => t.type);
|
|
3638
3732
|
}
|
|
3639
3733
|
|
|
3734
|
+
// src/lib/enforce-size.ts
|
|
3735
|
+
function enforceCanonicalSize(meta, entry) {
|
|
3736
|
+
const dims = canonicalSizeForScope(meta.scope);
|
|
3737
|
+
if (!dims)
|
|
3738
|
+
return;
|
|
3739
|
+
const hadW = typeof entry.width === "number";
|
|
3740
|
+
const hadH = typeof entry.height === "number";
|
|
3741
|
+
const mismatched = hadW && entry.width !== dims.width || hadH && entry.height !== dims.height;
|
|
3742
|
+
entry.width = dims.width;
|
|
3743
|
+
entry.height = dims.height;
|
|
3744
|
+
if (mismatched) {
|
|
3745
|
+
return `${meta.type} is a fixed-size element; using canonical ${dims.width}x${dims.height}.`;
|
|
3746
|
+
}
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3640
3750
|
// src/commands/create.ts
|
|
3641
3751
|
var CREATE_HELP = `
|
|
3642
3752
|
Place a new element described by a JSON shape. The JSON is validated against
|
|
@@ -3647,6 +3757,23 @@ type-specific fields (e.g. \`status\` on slices, \`fields\` on stickies).
|
|
|
3647
3757
|
Notes use \`title\` instead of \`name\`. The CLI fills in the id and modelId
|
|
3648
3758
|
automatically — agents do not need to supply them.
|
|
3649
3759
|
|
|
3760
|
+
Fixed-size elements (command, event, read-model, screen, processor,
|
|
3761
|
+
external-event) are not resizable in the editor: the CLI always writes their
|
|
3762
|
+
canonical dimensions, so width/height are optional and any supplied size is
|
|
3763
|
+
overridden (a note is printed when it differs). Containers (slice, chapter,
|
|
3764
|
+
context, …) are resizable — pass the size you want.
|
|
3765
|
+
|
|
3766
|
+
Screens accept an optional \`design\` field — an Excalidraw scene as a JSON
|
|
3767
|
+
array of elements. The CLI converts the array to the Y.Doc representation that
|
|
3768
|
+
the canvas streams in realtime, so passing valid Excalidraw JSON is enough:
|
|
3769
|
+
|
|
3770
|
+
eventmodeler create screen '{"name":"OrderForm","x":0,"y":0,"width":400,"height":300,"fields":[],"design":[{"id":"r1","type":"rectangle","x":10,"y":10,"width":80,"height":40}]}'
|
|
3771
|
+
|
|
3772
|
+
Flows are nameless edges between elements. Provide flowType, sourceId,
|
|
3773
|
+
targetId, and optional handles + mappings:
|
|
3774
|
+
|
|
3775
|
+
eventmodeler create flow '{"flowType":"CommandToEvent","sourceId":"<commandStickyId>","targetId":"<eventStickyId>","sourceHandle":"right-source","targetHandle":"left-target","mappings":[{"sourceFieldId":"<uuid>","targetFieldId":"<uuid>"}]}'
|
|
3776
|
+
|
|
3650
3777
|
Examples:
|
|
3651
3778
|
eventmodeler create slice '{"name":"PlaceOrder","x":0,"y":0,"width":300,"height":200}'
|
|
3652
3779
|
eventmodeler create event '{"name":"OrderPlaced","x":40,"y":40,"width":160,"height":100,"fields":[{"name":"orderId","fieldType":"UUID","isList":false,"isGenerated":true}]}'
|
|
@@ -3667,6 +3794,11 @@ function registerCreateCommands(program) {
|
|
|
3667
3794
|
console.error(`Invalid JSON: ${err.message}`);
|
|
3668
3795
|
process.exit(2);
|
|
3669
3796
|
}
|
|
3797
|
+
if (parsed && typeof parsed === "object") {
|
|
3798
|
+
const note = enforceCanonicalSize(meta, parsed);
|
|
3799
|
+
if (note)
|
|
3800
|
+
console.error(note);
|
|
3801
|
+
}
|
|
3670
3802
|
const validation = validateEntry(meta.scope, parsed);
|
|
3671
3803
|
if (!validation.ok) {
|
|
3672
3804
|
console.error(`Validation failed for ${meta.type}:`);
|
|
@@ -3749,6 +3881,16 @@ fields by design — edit the original and all copies pick up the change. The
|
|
|
3749
3881
|
CLI refuses both name-based updates (ambiguous with the original) and
|
|
3750
3882
|
--id <copy-uuid> updates (would diverge from the original).
|
|
3751
3883
|
|
|
3884
|
+
Flows have no addressable name and must be updated via uuid:
|
|
3885
|
+
|
|
3886
|
+
eventmodeler --id <flowId> update flow '<json>'
|
|
3887
|
+
|
|
3888
|
+
Screens accept a typed \`design\` field — an array of Excalidraw elements.
|
|
3889
|
+
The CLI converts it to the Y.Doc array the canvas streams in realtime, so
|
|
3890
|
+
agents can emit Excalidraw JSON directly without worrying about CRDT wire
|
|
3891
|
+
shape. Omitting \`design\` on update wipes the existing design (replace
|
|
3892
|
+
semantics); to preserve it, round-trip via \`show screen ... | jq\`.
|
|
3893
|
+
|
|
3752
3894
|
This is a *replace*, not a patch: keys present in the previous entry but
|
|
3753
3895
|
absent in the new JSON are removed.
|
|
3754
3896
|
`;
|
|
@@ -3768,6 +3910,9 @@ function registerUpdateCommands(program) {
|
|
|
3768
3910
|
process.exit(2);
|
|
3769
3911
|
}
|
|
3770
3912
|
json = args[0];
|
|
3913
|
+
} else if (meta.nameless) {
|
|
3914
|
+
console.error(`${meta.type} entries have no name — address them by uuid: ` + `eventmodeler --id <${meta.idKey}> update ${meta.type} '<json>'`);
|
|
3915
|
+
process.exit(2);
|
|
3771
3916
|
} else {
|
|
3772
3917
|
if (args.length < 2) {
|
|
3773
3918
|
console.error(`Usage: eventmodeler update <type> "<name>" '<json>'`);
|
|
@@ -3783,6 +3928,11 @@ function registerUpdateCommands(program) {
|
|
|
3783
3928
|
console.error(`Invalid JSON: ${err.message}`);
|
|
3784
3929
|
process.exit(2);
|
|
3785
3930
|
}
|
|
3931
|
+
if (parsed && typeof parsed === "object") {
|
|
3932
|
+
const note = enforceCanonicalSize(meta, parsed);
|
|
3933
|
+
if (note)
|
|
3934
|
+
console.error(note);
|
|
3935
|
+
}
|
|
3786
3936
|
const validation = validateEntry(meta.scope, parsed);
|
|
3787
3937
|
if (!validation.ok) {
|
|
3788
3938
|
console.error(`Validation failed for ${meta.type}:`);
|
|
@@ -3835,6 +3985,10 @@ function registerRemoveCommands(program) {
|
|
|
3835
3985
|
}
|
|
3836
3986
|
const modelId = resolveModelId(opts.model);
|
|
3837
3987
|
const idOverride = getGlobalId();
|
|
3988
|
+
if (meta.nameless && !idOverride) {
|
|
3989
|
+
console.error(`${meta.type} entries have no name — address them by uuid: ` + `eventmodeler --id <${meta.idKey}> remove ${meta.type}`);
|
|
3990
|
+
process.exit(2);
|
|
3991
|
+
}
|
|
3838
3992
|
let summary = `Removed ${meta.type}.`;
|
|
3839
3993
|
await withDoc(modelId, (doc) => {
|
|
3840
3994
|
const { id, entry } = resolveEntity(doc, meta.scope, meta.idKey, meta.nameKey, name, {
|