edgeway 0.2.0 → 0.3.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/README.md +602 -204
  4. data/js/cloudflare-kv.js +47 -0
  5. data/js/cloudflare-ratelimit.js +31 -0
  6. data/js/cloudflare-test-database.js +112 -0
  7. data/js/cloudflare-test-runner.js +76 -0
  8. data/js/cloudflare.js +25 -4
  9. data/js/fetch.js +113 -0
  10. data/js/jspi.js +32 -0
  11. data/js/jwt.js +5 -39
  12. data/js/runtime.js +42 -5
  13. data/lib/edgeway/application.rb +16 -7
  14. data/lib/edgeway/cache/limits.rb +8 -0
  15. data/lib/edgeway/cache/memory_store.rb +24 -0
  16. data/lib/edgeway/cache/null_store.rb +13 -0
  17. data/lib/edgeway/cache/store.rb +189 -0
  18. data/lib/edgeway/cache.rb +13 -0
  19. data/lib/edgeway/cli/build/cache_config.rb +108 -0
  20. data/lib/edgeway/cli/build/database_config.rb +4 -0
  21. data/lib/edgeway/cli/build/js_files.rb +30 -0
  22. data/lib/edgeway/cli/build.rb +17 -10
  23. data/lib/edgeway/cli/cloudflare_test/wasm_test_cli.rb +35 -0
  24. data/lib/edgeway/cli/cloudflare_test.rb +120 -0
  25. data/lib/edgeway/cli/test.rb +25 -9
  26. data/lib/edgeway/cli/toolchain.rb +5 -0
  27. data/lib/edgeway/cli.rb +2 -0
  28. data/lib/edgeway/controller/base.rb +22 -3
  29. data/lib/edgeway/controller/caching.rb +140 -0
  30. data/lib/edgeway/controller/callbacks.rb +5 -1
  31. data/lib/edgeway/controller/rate_limiting.rb +145 -0
  32. data/lib/edgeway/db/query_stats.rb +2 -6
  33. data/lib/edgeway/errors.rb +21 -0
  34. data/lib/edgeway/generators/app/templates/.github/workflows/ci.yml.tt +3 -3
  35. data/lib/edgeway/generators/app/templates/README.md.tt +3 -1
  36. data/lib/edgeway/generators/app/templates/bin/setup.tt +2 -3
  37. data/lib/edgeway/generators/app/templates/config/cache.yml +22 -0
  38. data/lib/edgeway/generators/app/templates/config/database.yml +8 -2
  39. data/lib/edgeway/generators/app/templates/public/.assetsignore +1 -0
  40. data/lib/edgeway/generators/app/templates/wrangler.toml.tt +34 -2
  41. data/lib/edgeway/http/client.rb +80 -0
  42. data/lib/edgeway/http/request.rb +5 -0
  43. data/lib/edgeway/http/stub_transport.rb +38 -0
  44. data/lib/edgeway/logger.rb +33 -5
  45. data/lib/edgeway/rate_limit/limiter.rb +9 -0
  46. data/lib/edgeway/rate_limit/null_limiter.rb +9 -0
  47. data/lib/edgeway/rate_limit/stub_limiter.rb +24 -0
  48. data/lib/edgeway/rate_limit.rb +2 -0
  49. data/lib/edgeway/server.rb +3 -2
  50. data/lib/edgeway/service/cloudflare/d1.rb +6 -21
  51. data/lib/edgeway/service/cloudflare/jwt.rb +3 -15
  52. data/lib/edgeway/service/cloudflare/kv.rb +45 -0
  53. data/lib/edgeway/service/cloudflare/kv_store.rb +58 -0
  54. data/lib/edgeway/service/cloudflare/rate_limit.rb +27 -0
  55. data/lib/edgeway/service/cloudflare/rate_limiter.rb +33 -0
  56. data/lib/edgeway/service/cloudflare/test_databases.rb +65 -0
  57. data/lib/edgeway/service/fetch.rb +26 -0
  58. data/lib/edgeway/service/import_result.rb +24 -0
  59. data/lib/edgeway/test/sqlite_databases.rb +18 -0
  60. data/lib/edgeway/test.rb +72 -33
  61. data/lib/edgeway/version.rb +1 -1
  62. data/lib/edgeway.rb +6 -0
  63. metadata +34 -1
