solid_objects 0.12.1 → 0.13.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 +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +58 -11
  4. data/docs/adr/0009-realtime-updates.md +5 -1
  5. data/docs/architecture.md +3 -2
  6. data/docs/authorization.md +11 -4
  7. data/docs/correctness.md +3 -3
  8. data/docs/dashboard.md +200 -0
  9. data/docs/database-schema.md +5 -4
  10. data/docs/realtime.md +22 -14
  11. data/docs/roadmap.md +24 -6
  12. data/docs/security.md +7 -7
  13. data/examples/application/README.md +5 -5
  14. data/examples/application/app/actors/chat_room_actor.rb +1 -1
  15. data/examples/application/app/actors/shopping_cart_actor.rb +2 -2
  16. data/lib/solid_objects/actor.rb +1 -1
  17. data/lib/solid_objects/version.rb +1 -1
  18. data/lib/solid_objects/web/action.rb +109 -0
  19. data/lib/solid_objects/web/application.rb +239 -0
  20. data/lib/solid_objects/web/csrf_protection.rb +130 -0
  21. data/lib/solid_objects/web/helpers.rb +227 -0
  22. data/lib/solid_objects/web/paginator.rb +64 -0
  23. data/lib/solid_objects/web/route.rb +55 -0
  24. data/lib/solid_objects/web/router.rb +46 -0
  25. data/lib/solid_objects/web/statistics.rb +78 -0
  26. data/lib/solid_objects/web.rb +222 -0
  27. data/sig/generated/lib/solid_objects/web/action.rbs +78 -0
  28. data/sig/generated/lib/solid_objects/web/application.rbs +50 -0
  29. data/sig/generated/lib/solid_objects/web/csrf_protection.rbs +55 -0
  30. data/sig/generated/lib/solid_objects/web/helpers.rbs +118 -0
  31. data/sig/generated/lib/solid_objects/web/paginator.rbs +54 -0
  32. data/sig/generated/lib/solid_objects/web/route.rbs +45 -0
  33. data/sig/generated/lib/solid_objects/web/router.rbs +29 -0
  34. data/sig/generated/lib/solid_objects/web/statistics.rbs +46 -0
  35. data/sig/generated/lib/solid_objects/web.rbs +129 -0
  36. data/web/assets/javascripts/application.js +118 -0
  37. data/web/assets/javascripts/charts.js +190 -0
  38. data/web/assets/stylesheets/application.css +527 -0
  39. data/web/views/_messages.erb +29 -0
  40. data/web/views/_navigation.erb +15 -0
  41. data/web/views/_paging.erb +17 -0
  42. data/web/views/_status_filter.erb +8 -0
  43. data/web/views/_summary.erb +39 -0
  44. data/web/views/broadcasts.erb +35 -0
  45. data/web/views/dashboard.erb +128 -0
  46. data/web/views/dead_letter.erb +40 -0
  47. data/web/views/dead_letters.erb +42 -0
  48. data/web/views/effects.erb +35 -0
  49. data/web/views/instance.erb +139 -0
  50. data/web/views/instances.erb +49 -0
  51. data/web/views/layout.erb +22 -0
  52. data/web/views/mailbox.erb +35 -0
  53. data/web/views/message.erb +34 -0
  54. data/web/views/processes.erb +37 -0
  55. data/web/views/reminders.erb +37 -0
  56. metadata +55 -2
