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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +58 -11
- data/docs/adr/0009-realtime-updates.md +5 -1
- data/docs/architecture.md +3 -2
- data/docs/authorization.md +11 -4
- data/docs/correctness.md +3 -3
- data/docs/dashboard.md +200 -0
- data/docs/database-schema.md +5 -4
- data/docs/realtime.md +22 -14
- data/docs/roadmap.md +24 -6
- data/docs/security.md +7 -7
- data/examples/application/README.md +5 -5
- data/examples/application/app/actors/chat_room_actor.rb +1 -1
- data/examples/application/app/actors/shopping_cart_actor.rb +2 -2
- data/lib/solid_objects/actor.rb +1 -1
- data/lib/solid_objects/version.rb +1 -1
- data/lib/solid_objects/web/action.rb +109 -0
- data/lib/solid_objects/web/application.rb +239 -0
- data/lib/solid_objects/web/csrf_protection.rb +130 -0
- data/lib/solid_objects/web/helpers.rb +227 -0
- data/lib/solid_objects/web/paginator.rb +64 -0
- data/lib/solid_objects/web/route.rb +55 -0
- data/lib/solid_objects/web/router.rb +46 -0
- data/lib/solid_objects/web/statistics.rb +78 -0
- data/lib/solid_objects/web.rb +222 -0
- data/sig/generated/lib/solid_objects/web/action.rbs +78 -0
- data/sig/generated/lib/solid_objects/web/application.rbs +50 -0
- data/sig/generated/lib/solid_objects/web/csrf_protection.rbs +55 -0
- data/sig/generated/lib/solid_objects/web/helpers.rbs +118 -0
- data/sig/generated/lib/solid_objects/web/paginator.rbs +54 -0
- data/sig/generated/lib/solid_objects/web/route.rbs +45 -0
- data/sig/generated/lib/solid_objects/web/router.rbs +29 -0
- data/sig/generated/lib/solid_objects/web/statistics.rbs +46 -0
- data/sig/generated/lib/solid_objects/web.rbs +129 -0
- data/web/assets/javascripts/application.js +118 -0
- data/web/assets/javascripts/charts.js +190 -0
- data/web/assets/stylesheets/application.css +527 -0
- data/web/views/_messages.erb +29 -0
- data/web/views/_navigation.erb +15 -0
- data/web/views/_paging.erb +17 -0
- data/web/views/_status_filter.erb +8 -0
- data/web/views/_summary.erb +39 -0
- data/web/views/broadcasts.erb +35 -0
- data/web/views/dashboard.erb +128 -0
- data/web/views/dead_letter.erb +40 -0
- data/web/views/dead_letters.erb +42 -0
- data/web/views/effects.erb +35 -0
- data/web/views/instance.erb +139 -0
- data/web/views/instances.erb +49 -0
- data/web/views/layout.erb +22 -0
- data/web/views/mailbox.erb +35 -0
- data/web/views/message.erb +34 -0
- data/web/views/processes.erb +37 -0
- data/web/views/reminders.erb +37 -0
- 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
|