data/lib/edgeway/test.rb CHANGED
@@ -3,14 +3,15 @@
3
3
  # and tmp/test_app.rb, which `edgeway test` rewrites on every run (and which
4
4
  # is git-ignored): Spinel resolves require
5
5
  # at compile time, so the app's files are listed there (in Build's order)
6
- # rather than found at run time. Unlike build/main.rb it never calls
6
+ # rather than found at run time, and so is the database the tests use
7
+ # (Edgeway::TestDatabases). Unlike build/main.rb it never calls
7
8
  # Edgeway::Server.run. Run the tests with `edgeway test`, not spinel_test-unit
8
9
  # directly: a missing or stale tmp/test_app.rb only shows up as Spinel's own
9
10
  # "cannot find tmp/test_app" (the message cannot be customised at compile time).
10
11
  require "spinel_test/unit"
11
12
  require "edgeway"
12
- require "edgeway/db/memory"
13
- require "edgeway/db/sqlite"
13
+ require "edgeway/http/stub_transport"
14
+ require "edgeway/rate_limit/stub_limiter"
14
15
  require "tmp/test_app"
15
16
 
16
17
  module Edgeway
@@ -25,17 +26,28 @@ module Edgeway
25
26
  end
26
27
  end
27
28
 
28
- # What a model test needs: a fresh in-memory SQLite database per test
29
- # (SQLiteAdapter), with the app's db/migrations applied in file name order,
30
- # so a test can check what was stored (Todo.find, db.select_all) and read
31
- # db.log for the SQL. A database under databases: in config/database.yml
32
- # gets its own, with db/NAME/migrations, read with db(:name). Edgeway's own
33
- # tests use MemoryAdapter instead, which stores nothing.
29
+ # What a model test needs: a fresh database per test (Edgeway::TestDatabases,
30
+ # chosen by `edgeway test` from config/database.yml), with the app's
31
+ # db/migrations applied in file name order, so a test can check what was
32
+ # stored (Todo.find, db.select_all) and read db.log for the SQL. A database
33
+ # under databases: in config/database.yml gets its own, with
34
+ # db/NAME/migrations, read with db(:name). Edgeway's own tests use
35
+ # MemoryAdapter instead, which stores nothing. Edgeway.cache is a NullStore in
36
+ # every test, whatever config/cache.yml says; a test that checks caching sets
37
+ # `Edgeway.cache = Edgeway::Cache::MemoryStore.new` itself. The rate limiter
38
+ # allows every request and records the checks (stub_rate_limit,
39
+ # rate_limit_checks).
34
40
  class UnitTest < SpinelTest::Unit::TestCase
35
41
  def setup
36
42
  @databases = {}
37
- open_database(Edgeway::Model::PRIMARY, "db/migrations")
38
- Edgeway::TEST_DATABASES.each { |name| open_extra_database(name) }
43
+ @http = Edgeway::HTTP::StubTransport.new
44
+ Edgeway::HTTP.client = @http
45
+ Edgeway.cache = Edgeway::Cache::NullStore.new
46
+ @rate_limiter = Edgeway::RateLimit::StubLimiter.new
47
+ Edgeway::Controller.rate_limiter = @rate_limiter
48
+ Edgeway::TestDatabases.reset
49
+ open_database(Edgeway::Model::PRIMARY)
50
+ Edgeway::TEST_DATABASES.each { |name| open_database(name) }
39
51
  end
40
52
 
41
53
  def teardown
@@ -47,19 +59,26 @@ module Edgeway
47
59
 
48
60
  def db(name = Edgeway::Model::PRIMARY) = @databases.fetch(name.to_s)
49
61
 
50
- private
62
+ def stub_http(verb, url, status: 200, body: "", headers: {})
63
+ @http.stub(verb, url, status, body, headers)
64
+ end
51
65
 
