Skip to content

Commit

Permalink
jets v5
Browse files Browse the repository at this point in the history
Single Lambda Function for Controllers
* For controllers, a single Lambda function is deployed going forward.
* APIGW serves as proxy endpoint for requests to the single Lambda function. Techniquely, there are 2 APIGW endpoints.
* Jobs and other classes still create a discrete lambda function per Ruby method.

Jets Engines support
* Jets Engines closely resemble Rails engines.
* Use as many Rails middlewares as possible

Jets Controllers are "ActionController and ActionView compatible."
* View Scope has first-class citizens access to Jets Controller instances.
* Breaking Change: `resources :posts` and `delete` route method routes to controller `destroy` method like rails instead of `delete` method.

Jets Controllers now support:
* around filters
* cache control and etag caching support
* content security policy
* cookies support via actionpack
* flash support
* forgery protection improvements
* importmap support
* i18n support

New Jets CLI structure that
* Close to Rails CLI structure

Jets Pro support
* deploys, release history, rollback support
* use jets-api gem

Refactor CloudFormation Builders
* Use CamelCase properties internally
* Short name template filenames and class names without the _builder.
* Fully qualify LambdaFunction logical id.

Misc
* Remove afterburner turbo and mega mode to prepare for container-based Rails support.
* Autoloaders refactor. gem (Jets internal), main (user app), once (user app)
* CORS via with middleware only.
* Improve ActionMailer integration. Improve preview support.
* logger active support logger and tagged logging support
* dynamodb event conventional table namespace
* enable iot rule by default bug fix
* create named route methods for all CRUD actions
* Jets.cache support

Breaking changes:
* Pass request.headers straight without downcase. IE: `X-Amzn-Trace-Id`. Introduce request.downcase_headers instead.
* Jets.config.prewarm.concurrency option removed.
* dynomite decoupling and integration improvements
  • Loading branch information
tongueroo committed Dec 4, 2023
1 parent 8738dcd commit f1145a2
Show file tree
Hide file tree
Showing 887 changed files with 20,485 additions and 15,482 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
_yardoc
coverage
doc/
docs/
InstalledFiles
lib/bundler/man
pkg
Expand All @@ -15,10 +16,13 @@ spec/reports
test/tmp
test/version_tmp
tmp
node_modules

.codebuild/definitions
/html
/demo
Gemfile.lock
spec/fixtures/apps/franky/dynamodb/migrate
spec/fixtures/demo/dynamodb/migrate
spec/fixtures/demo/public/assets
spec/fixtures/project/handlers
yarn.lock
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,59 @@
All notable changes to this project will be documented in this file.
This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/).

## [5.0.0] - Unreleased
Single Lambda Function for Controllers
* For controllers, a single Lambda function is deployed going forward.
* APIGW serves as proxy endpoint for requests to the single Lambda function. Techniquely, there are 2 APIGW endpoints.
* Jobs and other classes still create a discrete lambda function per Ruby method.

Jets Engines support
* Jets Engines closely resemble Rails engines.
* Use as many Rails middlewares as possible

Jets Controllers are "ActionController and ActionView compatible."
* View Scope has first-class citizens access to Jets Controller instances.
* Breaking Change: `resources :posts` and `delete` route method routes to controller `destroy` method like rails instead of `delete` method.

Jets Controllers now support:
* around filters
* cache control and etag caching support
* content security policy
* cookies support via actionpack
* flash support
* forgery protection improvements
* importmap support
* i18n support

New Jets CLI structure that
* Close to Rails CLI structure

Jets Pro support
* deploys, release history, rollback support
* use jets-api gem

Refactor CloudFormation Builders
* Use CamelCase properties internally
* Short name template filenames and class names without the _builder.
* Fully qualify LambdaFunction logical id.

Misc
* Remove afterburner turbo and mega mode to prepare for container-based Rails support.
* Autoloaders refactor. gem (Jets internal), main (user app), once (user app)
* CORS via with middleware only.
* Improve ActionMailer integration. Improve preview support.
* logger active support logger and tagged logging support
* dynamodb event conventional table namespace
* enable iot rule by default bug fix
* create named route methods for all CRUD actions
* Jets.cache support

Breaking changes:
* Pass request.headers straight without downcase. IE: `X-Amzn-Trace-Id`. Introduce request.downcase_headers instead.
* Jets.config.prewarm.concurrency option removed.
* dynomite decoupling and integration improvements


