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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/COMMERCIAL-LICENSE.md +8 -0
  4. data/LICENSE +373 -0
  5. data/LICENSE.txt +373 -21
  6. data/NOTICE +11 -0
  7. data/README.md +11 -7
  8. data/exe/tina4ruby +6 -0
  9. data/lib/tina4/ai.rb +6 -0
  10. data/lib/tina4/ai_client.rb +10 -3
  11. data/lib/tina4/api.rb +57 -7
  12. data/lib/tina4/auth.rb +18 -12
  13. data/lib/tina4/auto_crud.rb +83 -27
  14. data/lib/tina4/background.rb +7 -1
  15. data/lib/tina4/base64.rb +59 -0
  16. data/lib/tina4/cache.rb +6 -0
  17. data/lib/tina4/cache_backends/base_backend.rb +6 -0
  18. data/lib/tina4/cache_backends/database_backend.rb +6 -0
  19. data/lib/tina4/cache_backends/file_backend.rb +6 -0
  20. data/lib/tina4/cache_backends/memcached_backend.rb +6 -0
  21. data/lib/tina4/cache_backends/memory_backend.rb +6 -0
  22. data/lib/tina4/cache_backends/mongo_backend.rb +6 -0
  23. data/lib/tina4/cache_backends/redis_backend.rb +6 -0
  24. data/lib/tina4/cache_backends/valkey_backend.rb +6 -0
  25. data/lib/tina4/cache_backends.rb +6 -0
  26. data/lib/tina4/cli.rb +22 -7
  27. data/lib/tina4/constants.rb +12 -8
  28. data/lib/tina4/container.rb +6 -0
  29. data/lib/tina4/context/chunker.rb +6 -0
  30. data/lib/tina4/context.rb +13 -5
  31. data/lib/tina4/cors.rb +66 -10
  32. data/lib/tina4/crud.rb +78 -9
  33. data/lib/tina4/database/sqlite3_adapter.rb +9 -1
  34. data/lib/tina4/database.rb +260 -44
  35. data/lib/tina4/database_adapter.rb +6 -0
  36. data/lib/tina4/database_result.rb +6 -0
  37. data/lib/tina4/database_url.rb +6 -0
  38. data/lib/tina4/debug.rb +6 -0
  39. data/lib/tina4/dev.rb +6 -0
  40. data/lib/tina4/dev_admin.rb +215 -89
  41. data/lib/tina4/dev_mailbox.rb +6 -1
  42. data/lib/tina4/dispatch_pipeline.rb +86 -1
  43. data/lib/tina4/docs.rb +6 -0
  44. data/lib/tina4/docstore.rb +23 -4
  45. data/lib/tina4/drivers/arango_graph_driver.rb +8 -1
  46. data/lib/tina4/drivers/bolt_graph_driver.rb +6 -0
  47. data/lib/tina4/drivers/firebird_driver.rb +95 -6
  48. data/lib/tina4/drivers/mongodb_driver.rb +6 -0
  49. data/lib/tina4/drivers/mssql_driver.rb +54 -39
  50. data/lib/tina4/drivers/mysql_driver.rb +6 -0
  51. data/lib/tina4/drivers/odbc_driver.rb +6 -0
  52. data/lib/tina4/drivers/postgres_driver.rb +35 -8
  53. data/lib/tina4/drivers/schema_split.rb +6 -0
  54. data/lib/tina4/drivers/sqlite_driver.rb +8 -1
  55. data/lib/tina4/drivers/ultipa_graph_driver.rb +6 -0
  56. data/lib/tina4/env.rb +6 -0
  57. data/lib/tina4/error_overlay.rb +6 -0
  58. data/lib/tina4/events.rb +6 -0
  59. data/lib/tina4/feedback.rb +9 -2
  60. data/lib/tina4/field_types.rb +6 -0
  61. data/lib/tina4/form_parser.rb +241 -0
  62. data/lib/tina4/frond.rb +196 -56
  63. data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +6 -0
  64. data/lib/tina4/gallery/database/src/routes/api/gallery_db.rb +6 -0
  65. data/lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb +6 -0
  66. data/lib/tina4/gallery/orm/src/routes/api/gallery_products.rb +6 -0
  67. data/lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb +6 -0
  68. data/lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb +6 -0
  69. data/lib/tina4/gallery/templates/src/routes/gallery_page.rb +6 -0
  70. data/lib/tina4/graph.rb +6 -0
  71. data/lib/tina4/graphql.rb +28 -27
  72. data/lib/tina4/health.rb +6 -0
  73. data/lib/tina4/html_element.rb +6 -0
  74. data/lib/tina4/http_server.rb +690 -0
  75. data/lib/tina4/imap_client.rb +352 -0
  76. data/lib/tina4/import_helper.rb +6 -0
  77. data/lib/tina4/job.rb +6 -0
  78. data/lib/tina4/localization.rb +6 -0
  79. data/lib/tina4/log.rb +6 -0
  80. data/lib/tina4/mail_socket.rb +124 -0
  81. data/lib/tina4/mcp.rb +15 -8
  82. data/lib/tina4/messenger.rb +86 -55
  83. data/lib/tina4/metrics.rb +6 -0
  84. data/lib/tina4/middleware.rb +24 -9
  85. data/lib/tina4/migration.rb +6 -0
  86. data/lib/tina4/model_collection.rb +6 -0
  87. data/lib/tina4/mqtt.rb +9 -2
  88. data/lib/tina4/mqtt_message.rb +6 -0
  89. data/lib/tina4/orm.rb +72 -16
  90. data/lib/tina4/parse_json.rb +25 -0
  91. data/lib/tina4/plan.rb +9 -2
  92. data/lib/tina4/point.rb +6 -0
  93. data/lib/tina4/port_takeover.rb +6 -0
  94. data/lib/tina4/project_index.rb +6 -0
  95. data/lib/tina4/public/THIRD-PARTY-NOTICES.md +55 -0
  96. data/lib/tina4/public/bundled-component-provenance.json +48 -0
  97. data/lib/tina4/public/js/tina4js.min.js +13 -3
  98. data/lib/tina4/public/licenses/swagger-ui-3.10.0-original-notice.txt +11 -0
  99. data/lib/tina4/public/licenses/swagger-ui-5.17.14-NOTICE.txt +2 -0
  100. data/lib/tina4/public/licenses/swagger-ui-Apache-2.0.txt +202 -0
  101. data/lib/tina4/public/licenses/tina4-css-MIT.txt +21 -0
  102. data/lib/tina4/public/licenses/tina4-dev-admin-components.json +240 -0
  103. data/lib/tina4/public/licenses/tina4-dev-admin-third-party.txt +919 -0
  104. data/lib/tina4/public/licenses/tina4-js-MIT.txt +20 -0
  105. data/lib/tina4/push.rb +9 -3
  106. data/lib/tina4/query_builder.rb +6 -0
  107. data/lib/tina4/queue.rb +6 -0
  108. data/lib/tina4/queue_backends/kafka_backend.rb +10 -2
  109. data/lib/tina4/queue_backends/lite_backend.rb +6 -0
  110. data/lib/tina4/queue_backends/mongo_backend.rb +6 -0
  111. data/lib/tina4/queue_backends/rabbitmq_backend.rb +10 -2
  112. data/lib/tina4/rack_app.rb +11 -1
  113. data/lib/tina4/rate_limiter.rb +6 -0
  114. data/lib/tina4/realtime/attachment.rb +6 -0
  115. data/lib/tina4/realtime/channel.rb +6 -0
  116. data/lib/tina4/realtime/channel_member.rb +6 -0
  117. data/lib/tina4/realtime/local_storage.rb +6 -0
  118. data/lib/tina4/realtime/message.rb +6 -0
  119. data/lib/tina4/realtime/s3_storage.rb +6 -0
  120. data/lib/tina4/realtime/storage.rb +6 -0
  121. data/lib/tina4/realtime/storage_backend.rb +6 -0
  122. data/lib/tina4/realtime/workspace.rb +6 -0
  123. data/lib/tina4/realtime.rb +10 -3
  124. data/lib/tina4/request.rb +85 -127
  125. data/lib/tina4/response.rb +71 -9
  126. data/lib/tina4/response_cache.rb +6 -0
  127. data/lib/tina4/router.rb +6 -0
  128. data/lib/tina4/secret_file.rb +34 -0
  129. data/lib/tina4/seeder.rb +9 -3
  130. data/lib/tina4/service.rb +8 -2
  131. data/lib/tina4/service_runner.rb +6 -0
  132. data/lib/tina4/session.rb +6 -0
  133. data/lib/tina4/session_handlers/database_handler.rb +6 -0
  134. data/lib/tina4/session_handlers/file_handler.rb +6 -0
  135. data/lib/tina4/session_handlers/memcached_handler.rb +6 -0
  136. data/lib/tina4/session_handlers/mongo_handler.rb +108 -39
  137. data/lib/tina4/session_handlers/mongo_wire_client.rb +23 -9
  138. data/lib/tina4/session_handlers/redis_handler.rb +6 -0
  139. data/lib/tina4/session_handlers/resp_client.rb +6 -0
  140. data/lib/tina4/session_handlers/valkey_handler.rb +6 -0
  141. data/lib/tina4/shutdown.rb +17 -14
  142. data/lib/tina4/smtp_client.rb +222 -0
  143. data/lib/tina4/sql_translator.rb +93 -0
  144. data/lib/tina4/sqlite3_gem.rb +27 -0
  145. data/lib/tina4/sso.rb +25 -8
  146. data/lib/tina4/swagger.rb +6 -0
  147. data/lib/tina4/template.rb +6 -0
  148. data/lib/tina4/test.rb +8 -2
  149. data/lib/tina4/test_client.rb +8 -1
  150. data/lib/tina4/testing.rb +8 -1
  151. data/lib/tina4/validator.rb +6 -0
  152. data/lib/tina4/version.rb +7 -1
  153. data/lib/tina4/webserver.rb +25 -143
  154. data/lib/tina4/websocket.rb +10 -4
  155. data/lib/tina4/websocket_backplane.rb +19 -2
  156. data/lib/tina4/wsdl.rb +31 -16
  157. data/lib/tina4/xml_parser.rb +259 -0
  158. data/lib/tina4.rb +87 -31
  159. data/lib/tina4ruby.rb +6 -0
  160. 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
- record = klass.find_by_id(args[pk_field])
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 = klass.find_by_id(args[pk_field])
167
- return nil unless record
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 = klass.find_by_id(args[pk_field])
176
- return false unless record
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
- if ch =~ /\s/
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 "{}()[]!:=@$,".include?(ch)
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 = JSON.parse(body)
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 = JSON.parse(variables) if variables.is_a?(String) && !variables.empty?
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
 
@@ -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.