52
- def open_extra_database(name)
53
- migrations = "db/#{name}/migrations"
54
- unless File.directory?(File.join(Edgeway::TEST_APP_ROOT, migrations))
55
- raise Edgeway::ConfigurationError, "database #{name} (config/database.yml) has no #{migrations} directory"
56
- end
57
- open_database(name, migrations)
66
+ def stub_http_error(verb, url, message = "connection failed", timeout: false)
67
+ @http.stub_error(verb, url, message, timeout)
68
+ end
69
+
70
+ def http_requests = @http.requests
71
+
72
+ def stub_rate_limit(binding_name, exceeded: true)
73
+ @rate_limiter.stub(binding_name, exceeded)
58
74
  end
59
75
 
60
- def open_database(name, migrations)
61
- database = Edgeway::DB::SQLiteAdapter.new(":memory:")
62
- database.apply_migrations(File.join(Edgeway::TEST_APP_ROOT, migrations))
76
+ def rate_limit_checks = @rate_limiter.checks
77
+
78
+ private
79
+
80
+ def open_database(name)
81
+ database = Edgeway::TestDatabases.open(name)
63
82
  Edgeway::Model.connect(name, database)
64
83
  @databases[name] = database
65
84
  end
@@ -76,11 +95,11 @@ module Edgeway
76
95
  @json = nil
77
96
  end
78
97
 
79
- def get(path, json: nil, headers: {}) = request("GET", path, json, headers)
80
- def delete(path, json: nil, headers: {}) = request("DELETE", path, json, headers)
81
- def post(path, json: nil, headers: {}) = request("POST", path, json, headers)
82
- def put(path, json: nil, headers: {}) = request("PUT", path, json, headers)
83
- def patch(path, json: nil, headers: {}) = request("PATCH", path, json, headers)
98
+ def get(path, json: nil, headers: {}, remote_addr: "") = request("GET", path, json, headers, remote_addr)
99
+ def delete(path, json: nil, headers: {}, remote_addr: "") = request("DELETE", path, json, headers, remote_addr)
100
+ def post(path, json: nil, headers: {}, remote_addr: "") = request("POST", path, json, headers, remote_addr)
101
+ def put(path, json: nil, headers: {}, remote_addr: "") = request("PUT", path, json, headers, remote_addr)
102
+ def patch(path, json: nil, headers: {}, remote_addr: "") = request("PATCH", path, json, headers, remote_addr)
84
103
 
85
104
  # The body parsed as JSON.
86
105
  def json
@@ -94,7 +113,7 @@ module Edgeway
94
113
 
95
114
  private
96
115
 
97
- def request(verb, target, json, headers)
116
+ def request(verb, target, json, headers, remote_addr)
98
117
  path = target
99
118
  query = ""
100
119
  q = target.index("?")
@@ -104,15 +123,35 @@ module Edgeway
104
123
  end
105
124
  body = json.nil? ? "" : JSON.generate(json)
106
125
  content_type = json.nil? ? "" : "application/json"
107
- headers.each { |k, v| ENV["HTTP_" + k.upcase.gsub("-", "_")] = v }
108
- begin
109
- res = Edgeway.application.call(Edgeway::HTTP::Request.new(verb, path, query, content_type, body))
110
- ensure
111
- headers.each { |k, _v| ENV.delete("HTTP_" + k.upcase.gsub("-", "_")) }
112
- end
126
+ res = call_application(Edgeway::HTTP::Request.new(verb, path, query, content_type, body), headers, remote_addr)
113
127
  @json = nil
114
128
  @response = Edgeway::TestResponse.new(res.status, res.body, res.headers)
115
129
  @response
116
130
  end
