active_canvas 0.0.1

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 (80) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +318 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/javascripts/active_canvas/editor/ai_panel.js +1607 -0
  6. data/app/assets/javascripts/active_canvas/editor/asset_manager.js +498 -0
  7. data/app/assets/javascripts/active_canvas/editor/blocks.js +1083 -0
  8. data/app/assets/javascripts/active_canvas/editor/code_panel.js +572 -0
  9. data/app/assets/javascripts/active_canvas/editor/component_toolbar.js +394 -0
  10. data/app/assets/javascripts/active_canvas/editor/panels.js +460 -0
  11. data/app/assets/javascripts/active_canvas/editor/utils.js +56 -0
  12. data/app/assets/javascripts/active_canvas/editor.js +295 -0
  13. data/app/assets/stylesheets/active_canvas/application.css +15 -0
  14. data/app/assets/stylesheets/active_canvas/editor.css +2929 -0
  15. data/app/controllers/active_canvas/admin/ai_controller.rb +181 -0
  16. data/app/controllers/active_canvas/admin/application_controller.rb +56 -0
  17. data/app/controllers/active_canvas/admin/media_controller.rb +61 -0
  18. data/app/controllers/active_canvas/admin/page_types_controller.rb +57 -0
  19. data/app/controllers/active_canvas/admin/page_versions_controller.rb +23 -0
  20. data/app/controllers/active_canvas/admin/pages_controller.rb +133 -0
  21. data/app/controllers/active_canvas/admin/partials_controller.rb +88 -0
  22. data/app/controllers/active_canvas/admin/settings_controller.rb +256 -0
  23. data/app/controllers/active_canvas/application_controller.rb +20 -0
  24. data/app/controllers/active_canvas/pages_controller.rb +18 -0
  25. data/app/controllers/concerns/active_canvas/current_user.rb +12 -0
  26. data/app/controllers/concerns/active_canvas/rate_limitable.rb +75 -0
  27. data/app/controllers/concerns/active_canvas/tailwind_compilation.rb +39 -0
  28. data/app/helpers/active_canvas/application_helper.rb +4 -0
  29. data/app/jobs/active_canvas/application_job.rb +4 -0
  30. data/app/jobs/active_canvas/compile_tailwind_job.rb +64 -0
  31. data/app/mailers/active_canvas/application_mailer.rb +6 -0
  32. data/app/models/active_canvas/ai_model.rb +136 -0
  33. data/app/models/active_canvas/application_record.rb +5 -0
  34. data/app/models/active_canvas/media.rb +141 -0
  35. data/app/models/active_canvas/page.rb +85 -0
  36. data/app/models/active_canvas/page_type.rb +22 -0
  37. data/app/models/active_canvas/page_version.rb +80 -0
  38. data/app/models/active_canvas/partial.rb +73 -0
  39. data/app/models/active_canvas/setting.rb +292 -0
  40. data/app/services/active_canvas/ai_configuration.rb +40 -0
  41. data/app/services/active_canvas/ai_models.rb +128 -0
  42. data/app/services/active_canvas/ai_service.rb +289 -0
  43. data/app/services/active_canvas/content_sanitizer.rb +112 -0
  44. data/app/services/active_canvas/tailwind_compiler.rb +156 -0
  45. data/app/views/active_canvas/admin/media/index.html.erb +401 -0
  46. data/app/views/active_canvas/admin/media/show.html.erb +297 -0
  47. data/app/views/active_canvas/admin/page_types/_form.html.erb +25 -0
  48. data/app/views/active_canvas/admin/page_types/edit.html.erb +13 -0
  49. data/app/views/active_canvas/admin/page_types/index.html.erb +29 -0
  50. data/app/views/active_canvas/admin/page_types/new.html.erb +9 -0
  51. data/app/views/active_canvas/admin/page_types/show.html.erb +18 -0
  52. data/app/views/active_canvas/admin/page_versions/show.html.erb +469 -0
  53. data/app/views/active_canvas/admin/pages/_form.html.erb +62 -0
  54. data/app/views/active_canvas/admin/pages/content.html.erb +139 -0
  55. data/app/views/active_canvas/admin/pages/edit.html.erb +335 -0
  56. data/app/views/active_canvas/admin/pages/editor.html.erb +710 -0
  57. data/app/views/active_canvas/admin/pages/index.html.erb +149 -0
  58. data/app/views/active_canvas/admin/pages/new.html.erb +19 -0
  59. data/app/views/active_canvas/admin/pages/show.html.erb +258 -0
  60. data/app/views/active_canvas/admin/pages/versions.html.erb +333 -0
  61. data/app/views/active_canvas/admin/partials/edit.html.erb +182 -0
  62. data/app/views/active_canvas/admin/partials/editor.html.erb +703 -0
  63. data/app/views/active_canvas/admin/partials/index.html.erb +131 -0
  64. data/app/views/active_canvas/admin/settings/show.html.erb +1864 -0
  65. data/app/views/active_canvas/pages/no_homepage.html.erb +45 -0
  66. data/app/views/active_canvas/pages/show.html.erb +113 -0
  67. data/app/views/layouts/active_canvas/admin/application.html.erb +960 -0
  68. data/app/views/layouts/active_canvas/admin/editor.html.erb +826 -0
  69. data/app/views/layouts/active_canvas/application.html.erb +55 -0
  70. data/config/routes.rb +48 -0
  71. data/db/migrate/20260202000001_create_active_canvas_tables.rb +113 -0
  72. data/db/migrate/20260202000002_create_active_canvas_ai_models.rb +26 -0
  73. data/lib/active_canvas/configuration.rb +232 -0
  74. data/lib/active_canvas/engine.rb +44 -0
  75. data/lib/active_canvas/version.rb +3 -0
  76. data/lib/active_canvas.rb +26 -0
  77. data/lib/generators/active_canvas/install/install_generator.rb +263 -0
  78. data/lib/generators/active_canvas/install/templates/initializer.rb.tt +163 -0
  79. data/lib/tasks/active_canvas_tasks.rake +69 -0
  80. metadata +150 -0