## [4.0.10] - 2023-12-04
- [#678](https://github.com/boltops-tools/jets/pull/678) handle option method or http_method from route state

Expand All @@ -28,6 +81,7 @@ This project *loosely tries* to adhere to [Semantic Versioning](http://semver.or

## [4.0.3] - 2023-08-03
- [#657](https://github.com/boltops-tools/jets/pull/657) [Fix] ApiGateway for local Middleware: fix query_string_parameters
Breaking Changes:

## [4.0.2] - 2023-08-03
- [#660](https://github.com/boltops-tools/jets/pull/660) Fix prewarming
Expand Down
6 changes: 1 addition & 5 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ source "https://rubygems.org"
gemspec

# required here for specs
# TODO: Only require webpacker in Gemfile of project if possible.
# Need both because of jets/application.rb and jets/webpacker/middleware_setup.rb
group :development, :test do
gem "mysql2", "~> 0.5.2"
gem "dynomite"
gem "jetpacker"
gem "rspec_junit_formatter"
gem "dynomite", "~> 2.0.0"
end
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2021 Tung Nguyen
Copyright (c) Tung Nguyen

MIT License

Expand Down
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ task :default => :spec
RSpec::Core::RakeTask.new

require_relative "lib/jets"

desc "Generates cli reference docs as markdown"
task :docs do
Jets::Autoloaders.once.eager_load
Jets::Commands::Markdown::Creator.create_all
require "cli_markdown_jets"
CliMarkdown::Creator.new.create_all
end

# Thanks: https://docs.ruby-lang.org/en/2.1.0/RDoc/Task.html
Expand All @@ -21,4 +22,3 @@ require 'jets/rdoc'
RDoc::Task.new do |rdoc|
rdoc.options += Jets::Rdoc.options
end

9 changes: 0 additions & 9 deletions bin/release

This file was deleted.

28 changes: 28 additions & 0 deletions engines/internal/app/controllers/jets/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

class Jets::ApplicationController < Jets::Controller::Base # :nodoc:
prepend_view_path File.expand_path("../../../app/views", __dir__)
layout "application"

before_action :disable_content_security_policy_nonce!

content_security_policy do |policy|
policy.script_src :self, :unsafe_inline
policy.style_src :self, :unsafe_inline
end

private
def require_local!
unless local_request?
render html: "<p>For security purposes, this information is only available to local requests.</p>".html_safe, status: :forbidden
end
end

def local_request?
Jets.application.config.consider_all_requests_local || request.local?
end

def disable_content_security_policy_nonce!
request.content_security_policy_nonce_generator = nil
end
end
6 changes: 6 additions & 0 deletions engines/internal/app/controllers/jets/bare_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Parent class for MountController
class Jets::BareController < Jets::Controller::Base
layout false
abstract!
skip_forgery_protection
end
55 changes: 55 additions & 0 deletions engines/internal/app/controllers/jets/health_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Jets
# Built-in Health Check Endpoint
#
# \Jets also comes with a built-in health check endpoint that is reachable at
# the +/up+ path. This endpoint will return a 200 status code if the app has
# booted with no exceptions, and a 500 status code otherwise.
#
# In production, many applications are required to report their status upstream,
# whether it's to an uptime monitor that will page an engineer when things go
# wrong, or a load balancer or Kubernetes controller used to determine a pod's
# health. This health check is designed to be a one-size fits all that will work
# in many situations.
#
# While any newly generated \Jets applications will have the health check at
# +/up+, you can configure the path to be anything you'd like in your
# <tt>"config/routes.rb"</tt>:
#
# Jets.application.routes.draw do
# get "healthz" => "jets/health#show", as: :jets_health_check
# end
#
# The health check will now be accessible via the +/healthz+ path.
#
# NOTE: This endpoint does not reflect the status of all of your application's
# dependencies, such as the database or redis cluster. Replace
# <tt>"jets/health#show"</tt> with your own controller action if you have
# application specific needs.
#
# Think carefully about what you want to check as it can lead to situations
# where your application is being restarted due to a third-party service going
# bad. Ideally, you should design your application to handle those outages
# gracefully.
class HealthController < Jets::Controller::Base
rescue_from(Exception) { render_down }

def show
render_up
end

private
def render_up
render html: html_status(color: "green")
end

def render_down
render html: html_status(color: "red"), status: 500
end

def html_status(color:)
%(<!DOCTYPE html><html><body style="background-color: #{color}"></body></html>).html_safe
end
end
end
45 changes: 45 additions & 0 deletions engines/internal/app/controllers/jets/info_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

class Jets::InfoController < Jets::ApplicationController # :nodoc:
prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATH
layout -> { request.xhr? ? false : "application" }

before_action :require_local!

def index
redirect_to action: :routes
end

def properties
@info = Jets::Info.to_html
@page_title = "Properties"
end

def routes
if path = params[:path]
path = URI::DEFAULT_PARSER.escape path
normalized_path = with_leading_slash path
render json: {
exact: match_route { |it| it.match normalized_path },
fuzzy: match_route { |it| it.spec.to_s.match path }
}
else
@routes_table = routes_table
@page_title = "Routes"
end
end

private
def routes_table
text = Jets::Router::Help.new(format: "markdown").text
Kramdown::Document.new(text).to_html
end

def match_route
_routes.routes.filter_map { |route| route.path.spec.to_s if yield route.path }
end

def with_leading_slash(path)
("/" + path).squeeze("/")
end
end
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
# frozen_string_literal: true

class Jets::MailersController < Jets::Controller::Base # :nodoc:
around_action :set_locale, only: :preview
before_action :find_preview, only: [:preview]
before_action :set_locale, only: [:preview]
# TODO: allow multiple actions
# before_action :find_preview, :set_locale, only: :preview
before_action :require_local!, unless: :show_previews?

# TODO: add helper_method support
# helper_method :part_query, :locale_query
helper_method :part_query, :locale_query

# TODO: content_security_policy
# content_security_policy(false)
content_security_policy(false)

def index
@previews = ActionMailer::Preview.all
Expand All @@ -20,25 +17,26 @@ def index
def preview
if params[:path] == @preview.preview_name
@page_title = "Mailer Previews for #{@preview.preview_name}"
render :mailer
render action: "mailer"
else
@email_action = File.basename(params[:path])

if @preview.email_exists?(@email_action)
@page_title = "Mailer Preview for #{@preview.preview_name}##{@email_action}"
@email = @preview.call(@email_action, params)

if params[:part]
part_type = Mime::Type.lookup(params[:part])

if part = find_part(part_type)
response.headers["Content-Type"] = params[:part]
response.content_type = part_type
render plain: part.respond_to?(:decoded) ? part.decoded : part
else
raise AbstractController::ActionNotFound, "Email part '#{part_type}' not found in #{@preview.name}##{@email_action}"
end
else
@part = find_preferred_part(Mime[:html], Mime[:text])
render :email, layout: false, formats: %w[html]
@part = find_preferred_part(request.format, Mime[:html], Mime[:text])
render action: "email", layout: false, formats: [:html]
end
else
raise AbstractController::ActionNotFound, "Email '#{@email_action}' not found in #{@preview.name}"
Expand All @@ -53,7 +51,7 @@ def show_previews? # :doc:

def find_preview # :doc:
candidates = []
params[:path].to_s.scan(%r{/|$}) { candidates << $` } # ` # hack to fix syntax highlighting
params[:path].to_s.scan(%r{/|$}) { candidates << $` }
preview = candidates.detect { |candidate| ActionMailer::Preview.exists?(candidate) }

if preview
Expand Down Expand Up @@ -91,7 +89,7 @@ def locale_query(locale)
request.query_parameters.merge(locale: locale).to_query
end

def set_locale
I18n.locale = params[:locale] || I18n.default_locale
def set_locale(&block)
I18n.with_locale(params[:locale] || I18n.default_locale, &block)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ def call

status, headers, io = mount_class.call(env)
body = read_body(io)
render(
status: status,
headers: headers,
body: body,
)
self.headers.merge!(headers)
render body: body, status: status
end

private
Expand All @@ -32,15 +29,14 @@ def read_body(io)
result.join
end

# Locally Jets::Router::Finder gets called twice because it also gets called in Jets::Controller::Middleware::Local
# On Lambda, Jets::Router::Finder only gets called once.
# TODO: Maybe add caching improvement.
# Locally Jets::Router::Matcher gets called in Jets::Controller::Middleware::Mimic
# On Lambda, Jets::Router::Matcher in handlers.
def find_route
Jets::Router::Finder.new(event["path"], "ANY").run
Jets::Router::Matcher.new.find_by_request(request, "ANY")
end

def build_env(path)
env = Jets::Controller::Rack::Env.new(event, context, adapter: true).convert
env = Jets::Controller::RackAdapter::Env.new(event, context, adapter: true).convert
# remap path info
mount_at = mount_at(path)
path_info = env["PATH_INFO"]
Expand Down
Loading

0 comments on commit f1145a2

Please sign in to comment.