131
+
132
+ def call_application(http_request, headers, remote_addr)
133
+ variables = { "REMOTE_ADDR" => remote_addr }
134
+ headers.each { |name, value| variables["HTTP_" + name.upcase.gsub("-", "_")] = value }
135
+ with_environment(variables) { Edgeway.application.call(http_request) }
136
+ end
137
+
138
+ def with_environment(variables)
139
+ previous = {}
140
+ variables.each_key { |name| previous[name] = ENV[name].to_s unless ENV[name].nil? }
141
+ begin
142
+ variables.each { |name, value| ENV[name] = value }
143
+ yield
144
+ ensure
145
+ variables.each_key { |name| restore_variable(name, previous) }
146
+ end
147
+ end
148
+
149
+ def restore_variable(name, previous)
150
+ if previous.key?(name)
151
+ ENV[name] = previous[name]
152
+ else
153
+ ENV.delete(name)
154
+ end
155
+ end
117
156
  end
118
157
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Edgeway
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/edgeway.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "digest"
1
2
  require "json"
2
3
  require "time"
3
4
  require "uri"
@@ -11,6 +12,7 @@ require_relative "edgeway/http/response"
11
12
  require_relative "edgeway/http/parameters"
12
13
  require_relative "edgeway/http/json_body"
13
14
  require_relative "edgeway/http/request"
15
+ require_relative "edgeway/http/client"
14
16
  require_relative "edgeway/routing/route"
15
17
  require_relative "edgeway/routing/route_set"
16
18
  require_relative "edgeway/routing/mapper"
@@ -22,11 +24,15 @@ require_relative "edgeway/model/macros"
22
24
  require_relative "edgeway/model/relation"
23
25
  require_relative "edgeway/model/persistence"
24
26
  require_relative "edgeway/model/base"
27
+ require_relative "edgeway/cache"
28
+ require_relative "edgeway/rate_limit"
25
29
  require_relative "edgeway/http/auth/jwt"
26
30
  require_relative "edgeway/controller/callbacks"
27
31
  require_relative "edgeway/controller/rescuable"
28
32
  require_relative "edgeway/controller/rendering"
29
33
  require_relative "edgeway/controller/authentication"
34
+ require_relative "edgeway/controller/caching"
35
+ require_relative "edgeway/controller/rate_limiting"
30
36
  require_relative "edgeway/controller/base"
31
37
  require_relative "edgeway/controller/dispatcher"
32
38
  require_relative "edgeway/application"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: edgeway
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Yaginuma
@@ -22,20 +22,35 @@ files:
22
22
  - exe/edgeway
23
23
  - js/cgi.js
24
24
  - js/cloudflare-d1-sessions.js
25
+ - js/cloudflare-kv.js
26
+ - js/cloudflare-ratelimit.js
27
+ - js/cloudflare-test-database.js
28
+ - js/cloudflare-test-runner.js
25
29
  - js/cloudflare.js
26
30
  - js/cors.js
31
+ - js/fetch.js
27
32
  - js/headers.js
33
+ - js/jspi.js
28
34
  - js/jwt.js
29
35
  - js/runtime.js
30
36
  - js/wasi-shim.js
31
37
  - lib/edgeway.rb
32
38
  - lib/edgeway/application.rb
39
+ - lib/edgeway/cache.rb
40
+ - lib/edgeway/cache/limits.rb
41
+ - lib/edgeway/cache/memory_store.rb
42
+ - lib/edgeway/cache/null_store.rb
43
+ - lib/edgeway/cache/store.rb
33
44
  - lib/edgeway/cli.rb
34
45
  - lib/edgeway/cli/build.rb
35
46
  - lib/edgeway/cli/build/app_config.rb
36
47
  - lib/edgeway/cli/build/app_files.rb
48
+ - lib/edgeway/cli/build/cache_config.rb
37
49
  - lib/edgeway/cli/build/database_config.rb
50
+ - lib/edgeway/cli/build/js_files.rb
38
51
  - lib/edgeway/cli/build/view_compiler.rb
52
+ - lib/edgeway/cli/cloudflare_test.rb
53
+ - lib/edgeway/cli/cloudflare_test/wasm_test_cli.rb
39
54
  - lib/edgeway/cli/generate.rb
40
55
  - lib/edgeway/cli/new.rb
41
56
  - lib/edgeway/cli/package_manager.rb
