belt 0.2.17 → 0.3.14
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +226 -0
- data/README.md +42 -3
- data/lib/belt/action_router.rb +34 -19
- data/lib/belt/cli/app_detection.rb +30 -3
- data/lib/belt/cli/auth_command.rb +395 -0
- data/lib/belt/cli/console_command.rb +17 -2
- data/lib/belt/cli/deploy_command.rb +51 -17
- data/lib/belt/cli/destroy_command.rb +62 -25
- data/lib/belt/cli/doctor_command.rb +166 -22
- data/lib/belt/cli/environment_command.rb +12 -0
- data/lib/belt/cli/explain_command.rb +112 -0
- data/lib/belt/cli/frontend_command.rb +31 -10
- data/lib/belt/cli/frontend_deploy_command.rb +110 -21
- data/lib/belt/cli/frontend_env_command.rb +56 -19
- data/lib/belt/cli/frontend_env_map.rb +30 -10
- data/lib/belt/cli/frontend_registry.rb +373 -0
- data/lib/belt/cli/frontend_setup_command.rb +71 -5
- data/lib/belt/cli/generate_command.rb +61 -42
- data/lib/belt/cli/index_command.rb +192 -0
- data/lib/belt/cli/lambda_config_command.rb +9 -3
- data/lib/belt/cli/routes_command/request_model_inference.rb +131 -0
- data/lib/belt/cli/routes_command/route_inference.rb +4 -3
- data/lib/belt/cli/routes_command.rb +31 -19
- data/lib/belt/cli/server_command.rb +28 -15
- data/lib/belt/cli/tables_command.rb +3 -1
- data/lib/belt/cli/terraform_command.rb +9 -0
- data/lib/belt/cli/views_command.rb +15 -15
- data/lib/belt/cli/zip_artifact_builder.rb +199 -0
- data/lib/belt/cli.rb +17 -9
- data/lib/belt/docs/backups.md +101 -0
- data/lib/belt/docs/console.md +65 -0
- data/lib/belt/docs/controllers.md +155 -0
- data/lib/belt/docs/deployment.md +166 -0
- data/lib/belt/docs/frontend.md +103 -0
- data/lib/belt/docs/generators.md +137 -0
- data/lib/belt/docs/lambda_handler.md +105 -0
- data/lib/belt/docs/models.md +160 -0
- data/lib/belt/docs/observability.md +94 -0
- data/lib/belt/docs/plugins.md +94 -0
- data/lib/belt/docs/routing.md +138 -0
- data/lib/belt/docs/structure.md +96 -0
- data/lib/belt/inflector.rb +8 -0
- data/lib/belt/route_dsl.rb +318 -100
- data/lib/belt/version.rb +1 -1
- data/lib/templates/frontend/react/env.yml.example +2 -2
- data/lib/templates/generate/auth/cognito.tf.erb +71 -0
- data/lib/templates/generate/auth/cognito_outputs.tf.erb +19 -0
- data/lib/templates/generate/auth/frontend/ConfirmEmail.jsx +55 -0
- data/lib/templates/generate/auth/frontend/Login.jsx +79 -0
- data/lib/templates/generate/auth/frontend/ProtectedRoute.jsx +9 -0
- data/lib/templates/generate/auth/frontend/SignUp.jsx +58 -0
- data/lib/templates/generate/auth/frontend/apiClient.js +34 -0
- data/lib/templates/generate/auth/frontend/auth.css +157 -0
- data/lib/templates/generate/auth/frontend/auth.js +121 -0
- data/lib/templates/generate/model.rb.erb +4 -6
- data/lib/templates/module/frontend.tf.erb +49 -43
- data/lib/templates/module/outputs.tf.erb +1 -1
- data/lib/templates/new_app/AGENTS.md.erb +170 -20
- data/lib/templates/new_app/config/lambda/api.yml.erb +1 -0
- data/lib/templates/new_app/config/routes.rb.erb +8 -3
- data/lib/templates/new_app/lambda/api.rb.erb +1 -1
- metadata +56 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Routing
|
|
2
|
+
|
|
3
|
+
Belt routes map HTTP requests to controller actions. Routes are defined in
|
|
4
|
+
`config/routes.rb` using a Ruby DSL that mirrors infrastructure (API Gateway + Lambda).
|
|
5
|
+
|
|
6
|
+
## Defining Routes
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
Belt.application.routes.draw do
|
|
10
|
+
gateway :api do
|
|
11
|
+
resources :posts
|
|
12
|
+
resources :comments, only: [:index, :create]
|
|
13
|
+
resource :profile, only: [:show, :update]
|
|
14
|
+
get "health", action: :health
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Route DSL Keywords
|
|
20
|
+
|
|
21
|
+
| Keyword | Purpose | Creates Lambda? |
|
|
22
|
+
|---------|---------|-----------------|
|
|
23
|
+
| `gateway` | Creates an API Gateway + default Lambda | Yes |
|
|
24
|
+
| `function` | Routes to a different Lambda (overrides gateway default) | Yes |
|
|
25
|
+
| `namespace` | Adds path prefix + controller module nesting | No |
|
|
26
|
+
| `scope` | Flexible path/module/auth grouping | No |
|
|
27
|
+
|
|
28
|
+
## How `resources` Maps to Verbs
|
|
29
|
+
|
|
30
|
+
`resources :posts` generates:
|
|
31
|
+
|
|
32
|
+
| Verb | Path | Action |
|
|
33
|
+
|------|------|--------|
|
|
34
|
+
| GET | /posts | index |
|
|
35
|
+
| POST | /posts | create |
|
|
36
|
+
| GET | /posts/{post_id} | show |
|
|
37
|
+
| PUT | /posts/{post_id} | update |
|
|
38
|
+
| DELETE | /posts/{post_id} | destroy |
|
|
39
|
+
|
|
40
|
+
**Note:** Belt uses PUT, not PATCH, for updates.
|
|
41
|
+
|
|
42
|
+
Use `only:` or `except:` to limit generated routes:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
resources :posts, only: [:index, :show, :create]
|
|
46
|
+
resources :comments, except: [:destroy]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Singular Resources
|
|
50
|
+
|
|
51
|
+
`resource :profile` (no `:id` in the path):
|
|
52
|
+
|
|
53
|
+
| Verb | Path | Action |
|
|
54
|
+
|------|------|--------|
|
|
55
|
+
| GET | /profile | show |
|
|
56
|
+
| PUT | /profile | update |
|
|
57
|
+
| POST | /profile | create |
|
|
58
|
+
| DELETE | /profile | destroy |
|
|
59
|
+
|
|
60
|
+
## Namespace and Scope
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
gateway :api do
|
|
64
|
+
# Namespace: adds path prefix AND controller module
|
|
65
|
+
namespace :admin do
|
|
66
|
+
resources :users # → /admin/users → Admin::UsersController
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Scope: flexible grouping without full nesting
|
|
70
|
+
scope path: 'v2', module: 'legacy' do
|
|
71
|
+
resources :widgets # → /v2/widgets → Legacy::WidgetsController
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Multiple Lambdas
|
|
77
|
+
|
|
78
|
+
Use `function` when routes should be handled by a separate Lambda:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
gateway :api do
|
|
82
|
+
resources :posts # → handled by "api" Lambda
|
|
83
|
+
|
|
84
|
+
function :worker do
|
|
85
|
+
resources :jobs # → handled by "worker" Lambda
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Authentication
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
gateway :api, auth: :cognito do
|
|
94
|
+
resources :posts # requires cognito auth
|
|
95
|
+
get "health", action: :health, auth: :none # public
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Table Access
|
|
100
|
+
|
|
101
|
+
Declare which DynamoDB tables a route accesses (used by Terraform for IAM):
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
resources :posts, tables: [:posts, :comments]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Inspecting Routes
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
belt routes # display all routes
|
|
111
|
+
belt routes -g posts # filter by pattern
|
|
112
|
+
belt routes -f json # machine-readable output
|
|
113
|
+
belt routes --namespace api # generate Ruby route manifest
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Runtime Routing
|
|
117
|
+
|
|
118
|
+
The Lambda entry point uses `Belt::ActionRouter` with the generated route manifest:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
require "belt"
|
|
122
|
+
include Belt::LambdaHandler
|
|
123
|
+
|
|
124
|
+
ROUTER = Belt::ActionRouter.new(routes: Routes::API, gateway: "api")
|
|
125
|
+
|
|
126
|
+
def execute(path:, body:, event:)
|
|
127
|
+
ROUTER.route(event: event, body: body)
|
|
128
|
+
end
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The router matches the incoming HTTP method + path against the manifest and
|
|
132
|
+
dispatches to the appropriate controller and action.
|
|
133
|
+
|
|
134
|
+
## See Also
|
|
135
|
+
|
|
136
|
+
- `belt explain controllers` — how controllers handle requests
|
|
137
|
+
- `belt explain deployment` — how routes become infrastructure
|
|
138
|
+
- `belt routes --help` — full CLI options
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
A Belt application follows a conventional directory layout. Understanding
|
|
4
|
+
this structure helps you navigate and extend the app effectively.
|
|
5
|
+
|
|
6
|
+
## Standard Layout
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
my-app/
|
|
10
|
+
├── lambda/ # Application code (deployed to Lambda)
|
|
11
|
+
│ ├── api.rb # Lambda entry point
|
|
12
|
+
│ ├── config/
|
|
13
|
+
│ │ └── environment.rb # App boot file (models, libs, AWS setup)
|
|
14
|
+
│ ├── controllers/
|
|
15
|
+
│ │ ├── application_controller.rb
|
|
16
|
+
│ │ └── my_app/ # Namespaced controllers
|
|
17
|
+
│ │ ├── posts_controller.rb
|
|
18
|
+
│ │ └── admin/
|
|
19
|
+
│ │ └── users_controller.rb
|
|
20
|
+
│ ├── models/
|
|
21
|
+
│ │ ├── application_record.rb # Base model class
|
|
22
|
+
│ │ ├── post.rb
|
|
23
|
+
│ │ └── concerns/ # Shared model behavior
|
|
24
|
+
│ ├── lib/
|
|
25
|
+
│ │ └── routes/ # Auto-generated route manifests
|
|
26
|
+
│ │ └── api_routes.rb
|
|
27
|
+
│ └── Gemfile # Lambda-specific dependencies
|
|
28
|
+
├── config/
|
|
29
|
+
│ ├── routes.rb # Route definitions (DSL)
|
|
30
|
+
│ ├── contracts.rb # API request/response contracts
|
|
31
|
+
│ └── lambda/ # Per-lambda configuration
|
|
32
|
+
│ └── api.yml # Timeout, memory, env vars
|
|
33
|
+
├── infrastructure/
|
|
34
|
+
│ ├── modules/ # Shared Terraform modules
|
|
35
|
+
│ │ └── main/
|
|
36
|
+
│ ├── schema.tf.rb # DynamoDB table schema (Ruby DSL)
|
|
37
|
+
│ ├── dev01/ # Per-environment Terraform
|
|
38
|
+
│ │ ├── main.tf
|
|
39
|
+
│ │ ├── variables.tf
|
|
40
|
+
│ │ ├── terraform.tfvars
|
|
41
|
+
│ │ ├── backend.tf
|
|
42
|
+
│ │ └── outputs.tf
|
|
43
|
+
│ └── prod/
|
|
44
|
+
│ └── ...
|
|
45
|
+
├── frontend/ # Optional frontend (React/Vue/Svelte)
|
|
46
|
+
├── config/frontends.yml # Optional: multiple named frontends
|
|
47
|
+
├── Gemfile # Project-level dependencies (CLI, dev tools)
|
|
48
|
+
├── Rakefile # Rake tasks
|
|
49
|
+
├── AGENTS.md # AI agent guide
|
|
50
|
+
└── .gitignore
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Key Files
|
|
54
|
+
|
|
55
|
+
### `lambda/api.rb` — Lambda Entry Point
|
|
56
|
+
|
|
57
|
+
The file AWS Lambda invokes. Includes `Belt::LambdaHandler` and defines `execute`.
|
|
58
|
+
|
|
59
|
+
### `lambda/config/environment.rb` — Boot File
|
|
60
|
+
|
|
61
|
+
Loaded by both Lambda and `belt console`. Sets up AWS clients, requires models,
|
|
62
|
+
configures the app. Everything your app needs to run.
|
|
63
|
+
|
|
64
|
+
### `config/routes.rb` — Route Definitions
|
|
65
|
+
|
|
66
|
+
The Ruby DSL that defines your API. Read by both the Conveyor Belt Terraform
|
|
67
|
+
provider (for infrastructure) and `belt routes` (for manifests).
|
|
68
|
+
|
|
69
|
+
### `config/lambda/api.yml` — Lambda Config
|
|
70
|
+
|
|
71
|
+
Per-function settings: handler path, runtime, timeout, memory, environment
|
|
72
|
+
variables, layers, triggers.
|
|
73
|
+
|
|
74
|
+
### `infrastructure/schema.tf.rb` — Table Schema
|
|
75
|
+
|
|
76
|
+
DynamoDB table definitions in Ruby DSL. Used by `belt setup tables` to generate
|
|
77
|
+
Terraform resources.
|
|
78
|
+
|
|
79
|
+
## Conventions
|
|
80
|
+
|
|
81
|
+
- **Controller namespacing**: Controllers live under `lambda/controllers/<app_name>/`
|
|
82
|
+
to avoid conflicts across modules.
|
|
83
|
+
- **Route manifests**: Generated files in `lambda/lib/routes/` — don't edit manually.
|
|
84
|
+
Regenerate with `belt routes --namespace <name>`.
|
|
85
|
+
- **Two Gemfiles**: Project root Gemfile is for dev tools (belt CLI, rspec).
|
|
86
|
+
`lambda/Gemfile` is what gets packaged into the Lambda.
|
|
87
|
+
- **Config over code**: Lambda configuration (timeout, memory, env vars) goes in
|
|
88
|
+
YAML files, not hardcoded in Terraform.
|
|
89
|
+
- **Frontends**: Default directory is `frontend/`. Multiple SPAs (customer + ops,
|
|
90
|
+
etc.) are declared in `config/frontends.yml`. See `belt explain frontend`.
|
|
91
|
+
|
|
92
|
+
## See Also
|
|
93
|
+
|
|
94
|
+
- `belt explain routing` — how routes.rb maps to infrastructure
|
|
95
|
+
- `belt explain controllers` — controller conventions
|
|
96
|
+
- `belt explain deployment` — how this structure gets deployed
|
data/lib/belt/inflector.rb
CHANGED
|
@@ -42,6 +42,14 @@ module Belt
|
|
|
42
42
|
word.to_s.split('_').map(&:capitalize).join
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
# "conversation_id" → "conversationId"
|
|
46
|
+
def camelize_lower(word)
|
|
47
|
+
parts = word.to_s.split('_')
|
|
48
|
+
return word if parts.empty?
|
|
49
|
+
|
|
50
|
+
parts.first + parts[1..].map(&:capitalize).join
|
|
51
|
+
end
|
|
52
|
+
|
|
45
53
|
# "BlogPost" → "blog_post"
|
|
46
54
|
def underscore(word)
|
|
47
55
|
word.to_s
|