@@ -0,0 +1,78 @@
1
+ # Generated from lib/solid_objects/web/action.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # One request. A route handler runs inside an instance of this class, so a
6
+ # handler and the template it renders share the same helpers and the same
7
+ # request.
8
+ class Action
9
+ include Helpers
10
+
11
+ @response_status: Integer
12
+
13
+ @layout_rendered: bool
14
+
15
+ @request: untyped
16
+
17
+ @captures: Hash[Symbol, String?]
18
+
19
+ @route: Route
20
+
21
+ @env: Hash[String, untyped]
22
+
23
+ attr_reader env: untyped
24
+
25
+ attr_reader route: untyped
26
+
27
+ attr_reader response_status: untyped
28
+
29
+ # @rbs (env: Hash[String, untyped], route: Route) -> void
30
+ def initialize: (env: Hash[String, untyped], route: Route) -> void
31
+
32
+ # Sets the status a rendered page is served with. `halt` and `redirect`
33
+ # stop the handler, so a page that must render its own body and still
34
+ # report a failure needs this instead.
35
+ # @rbs (Integer) -> void
36
+ def status: (Integer) -> void
37
+
38
+ # @rbs () -> untyped
39
+ def request: () -> untyped
40
+
41
+ # @rbs () -> Hash[untyped, untyped]?
42
+ def session: () -> Hash[untyped, untyped]?
43
+
44
+ # @rbs (Symbol) -> String?
45
+ def route_params: (Symbol) -> String?
46
+
47
+ # @rbs (String) -> untyped
48
+ def url_params: (String) -> untyped
49
+
50
+ # @rbs () -> untyped
51
+ def call: () -> untyped
52
+
53
+ # The layout is rendered once per request. The flag is raised before the
54
+ # page body runs so a partial the body renders returns its own fragment
55
+ # rather than a second whole page. The layout reads the page it wraps
56
+ # from `locals.fetch(:content)`.
57
+ # @rbs (Symbol, ?Hash[Symbol, untyped]) -> String
58
+ def erb: (Symbol, ?Hash[Symbol, untyped]) -> String
59
+
60
+ # @rbs (Integer, ?String) -> void
61
+ def halt: (Integer, ?String) -> void
62
+
63
+ # @rbs (String) -> void
64
+ def redirect: (String) -> void
65
+
66
+ # @rbs (untyped) -> void
67
+ def json: (untyped) -> void
68
+
69
+ private
70
+
71
+ # `locals` is a local variable of this method, so a template reads it by
72
+ # name, and every helper is reachable because the template runs against
73
+ # this object.
74
+ # @rbs (untyped, Hash[Symbol, untyped]) -> String
75
+ def evaluate: (untyped, Hash[Symbol, untyped]) -> String
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,50 @@
1
+ # Generated from lib/solid_objects/web/application.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # The pages. Each route states the administration policy it needs, and
6
+ # `call` asks that policy before the handler runs, so a page cannot read
7
+ # the actor tables on behalf of an unauthorized request.
8
+ class Application
9
+ extend Router
10
+
11
+ SCRIPT_PLACEHOLDER: ::String
12
+
13
+ CONTENT_SECURITY_POLICY: untyped
14
+
15
+ MAILBOX_MEMBERSHIPS: untyped
16
+
17
+ RECENT_LIMIT: ::Integer
18
+
19
+ CHART_TYPE_LIMIT: ::Integer
20
+
21
+ # @rbs (Hash[String, untyped]) -> Array[untyped]
22
+ def call: (Hash[String, untyped]) -> Array[untyped]
23
+
24
+ private
25
+
26
+ # @rbs (Action, untyped) -> Array[untyped]
27
+ def respond: (Action, untyped) -> Array[untyped]
28
+
29
+ # @rbs (Action) -> bool
30
+ def authorized?: (Action) -> bool
31
+
32
+ # @rbs (Hash[String, untyped]) -> Hash[String, String]
33
+ def page_headers: (Hash[String, untyped]) -> Hash[String, String]
34
+
35
+ # The chart host is named only when one is configured, so a deployment
36
+ # that vendors the library or turns charts off never advertises a third
37
+ # party origin it does not use.
38
+ # @rbs (Hash[String, untyped]) -> String
39
+ def content_security_policy: (Hash[String, untyped]) -> String
40
+
41
+ # The cascade header lets a host application serve its own 404 for a path
42
+ # below the mount that the dashboard does not define.
43
+ # @rbs () -> Array[untyped]
44
+ def not_found: () -> Array[untyped]
45
+
46
+ # @rbs () -> Array[untyped]
47
+ def forbidden: () -> Array[untyped]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,55 @@
1
+ # Generated from lib/solid_objects/web/csrf_protection.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # A state changing request must carry the token of the session that asked
6
+ # for the form. The token a form receives is masked with a fresh one-time
7
+ # pad on every request, so the bytes on the wire differ each time and a
8
+ # compression side channel cannot recover the session token.
9
+ class CsrfProtection
10
+ SAFE_METHODS: untyped
11
+
12
+ TOKEN_BYTES: ::Integer
13
+
14
+ MISSING_SESSION: ::String
15
+
16
+ # @rbs (untyped) -> void
17
+ def initialize: (untyped) -> void
18
+
19
+ # @rbs (Hash[String, untyped]) -> Array[untyped]
20
+ def call: (Hash[String, untyped]) -> Array[untyped]
21
+
22
+ private
23
+
24
+ # @rbs (Hash[String, untyped]) -> bool
25
+ def accept?: (Hash[String, untyped]) -> bool
26
+
27
+ # @rbs (Hash[String, untyped], String?) -> bool
28
+ def valid?: (Hash[String, untyped], String?) -> bool
29
+
30
+ # @rbs (String, String) -> bool
31
+ def matches?: (String, String) -> bool
32
+
33
+ # @rbs (String) -> String
34
+ def mask: (String) -> String
35
+
36
+ # @rbs (String) -> String
37
+ def unmask: (String) -> String
38
+
39
+ # @rbs (String, String) -> String
40
+ def exclusive_or: (String, String) -> String
41
+
42
+ # @rbs (String) -> String
43
+ def encode: (String) -> String
44
+
45
+ # @rbs (String) -> String?
46
+ def decode: (String) -> String?
47
+
48
+ # @rbs (Hash[String, untyped]) -> Hash[untyped, untyped]
49
+ def session!: (Hash[String, untyped]) -> Hash[untyped, untyped]
50
+
51
+ # @rbs () -> Array[untyped]
52
+ def forbidden: () -> Array[untyped]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,118 @@
1
+ # Generated from lib/solid_objects/web/helpers.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # The methods a view may call. Everything a template prints goes through
6
+ # `h`, because an actor id, an operation name, and an exception message are
7
+ # all application supplied strings that reach this page unchanged.
8
+ module Helpers
9
+ # Only these survive a page link. A filter an operator set stays set when
10
+ # they turn the page; anything else the query string carries does not
11
+ # come back.
12
+ FORWARDED_PARAMS: untyped
13
+
14
+ TRUNCATION_LIMIT: ::Integer
15
+
16
+ # @rbs (untyped) -> String
17
+ def h: (untyped) -> String
18
+
19
+ # @rbs () -> String
20
+ def root_path: () -> String
21
+
22
+ # @rbs (String) -> String
23
+ def path_to: (String) -> String
24
+
25
+ # @rbs () -> String
26
+ def current_path: () -> String
27
+
28
+ # @rbs (String) -> bool
29
+ def current_tab?: (String) -> bool
30
+
31
+ # @rbs () -> Hash[String, String]
32
+ def tabs: () -> Hash[String, String]
33
+
34
+ # @rbs () -> String?
35
+ def csp_nonce: () -> String?
36
+
37
+ # @rbs () -> String
38
+ def csrf_tag: () -> String
39
+
40
+ # @rbs (String) -> String
41
+ def form_to: (String) -> String
42
+
43
+ # @rbs (untyped) -> String
44
+ def relative_time: (untyped) -> String
45
+
46
+ # @rbs (untyped) -> String
47
+ def number: (untyped) -> String
48
+
49
+ # @rbs (Numeric?) -> String
50
+ def duration: (Numeric?) -> String
51
+
52
+ # @rbs (untyped, ?Integer) -> String
53
+ def json_block: (untyped, ?Integer) -> String
54
+
55
+ # @rbs (String, ?Integer) -> String
56
+ def truncate: (String, ?Integer) -> String
57
+
58
+ # @rbs (String?) -> String
59
+ def status_label: (String?) -> String
60
+
61
+ # @rbs (untyped) -> String
62
+ def actor_label: (untyped) -> String
63
+
64
+ # @rbs (untyped) -> String
65
+ def instance_link: (untyped) -> String
66
+
67
+ # @rbs (?Hash[String, untyped]) -> String
68
+ def query_string: (?Hash[String, untyped]) -> String
69
+
70
+ # @rbs (?Hash[String, untyped]) -> String
71
+ def page_link: (?Hash[String, untyped]) -> String
72
+
73
+ # @rbs (Instance) -> String
74
+ def lease_state: (Instance) -> String
75
+
76
+ # @rbs () -> Statistics
77
+ def statistics: () -> Statistics
78
+
79
+ # @rbs (untyped) -> Paginator
80
+ def paginate: (untyped) -> Paginator
81
+
82
+ # An unrecognized filter falls back to the default rather than returning
83
+ # nothing, so a hand edited query string cannot make a page look empty.
84
+ # @rbs (Array[String], ?default: String?) -> String?
85
+ def filter_value: (Array[String], ?default: String?) -> String?
86
+
87
+ # @rbs () -> Instance
88
+ def find_instance: () -> Instance
89
+
90
+ # @rbs () -> untyped
91
+ def filtered_instances: () -> untyped
92
+
93
+ # @rbs (String) -> untyped
94
+ def mailbox_messages: (String) -> untyped
95
+
96
+ # Chart data travels in an attribute rather than an inline script block,
97
+ # so the page needs no script-src exception and an actor type cannot
98
+ # close the attribute and open a tag.
99
+ #
100
+ # The container is not decoration. Chart.js measures a responsive canvas
101
+ # against its parent, so the parent has to have a height of its own; a
102
+ # panel that sizes to its children would grow a little on every redraw.
103
+ # @rbs (String, untyped) -> String
104
+ def chart: (String, untyped) -> String
105
+
106
+ # A vendored copy is a path below the mount; a CDN copy is an absolute
107
+ # URL and is left alone.
108
+ # @rbs () -> String
109
+ def chart_library_source: () -> String
110
+
111
+ # @rbs () -> String
112
+ def chart_library_integrity_attributes: () -> String
113
+
114
+ # @rbs () -> String
115
+ def environment_name: () -> String
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,54 @@
1
+ # Generated from lib/solid_objects/web/paginator.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # Counts and slices one relation. The page size is clamped because the page
6
+ # number and the page size both arrive from the query string, and an
7
+ # operator page that accepts an unbounded limit is a denial of service
8
+ # against the database the actors run on.
9
+ class Paginator
10
+ DEFAULT_PER_PAGE: ::Integer
11
+
12
+ MAXIMUM_PER_PAGE: ::Integer
13
+
14
+ @page: Integer
15
+
16
+ @per_page: Integer
17
+
18
+ @total: Integer
19
+
20
+ @records: Array[untyped]
21
+
22
+ attr_reader page: untyped
23
+
24
+ attr_reader per_page: untyped
25
+
26
+ attr_reader total: untyped
27
+
28
+ attr_reader records: untyped
29
+
30
+ # @rbs (relation: untyped, ?page: String?, ?per_page: String?) -> void
31
+ def initialize: (relation: untyped, ?page: String?, ?per_page: String?) -> void
32
+
33
+ # @rbs () -> Integer
34
+ def last_page: () -> Integer
35
+
36
+ # @rbs () -> Integer?
37
+ def previous_page: () -> Integer?
38
+
39
+ # @rbs () -> Integer?
40
+ def next_page: () -> Integer?
41
+
42
+ # @rbs () -> Integer
43
+ def first_record: () -> Integer
44
+
45
+ # @rbs () -> Integer
46
+ def last_record: () -> Integer
47
+
48
+ private
49
+
50
+ # @rbs (String?, default: Integer, maximum: Integer) -> Integer
51
+ def bounded: (String?, default: Integer, maximum: Integer) -> Integer
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ # Generated from lib/solid_objects/web/route.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ class Route
6
+ # A named segment stops at the next slash, so `/instances/:id` never
7
+ # swallows `/instances/1/pause` and route order cannot hide a page.
8
+ NAMED_SEGMENT: ::Regexp
9
+
10
+ SEGMENT_CAPTURE: ::String
11
+
12
+ @matcher: String | Regexp
13
+
14
+ @request_method: String
15
+
16
+ @pattern: String
17
+
18
+ @policy: Hash[Symbol, String]
19
+
20
+ @handler: Proc
21
+
22
+ attr_reader request_method: untyped
23
+
24
+ attr_reader pattern: untyped
25
+
26
+ attr_reader policy: untyped
27
+
28
+ attr_reader handler: untyped
29
+
30
+ # @rbs (request_method: String, pattern: String, policy: Hash[Symbol, String], handler: Proc) -> void
31
+ def initialize: (request_method: String, pattern: String, policy: Hash[Symbol, String], handler: Proc) -> void
32
+
33
+ # @rbs (String) -> bool
34
+ def match?: (String) -> bool
35
+
36
+ # @rbs (String) -> Hash[Symbol, String?]
37
+ def capture: (String) -> Hash[Symbol, String?]
38
+
39
+ private
40
+
41
+ # @rbs (String) -> (String | Regexp)
42
+ def compile: (String) -> (String | Regexp)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ # Generated from lib/solid_objects/web/router.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # Declares the pages of the dashboard. Every route carries the
6
+ # administration policy it needs, and a route declared without one raises
7
+ # at load time. A new page therefore cannot reach the database before an
8
+ # application has said who may read it.
9
+ module Router
10
+ # @rbs (String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
11
+ def head: (String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
12
+
13
+ # @rbs (String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
14
+ def get: (String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
15
+
16
+ # @rbs (String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
17
+ def post: (String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
18
+
19
+ # @rbs (String, String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
20
+ def route: (String, String, policy: Hash[Symbol, String]?) { () -> untyped } -> void
21
+
22
+ # @rbs () -> Hash[String, Array[Route]]
23
+ def routes: () -> Hash[String, Array[Route]]
24
+
25
+ # @rbs (String, String) -> Route?
26
+ def match: (String, String) -> Route?
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ # Generated from lib/solid_objects/web/statistics.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class Web
5
+ # The counts behind the dashboard and behind `GET /stats`. Both read the
6
+ # same object, so the polled JSON and the rendered page can never disagree
7
+ # about what a number means.
8
+ class Statistics
9
+ EFFECT_STATUSES: untyped
10
+
11
+ BROADCAST_STATUSES: untyped
12
+
13
+ REMINDER_STATUSES: untyped
14
+
15
+ PROCESS_STATES: untyped
16
+
17
+ @now: Time
18
+
19
+ attr_reader now: untyped
20
+
21
+ # @rbs (?now: Time) -> void
22
+ def initialize: (?now: Time) -> void
23
+
24
+ # @rbs () -> Hash[Symbol, untyped]
25
+ def to_h: () -> Hash[Symbol, untyped]
26
+
27
+ # @rbs () -> Hash[Symbol, Integer]
28
+ def instances: () -> Hash[Symbol, Integer]
29
+
30
+ # The oldest ready message that is already due is the queue latency of
31
+ # this runtime: how far behind the workers are, in seconds.
32
+ # @rbs () -> Hash[Symbol, untyped]
33
+ def mailbox: () -> Hash[Symbol, untyped]
34
+
35
+ # @rbs () -> Hash[Symbol, Integer]
36
+ def reminders: () -> Hash[Symbol, Integer]
37
+
38
+ private
39
+
40
+ # A status the schema allows but the table does not currently hold still
41
+ # reports zero, so a row of counts keeps the same shape between polls.
42
+ # @rbs (untyped, Symbol, Array[String]) -> Hash[Symbol, Integer]
43
+ def grouped: (untyped, Symbol, Array[String]) -> Hash[Symbol, Integer]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,129 @@
1
+ # Generated from lib/solid_objects/web.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ # An operator dashboard for the actor runtime, served as a Rack application:
5
+ #
6
+ # Rails.application.routes.draw do
7
+ # mount SolidObjects::Web => "/solid_objects"
8
+ # end
9
+ #
10
+ # It is deliberately not loaded by `require "solid_objects"`. A worker
11
+ # process must not carry a web stack, and an application that never mounts
12
+ # the dashboard must not pay for it.
13
+ #
14
+ # Every page asks `configuration.authorize_administration` first. That block
15
+ # denies by default, so a mount alone exposes nothing until an application
16
+ # states who may read it.
17
+ class Web
18
+ ROOT: untyped
19
+
20
+ VIEWS: untyped
21
+
22
+ ASSETS: untyped
23
+
24
+ NONCE_KEY: ::String
25
+
26
+ CSRF_TOKEN_KEY: ::String
27
+
28
+ NONCE_BYTES: ::Integer
29
+
30
+ ASSET_CACHE_SECONDS: ::Integer
31
+
32
+ TEMPLATE_NAME: ::Regexp
33
+
34
+ # The dashboard charts need a charting library, and this one is fetched
35
+ # from a public CDN with a subresource integrity hash, so a compromised CDN
36
+ # cannot substitute other code. A deployment with no outbound network
37
+ # access should vendor the file and point `chart_library_url` at it, or set
38
+ # that to nil to render the dashboard without charts.
39
+ CHART_LIBRARY_URL: ::String
40
+
41
+ CHART_LIBRARY_INTEGRITY: ::String
42
+
43
+ DEFAULT_TABS: untyped
44
+
45
+ LOCK: untyped
46
+
47
+ # A path below the mount serves a vendored copy; an absolute URL is
48
+ # fetched from that host and is named in the content security policy.
49
+ # nil renders the dashboard without charts.
50
+ # @rbs @chart_library_url: String?
51
+ # @rbs @chart_library_integrity: String?
52
+ attr_writer chart_library_url: untyped
53
+
54
+ # A path below the mount serves a vendored copy; an absolute URL is
55
+ # fetched from that host and is named in the content security policy.
56
+ # nil renders the dashboard without charts.
57
+ # @rbs @chart_library_url: String?
58
+ # @rbs @chart_library_integrity: String?
59
+ attr_writer chart_library_integrity: untyped
60
+
61
+ # @rbs () -> String?
62
+ def self.chart_library_url: () -> String?
63
+
64
+ # @rbs () -> String?
65
+ def self.chart_library_integrity: () -> String?
66
+
67
+ # @rbs () -> bool
68
+ def self.charts?: () -> bool
69
+
70
+ # The origin the content security policy has to allow. A vendored copy
71
+ # served from the mount has none, so the policy stays at 'self'.
72
+ # @rbs () -> String?
73
+ def self.chart_library_origin: () -> String?
74
+
75
+ # @rbs () -> Hash[String, String]
76
+ def self.tabs: () -> Hash[String, String]
77
+
78
+ # Searched in order, so an extension directory added first wins over the
79
+ # packaged one and an application can replace a single page.
80
+ # @rbs () -> Array[String]
81
+ def self.views: () -> Array[String]
82
+
83
+ # @rbs () -> Array[[Array[untyped], Proc?]]
84
+ def self.middlewares: () -> Array[[ Array[untyped], Proc? ]]
85
+
86
+ # The built stack is memoized, so a middleware added after the first
87
+ # request would otherwise be dropped without a word.
88
+ # @rbs (*untyped) ?{ () -> untyped } -> void
89
+ def self.use: (*untyped) ?{ () -> untyped } -> void
90
+
91
+ # Adds pages to the dashboard. The extension receives the application
92
+ # class and declares its own routes on it, which means its routes carry
93
+ # an authorization policy like every other route.
94
+ #
95
+ # @rbs (untyped, tab: String, path: String, ?views: String?) -> void
96
+ def self.register: (untyped, tab: String, path: String, ?views: String?) -> void
97
+
98
+ # @rbs (Symbol) -> untyped
99
+ def self.template: (Symbol) -> untyped
100
+
101
+ # @rbs () -> void
102
+ def self.reset!: () -> void
103
+
104
+ # @rbs (Hash[String, untyped]) -> Array[untyped]
105
+ def self.call: (Hash[String, untyped]) -> Array[untyped]
106
+
107
+ # @rbs () -> Web
108
+ def self.application: () -> Web
109
+
110
+ # @rbs () -> Hash[Symbol, untyped]
111
+ private def self.templates: () -> Hash[Symbol, untyped]
112
+
113
+ # A template name never comes from a request, and this keeps it that way
114
+ # rather than trusting every future caller to know it.
115
+ # @rbs (Symbol) -> String
116
+ private def self.template_path: (Symbol) -> String
117
+
118
+ # @rbs (Hash[String, untyped]) -> Array[untyped]
119
+ def call: (Hash[String, untyped]) -> Array[untyped]
120
+
121
+ # @rbs () -> untyped
122
+ def app: () -> untyped
123
+
124
+ private
125
+
126
+ # @rbs () -> untyped
127
+ def build: () -> untyped
128
+ end
129
+ end