@@ -46,8 +61,10 @@ files:
46
61
  - lib/edgeway/config.rb
47
62
  - lib/edgeway/controller/authentication.rb
48
63
  - lib/edgeway/controller/base.rb
64
+ - lib/edgeway/controller/caching.rb
49
65
  - lib/edgeway/controller/callbacks.rb
50
66
  - lib/edgeway/controller/dispatcher.rb
67
+ - lib/edgeway/controller/rate_limiting.rb
51
68
  - lib/edgeway/controller/rendering.rb
52
69
  - lib/edgeway/controller/rescuable.rb
53
70
  - lib/edgeway/db/adapter.rb
@@ -68,21 +85,25 @@ files:
68
85
  - lib/edgeway/generators/app/templates/bin/deploy.tt
69
86
  - lib/edgeway/generators/app/templates/bin/setup.tt
70
87
  - lib/edgeway/generators/app/templates/bin/test.tt
88
+ - lib/edgeway/generators/app/templates/config/cache.yml
71
89
  - lib/edgeway/generators/app/templates/config/database.yml
72
90
  - lib/edgeway/generators/app/templates/config/routes.rb
73
91
  - lib/edgeway/generators/app/templates/db/migrations/.keep
74
92
  - lib/edgeway/generators/app/templates/mise.toml.tt
75
93
  - lib/edgeway/generators/app/templates/package.json.tt
94
+ - lib/edgeway/generators/app/templates/public/.assetsignore
76
95
  - lib/edgeway/generators/app/templates/src/worker.js
77
96
  - lib/edgeway/generators/app/templates/test/controllers/health_test.rb
78
97
  - lib/edgeway/generators/app/templates/test/test_helper.rb
79
98
  - lib/edgeway/generators/app/templates/wrangler.toml.tt
80
99
  - lib/edgeway/http/auth/jwt.rb
81
100
  - lib/edgeway/http/auth/stub.rb
101
+ - lib/edgeway/http/client.rb
82
102
  - lib/edgeway/http/json_body.rb
83
103
  - lib/edgeway/http/parameters.rb
84
104
  - lib/edgeway/http/request.rb
85
105
  - lib/edgeway/http/response.rb
106
+ - lib/edgeway/http/stub_transport.rb
86
107
  - lib/edgeway/inflector.rb
87
108
  - lib/edgeway/logger.rb
88
109
  - lib/edgeway/model/attributes.rb
@@ -92,13 +113,25 @@ files:
92
113
  - lib/edgeway/model/persistence.rb
93
114
  - lib/edgeway/model/relation.rb
94
115
  - lib/edgeway/model/validations.rb
116
+ - lib/edgeway/rate_limit.rb
117
+ - lib/edgeway/rate_limit/limiter.rb
118
+ - lib/edgeway/rate_limit/null_limiter.rb
119
+ - lib/edgeway/rate_limit/stub_limiter.rb
95
120
  - lib/edgeway/routing/mapper.rb
96
121
  - lib/edgeway/routing/route.rb
97
122
  - lib/edgeway/routing/route_set.rb
98
123
  - lib/edgeway/server.rb
99
124
  - lib/edgeway/service/cloudflare/d1.rb
100
125
  - lib/edgeway/service/cloudflare/jwt.rb
126
+ - lib/edgeway/service/cloudflare/kv.rb
127
+ - lib/edgeway/service/cloudflare/kv_store.rb
128
+ - lib/edgeway/service/cloudflare/rate_limit.rb
129
+ - lib/edgeway/service/cloudflare/rate_limiter.rb
130
+ - lib/edgeway/service/cloudflare/test_databases.rb
131
+ - lib/edgeway/service/fetch.rb
132
+ - lib/edgeway/service/import_result.rb
101
133
  - lib/edgeway/test.rb
134
+ - lib/edgeway/test/sqlite_databases.rb
102
135
  - lib/edgeway/version.rb
103
136
  - lib/edgeway/view.rb
104
137
  homepage: https://github.com/y-yagi/edgeway