tina4ruby 3.13.137 → 3.13.138
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 +36 -0
- data/COMMERCIAL-LICENSE.md +8 -0
- data/LICENSE +373 -0
- data/LICENSE.txt +373 -21
- data/NOTICE +11 -0
- data/README.md +11 -7
- data/exe/tina4ruby +6 -0
- data/lib/tina4/ai.rb +6 -0
- data/lib/tina4/ai_client.rb +10 -3
- data/lib/tina4/api.rb +57 -7
- data/lib/tina4/auth.rb +18 -12
- data/lib/tina4/auto_crud.rb +83 -27
- data/lib/tina4/background.rb +7 -1
- data/lib/tina4/base64.rb +59 -0
- data/lib/tina4/cache.rb +6 -0
- data/lib/tina4/cache_backends/base_backend.rb +6 -0
- data/lib/tina4/cache_backends/database_backend.rb +6 -0
- data/lib/tina4/cache_backends/file_backend.rb +6 -0
- data/lib/tina4/cache_backends/memcached_backend.rb +6 -0
- data/lib/tina4/cache_backends/memory_backend.rb +6 -0
- data/lib/tina4/cache_backends/mongo_backend.rb +6 -0
- data/lib/tina4/cache_backends/redis_backend.rb +6 -0
- data/lib/tina4/cache_backends/valkey_backend.rb +6 -0
- data/lib/tina4/cache_backends.rb +6 -0
- data/lib/tina4/cli.rb +22 -7
- data/lib/tina4/constants.rb +12 -8
- data/lib/tina4/container.rb +6 -0
- data/lib/tina4/context/chunker.rb +6 -0
- data/lib/tina4/context.rb +13 -5
- data/lib/tina4/cors.rb +66 -10
- data/lib/tina4/crud.rb +78 -9
- data/lib/tina4/database/sqlite3_adapter.rb +9 -1
- data/lib/tina4/database.rb +260 -44
- data/lib/tina4/database_adapter.rb +6 -0
- data/lib/tina4/database_result.rb +6 -0
- data/lib/tina4/database_url.rb +6 -0
- data/lib/tina4/debug.rb +6 -0
- data/lib/tina4/dev.rb +6 -0
- data/lib/tina4/dev_admin.rb +215 -89
- data/lib/tina4/dev_mailbox.rb +6 -1
- data/lib/tina4/dispatch_pipeline.rb +86 -1
- data/lib/tina4/docs.rb +6 -0
- data/lib/tina4/docstore.rb +23 -4
- data/lib/tina4/drivers/arango_graph_driver.rb +8 -1
- data/lib/tina4/drivers/bolt_graph_driver.rb +6 -0
- data/lib/tina4/drivers/firebird_driver.rb +95 -6
- data/lib/tina4/drivers/mongodb_driver.rb +6 -0
- data/lib/tina4/drivers/mssql_driver.rb +54 -39
- data/lib/tina4/drivers/mysql_driver.rb +6 -0
- data/lib/tina4/drivers/odbc_driver.rb +6 -0
- data/lib/tina4/drivers/postgres_driver.rb +35 -8
- data/lib/tina4/drivers/schema_split.rb +6 -0
- data/lib/tina4/drivers/sqlite_driver.rb +8 -1
- data/lib/tina4/drivers/ultipa_graph_driver.rb +6 -0
- data/lib/tina4/env.rb +6 -0
- data/lib/tina4/error_overlay.rb +6 -0
- data/lib/tina4/events.rb +6 -0
- data/lib/tina4/feedback.rb +9 -2
- data/lib/tina4/field_types.rb +6 -0
- data/lib/tina4/form_parser.rb +241 -0
- data/lib/tina4/frond.rb +196 -56
- data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +6 -0
- data/lib/tina4/gallery/database/src/routes/api/gallery_db.rb +6 -0
- data/lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb +6 -0
- data/lib/tina4/gallery/orm/src/routes/api/gallery_products.rb +6 -0
- data/lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb +6 -0
- data/lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb +6 -0
- data/lib/tina4/gallery/templates/src/routes/gallery_page.rb +6 -0
- data/lib/tina4/graph.rb +6 -0
- data/lib/tina4/graphql.rb +28 -27
- data/lib/tina4/health.rb +6 -0
- data/lib/tina4/html_element.rb +6 -0
- data/lib/tina4/http_server.rb +690 -0
- data/lib/tina4/imap_client.rb +352 -0
- data/lib/tina4/import_helper.rb +6 -0
- data/lib/tina4/job.rb +6 -0
- data/lib/tina4/localization.rb +6 -0
- data/lib/tina4/log.rb +6 -0
- data/lib/tina4/mail_socket.rb +124 -0
- data/lib/tina4/mcp.rb +15 -8
- data/lib/tina4/messenger.rb +86 -55
- data/lib/tina4/metrics.rb +6 -0
- data/lib/tina4/middleware.rb +24 -9
- data/lib/tina4/migration.rb +6 -0
- data/lib/tina4/model_collection.rb +6 -0
- data/lib/tina4/mqtt.rb +9 -2
- data/lib/tina4/mqtt_message.rb +6 -0
- data/lib/tina4/orm.rb +72 -16
- data/lib/tina4/parse_json.rb +25 -0
- data/lib/tina4/plan.rb +9 -2
- data/lib/tina4/point.rb +6 -0
- data/lib/tina4/port_takeover.rb +6 -0
- data/lib/tina4/project_index.rb +6 -0
- data/lib/tina4/public/THIRD-PARTY-NOTICES.md +55 -0
- data/lib/tina4/public/bundled-component-provenance.json +48 -0
- data/lib/tina4/public/js/tina4js.min.js +13 -3
- data/lib/tina4/public/licenses/swagger-ui-3.10.0-original-notice.txt +11 -0
- data/lib/tina4/public/licenses/swagger-ui-5.17.14-NOTICE.txt +2 -0
- data/lib/tina4/public/licenses/swagger-ui-Apache-2.0.txt +202 -0
- data/lib/tina4/public/licenses/tina4-css-MIT.txt +21 -0
- data/lib/tina4/public/licenses/tina4-dev-admin-components.json +240 -0
- data/lib/tina4/public/licenses/tina4-dev-admin-third-party.txt +919 -0
- data/lib/tina4/public/licenses/tina4-js-MIT.txt +20 -0
- data/lib/tina4/push.rb +9 -3
- data/lib/tina4/query_builder.rb +6 -0
- data/lib/tina4/queue.rb +6 -0
- data/lib/tina4/queue_backends/kafka_backend.rb +10 -2
- data/lib/tina4/queue_backends/lite_backend.rb +6 -0
- data/lib/tina4/queue_backends/mongo_backend.rb +6 -0
- data/lib/tina4/queue_backends/rabbitmq_backend.rb +10 -2
- data/lib/tina4/rack_app.rb +11 -1
- data/lib/tina4/rate_limiter.rb +6 -0
- data/lib/tina4/realtime/attachment.rb +6 -0
- data/lib/tina4/realtime/channel.rb +6 -0
- data/lib/tina4/realtime/channel_member.rb +6 -0
- data/lib/tina4/realtime/local_storage.rb +6 -0
- data/lib/tina4/realtime/message.rb +6 -0
- data/lib/tina4/realtime/s3_storage.rb +6 -0
- data/lib/tina4/realtime/storage.rb +6 -0
- data/lib/tina4/realtime/storage_backend.rb +6 -0
- data/lib/tina4/realtime/workspace.rb +6 -0
- data/lib/tina4/realtime.rb +10 -3
- data/lib/tina4/request.rb +85 -127
- data/lib/tina4/response.rb +71 -9
- data/lib/tina4/response_cache.rb +6 -0
- data/lib/tina4/router.rb +6 -0
- data/lib/tina4/secret_file.rb +34 -0
- data/lib/tina4/seeder.rb +9 -3
- data/lib/tina4/service.rb +8 -2
- data/lib/tina4/service_runner.rb +6 -0
- data/lib/tina4/session.rb +6 -0
- data/lib/tina4/session_handlers/database_handler.rb +6 -0
- data/lib/tina4/session_handlers/file_handler.rb +6 -0
- data/lib/tina4/session_handlers/memcached_handler.rb +6 -0
- data/lib/tina4/session_handlers/mongo_handler.rb +108 -39
- data/lib/tina4/session_handlers/mongo_wire_client.rb +23 -9
- data/lib/tina4/session_handlers/redis_handler.rb +6 -0
- data/lib/tina4/session_handlers/resp_client.rb +6 -0
- data/lib/tina4/session_handlers/valkey_handler.rb +6 -0
- data/lib/tina4/shutdown.rb +17 -14
- data/lib/tina4/smtp_client.rb +222 -0
- data/lib/tina4/sql_translator.rb +93 -0
- data/lib/tina4/sqlite3_gem.rb +27 -0
- data/lib/tina4/sso.rb +25 -8
- data/lib/tina4/swagger.rb +6 -0
- data/lib/tina4/template.rb +6 -0
- data/lib/tina4/test.rb +8 -2
- data/lib/tina4/test_client.rb +8 -1
- data/lib/tina4/testing.rb +8 -1
- data/lib/tina4/validator.rb +6 -0
- data/lib/tina4/version.rb +7 -1
- data/lib/tina4/webserver.rb +25 -143
- data/lib/tina4/websocket.rb +10 -4
- data/lib/tina4/websocket_backplane.rb +19 -2
- data/lib/tina4/wsdl.rb +31 -16
- data/lib/tina4/xml_parser.rb +259 -0
- data/lib/tina4.rb +87 -31
- data/lib/tina4ruby.rb +6 -0
- metadata +43 -140
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: Auth — JWT login with a visual demo page.
|
|
2
8
|
|
|
3
9
|
Tina4::Router.get("/gallery/auth") do |request, response|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: Database — raw SQL query demo.
|
|
2
8
|
|
|
3
9
|
Tina4::Router.get("/api/gallery/db/tables") do |request, response|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: Error Overlay — deliberately crash to demo the debug overlay.
|
|
2
8
|
#
|
|
3
9
|
# This route deliberately raises an error to showcase the error overlay.
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: ORM — Product CRUD endpoints.
|
|
2
8
|
|
|
3
9
|
Tina4::Router.get("/api/gallery/products") do |request, response|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: Queue — interactive queue demo with visual web UI.
|
|
2
8
|
#
|
|
3
9
|
# Uses a SQLite database directly for the demo queue table,
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: REST API — simple JSON endpoints.
|
|
2
8
|
|
|
3
9
|
Tina4::Router.get("/api/gallery/hello") do |request, response|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2026 Code Infinity
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
1
7
|
# Gallery: Templates — render an HTML page with dynamic data via template.
|
|
2
8
|
|
|
3
9
|
Tina4::Router.get "/gallery/page", template: "gallery_page.twig" do |request, response|
|
data/lib/tina4/graph.rb
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# Copyright (c) 2026 Code Infinity
|
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
2
8
|
|
|
3
9
|
require "uri"
|
|
4
10
|
|
data/lib/tina4/graphql.rb
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: false
|
|
2
|
+
# Copyright (c) 2026 Code Infinity
|
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
2
8
|
|
|
3
9
|
require "json"
|
|
10
|
+
require_relative "parse_json"
|
|
4
11
|
|
|
5
12
|
module Tina4
|
|
6
13
|
# Lightweight, zero-dependency GraphQL implementation for Tina4 Ruby.
|
|
@@ -140,9 +147,15 @@ module Tina4
|
|
|
140
147
|
# ── Queries ──
|
|
141
148
|
|
|
142
149
|
# Single record: user(id: ID!): User
|
|
150
|
+
# The row an ID argument addresses, or nil. The ID is bound, never
|
|
151
|
+
# interpolated, and a non-integer ID on an integer key addresses nothing.
|
|
152
|
+
find_addressed = lambda do |raw_id|
|
|
153
|
+
pk_value = klass.respond_to?(:coerce_primary_key) ? klass.coerce_primary_key(raw_id) : raw_id
|
|
154
|
+
pk_value.nil? ? nil : klass.find_by_id(pk_value)
|
|
155
|
+
end
|
|
156
|
+
|
|
143
157
|
add_query(table_lower, { pk_field => { type: "ID!" } }, type_name) do |_root, args, _ctx|
|
|
144
|
-
|
|
145
|
-
record&.to_hash
|
|
158
|
+
find_addressed.call(args[pk_field])&.to_hash
|
|
146
159
|
end
|
|
147
160
|
|
|
148
161
|
# List: users(limit: Int, offset: Int): [User]
|
|
@@ -163,8 +176,10 @@ module Tina4
|
|
|
163
176
|
|
|
164
177
|
# Update
|
|
165
178
|
add_mutation("update#{model_name}", { pk_field => { type: "ID!" }, "input" => { type: "#{type_name}Input!" } }, type_name) do |_root, args, _ctx|
|
|
166
|
-
record =
|
|
167
|
-
return
|
|
179
|
+
record = find_addressed.call(args[pk_field])
|
|
180
|
+
# `next`, not `return`: this block outlives from_orm, so a `return` here
|
|
181
|
+
# raised LocalJumpError (an internal error) for a non-matching id.
|
|
182
|
+
next nil unless record
|
|
168
183
|
(args["input"] || {}).each { |k, v| record.send(:"#{k}=", v) if record.respond_to?(:"#{k}=") }
|
|
169
184
|
record.save
|
|
170
185
|
record.to_hash
|
|
@@ -172,8 +187,8 @@ module Tina4
|
|
|
172
187
|
|
|
173
188
|
# Delete
|
|
174
189
|
add_mutation("delete#{model_name}", { pk_field => { type: "ID!" } }, "Boolean") do |_root, args, _ctx|
|
|
175
|
-
record =
|
|
176
|
-
|
|
190
|
+
record = find_addressed.call(args[pk_field])
|
|
191
|
+
next false unless record
|
|
177
192
|
record.delete
|
|
178
193
|
true
|
|
179
194
|
end
|
|
@@ -217,8 +232,6 @@ module Tina4
|
|
|
217
232
|
def parse
|
|
218
233
|
document = { kind: :document, definitions: [] }
|
|
219
234
|
while current
|
|
220
|
-
skip(:comma)
|
|
221
|
-
break unless current
|
|
222
235
|
document[:definitions] << parse_definition
|
|
223
236
|
end
|
|
224
237
|
document
|
|
@@ -234,8 +247,10 @@ module Tina4
|
|
|
234
247
|
while i < src.length
|
|
235
248
|
ch = src[i]
|
|
236
249
|
|
|
237
|
-
# Skip whitespace
|
|
238
|
-
|
|
250
|
+
# Skip whitespace. Commas are insignificant in GraphQL (spec 2.1.7) and
|
|
251
|
+
# are skipped with it; emitting them as punctuation made every
|
|
252
|
+
# comma-separated argument or field list a parse error.
|
|
253
|
+
if ch =~ /\s/ || ch == ","
|
|
239
254
|
i += 1
|
|
240
255
|
next
|
|
241
256
|
end
|
|
@@ -247,7 +262,7 @@ module Tina4
|
|
|
247
262
|
end
|
|
248
263
|
|
|
249
264
|
# Punctuation
|
|
250
|
-
if "{}()[]
|
|
265
|
+
if "{}()[]!:=@$".include?(ch)
|
|
251
266
|
tokens << Token.new(:punct, ch, i)
|
|
252
267
|
i += 1
|
|
253
268
|
next
|
|
@@ -355,10 +370,6 @@ module Tina4
|
|
|
355
370
|
advance
|
|
356
371
|
end
|
|
357
372
|
|
|
358
|
-
def skip(type, value = nil)
|
|
359
|
-
match(type, value) while current && current.type == type && (value.nil? || current.value == value)
|
|
360
|
-
end
|
|
361
|
-
|
|
362
373
|
# ── Parse rules ──
|
|
363
374
|
|
|
364
375
|
def parse_definition
|
|
@@ -401,8 +412,6 @@ module Tina4
|
|
|
401
412
|
expect(:punct, "(")
|
|
402
413
|
vars = []
|
|
403
414
|
until current&.value == ")"
|
|
404
|
-
skip(:comma)
|
|
405
|
-
break if current&.value == ")"
|
|
406
415
|
expect(:punct, "$")
|
|
407
416
|
vname = expect(:name).value
|
|
408
417
|
expect(:punct, ":")
|
|
@@ -433,8 +442,6 @@ module Tina4
|
|
|
433
442
|
expect(:punct, "{")
|
|
434
443
|
selections = []
|
|
435
444
|
until current&.value == "}"
|
|
436
|
-
skip(:comma)
|
|
437
|
-
break if current&.value == "}"
|
|
438
445
|
|
|
439
446
|
if current&.type == :spread
|
|
440
447
|
selections << parse_fragment_spread
|
|
@@ -496,8 +503,6 @@ module Tina4
|
|
|
496
503
|
expect(:punct, "(")
|
|
497
504
|
args = {}
|
|
498
505
|
until current&.value == ")"
|
|
499
|
-
skip(:comma)
|
|
500
|
-
break if current&.value == ")"
|
|
501
506
|
arg_name = expect(:name).value
|
|
502
507
|
expect(:punct, ":")
|
|
503
508
|
args[arg_name] = parse_value
|
|
@@ -547,8 +552,6 @@ module Tina4
|
|
|
547
552
|
expect(:punct, "[")
|
|
548
553
|
items = []
|
|
549
554
|
until current&.value == "]"
|
|
550
|
-
skip(:comma)
|
|
551
|
-
break if current&.value == "]"
|
|
552
555
|
items << parse_value
|
|
553
556
|
end
|
|
554
557
|
expect(:punct, "]")
|
|
@@ -559,8 +562,6 @@ module Tina4
|
|
|
559
562
|
expect(:punct, "{")
|
|
560
563
|
obj = {}
|
|
561
564
|
until current&.value == "}"
|
|
562
|
-
skip(:comma)
|
|
563
|
-
break if current&.value == "}"
|
|
564
565
|
key = expect(:name).value
|
|
565
566
|
expect(:punct, ":")
|
|
566
567
|
obj[key] = parse_value
|
|
@@ -1057,7 +1058,7 @@ module Tina4
|
|
|
1057
1058
|
|
|
1058
1059
|
# Handle an HTTP request body (JSON string)
|
|
1059
1060
|
def handle_request(body, context: {})
|
|
1060
|
-
payload =
|
|
1061
|
+
payload = Tina4.parse_json(body)
|
|
1061
1062
|
query = payload["query"] || ""
|
|
1062
1063
|
variables = payload["variables"] || {}
|
|
1063
1064
|
op_name = payload["operationName"]
|
|
@@ -1094,7 +1095,7 @@ module Tina4
|
|
|
1094
1095
|
query = request.query["query"]
|
|
1095
1096
|
if query
|
|
1096
1097
|
variables = request.query["variables"]
|
|
1097
|
-
variables =
|
|
1098
|
+
variables = Tina4.parse_json(variables) if variables.is_a?(String) && !variables.empty?
|
|
1098
1099
|
result = graphql.execute(query, variables: variables || {}, context: { request: request })
|
|
1099
1100
|
response.json(result)
|
|
1100
1101
|
else
|
data/lib/tina4/health.rb
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# Copyright (c) 2026 Code Infinity
|
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
2
8
|
|
|
3
9
|
require "json"
|
|
4
10
|
|
data/lib/tina4/html_element.rb
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# Copyright (c) 2026 Code Infinity
|
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
2
8
|
|
|
3
9
|
module Tina4
|
|
4
10
|
# Marker for trusted, pre-sanitised HTML that must render UNESCAPED.
|