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.
Files changed (2) hide show
  1. package/dist/index.js +160 -6
  2. 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().optional(),
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: canonicalSticky("screenId"),
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>" // only when linkedCopy = true
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, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eventmodeler",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "CLI tool for event modeling - explore, design, and generate code from your event models",
5
5
  "type": "module",
6
6
  "repository": {