event_engine 0.1.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +53 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +517 -0
  5. data/Rakefile +12 -0
  6. data/app/assets/config/event_engine_manifest.js +1 -0
  7. data/app/assets/stylesheets/event_engine/application.css +15 -0
  8. data/app/controllers/event_engine/application_controller.rb +4 -0
  9. data/app/helpers/event_engine/application_helper.rb +4 -0
  10. data/app/jobs/event_engine/application_job.rb +4 -0
  11. data/app/mailers/event_engine/application_mailer.rb +6 -0
  12. data/app/models/event_engine/application_record.rb +5 -0
  13. data/app/views/layouts/event_engine/application.html.erb +15 -0
  14. data/config/routes.rb +2 -0
  15. data/lib/event_engine/configuration.rb +20 -0
  16. data/lib/event_engine/definition_loader.rb +26 -0
  17. data/lib/event_engine/dsl_compiler.rb +50 -0
  18. data/lib/event_engine/engine.rb +56 -0
  19. data/lib/event_engine/event.rb +32 -0
  20. data/lib/event_engine/event_builder.rb +45 -0
  21. data/lib/event_engine/event_definition/inputs.rb +43 -0
  22. data/lib/event_engine/event_definition/payloads.rb +47 -0
  23. data/lib/event_engine/event_definition/schemas.rb +158 -0
  24. data/lib/event_engine/event_definition/validation.rb +18 -0
  25. data/lib/event_engine/event_definition.rb +76 -0
  26. data/lib/event_engine/event_schema.rb +99 -0
  27. data/lib/event_engine/event_schema_dumper.rb +13 -0
  28. data/lib/event_engine/event_schema_loader.rb +37 -0
  29. data/lib/event_engine/event_schema_merger.rb +62 -0
  30. data/lib/event_engine/event_schema_writer.rb +47 -0
  31. data/lib/event_engine/handler_registry.rb +23 -0
  32. data/lib/event_engine/lifecycle_definition.rb +86 -0
  33. data/lib/event_engine/process_type.rb +26 -0
  34. data/lib/event_engine/railtie.rb +9 -0
  35. data/lib/event_engine/reference/guide.md +129 -0
  36. data/lib/event_engine/reference.rb +16 -0
  37. data/lib/event_engine/schema_catalog.rb +50 -0
  38. data/lib/event_engine/schema_compatibility.rb +50 -0
  39. data/lib/event_engine/schema_diff.rb +35 -0
  40. data/lib/event_engine/schema_drift_guard.rb +38 -0
  41. data/lib/event_engine/schema_registry.rb +122 -0
  42. data/lib/event_engine/subject_registry.rb +40 -0
  43. data/lib/event_engine/the_local/agents/event_engine-develop.md +142 -0
  44. data/lib/event_engine/the_local/agents/event_engine-info.md +140 -0
  45. data/lib/event_engine/the_local/agents/event_engine-install.md +140 -0
  46. data/lib/event_engine/the_local.rb +55 -0
  47. data/lib/event_engine/version.rb +3 -0
  48. data/lib/event_engine.rb +197 -0
  49. data/lib/generators/event_engine/install_generator.rb +31 -0
  50. data/lib/generators/event_engine/templates/event_schema.rb +10 -0
  51. data/lib/generators/event_engine/templates/initializer.rb +4 -0
  52. data/lib/tasks/event_engine_catalog.rake +13 -0
  53. data/lib/tasks/event_engine_schema.rake +82 -0
  54. data/lib/tasks/event_engine_schema_check.rake +20 -0
  55. data/lib/tasks/event_engine_tasks.rake +4 -0
  56. metadata +127 -0
