maquina_stream 0.1.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 +7 -0
- data/.rdoc_options +30 -0
- data/CHANGELOG.md +38 -0
- data/LICENSE.txt +21 -0
- data/README.md +163 -0
- data/app/assets/stylesheets/maquina_stream/components/attachment.css +35 -0
- data/app/assets/stylesheets/maquina_stream/components/code_block.css +30 -0
- data/app/assets/stylesheets/maquina_stream/components/shimmer.css +31 -0
- data/app/assets/stylesheets/maquina_stream/components/snippet.css +22 -0
- data/app/assets/stylesheets/maquina_stream/components/source_citation.css +14 -0
- data/app/assets/stylesheets/maquina_stream/components/suggestion.css +32 -0
- data/app/assets/stylesheets/maquina_stream/reveal.css +48 -0
- data/app/assets/stylesheets/maquina_stream/themes/dark.css +235 -0
- data/app/assets/stylesheets/maquina_stream/themes/light.css +117 -0
- data/app/controllers/maquina_stream/application_controller.rb +21 -0
- data/app/controllers/maquina_stream/blocks_controller.rb +41 -0
- data/app/controllers/maquina_stream/manifests_controller.rb +15 -0
- data/app/helpers/maquina_stream/components_helper.rb +80 -0
- data/app/javascript/maquina_stream/controllers/application_controller.js +169 -0
- data/app/javascript/maquina_stream/controllers/ms_autoscroll_controller.js +110 -0
- data/app/javascript/maquina_stream/controllers/ms_code_controller.js +96 -0
- data/app/javascript/maquina_stream/controllers/ms_deferred_controller.js +223 -0
- data/app/javascript/maquina_stream/controllers/ms_diagram_controller.js +40 -0
- data/app/javascript/maquina_stream/controllers/ms_link_safety_controller.js +196 -0
- data/app/javascript/maquina_stream/controllers/ms_math_controller.js +32 -0
- data/app/javascript/maquina_stream/controllers/ms_repair_controller.js +167 -0
- data/app/javascript/maquina_stream/controllers/ms_reveal_controller.js +320 -0
- data/app/javascript/maquina_stream/controllers/ms_table_controller.js +183 -0
- data/app/javascript/maquina_stream/index.js +59 -0
- data/app/views/maquina_stream/components/_attachment.html.erb +139 -0
- data/app/views/maquina_stream/components/_code_block.html.erb +74 -0
- data/app/views/maquina_stream/components/_shimmer.html.erb +36 -0
- data/app/views/maquina_stream/components/_snippet.html.erb +50 -0
- data/app/views/maquina_stream/components/_source_citation.html.erb +42 -0
- data/app/views/maquina_stream/components/_suggestion.html.erb +73 -0
- data/config/importmap.rb +10 -0
- data/config/locales/en.yml +79 -0
- data/config/locales/es.yml +82 -0
- data/config/routes.rb +11 -0
- data/docs/configuration.md +219 -0
- data/docs/deferred-renderers.md +184 -0
- data/docs/getting-started.md +356 -0
- data/docs/javascript.md +298 -0
- data/docs/registries.md +283 -0
- data/docs/repair.md +162 -0
- data/docs/security.md +247 -0
- data/docs/streaming.md +308 -0
- data/lib/generators/maquina_stream/install/USAGE +26 -0
- data/lib/generators/maquina_stream/install/install_generator.rb +199 -0
- data/lib/generators/maquina_stream/install/templates/initializer.rb.tt +121 -0
- data/lib/generators/maquina_stream/streamable/USAGE +28 -0
- data/lib/generators/maquina_stream/streamable/streamable_generator.rb +187 -0
- data/lib/generators/maquina_stream/streamable/templates/migration.rb.tt +21 -0
- data/lib/generators/maquina_stream/streamable/templates/model.rb.tt +4 -0
- data/lib/maquina_stream/block.rb +99 -0
- data/lib/maquina_stream/broadcaster.rb +233 -0
- data/lib/maquina_stream/component_cache.rb +0 -0
- data/lib/maquina_stream/components/contract.rb +184 -0
- data/lib/maquina_stream/components.rb +135 -0
- data/lib/maquina_stream/configuration.rb +240 -0
- data/lib/maquina_stream/document.rb +296 -0
- data/lib/maquina_stream/engine.rb +46 -0
- data/lib/maquina_stream/errors.rb +17 -0
- data/lib/maquina_stream/export.rb +66 -0
- data/lib/maquina_stream/frame.rb +73 -0
- data/lib/maquina_stream/manifest.rb +137 -0
- data/lib/maquina_stream/registries.rb +116 -0
- data/lib/maquina_stream/renderer/fence.rb +115 -0
- data/lib/maquina_stream/renderer/post_pass.rb +363 -0
- data/lib/maquina_stream/renderer/tag_blocks.rb +276 -0
- data/lib/maquina_stream/renderer/view_context.rb +72 -0
- data/lib/maquina_stream/renderer.rb +128 -0
- data/lib/maquina_stream/sanitizer.rb +392 -0
- data/lib/maquina_stream/streamable.rb +281 -0
- data/lib/maquina_stream/text_direction.rb +56 -0
- data/lib/maquina_stream/themes.rb +84 -0
- data/lib/maquina_stream/version.rb +5 -0
- data/lib/maquina_stream.rb +175 -0
- metadata +204 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MaquinaStream
|
|
4
|
+
# Which way a piece of text reads.
|
|
5
|
+
#
|
|
6
|
+
# A message is one document but not necessarily one direction: an assistant
|
|
7
|
+
# answering in Arabic quotes an English identifier, a Hebrew paragraph sits
|
|
8
|
+
# next to a Ruby fence. Direction is therefore decided per block, the way the
|
|
9
|
+
# bidi algorithm decides it — by the FIRST STRONG character — and not by the
|
|
10
|
+
# document, the locale or the host.
|
|
11
|
+
#
|
|
12
|
+
# `dir="auto"` on every block would let the browser do exactly this, at the
|
|
13
|
+
# cost of eleven bytes on every block of every frame for the majority of
|
|
14
|
+
# documents that are left-to-right and need nothing. So the strong character
|
|
15
|
+
# is found here and the attribute is emitted only when it changes something.
|
|
16
|
+
#
|
|
17
|
+
# The render pipeline calls this per block. A host calls it when it renders
|
|
18
|
+
# text of its own — a message header, an attachment filename — that came from
|
|
19
|
+
# the same place the buffer did.
|
|
20
|
+
module TextDirection
|
|
21
|
+
# The scripts written right to left, as Ruby knows them.
|
|
22
|
+
RTL = /[\p{Hebrew}\p{Arabic}\p{Syriac}\p{Thaana}\p{Nko}\p{Samaritan}\p{Mandaic}\p{Adlam}]/
|
|
23
|
+
|
|
24
|
+
# Only a letter is strong. Digits, punctuation and whitespace take their
|
|
25
|
+
# direction from what surrounds them, which is why "١٢٣ Ruby" reads
|
|
26
|
+
# left-to-right and "مرحبا 123" does not.
|
|
27
|
+
STRONG = /[\p{L}\p{Nl}]/
|
|
28
|
+
|
|
29
|
+
# Explicit bidi controls. They are what a Trojan Source attack is made of:
|
|
30
|
+
# an override inside a comment reorders the rendering of code that the
|
|
31
|
+
# parser reads in a different order entirely.
|
|
32
|
+
CONTROLS = /[\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/
|
|
33
|
+
|
|
34
|
+
# The direction `text` reads in: `:rtl`, `:ltr`, or nil when nothing in it
|
|
35
|
+
# is strong either way.
|
|
36
|
+
#
|
|
37
|
+
# Nil is a real answer, not a failure — a block of digits or punctuation
|
|
38
|
+
# has no direction of its own, and stamping one on it would be a guess. The
|
|
39
|
+
# caller emits no `dir` attribute for it.
|
|
40
|
+
def self.of(text)
|
|
41
|
+
strong = text.to_s[STRONG]
|
|
42
|
+
return nil unless strong
|
|
43
|
+
|
|
44
|
+
strong.match?(RTL) ? :rtl : :ltr
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Whether `text` contains an explicit bidi control character.
|
|
48
|
+
#
|
|
49
|
+
# True is a reason to be suspicious, not to render differently: see
|
|
50
|
+
# CONTROLS. Code that displays a filename or a link target unescaped should
|
|
51
|
+
# check this first.
|
|
52
|
+
def self.controls?(text)
|
|
53
|
+
text.to_s.match?(CONTROLS)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rouge"
|
|
4
|
+
|
|
5
|
+
module MaquinaStream
|
|
6
|
+
# Two stylesheets, one per scheme, generated from the Rouge themes named in
|
|
7
|
+
# the configuration.
|
|
8
|
+
#
|
|
9
|
+
# Highlighting emits classes and never inline colour, so switching to dark
|
|
10
|
+
# mode is a stylesheet concern and needs no re-render — which matters, because
|
|
11
|
+
# a re-render mid-stream would mean re-broadcasting sealed blocks to change a
|
|
12
|
+
# colour.
|
|
13
|
+
#
|
|
14
|
+
# The two files are generated, not written: `rake maquina_stream:themes`
|
|
15
|
+
# rewrites them from `config.themes`. A host that changes those theme names
|
|
16
|
+
# re-runs that task.
|
|
17
|
+
module Themes
|
|
18
|
+
# Every generated rule is scoped to a code block, so the themes cannot
|
|
19
|
+
# reach anything else on a host's page.
|
|
20
|
+
SCOPE = "[data-ms-code]"
|
|
21
|
+
|
|
22
|
+
# An explicitly chosen dark theme.
|
|
23
|
+
DARK_SELECTOR = '[data-theme="dark"]'
|
|
24
|
+
|
|
25
|
+
# An explicitly chosen light theme, and the default.
|
|
26
|
+
LIGHT_SELECTOR = ':root:not([data-theme="dark"])'
|
|
27
|
+
|
|
28
|
+
# Raised when `config.themes` names a theme Rouge does not define. Raising
|
|
29
|
+
# rather than falling back silently is how the `github_dark` typo in the
|
|
30
|
+
# original default was found.
|
|
31
|
+
class UnknownTheme < Error; end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
# The generated CSS for one scheme, as a String.
|
|
35
|
+
#
|
|
36
|
+
# `scheme` is `:light` or `:dark`; anything else raises ArgumentError.
|
|
37
|
+
# An unknown Rouge theme name raises UnknownTheme.
|
|
38
|
+
def stylesheet(scheme, config: MaquinaStream.config)
|
|
39
|
+
case scheme.to_sym
|
|
40
|
+
when :light then light(config)
|
|
41
|
+
when :dark then dark(config)
|
|
42
|
+
else raise ArgumentError, "scheme must be :light or :dark"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Where the generated stylesheet for `scheme` lives on disk. What the
|
|
47
|
+
# rake task writes to.
|
|
48
|
+
def path(scheme)
|
|
49
|
+
File.expand_path("../../app/assets/stylesheets/maquina_stream/themes/#{scheme}.css", __dir__)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
def light(config)
|
|
54
|
+
<<~CSS
|
|
55
|
+
/* Generated by `rake maquina_stream:themes`. Do not edit by hand. */
|
|
56
|
+
#{render(config.themes.fetch(:light), "#{LIGHT_SELECTOR} #{SCOPE}")}
|
|
57
|
+
CSS
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The dark rules are written twice on purpose: once behind the media
|
|
61
|
+
# query for a viewer who never chose, and once behind the explicit
|
|
62
|
+
# attribute so a chosen theme beats the system preference.
|
|
63
|
+
def dark(config)
|
|
64
|
+
rules = render(config.themes.fetch(:dark), "#{DARK_SELECTOR} #{SCOPE}")
|
|
65
|
+
system = render(config.themes.fetch(:dark), ":root:not([data-theme=\"light\"]) #{SCOPE}")
|
|
66
|
+
|
|
67
|
+
<<~CSS
|
|
68
|
+
/* Generated by `rake maquina_stream:themes`. Do not edit by hand. */
|
|
69
|
+
#{rules}
|
|
70
|
+
@media (prefers-color-scheme: dark) {
|
|
71
|
+
#{system}
|
|
72
|
+
}
|
|
73
|
+
CSS
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def render(name, scope)
|
|
77
|
+
theme = Rouge::Theme.find(name.to_s)
|
|
78
|
+
raise UnknownTheme, "Rouge has no theme named #{name.inspect}" unless theme
|
|
79
|
+
|
|
80
|
+
theme.render(scope: scope)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "maquina_stream/version"
|
|
4
|
+
require "maquina_stream/errors"
|
|
5
|
+
require "maquina_stream/configuration"
|
|
6
|
+
require "maquina_stream/registries"
|
|
7
|
+
require "maquina_stream/streamable"
|
|
8
|
+
require "maquina_stream/renderer"
|
|
9
|
+
require "maquina_stream/document"
|
|
10
|
+
require "maquina_stream/block"
|
|
11
|
+
require "maquina_stream/broadcaster"
|
|
12
|
+
require "maquina_stream/frame"
|
|
13
|
+
require "maquina_stream/manifest"
|
|
14
|
+
require "maquina_stream/sanitizer"
|
|
15
|
+
require "maquina_stream/text_direction"
|
|
16
|
+
require "maquina_stream/themes"
|
|
17
|
+
require "maquina_stream/export"
|
|
18
|
+
require "maquina_stream/component_cache"
|
|
19
|
+
require "maquina_stream/components"
|
|
20
|
+
require "maquina_stream/components/contract"
|
|
21
|
+
require "maquina_stream/engine" if defined?(Rails::Engine)
|
|
22
|
+
|
|
23
|
+
# Server-rendered streaming markdown for Rails, over Turbo, with a repair path.
|
|
24
|
+
#
|
|
25
|
+
# A model writes markdown a token at a time. The engine renders it on the
|
|
26
|
+
# server, broadcasts small patches as it grows, and reconciles the browser with
|
|
27
|
+
# the truth when frames go missing — which they do, because Action Cable offers
|
|
28
|
+
# no delivery guarantee. **Only rendered HTML reaches the browser**; the client
|
|
29
|
+
# never parses markdown.
|
|
30
|
+
#
|
|
31
|
+
# ## The whole integration
|
|
32
|
+
#
|
|
33
|
+
# ```ruby
|
|
34
|
+
# class Message < ApplicationRecord
|
|
35
|
+
# include MaquinaStream::Streamable
|
|
36
|
+
#
|
|
37
|
+
# maquina_stream buffer: :content,
|
|
38
|
+
# stream_for: ->(m) { [m.conversation, :messages] }
|
|
39
|
+
# end
|
|
40
|
+
#
|
|
41
|
+
# broadcaster = MaquinaStream::Broadcaster.new(message)
|
|
42
|
+
# model.stream { |token| broadcaster.append(token) }
|
|
43
|
+
# broadcaster.seal!
|
|
44
|
+
# ```
|
|
45
|
+
#
|
|
46
|
+
# ```erb
|
|
47
|
+
# <%= MaquinaStream.render(message) %>
|
|
48
|
+
# ```
|
|
49
|
+
#
|
|
50
|
+
# ## What a host owns
|
|
51
|
+
#
|
|
52
|
+
# The engine resolves nothing and authorizes nothing on its own. Three things
|
|
53
|
+
# are the host's, and none of them has a default the engine could guess:
|
|
54
|
+
#
|
|
55
|
+
# | Host responsibility | Where it goes |
|
|
56
|
+
# |---|---|
|
|
57
|
+
# | Looking a record up by its stream id | Configuration#find_stream |
|
|
58
|
+
# | Deciding whether a request may see it | Configuration#authorize |
|
|
59
|
+
# | Persisting the buffer, sequence and status | MaquinaStream::Streamable |
|
|
60
|
+
#
|
|
61
|
+
# **With no `authorize` configured, every repair request is refused.** That is
|
|
62
|
+
# deliberate: an engine that guesses is an engine that leaks.
|
|
63
|
+
#
|
|
64
|
+
# ## Where to look next
|
|
65
|
+
#
|
|
66
|
+
# | Object | Responsibility |
|
|
67
|
+
# |---|---|
|
|
68
|
+
# | MaquinaStream::Configuration | Every option, its default and what changing it costs |
|
|
69
|
+
# | MaquinaStream::Streamable | The host contract, and the macro that generates it |
|
|
70
|
+
# | MaquinaStream::Broadcaster | Frame coalescing and Turbo Stream emission |
|
|
71
|
+
# | MaquinaStream::Renderer | Markdown in, sanitized HTML out. A pure function |
|
|
72
|
+
# | MaquinaStream::Document | Splits a rendered message into blocks and decides which may freeze |
|
|
73
|
+
# | MaquinaStream::Block | One top-level block: id, markdown, HTML, digest |
|
|
74
|
+
# | MaquinaStream::Frame | One broadcast: what changed since the last one |
|
|
75
|
+
# | MaquinaStream::Manifest | What the browser is told the message currently is |
|
|
76
|
+
# | MaquinaStream::Sanitizer | Allowlist plus URL hardening, the last pass before output |
|
|
77
|
+
# | MaquinaStream::Export | A whole message, back out as markdown |
|
|
78
|
+
# | MaquinaStream::TextDirection | Which way a piece of text reads |
|
|
79
|
+
# | MaquinaStream::Components::Contract | The engine's half of a vendored component |
|
|
80
|
+
#
|
|
81
|
+
# Longer-form documentation ships in `docs/`: `getting-started.md`,
|
|
82
|
+
# `configuration.md`, `streaming.md`, `repair.md`, `registries.md`,
|
|
83
|
+
# `javascript.md`, `security.md` and `deferred-renderers.md`.
|
|
84
|
+
module MaquinaStream
|
|
85
|
+
extend Registries
|
|
86
|
+
|
|
87
|
+
# Components destined for maquina_components, vendored inside the engine for
|
|
88
|
+
# now. Everything renders through MaquinaStream::Components, so extraction is
|
|
89
|
+
# a matter of publishing the partial there and dropping the name from here.
|
|
90
|
+
VENDORED_COMPONENTS = %i[attachment code_block suggestion snippet].freeze
|
|
91
|
+
|
|
92
|
+
class << self
|
|
93
|
+
# The current Configuration. Memoized; the same object `configure`
|
|
94
|
+
# yields.
|
|
95
|
+
def config
|
|
96
|
+
@config ||= Configuration.new
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Configures the engine. Yields the Configuration and returns it.
|
|
100
|
+
#
|
|
101
|
+
# ```ruby
|
|
102
|
+
# MaquinaStream.configure do |c|
|
|
103
|
+
# c.find_stream = ->(sid) { Message.find_by(id: sid) }
|
|
104
|
+
# c.authorize = ->(record, request) { record.conversation.readable_by?(request) }
|
|
105
|
+
# end
|
|
106
|
+
# ```
|
|
107
|
+
#
|
|
108
|
+
# Every option, with its default and the consequence of changing it, is
|
|
109
|
+
# documented on Configuration. Call this once from an initializer:
|
|
110
|
+
# configuration is global and read on every render, so changing it
|
|
111
|
+
# mid-stream changes what later frames of an open message look like.
|
|
112
|
+
def configure
|
|
113
|
+
yield config
|
|
114
|
+
config
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Throws away the configuration and starts again from the defaults.
|
|
118
|
+
#
|
|
119
|
+
# For tests. A host that calls this in production loses its `find_stream`
|
|
120
|
+
# and `authorize` seams, and every repair request after it is refused.
|
|
121
|
+
def reset_configuration!
|
|
122
|
+
@config = Configuration.new
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Renders a whole message to HTML, cached once it is sealed. Returns an
|
|
126
|
+
# `html_safe` String.
|
|
127
|
+
#
|
|
128
|
+
# ```erb
|
|
129
|
+
# <%= MaquinaStream.render(message) %>
|
|
130
|
+
# ```
|
|
131
|
+
#
|
|
132
|
+
# This is the history path — one call, one finished message on a page. It
|
|
133
|
+
# is not what a live stream uses: an open stream goes out frame by frame
|
|
134
|
+
# through Broadcaster. Pagination stays the host's; the engine renders the
|
|
135
|
+
# messages the host chose, in the order it chose them.
|
|
136
|
+
#
|
|
137
|
+
# `record` must satisfy MaquinaStream::Streamable. `config:` defaults to
|
|
138
|
+
# the global MaquinaStream.config.
|
|
139
|
+
#
|
|
140
|
+
# A sealed message is immutable, so its HTML is a pure function of its
|
|
141
|
+
# buffer and can be cached by digest — which is what makes a page of history
|
|
142
|
+
# cheap: re-rendering fifty finished messages on every page load is work
|
|
143
|
+
# nobody asked for. An open message is never cached; it is about to change.
|
|
144
|
+
#
|
|
145
|
+
# The digest is of the buffer, so a host that edits a message gets a new key
|
|
146
|
+
# rather than a stale render.
|
|
147
|
+
def render(record, config: self.config)
|
|
148
|
+
markdown = record.maquina_stream_buffer
|
|
149
|
+
|
|
150
|
+
# Through Document, not Renderer. Renderer produces the HTML; Document is
|
|
151
|
+
# what stamps each block with the id and digest the DOM contract requires,
|
|
152
|
+
# and without those a page cannot be repaired at all — ms-repair would
|
|
153
|
+
# have nothing to compare a manifest against.
|
|
154
|
+
return document_html(record, markdown, config) if record.maquina_stream_open?
|
|
155
|
+
|
|
156
|
+
ComponentCache.fetch("document", record.maquina_stream_id, Digest::SHA256.hexdigest(markdown.to_s)) do
|
|
157
|
+
document_html(record, markdown, config)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def document_html(record, markdown, config)
|
|
164
|
+
blocks = Document.new(
|
|
165
|
+
markdown,
|
|
166
|
+
config: config,
|
|
167
|
+
sid: record.maquina_stream_id,
|
|
168
|
+
mode: record.maquina_stream_open? ? :streaming : :static
|
|
169
|
+
).blocks
|
|
170
|
+
|
|
171
|
+
html = blocks.map(&:html).join("\n")
|
|
172
|
+
html.respond_to?(:html_safe) ? html.html_safe : html
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: maquina_stream
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Mario Alberto Chávez
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '8.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: maquina_remend
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.1'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0.1'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: commonmarker
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: nokogiri
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rouge
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
description: Rails engine that renders a streaming markdown buffer to HTML on the
|
|
83
|
+
server and broadcasts it over Turbo Streams. Only rendered HTML reaches the browser.
|
|
84
|
+
executables: []
|
|
85
|
+
extensions: []
|
|
86
|
+
extra_rdoc_files:
|
|
87
|
+
- CHANGELOG.md
|
|
88
|
+
- LICENSE.txt
|
|
89
|
+
- README.md
|
|
90
|
+
files:
|
|
91
|
+
- ".rdoc_options"
|
|
92
|
+
- CHANGELOG.md
|
|
93
|
+
- LICENSE.txt
|
|
94
|
+
- README.md
|
|
95
|
+
- app/assets/stylesheets/maquina_stream/components/attachment.css
|
|
96
|
+
- app/assets/stylesheets/maquina_stream/components/code_block.css
|
|
97
|
+
- app/assets/stylesheets/maquina_stream/components/shimmer.css
|
|
98
|
+
- app/assets/stylesheets/maquina_stream/components/snippet.css
|
|
99
|
+
- app/assets/stylesheets/maquina_stream/components/source_citation.css
|
|
100
|
+
- app/assets/stylesheets/maquina_stream/components/suggestion.css
|
|
101
|
+
- app/assets/stylesheets/maquina_stream/reveal.css
|
|
102
|
+
- app/assets/stylesheets/maquina_stream/themes/dark.css
|
|
103
|
+
- app/assets/stylesheets/maquina_stream/themes/light.css
|
|
104
|
+
- app/controllers/maquina_stream/application_controller.rb
|
|
105
|
+
- app/controllers/maquina_stream/blocks_controller.rb
|
|
106
|
+
- app/controllers/maquina_stream/manifests_controller.rb
|
|
107
|
+
- app/helpers/maquina_stream/components_helper.rb
|
|
108
|
+
- app/javascript/maquina_stream/controllers/application_controller.js
|
|
109
|
+
- app/javascript/maquina_stream/controllers/ms_autoscroll_controller.js
|
|
110
|
+
- app/javascript/maquina_stream/controllers/ms_code_controller.js
|
|
111
|
+
- app/javascript/maquina_stream/controllers/ms_deferred_controller.js
|
|
112
|
+
- app/javascript/maquina_stream/controllers/ms_diagram_controller.js
|
|
113
|
+
- app/javascript/maquina_stream/controllers/ms_link_safety_controller.js
|
|
114
|
+
- app/javascript/maquina_stream/controllers/ms_math_controller.js
|
|
115
|
+
- app/javascript/maquina_stream/controllers/ms_repair_controller.js
|
|
116
|
+
- app/javascript/maquina_stream/controllers/ms_reveal_controller.js
|
|
117
|
+
- app/javascript/maquina_stream/controllers/ms_table_controller.js
|
|
118
|
+
- app/javascript/maquina_stream/index.js
|
|
119
|
+
- app/views/maquina_stream/components/_attachment.html.erb
|
|
120
|
+
- app/views/maquina_stream/components/_code_block.html.erb
|
|
121
|
+
- app/views/maquina_stream/components/_shimmer.html.erb
|
|
122
|
+
- app/views/maquina_stream/components/_snippet.html.erb
|
|
123
|
+
- app/views/maquina_stream/components/_source_citation.html.erb
|
|
124
|
+
- app/views/maquina_stream/components/_suggestion.html.erb
|
|
125
|
+
- config/importmap.rb
|
|
126
|
+
- config/locales/en.yml
|
|
127
|
+
- config/locales/es.yml
|
|
128
|
+
- config/routes.rb
|
|
129
|
+
- docs/configuration.md
|
|
130
|
+
- docs/deferred-renderers.md
|
|
131
|
+
- docs/getting-started.md
|
|
132
|
+
- docs/javascript.md
|
|
133
|
+
- docs/registries.md
|
|
134
|
+
- docs/repair.md
|
|
135
|
+
- docs/security.md
|
|
136
|
+
- docs/streaming.md
|
|
137
|
+
- lib/generators/maquina_stream/install/USAGE
|
|
138
|
+
- lib/generators/maquina_stream/install/install_generator.rb
|
|
139
|
+
- lib/generators/maquina_stream/install/templates/initializer.rb.tt
|
|
140
|
+
- lib/generators/maquina_stream/streamable/USAGE
|
|
141
|
+
- lib/generators/maquina_stream/streamable/streamable_generator.rb
|
|
142
|
+
- lib/generators/maquina_stream/streamable/templates/migration.rb.tt
|
|
143
|
+
- lib/generators/maquina_stream/streamable/templates/model.rb.tt
|
|
144
|
+
- lib/maquina_stream.rb
|
|
145
|
+
- lib/maquina_stream/block.rb
|
|
146
|
+
- lib/maquina_stream/broadcaster.rb
|
|
147
|
+
- lib/maquina_stream/component_cache.rb
|
|
148
|
+
- lib/maquina_stream/components.rb
|
|
149
|
+
- lib/maquina_stream/components/contract.rb
|
|
150
|
+
- lib/maquina_stream/configuration.rb
|
|
151
|
+
- lib/maquina_stream/document.rb
|
|
152
|
+
- lib/maquina_stream/engine.rb
|
|
153
|
+
- lib/maquina_stream/errors.rb
|
|
154
|
+
- lib/maquina_stream/export.rb
|
|
155
|
+
- lib/maquina_stream/frame.rb
|
|
156
|
+
- lib/maquina_stream/manifest.rb
|
|
157
|
+
- lib/maquina_stream/registries.rb
|
|
158
|
+
- lib/maquina_stream/renderer.rb
|
|
159
|
+
- lib/maquina_stream/renderer/fence.rb
|
|
160
|
+
- lib/maquina_stream/renderer/post_pass.rb
|
|
161
|
+
- lib/maquina_stream/renderer/tag_blocks.rb
|
|
162
|
+
- lib/maquina_stream/renderer/view_context.rb
|
|
163
|
+
- lib/maquina_stream/sanitizer.rb
|
|
164
|
+
- lib/maquina_stream/streamable.rb
|
|
165
|
+
- lib/maquina_stream/text_direction.rb
|
|
166
|
+
- lib/maquina_stream/themes.rb
|
|
167
|
+
- lib/maquina_stream/version.rb
|
|
168
|
+
homepage: https://github.com/maquina-app/maquina_stream
|
|
169
|
+
licenses:
|
|
170
|
+
- MIT
|
|
171
|
+
metadata:
|
|
172
|
+
homepage_uri: https://maquina.app
|
|
173
|
+
source_code_uri: https://github.com/maquina-app/maquina_stream
|
|
174
|
+
changelog_uri: https://github.com/maquina-app/maquina_stream/blob/main/CHANGELOG.md
|
|
175
|
+
documentation_uri: https://rubydoc.info/gems/maquina_stream/0.1.0
|
|
176
|
+
rubygems_mfa_required: 'true'
|
|
177
|
+
rdoc_options:
|
|
178
|
+
- "--markup"
|
|
179
|
+
- markdown
|
|
180
|
+
- "--main"
|
|
181
|
+
- README.md
|
|
182
|
+
- "--title"
|
|
183
|
+
- maquina_stream 0.1.0
|
|
184
|
+
- "--exclude"
|
|
185
|
+
- "(?:\\A|/)test/"
|
|
186
|
+
- "--exclude"
|
|
187
|
+
- "(?:\\A|/)sdd/"
|
|
188
|
+
require_paths:
|
|
189
|
+
- lib
|
|
190
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - ">="
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '3.3'
|
|
195
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
|
+
requirements:
|
|
197
|
+
- - ">="
|
|
198
|
+
- !ruby/object:Gem::Version
|
|
199
|
+
version: '0'
|
|
200
|
+
requirements: []
|
|
201
|
+
rubygems_version: 4.0.17
|
|
202
|
+
specification_version: 4
|
|
203
|
+
summary: Streaming markdown rendering for Rails, server-side.
|
|
204
|
+
test_files: []
|