@@ -0,0 +1,55 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+
7
+ <title><%= yield(:page_title).presence || "Active Canvas" %></title>
8
+
9
+ <%= csrf_meta_tags %>
10
+ <%= csp_meta_tag %>
11
+
12
+ <!-- SEO Meta Tags -->
13
+ <%= yield :seo_meta %>
14
+
15
+ <!-- Open Graph / Social -->
16
+ <%= yield :og_meta %>
17
+
18
+ <!-- Twitter Card -->
19
+ <%= yield :twitter_meta %>
20
+
21
+ <!-- Canonical URL -->
22
+ <%= yield :canonical %>
23
+
24
+ <!-- Structured Data -->
25
+ <%= yield :structured_data %>
26
+
27
+ <%= yield :head %>
28
+
29
+ <!-- ActiveCanvas: framework=<%= ActiveCanvas::Setting.css_framework %> compiled_mode=<%= ActiveCanvas::Setting.tailwind_compiled_mode? %> available=<%= ActiveCanvas::TailwindCompiler.available? %> env=<%= Rails.env %> -->
30
+ <% if ActiveCanvas::Setting.tailwind_compiled_mode? %>
31
+ <!-- ActiveCanvas: Using compiled Tailwind CSS (no CDN) -->
32
+ <% elsif ActiveCanvas::Setting.css_framework_url.present? %>
33
+ <!-- ActiveCanvas: Loading CSS framework from CDN -->
34
+ <% if ActiveCanvas::Setting.css_framework_type == :script %>
35
+ <script src="<%= ActiveCanvas::Setting.css_framework_url %>"></script>
36
+ <% else %>
37
+ <link rel="stylesheet" href="<%= ActiveCanvas::Setting.css_framework_url %>">
38
+ <% end %>
39
+ <% end %>
40
+
41
+ <%= stylesheet_link_tag "active_canvas/application", media: "all" %>
42
+
43
+ <% if ActiveCanvas::Setting.global_css.present? %>
44
+ <style><%= ActiveCanvas::Setting.global_css.html_safe %></style>
45
+ <% end %>
46
+ </head>
47
+ <body>
48
+
49
+ <%= yield %>
50
+
51
+ <% if ActiveCanvas::Setting.global_js.present? %>
52
+ <script><%= ActiveCanvas::Setting.global_js.html_safe %></script>
53
+ <% end %>
54
+ </body>
55
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,48 @@
1
+ ActiveCanvas::Engine.routes.draw do
2
+ namespace :admin do
3
+ resources :pages do
4
+ member do
5
+ get :content
6
+ patch :update_content
7
+ get :editor
8
+ patch :save_editor
9
+ get :versions
10
+ end
11
+ resources :versions, only: [:show], controller: "page_versions"
12
+ end
13
+ resources :page_types
14
+ resources :partials, only: [:index, :edit, :update] do
15
+ member do
16
+ get :editor
17
+ patch :save_editor
18
+ end
19
+ end
20
+ resources :media, only: [:index, :show, :create, :destroy]
21
+ resource :settings, only: [:show, :update] do
22
+ patch :update_global_css
23
+ patch :update_global_js
24
+ patch :update_ai
25
+ post :sync_ai_models
26
+ patch :toggle_ai_model
27
+ patch :bulk_toggle_ai_models
28
+ post :create_ai_model
29
+ delete :destroy_ai_model
30
+ patch :update_tailwind_config
31
+ post :recompile_tailwind
32
+ end
33
+
34
+ namespace :ai do
35
+ post :chat
36
+ post :image
37
+ post :screenshot_to_code
38
+ get :models
39
+ get :status
40
+ end
41
+
42
+ root to: "pages#index"
43
+ end
44
+
45
+ root to: "pages#home"
46
+ get ":slug", to: "pages#show", as: :public_page,
47
+ constraints: ->(req) { ActiveCanvas::Page.published.exists?(slug: req.params[:slug]) }
48
+ end
@@ -0,0 +1,113 @@
1
+ class CreateActiveCanvasTables < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :active_canvas_page_types, if_not_exists: true do |t|
4
+ t.string :name, null: false
5
+ t.string :key, null: false
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :active_canvas_page_types, :key, unique: true, if_not_exists: true
11
+
12
+ create_table :active_canvas_pages, if_not_exists: true do |t|
13
+ t.string :title, null: false
14
+ t.string :slug
15
+ t.text :content
16
+ t.references :page_type, null: false, foreign_key: { to_table: :active_canvas_page_types }
17
+ t.boolean :published, default: false, null: false
18
+
19
+ # Editor data
20
+ t.text :content_css
21
+ t.text :content_js
22
+ t.text :content_components
23
+
24
+ # Tailwind compilation
25
+ t.text :compiled_tailwind_css
26
+ t.datetime :tailwind_compiled_at
27
+
28
+ # Header/Footer
29
+ t.boolean :show_header, default: true, null: false
30
+ t.boolean :show_footer, default: true, null: false
31
+
32
+ # SEO
33
+ t.string :meta_title
34
+ t.text :meta_description
35
+ t.string :canonical_url
36
+ t.string :meta_robots
37
+
38
+ # Open Graph
39
+ t.string :og_title
40
+ t.text :og_description
41
+ t.string :og_image
42
+
43
+ # Twitter
44
+ t.string :twitter_card
45
+ t.string :twitter_title
46
+ t.text :twitter_description
47
+ t.string :twitter_image
48
+
49
+ # Structured data
50
+ t.text :structured_data
51
+
52
+ t.timestamps
53
+ end
54
+
55
+ add_index :active_canvas_pages, :slug, unique: true, if_not_exists: true
56
+
57
+ create_table :active_canvas_page_versions, if_not_exists: true do |t|
58
+ t.references :page, null: false, foreign_key: { to_table: :active_canvas_pages }
59
+ t.integer :version_number, null: false
60
+ t.text :content_before
61
+ t.text :content_after
62
+ t.text :content_diff
63
+ t.text :css_before
64
+ t.text :css_after
65
+ t.string :change_summary
66
+ t.string :changed_by
67
+ t.integer :content_size_before
68
+ t.integer :content_size_after
69
+
70
+ t.timestamps
71
+ end
72
+
73
+ add_index :active_canvas_page_versions, [:page_id, :version_number], unique: true, if_not_exists: true
74
+ add_index :active_canvas_page_versions, :created_at, if_not_exists: true
75
+
76
+ create_table :active_canvas_partials, if_not_exists: true do |t|
77
+ t.string :name, null: false
78
+ t.string :partial_type, null: false
79
+ t.text :content
80
+ t.text :content_css
81
+ t.text :content_js
82
+ t.text :content_components
83
+ t.text :compiled_css
84
+ t.boolean :active, default: true, null: false
85
+
86
+ t.timestamps
87
+ end
88
+
89
+ add_index :active_canvas_partials, :partial_type, unique: true, if_not_exists: true
90
+
91
+ create_table :active_canvas_media, if_not_exists: true do |t|
92
+ t.string :filename, null: false
93
+ t.string :content_type
94
+ t.integer :byte_size
95
+ t.text :metadata
96
+
97
+ t.timestamps
98
+ end
99
+
100
+ add_index :active_canvas_media, :content_type, if_not_exists: true
101
+ add_index :active_canvas_media, :created_at, if_not_exists: true
102
+
103
+ create_table :active_canvas_settings, if_not_exists: true do |t|
104
+ t.string :key, null: false
105
+ t.text :value
106
+ t.text :encrypted_value
107
+
108
+ t.timestamps
109
+ end
110
+
111
+ add_index :active_canvas_settings, :key, unique: true, if_not_exists: true
112
+ end
113
+ end
@@ -0,0 +1,26 @@
1
+ class CreateActiveCanvasAiModels < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :active_canvas_ai_models, if_not_exists: true do |t|
4
+ t.string :model_id, null: false
5
+ t.string :provider, null: false
6
+ t.string :model_type
7
+ t.string :name
8
+ t.string :family
9
+ t.integer :context_window
10
+ t.integer :max_tokens
11
+ t.boolean :supports_functions, default: false
12
+ t.decimal :input_price_per_million, precision: 10, scale: 4
13
+ t.decimal :output_price_per_million, precision: 10, scale: 4
14
+ t.boolean :active, default: true
15
+ t.text :input_modalities
16
+ t.text :output_modalities
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :active_canvas_ai_models, :model_id, unique: true, if_not_exists: true
22
+ add_index :active_canvas_ai_models, :provider, if_not_exists: true
23
+ add_index :active_canvas_ai_models, :model_type, if_not_exists: true
24
+ add_index :active_canvas_ai_models, :active, if_not_exists: true
25
+ end
26
+ end
@@ -0,0 +1,232 @@
1
+ module ActiveCanvas
2
+ class Configuration
3
+ # ==> Authentication
4
+ # Authentication callback for public pages
5
+ # Set to a proc/lambda that will be called as a before_action
6
+ # Example: config.authenticate_public = -> { redirect_to login_path unless current_user }
7
+ attr_accessor :authenticate_public
8
+
9
+ # Authentication callback for admin pages
10
+ # Set to a proc/lambda or method name symbol
11
+ # Example: config.authenticate_admin = :authenticate_admin_user!
12
+ # Example: config.authenticate_admin = -> { redirect_to login_path unless current_user&.admin? }
13
+ attr_accessor :authenticate_admin
14
+
15
+ # HTTP Basic Auth credentials (used when authenticate_admin = :http_basic_auth)
16
+ attr_accessor :http_basic_user
17
+ attr_accessor :http_basic_password
18
+
19
+ # Parent controller class for admin controllers
20
+ # Set to a string like "Admin::ApplicationController" to inherit authentication
21
+ # Example: config.admin_parent_controller = "Admin::ApplicationController"
22
+ attr_accessor :admin_parent_controller
23
+ attr_accessor :public_parent_controller
24
+
25
+ # Current user method name (used by AI features, version tracking, etc.)
26
+ attr_accessor :current_user_method
27
+
28
+ # ==> CSS Framework
29
+ # Default CSS framework: :tailwind, :bootstrap5, :none
30
+ # Can be overridden in admin settings
31
+ attr_accessor :css_framework
32
+
33
+ # ==> Media Uploads
34
+ # Enable/disable file uploads
35
+ attr_accessor :enable_uploads
36
+
37
+ # Maximum upload size in bytes
38
+ attr_accessor :max_upload_size
39
+
40
+ # Allowed MIME types for uploads
41
+ attr_accessor :allowed_content_types
42
+
43
+ # Allow SVG uploads (disabled by default due to XSS risks)
44
+ attr_accessor :allow_svg_uploads
45
+
46
+ # Active Storage service name (nil = default service)
47
+ attr_accessor :storage_service
48
+
49
+ # Make uploads publicly accessible (false = use signed URLs)
50
+ attr_accessor :public_uploads
51
+
52
+ # ==> Editor Settings
53
+ # Default blocks available in the editor
54
+ attr_accessor :editor_blocks
55
+
56
+ # Enable/disable specific editor features
57
+ attr_accessor :enable_ai_features
58
+ attr_accessor :enable_code_editor
59
+ attr_accessor :enable_asset_manager
60
+
61
+ # ==> Page Settings
62
+ # Auto-save interval in seconds (0 = disabled)
63
+ attr_accessor :autosave_interval
64
+
65
+ # Maximum versions to keep per page (0 = unlimited)
66
+ attr_accessor :max_versions_per_page
67
+
68
+ # ==> Security
69
+ # Sanitize HTML content on save
70
+ attr_accessor :sanitize_content
71
+
72
+ # Allowed HTML tags (when sanitize_content is true)
73
+ attr_accessor :allowed_html_tags
74
+
75
+ # Allowed HTML attributes (when sanitize_content is true)
76
+ attr_accessor :allowed_html_attributes
77
+
78
+ # ==> AI Security
79
+ # Rate limit for AI requests (per minute per IP)
80
+ attr_accessor :ai_rate_limit_per_minute
81
+
82
+ # Maximum stream timeout for AI chat
83
+ attr_accessor :ai_stream_timeout
84
+
85
+ # Idle timeout for AI streaming (no data received)
86
+ attr_accessor :ai_stream_idle_timeout
87
+
88
+ # Maximum response size for AI streaming
89
+ attr_accessor :ai_max_response_size
90
+
91
+ # Maximum screenshot size (base64 encoded)
92
+ attr_accessor :max_screenshot_size
93
+
94
+ # Allowed hosts for AI-generated image downloads
95
+ attr_accessor :allowed_ai_image_hosts
96
+
97
+ # Dangerous content types that are always blocked
98
+ DANGEROUS_CONTENT_TYPES = %w[
99
+ application/x-executable
100
+ application/x-sharedlib
101
+ application/x-mach-binary
102
+ text/html
103
+ application/javascript
104
+ text/javascript
105
+ application/x-httpd-php
106
+ ].freeze
107
+
108
+ def initialize
109
+ # Authentication - open by default (configure in initializer!)
110
+ @authenticate_public = nil
111
+ @authenticate_admin = nil
112
+ @http_basic_user = nil
113
+ @http_basic_password = nil
114
+ @admin_parent_controller = "ActionController::Base"
115
+ @public_parent_controller = "ActionController::Base"
116
+ @current_user_method = :current_user
117
+
118
+ # CSS Framework
119
+ @css_framework = :tailwind
120
+
121
+ # Media Uploads
122
+ @enable_uploads = true
123
+ @max_upload_size = 10.megabytes
124
+ @allowed_content_types = %w[
125
+ image/jpeg
126
+ image/png
127
+ image/gif
128
+ image/webp
129
+ image/avif
130
+ application/pdf
131
+ ]
132
+ @allow_svg_uploads = false
133
+ @storage_service = nil
134
+ @public_uploads = false
135
+
136
+ # Editor Settings
137
+ @editor_blocks = :all
138
+ @enable_ai_features = true
139
+ @enable_code_editor = true
140
+ @enable_asset_manager = true
141
+
142
+ # Page Settings
143
+ @autosave_interval = 60
144
+ @max_versions_per_page = 50
145
+
146
+ # Security
147
+ @sanitize_content = true
148
+ @allowed_html_tags = %w[
149
+ h1 h2 h3 h4 h5 h6 p div span a img ul ol li
150
+ table thead tbody tr th td
151
+ section article header footer nav main aside
152
+ figure figcaption blockquote pre code
153
+ strong em b i u s mark small sub sup
154
+ br hr
155
+ form input button label select option textarea
156
+ iframe video audio source
157
+ ]
158
+ @allowed_html_attributes = %w[
159
+ class id style href src alt title target rel
160
+ width height loading name type value placeholder
161
+ disabled readonly checked selected multiple
162
+ action method enctype
163
+ controls autoplay loop muted poster
164
+ frameborder allowfullscreen allow
165
+ ]
166
+
167
+ # AI Security
168
+ @ai_rate_limit_per_minute = 30
169
+ @ai_stream_timeout = 5.minutes
170
+ @ai_stream_idle_timeout = 30.seconds
171
+ @ai_max_response_size = 1.megabyte
172
+ @max_screenshot_size = 10.megabytes
173
+ @allowed_ai_image_hosts = %w[
174
+ oaidalleapiprodscus.blob.core.windows.net
175
+ dalleprodsec.blob.core.windows.net
176
+ ]
177
+ end
178
+
179
+ # Get effective allowed content types (includes SVG if enabled, excludes dangerous types)
180
+ def effective_allowed_content_types
181
+ types = allowed_content_types.dup
182
+ types << "image/svg+xml" if allow_svg_uploads
183
+ types - DANGEROUS_CONTENT_TYPES
184
+ end
185
+
186
+ # Check if authentication is properly configured for production
187
+ def enforce_authentication!
188
+ return unless defined?(Rails) && Rails.env.production?
189
+ return if authenticate_admin.present?
190
+ return if admin_parent_controller != "ActionController::Base"
191
+
192
+ raise SecurityError, <<~MSG
193
+ [ActiveCanvas] Admin authentication is not configured!
194
+
195
+ Your admin interface is currently open to anyone. Configure authentication in your initializer:
196
+
197
+ ActiveCanvas.configure do |config|
198
+ # Option 1: Use your app's authentication method (recommended)
199
+ config.authenticate_admin = :authenticate_user!
200
+
201
+ # Option 2: Inherit from your admin base controller
202
+ config.admin_parent_controller = "Admin::ApplicationController"
203
+
204
+ # Option 3: Use HTTP Basic Auth
205
+ config.authenticate_admin = :http_basic_auth
206
+ config.http_basic_user = "admin"
207
+ config.http_basic_password = Rails.application.credentials.active_canvas_password
208
+ end
209
+
210
+ For development, you can use HTTP Basic Auth with default credentials,
211
+ but ALWAYS configure proper authentication for production.
212
+ MSG
213
+ end
214
+
215
+ # Check if HTTP Basic Auth is configured
216
+ def http_basic_auth_configured?
217
+ authenticate_admin == :http_basic_auth &&
218
+ http_basic_user.present? &&
219
+ http_basic_password.present?
220
+ end
221
+
222
+ # Helper to check if AI features are enabled
223
+ def ai_available?
224
+ @enable_ai_features
225
+ end
226
+
227
+ # Helper to check if Tailwind compilation is available
228
+ def tailwind_compilation_available?
229
+ @css_framework == :tailwind && defined?(Tailwindcss::Ruby)
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,44 @@
1
+ module ActiveCanvas
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace ActiveCanvas
4
+
5
+ # Prevent engine migrations from auto-running in the host app.
6
+ # Host apps copy migrations via: rails active_canvas:install:migrations
7
+ initializer "active_canvas.migrations", before: :append_migrations do
8
+ config.paths["db/migrate"] = []
9
+ end
10
+
11
+ # Ensure engine assets are precompiled
12
+ initializer "active_canvas.assets.precompile" do |app|
13
+ app.config.assets.precompile += %w[
14
+ active_canvas/editor.js
15
+ active_canvas/editor.css
16
+ ]
17
+ end
18
+
19
+ # Filter sensitive parameters from logs
20
+ initializer "active_canvas.filter_parameters" do |app|
21
+ app.config.filter_parameters += [
22
+ :ai_openai_api_key,
23
+ :ai_anthropic_api_key,
24
+ :ai_openrouter_api_key,
25
+ :http_basic_password,
26
+ /active_canvas.*api.*key/i,
27
+ /active_canvas.*password/i
28
+ ]
29
+ end
30
+
31
+ # Warn about authentication configuration
32
+ config.after_initialize do
33
+ if defined?(Rails::Server) && Rails.env.production?
34
+ unless ActiveCanvas.config.authenticate_admin.present?
35
+ Rails.logger.warn <<~MSG
36
+ [ActiveCanvas] WARNING: Admin authentication is not configured!
37
+ Your admin interface will be inaccessible until you configure authentication.
38
+ See the ActiveCanvas documentation for setup instructions.
39
+ MSG
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveCanvas
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,26 @@
1
+ require "active_canvas/version"
2
+ require "active_canvas/configuration"
3
+ require "active_canvas/engine"
4
+
5
+ # Load RubyLLM if available for AI features
6
+ begin
7
+ require "ruby_llm"
8
+ rescue LoadError
9
+ # RubyLLM is optional - AI features will be disabled if not available
10
+ end
11
+
12
+ module ActiveCanvas
13
+ class << self
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def configure
19
+ yield(configuration)
20
+ end
21
+
22
+ def config
23
+ configuration
24
+ end
25
+ end
26
+ end