@@ -0,0 +1,197 @@
1
+ require_relative "event_engine/version"
2
+
3
+ require "event_engine/engine"
4
+ require "event_engine/configuration"
5
+ require "event_engine/process_type"
6
+ require "event_engine/event_definition"
7
+ require "event_engine/lifecycle_definition"
8
+ require "event_engine/event_builder"
9
+ require "event_engine/handler_registry"
10
+ require "event_engine/event_schema"
11
+ require "event_engine/schema_registry"
12
+ require "event_engine/subject_registry"
13
+ require "event_engine/event"
14
+ require "event_engine/dsl_compiler"
15
+ require "event_engine/event_schema_loader"
16
+ require "event_engine/event_schema_writer"
17
+ require "event_engine/event_schema_merger"
18
+ require "event_engine/event_schema_dumper"
19
+ require "event_engine/schema_drift_guard"
20
+ require "event_engine/schema_compatibility"
21
+ require "event_engine/schema_catalog"
22
+ require "event_engine/railtie"
23
+ require "event_engine/definition_loader"
24
+ require "event_engine/the_local"
25
+
26
+ # EventEngine is the schema-first core of the event pipeline.
27
+ #
28
+ # Events are defined via a Ruby DSL and compiled into a canonical schema file.
29
+ # At boot, a helper method is installed on this module for each registered event
30
+ # (e.g. +EventEngine.cow_fed(cow: cow)+); the helper validates inputs, builds an
31
+ # +Event+, and dispatches it to registered handlers by level. Companion gems
32
+ # (e.g. event_engine-delivery) register handlers to process the events.
33
+ #
34
+ # @example Define, build, and dispatch an event
35
+ # EventEngine.register_handler(MyHandler, levels: :all)
36
+ # EventEngine.cow_fed(cow: cow, occurred_at: Time.current)
37
+ module EventEngine
38
+ mattr_accessor :_installed_event_helpers, default: Set.new
39
+ class << self
40
+ # Returns the current configuration instance.
41
+ #
42
+ # @return [Configuration]
43
+ def configuration
44
+ @configuration ||= Configuration.new
45
+ end
46
+
47
+ # Yields the configuration for modification.
48
+ #
49
+ # @yieldparam config [Configuration] the configuration instance
50
+ # @example
51
+ # EventEngine.configure do |config|
52
+ # config.logger = Rails.logger
53
+ # end
54
+ def configure
55
+ yield(configuration)
56
+ end
57
+
58
+ def handler_registry
59
+ @handler_registry ||= HandlerRegistry.new
60
+ end
61
+
62
+ def subject_registry
63
+ @subject_registry ||= SubjectRegistry.new
64
+ end
65
+
66
+ def define_subjects(&block)
67
+ subject_registry.instance_eval(&block)
68
+ end
69
+
70
+ def reset_subjects!
71
+ @subject_registry = nil
72
+ end
73
+
74
+ def enriched_metadata(call_site_metadata)
75
+ defaults = evaluated_metadata_defaults
76
+ return call_site_metadata if defaults.nil?
77
+
78
+ defaults.merge(call_site_metadata || {})
79
+ end
80
+
81
+ def evaluated_metadata_defaults
82
+ callable = configuration.metadata_defaults
83
+ return nil unless callable
84
+
85
+ callable.call
86
+ rescue => error
87
+ configuration.logger&.error("EventEngine metadata_defaults raised: #{error.message}")
88
+ nil
89
+ end
90
+
91
+ def register_handler(handler, levels:)
92
+ handler_registry.register(handler, levels: levels)
93
+ end
94
+
95
+ def dispatch(event)
96
+ handler_registry.dispatch(event)
97
+ end
98
+
99
+ def reset_handlers!
100
+ handler_registry.clear!
101
+ end
102
+
103
+ # Loads a schema file, populates the registry, and installs helper methods.
104
+ # Called automatically by the engine at Rails boot.
105
+ #
106
+ # @param schema_path [String, Pathname] path to the compiled schema file
107
+ # @param registry [SchemaRegistry] the registry to populate
108
+ # @return [EventSchema] the loaded schema
109
+ def boot_from_schema!(schema_path:, registry:)
110
+ event_schema = EventSchemaLoader.load(schema_path)
111
+
112
+ registry.reset!
113
+ registry.load_from_schema!(event_schema)
114
+
115
+ install_helpers(registry: registry)
116
+
117
+ event_schema
118
+ end
119
+
120
+ # Installs singleton helper methods on the EventEngine module for each
121
+ # event in the registry. Previous helpers are removed first.
122
+ #
123
+ # @param registry [SchemaRegistry] the loaded registry
124
+ def install_helpers(registry:)
125
+ _installed_event_helpers.each do |method_name|
126
+ singleton_class.remove_method(method_name) if singleton_class.method_defined?(method_name)
127
+ end
128
+ _installed_event_helpers.clear
129
+
130
+ registry.events.each do |event_name|
131
+ schema = registry.schema(event_name)
132
+
133
+ required = schema.required_inputs
134
+ optional = schema.optional_inputs
135
+
136
+ define_singleton_method(event_name) do |**args|
137
+ event_version = args.delete(:event_version)
138
+ occurred_at = args.delete(:occurred_at)
139
+ metadata = args.delete(:metadata)
140
+ idempotency_key = args.delete(:idempotency_key)
141
+ aggregate_type = args.delete(:aggregate_type)
142
+ aggregate_id = args.delete(:aggregate_id)
143
+ aggregate_version = args.delete(:aggregate_version)
144
+
145
+ input_keys = required + optional
146
+ inputs = args.slice(*input_keys)
147
+
148
+ missing = required - inputs.keys
149
+ raise ArgumentError, "Missing required inputs: #{missing.join(', ')}" if missing.any?
150
+
151
+ unknown = args.keys - input_keys
152
+ raise ArgumentError, "Unknown inputs: #{unknown.join(', ')}" if unknown.any?
153
+
154
+ schema = registry.schema(event_name, version: event_version)
155
+ attrs = EventBuilder.build(schema: schema, data: inputs)
156
+ attrs[:occurred_at] = occurred_at || Time.current
157
+ attrs[:metadata] = EventEngine.enriched_metadata(metadata)
158
+ attrs[:idempotency_key] = idempotency_key || SecureRandom.uuid
159
+ attrs[:aggregate_type] = aggregate_type
160
+ attrs[:aggregate_id] = aggregate_id
161
+ attrs[:aggregate_version] = aggregate_version
162
+ attrs[:process_type] = schema.process_type
163
+ attrs[:subject] = schema.subject
164
+ attrs[:domain] = schema.domain
165
+
166
+ EventEngine.dispatch(Event.new(**attrs))
167
+ end
168
+
169
+ _installed_event_helpers << event_name
170
+ end
171
+ end
172
+
173
+ # Compiles event definitions from source into a registry.
174
+ # Used by rake tasks for schema drift detection.
175
+ #
176
+ # @return [SchemaRegistry]
177
+ def compiled_schema_registry
178
+ DefinitionLoader.ensure_loaded!
179
+ definitions = EventDefinition.descendants
180
+ compiled = DslCompiler.compile(definitions)
181
+ registry = SchemaRegistry.new
182
+ registry.load_from_schema!(compiled)
183
+ registry
184
+ end
185
+
186
+ # Loads the committed schema file into a registry.
187
+ # Used by rake tasks for schema drift detection.
188
+ #
189
+ # @return [SchemaRegistry]
190
+ def file_schema_registry
191
+ loaded = EventSchemaLoader.load(Rails.root.join("db/event_schema.rb"))
192
+ registry = SchemaRegistry.new
193
+ registry.load_from_schema!(loaded)
194
+ registry
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,31 @@
1
+ module EventEngine
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ desc "Install EventEngine (schema file, initializer, migrations)"
7
+
8
+ def create_event_schema
9
+ template "event_schema.rb", "db/event_schema.rb"
10
+ end
11
+
12
+ def create_initializer
13
+ template "initializer.rb", "config/initializers/event_engine.rb"
14
+ end
15
+
16
+ def print_next_steps
17
+ say <<~MSG
18
+
19
+ EventEngine installed.
20
+
21
+ Next steps:
22
+ 1. Define events in app/event_definitions/
23
+ 2. Run: bin/rails event_engine:schema:dump
24
+ 3. Commit db/event_schema.rb
25
+ 4. Configure transport in config/initializers/event_engine.rb
26
+
27
+ MSG
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ # This file is authoritative in production.
2
+ # It is generated from EventDefinitions via:
3
+ #
4
+ # bin/rails event_engine:schema:dump
5
+ #
6
+ # Do not edit manually.
7
+
8
+ EventEngine::EventSchema.define do |schema|
9
+ # schema.register(...)
10
+ end
@@ -0,0 +1,4 @@
1
+ EventEngine.configure do |c|
2
+ # Logger for EventEngine messages (defaults to Rails.logger)
3
+ # c.logger = Rails.logger
4
+ end
@@ -0,0 +1,13 @@
1
+ namespace :event_engine do
2
+ desc "Render the event schema and subjects as a markdown catalog"
3
+ task catalog: :environment do
4
+ EventEngine::DefinitionLoader.ensure_loaded!
5
+
6
+ catalog = EventEngine::SchemaCatalog.new(
7
+ schema_registry: EventEngine.file_schema_registry,
8
+ subject_registry: EventEngine.subject_registry
9
+ )
10
+
11
+ puts catalog.to_markdown
12
+ end
13
+ end
@@ -0,0 +1,82 @@
1
+ namespace :event_engine do
2
+ desc "Fail if event schema DSL has drifted from db/event_schema.rb"
3
+ task schema: :environment do
4
+ EventEngine::DefinitionLoader.ensure_loaded!
5
+
6
+ descendants = EventEngine::EventDefinition.descendants
7
+
8
+ if descendants.empty?
9
+ raise <<~MSG
10
+ EventEngine found no EventDefinitions.
11
+
12
+ Expected definitions to be loaded during eager load.
13
+ Ensure they live in an eager-load path (e.g. app/event_definitions).
14
+ MSG
15
+ end
16
+
17
+ EventEngine::SchemaDriftGuard.check!(
18
+ schema_path: Rails.root.join("db/event_schema.rb"),
19
+ definitions: descendants
20
+ )
21
+ end
22
+
23
+ namespace :schema do
24
+ desc "Regenerate event_schema.rb from EventDefinitions"
25
+ task dump: :environment do
26
+ EventEngine::DefinitionLoader.ensure_loaded!
27
+
28
+ descendants = EventEngine::EventDefinition.descendants
29
+
30
+ if descendants.empty?
31
+ raise <<~MSG
32
+ EventEngine found no EventDefinitions.
33
+
34
+ Expected definitions to be loaded during eager load.
35
+ Ensure they live in an eager-load path (e.g. app/event_definitions).
36
+ MSG
37
+ end
38
+
39
+ path = Rails.root.join("db/event_schema.rb")
40
+
41
+ EventEngine::EventSchemaDumper.dump!(
42
+ definitions: descendants,
43
+ path: path
44
+ )
45
+
46
+ puts "Dumping EventEngine schema to #{path}"
47
+ end
48
+
49
+ desc "Fail with a readable diff if definitions have drifted from db/event_schema.rb"
50
+ task verify: :environment do
51
+ EventEngine::DefinitionLoader.ensure_loaded!
52
+
53
+ descendants = EventEngine::EventDefinition.descendants
54
+
55
+ if descendants.empty?
56
+ raise <<~MSG
57
+ EventEngine found no EventDefinitions.
58
+
59
+ Expected definitions to be loaded during eager load.
60
+ Ensure they live in an eager-load path (e.g. app/event_definitions).
61
+ MSG
62
+ end
63
+
64
+ EventEngine::SchemaDriftGuard.check!(
65
+ schema_path: Rails.root.join("db/event_schema.rb"),
66
+ definitions: descendants
67
+ )
68
+ end
69
+
70
+ desc "Fail if new definitions break compatibility with the committed schema"
71
+ task compatibility: :environment do
72
+ EventEngine::DefinitionLoader.ensure_loaded!
73
+
74
+ violations = EventEngine::SchemaCompatibility.violations(
75
+ old_registry: EventEngine.file_schema_registry,
76
+ new_registry: EventEngine.compiled_schema_registry
77
+ )
78
+
79
+ raise "Breaking schema changes:\n#{violations.join("\n")}" if violations.any?
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,20 @@
1
+ namespace :event_engine do
2
+ desc "Fail if event schema DSL has drifted from db/event_schema.rb"
3
+ task schema_check: :environment do
4
+ compiled = EventEngine.compiled_schema_registry
5
+ file = EventEngine.file_schema_registry
6
+
7
+ if EventEngine::EventSchemaMerger.changed?(compiled, file)
8
+ raise <<~MSG
9
+ Schema drift detected.
10
+
11
+ The compiled EventDefinitions differ from db/event_schema.rb.
12
+
13
+ Run:
14
+ bin/rails event_engine:schema:dump
15
+
16
+ Then commit the updated schema file.
17
+ MSG
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :event_engine do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: event_engine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - tylercschneider
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-06-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.1.6
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '9'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 7.1.6
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '9'
33
+ description: 'The core of the EventEngine pipeline: define events with a Ruby DSL,
34
+ compile to a canonical schema, and dispatch built events to registered handlers
35
+ by level. Durable delivery, transports, the outbox, and the observability dashboard
36
+ live in the companion gem event_engine-delivery.'
37
+ email:
38
+ - tylercschneider@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - CHANGELOG.md
44
+ - MIT-LICENSE
45
+ - README.md
46
+ - Rakefile
47
+ - app/assets/config/event_engine_manifest.js
48
+ - app/assets/stylesheets/event_engine/application.css
49
+ - app/controllers/event_engine/application_controller.rb
50
+ - app/helpers/event_engine/application_helper.rb
51
+ - app/jobs/event_engine/application_job.rb
52
+ - app/mailers/event_engine/application_mailer.rb
53
+ - app/models/event_engine/application_record.rb
54
+ - app/views/layouts/event_engine/application.html.erb
55
+ - config/routes.rb
56
+ - lib/event_engine.rb
57
+ - lib/event_engine/configuration.rb
58
+ - lib/event_engine/definition_loader.rb
59
+ - lib/event_engine/dsl_compiler.rb
60
+ - lib/event_engine/engine.rb
61
+ - lib/event_engine/event.rb
62
+ - lib/event_engine/event_builder.rb
63
+ - lib/event_engine/event_definition.rb
64
+ - lib/event_engine/event_definition/inputs.rb
65
+ - lib/event_engine/event_definition/payloads.rb
66
+ - lib/event_engine/event_definition/schemas.rb
67
+ - lib/event_engine/event_definition/validation.rb
68
+ - lib/event_engine/event_schema.rb
69
+ - lib/event_engine/event_schema_dumper.rb
70
+ - lib/event_engine/event_schema_loader.rb
71
+ - lib/event_engine/event_schema_merger.rb
72
+ - lib/event_engine/event_schema_writer.rb
73
+ - lib/event_engine/handler_registry.rb
74
+ - lib/event_engine/lifecycle_definition.rb
75
+ - lib/event_engine/process_type.rb
76
+ - lib/event_engine/railtie.rb
77
+ - lib/event_engine/reference.rb
78
+ - lib/event_engine/reference/guide.md
79
+ - lib/event_engine/schema_catalog.rb
80
+ - lib/event_engine/schema_compatibility.rb
81
+ - lib/event_engine/schema_diff.rb
82
+ - lib/event_engine/schema_drift_guard.rb
83
+ - lib/event_engine/schema_registry.rb
84
+ - lib/event_engine/subject_registry.rb
85
+ - lib/event_engine/the_local.rb
86
+ - lib/event_engine/the_local/agents/event_engine-develop.md
87
+ - lib/event_engine/the_local/agents/event_engine-info.md
88
+ - lib/event_engine/the_local/agents/event_engine-install.md
89
+ - lib/event_engine/version.rb
90
+ - lib/generators/event_engine/install_generator.rb
91
+ - lib/generators/event_engine/templates/event_schema.rb
92
+ - lib/generators/event_engine/templates/initializer.rb
93
+ - lib/tasks/event_engine_catalog.rake
94
+ - lib/tasks/event_engine_schema.rake
95
+ - lib/tasks/event_engine_schema_check.rake
96
+ - lib/tasks/event_engine_tasks.rake
97
+ homepage: https://eventengine.co
98
+ licenses:
99
+ - MIT
100
+ metadata:
101
+ allowed_push_host: https://rubygems.org
102
+ rubygems_mfa_required: 'true'
103
+ homepage_uri: https://eventengine.co
104
+ source_code_uri: https://github.com/DYB-Development/event_engine
105
+ changelog_uri: https://github.com/DYB-Development/event_engine/blob/main/CHANGELOG.md
106
+ bug_tracker_uri: https://github.com/DYB-Development/event_engine/issues
107
+ documentation_uri: https://github.com/DYB-Development/event_engine#readme
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 3.2.0
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.5.16
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Schema-first event definitions and dispatch for Rails
127
+ test_files: []