tina4ruby 0.5.2 → 3.2.1
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 +1 -1
- data/README.md +434 -544
- data/exe/{tina4 → tina4ruby} +1 -0
- data/lib/tina4/ai.rb +312 -0
- data/lib/tina4/auth.rb +44 -3
- data/lib/tina4/auto_crud.rb +163 -0
- data/lib/tina4/cli.rb +389 -97
- data/lib/tina4/constants.rb +46 -0
- data/lib/tina4/cors.rb +74 -0
- data/lib/tina4/database/sqlite3_adapter.rb +139 -0
- data/lib/tina4/database.rb +144 -7
- data/lib/tina4/debug.rb +4 -79
- data/lib/tina4/dev_admin.rb +1162 -0
- data/lib/tina4/dev_mailbox.rb +191 -0
- data/lib/tina4/dev_reload.rb +9 -9
- data/lib/tina4/drivers/firebird_driver.rb +19 -3
- data/lib/tina4/drivers/mssql_driver.rb +3 -3
- data/lib/tina4/drivers/mysql_driver.rb +4 -4
- data/lib/tina4/drivers/postgres_driver.rb +9 -2
- data/lib/tina4/drivers/sqlite_driver.rb +1 -1
- data/lib/tina4/env.rb +42 -2
- data/lib/tina4/error_overlay.rb +252 -0
- data/lib/tina4/events.rb +90 -0
- data/lib/tina4/field_types.rb +4 -0
- data/lib/tina4/frond.rb +1497 -0
- data/lib/tina4/gallery/auth/meta.json +1 -0
- data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +114 -0
- data/lib/tina4/gallery/database/meta.json +1 -0
- data/lib/tina4/gallery/database/src/routes/api/gallery_db.rb +43 -0
- data/lib/tina4/gallery/error-overlay/meta.json +1 -0
- data/lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb +17 -0
- data/lib/tina4/gallery/orm/meta.json +1 -0
- data/lib/tina4/gallery/orm/src/routes/api/gallery_products.rb +16 -0
- data/lib/tina4/gallery/queue/meta.json +1 -0
- data/lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb +325 -0
- data/lib/tina4/gallery/rest-api/meta.json +1 -0
- data/lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb +14 -0
- data/lib/tina4/gallery/templates/meta.json +1 -0
- data/lib/tina4/gallery/templates/src/routes/gallery_page.rb +12 -0
- data/lib/tina4/gallery/templates/src/templates/gallery_page.twig +257 -0
- data/lib/tina4/health.rb +39 -0
- data/lib/tina4/html_element.rb +148 -0
- data/lib/tina4/localization.rb +2 -2
- data/lib/tina4/log.rb +203 -0
- data/lib/tina4/messenger.rb +562 -0
- data/lib/tina4/migration.rb +132 -29
- data/lib/tina4/orm.rb +463 -35
- data/lib/tina4/public/css/tina4.css +178 -1
- data/lib/tina4/public/css/tina4.min.css +1 -2
- data/lib/tina4/public/favicon.ico +0 -0
- data/lib/tina4/public/images/logo.svg +5 -0
- data/lib/tina4/public/images/tina4-logo-icon.webp +0 -0
- data/lib/tina4/public/js/frond.min.js +420 -0
- data/lib/tina4/public/js/tina4-dev-admin.min.js +367 -0
- data/lib/tina4/public/js/tina4.min.js +93 -0
- data/lib/tina4/public/swagger/index.html +90 -0
- data/lib/tina4/public/swagger/oauth2-redirect.html +63 -0
- data/lib/tina4/queue.rb +162 -6
- data/lib/tina4/queue_backends/lite_backend.rb +88 -0
- data/lib/tina4/rack_app.rb +331 -27
- data/lib/tina4/rate_limiter.rb +123 -0
- data/lib/tina4/request.rb +61 -15
- data/lib/tina4/response.rb +54 -24
- data/lib/tina4/response_cache.rb +551 -0
- data/lib/tina4/router.rb +90 -15
- data/lib/tina4/scss_compiler.rb +2 -2
- data/lib/tina4/seeder.rb +56 -61
- data/lib/tina4/service_runner.rb +303 -0
- data/lib/tina4/session.rb +85 -0
- data/lib/tina4/session_handlers/mongo_handler.rb +1 -1
- data/lib/tina4/session_handlers/valkey_handler.rb +43 -0
- data/lib/tina4/shutdown.rb +84 -0
- data/lib/tina4/sql_translation.rb +295 -0
- data/lib/tina4/template.rb +36 -6
- data/lib/tina4/templates/base.twig +2 -2
- data/lib/tina4/templates/errors/302.twig +14 -0
- data/lib/tina4/templates/errors/401.twig +9 -0
- data/lib/tina4/templates/errors/403.twig +22 -15
- data/lib/tina4/templates/errors/404.twig +22 -15
- data/lib/tina4/templates/errors/500.twig +31 -15
- data/lib/tina4/templates/errors/502.twig +9 -0
- data/lib/tina4/templates/errors/503.twig +12 -0
- data/lib/tina4/templates/errors/base.twig +37 -0
- data/lib/tina4/version.rb +1 -1
- data/lib/tina4/webserver.rb +28 -18
- data/lib/tina4.rb +118 -21
- metadata +68 -8
- data/lib/tina4/public/js/tina4.js +0 -134
- data/lib/tina4/public/js/tina4helper.js +0 -387
data/lib/tina4/webserver.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Tina4
|
|
4
4
|
class WebServer
|
|
5
|
-
def initialize(app, host: "0.0.0.0", port:
|
|
5
|
+
def initialize(app, host: "0.0.0.0", port: 7147)
|
|
6
6
|
@app = app
|
|
7
7
|
@host = host
|
|
8
8
|
@port = port
|
|
@@ -11,8 +11,8 @@ module Tina4
|
|
|
11
11
|
def start
|
|
12
12
|
require "webrick"
|
|
13
13
|
require "stringio"
|
|
14
|
-
Tina4.print_banner
|
|
15
|
-
Tina4::
|
|
14
|
+
Tina4.print_banner(host: @host, port: @port)
|
|
15
|
+
Tina4::Log.info("Starting Tina4 WEBrick server on http://#{@host}:#{@port}")
|
|
16
16
|
@server = WEBrick::HTTPServer.new(
|
|
17
17
|
BindAddress: @host,
|
|
18
18
|
Port: @port,
|
|
@@ -20,6 +20,9 @@ module Tina4
|
|
|
20
20
|
AccessLog: []
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
# Setup graceful shutdown with WEBrick server reference
|
|
24
|
+
Tina4::Shutdown.setup(server: @server)
|
|
25
|
+
|
|
23
26
|
# Use a custom servlet that passes ALL methods (including OPTIONS) to Rack
|
|
24
27
|
rack_app = @app
|
|
25
28
|
servlet = Class.new(WEBrick::HTTPServlet::AbstractServlet) do
|
|
@@ -35,21 +38,31 @@ module Tina4
|
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
define_method(:handle_request) do |webrick_req, webrick_res|
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
# Reject new requests during shutdown
|
|
42
|
+
if Tina4::Shutdown.shutting_down?
|
|
43
|
+
webrick_res.status = 503
|
|
44
|
+
webrick_res.body = '{"error":"Service shutting down"}'
|
|
45
|
+
webrick_res["content-type"] = "application/json"
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Tina4::Shutdown.track_request do
|
|
50
|
+
env = build_rack_env(webrick_req)
|
|
51
|
+
status, headers, body = @app.call(env)
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
webrick_res.status = status
|
|
54
|
+
headers.each do |key, value|
|
|
55
|
+
if key.downcase == "set-cookie"
|
|
56
|
+
Array(value.split("\n")).each { |c| webrick_res.cookies << WEBrick::Cookie.parse_set_cookie(c) }
|
|
57
|
+
else
|
|
58
|
+
webrick_res[key] = value
|
|
59
|
+
end
|
|
47
60
|
end
|
|
48
|
-
end
|
|
49
61
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
response_body = ""
|
|
63
|
+
body.each { |chunk| response_body += chunk }
|
|
64
|
+
webrick_res.body = response_body
|
|
65
|
+
end
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
define_method(:build_rack_env) do |req|
|
|
@@ -88,9 +101,6 @@ module Tina4
|
|
|
88
101
|
servlet.define_method(:webrick_req_port) { port }
|
|
89
102
|
|
|
90
103
|
@server.mount("/", servlet, rack_app)
|
|
91
|
-
|
|
92
|
-
trap("INT") { @server.shutdown }
|
|
93
|
-
trap("TERM") { @server.shutdown }
|
|
94
104
|
@server.start
|
|
95
105
|
end
|
|
96
106
|
|
data/lib/tina4.rb
CHANGED
|
@@ -10,7 +10,9 @@ end
|
|
|
10
10
|
|
|
11
11
|
# ── Core (always loaded) ──────────────────────────────────────────────
|
|
12
12
|
require_relative "tina4/version"
|
|
13
|
-
require_relative "tina4/
|
|
13
|
+
require_relative "tina4/constants"
|
|
14
|
+
require_relative "tina4/log"
|
|
15
|
+
require_relative "tina4/debug" # backward compat alias
|
|
14
16
|
require_relative "tina4/env"
|
|
15
17
|
require_relative "tina4/router"
|
|
16
18
|
require_relative "tina4/request"
|
|
@@ -21,13 +23,30 @@ require_relative "tina4/database_result"
|
|
|
21
23
|
require_relative "tina4/field_types"
|
|
22
24
|
require_relative "tina4/orm"
|
|
23
25
|
require_relative "tina4/migration"
|
|
26
|
+
require_relative "tina4/auto_crud"
|
|
27
|
+
require_relative "tina4/database/sqlite3_adapter"
|
|
24
28
|
require_relative "tina4/template"
|
|
29
|
+
require_relative "tina4/frond"
|
|
25
30
|
require_relative "tina4/auth"
|
|
26
31
|
require_relative "tina4/session"
|
|
27
32
|
require_relative "tina4/middleware"
|
|
33
|
+
require_relative "tina4/cors"
|
|
34
|
+
require_relative "tina4/rate_limiter"
|
|
35
|
+
require_relative "tina4/health"
|
|
36
|
+
require_relative "tina4/shutdown"
|
|
28
37
|
require_relative "tina4/localization"
|
|
29
38
|
require_relative "tina4/container"
|
|
30
39
|
require_relative "tina4/queue"
|
|
40
|
+
require_relative "tina4/service_runner"
|
|
41
|
+
require_relative "tina4/events"
|
|
42
|
+
require_relative "tina4/dev_admin"
|
|
43
|
+
require_relative "tina4/messenger"
|
|
44
|
+
require_relative "tina4/dev_mailbox"
|
|
45
|
+
require_relative "tina4/ai"
|
|
46
|
+
require_relative "tina4/sql_translation"
|
|
47
|
+
require_relative "tina4/response_cache"
|
|
48
|
+
require_relative "tina4/html_element"
|
|
49
|
+
require_relative "tina4/error_overlay"
|
|
31
50
|
|
|
32
51
|
module Tina4
|
|
33
52
|
# ── Lazy-loaded: database drivers ─────────────────────────────────────
|
|
@@ -43,7 +62,8 @@ module Tina4
|
|
|
43
62
|
module SessionHandlers
|
|
44
63
|
autoload :FileHandler, File.expand_path("tina4/session_handlers/file_handler", __dir__)
|
|
45
64
|
autoload :RedisHandler, File.expand_path("tina4/session_handlers/redis_handler", __dir__)
|
|
46
|
-
autoload :MongoHandler,
|
|
65
|
+
autoload :MongoHandler, File.expand_path("tina4/session_handlers/mongo_handler", __dir__)
|
|
66
|
+
autoload :ValkeyHandler, File.expand_path("tina4/session_handlers/valkey_handler", __dir__)
|
|
47
67
|
end
|
|
48
68
|
|
|
49
69
|
# ── Lazy-loaded: queue backends ───────────────────────────────────────
|
|
@@ -73,27 +93,52 @@ module Tina4
|
|
|
73
93
|
autoload :ScssCompiler, File.expand_path("tina4/scss_compiler", __dir__)
|
|
74
94
|
autoload :DevReload, File.expand_path("tina4/dev_reload", __dir__)
|
|
75
95
|
autoload :FakeData, File.expand_path("tina4/seeder", __dir__)
|
|
76
|
-
autoload :Seeder, File.expand_path("tina4/seeder", __dir__)
|
|
77
96
|
autoload :WSDL, File.expand_path("tina4/wsdl", __dir__)
|
|
78
97
|
BANNER = <<~'BANNER'
|
|
79
98
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝
|
|
99
|
+
______ _ __ __
|
|
100
|
+
/_ __/(_)___ ____ _/ // /
|
|
101
|
+
/ / / / __ \/ __ `/ // /_
|
|
102
|
+
/ / / / / / / /_/ /__ __/
|
|
103
|
+
/_/ /_/_/ /_/\__,_/ /_/
|
|
86
104
|
BANNER
|
|
87
105
|
|
|
88
106
|
class << self
|
|
89
107
|
attr_accessor :root_dir, :database
|
|
90
108
|
|
|
91
|
-
def print_banner
|
|
92
|
-
|
|
93
|
-
|
|
109
|
+
def print_banner(host: "0.0.0.0", port: 7147, server_name: nil)
|
|
110
|
+
is_tty = $stdout.respond_to?(:isatty) && $stdout.isatty
|
|
111
|
+
color = is_tty ? "\e[31m" : ""
|
|
112
|
+
reset = is_tty ? "\e[0m" : ""
|
|
113
|
+
|
|
114
|
+
is_debug = Tina4::Env.truthy?(ENV["TINA4_DEBUG"])
|
|
115
|
+
log_level = (ENV["TINA4_LOG_LEVEL"] || "[TINA4_LOG_ALL]").upcase
|
|
116
|
+
display = (host == "0.0.0.0" || host == "::") ? "localhost" : host
|
|
117
|
+
|
|
118
|
+
# Auto-detect server name if not provided
|
|
119
|
+
if server_name.nil?
|
|
120
|
+
if is_debug
|
|
121
|
+
server_name = "WEBrick"
|
|
122
|
+
else
|
|
123
|
+
begin
|
|
124
|
+
require "puma"
|
|
125
|
+
server_name = "puma"
|
|
126
|
+
rescue LoadError
|
|
127
|
+
server_name = "WEBrick"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
puts "#{color}#{BANNER}#{reset}"
|
|
133
|
+
puts " Tina4 Ruby v#{VERSION} — This is not a framework"
|
|
134
|
+
puts ""
|
|
135
|
+
puts " Server: http://#{display}:#{port} (#{server_name})"
|
|
136
|
+
puts " Swagger: http://localhost:#{port}/swagger"
|
|
137
|
+
puts " Dashboard: http://localhost:#{port}/__dev"
|
|
138
|
+
puts " Debug: #{is_debug ? 'ON' : 'OFF'} (Log level: #{log_level})"
|
|
94
139
|
puts ""
|
|
95
140
|
rescue
|
|
96
|
-
puts "
|
|
141
|
+
puts "#{color}TINA4 Ruby v#{VERSION}#{reset}"
|
|
97
142
|
end
|
|
98
143
|
|
|
99
144
|
def initialize!(root_dir = Dir.pwd)
|
|
@@ -103,11 +148,11 @@ module Tina4
|
|
|
103
148
|
print_banner
|
|
104
149
|
|
|
105
150
|
# Load environment
|
|
106
|
-
Tina4::Env.
|
|
151
|
+
Tina4::Env.load_env(root_dir)
|
|
107
152
|
|
|
108
153
|
# Setup debug logging
|
|
109
|
-
Tina4::
|
|
110
|
-
Tina4::
|
|
154
|
+
Tina4::Log.setup(root_dir)
|
|
155
|
+
Tina4::Log.info("Tina4 Ruby v#{VERSION} initializing...")
|
|
111
156
|
|
|
112
157
|
# Setup auth keys
|
|
113
158
|
Tina4::Auth.setup(root_dir)
|
|
@@ -121,7 +166,54 @@ module Tina4
|
|
|
121
166
|
# Auto-discover routes
|
|
122
167
|
auto_discover(root_dir)
|
|
123
168
|
|
|
124
|
-
Tina4::
|
|
169
|
+
Tina4::Log.info("Tina4 initialized successfully")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Initialize and start the web server.
|
|
173
|
+
# This is the primary entry point for app.rb files:
|
|
174
|
+
# Tina4.initialize!(__dir__)
|
|
175
|
+
# Tina4.run!
|
|
176
|
+
# Or combined: Tina4.run!(__dir__)
|
|
177
|
+
def run!(root_dir = Dir.pwd)
|
|
178
|
+
initialize!(root_dir) unless @root_dir
|
|
179
|
+
|
|
180
|
+
host = ENV.fetch("HOST", ENV.fetch("TINA4_HOST", "0.0.0.0"))
|
|
181
|
+
port = ENV.fetch("PORT", ENV.fetch("TINA4_PORT", "7147")).to_i
|
|
182
|
+
|
|
183
|
+
app = Tina4::RackApp.new(root_dir: root_dir)
|
|
184
|
+
is_debug = Tina4::Env.truthy?(ENV["TINA4_DEBUG"])
|
|
185
|
+
|
|
186
|
+
# Try Puma first (production-grade), fall back to WEBrick
|
|
187
|
+
if !is_debug
|
|
188
|
+
begin
|
|
189
|
+
require "puma"
|
|
190
|
+
require "puma/configuration"
|
|
191
|
+
require "puma/launcher"
|
|
192
|
+
|
|
193
|
+
config = Puma::Configuration.new do |user_config|
|
|
194
|
+
user_config.bind "tcp://#{host}:#{port}"
|
|
195
|
+
user_config.app app
|
|
196
|
+
user_config.threads 0, 16
|
|
197
|
+
user_config.workers 0
|
|
198
|
+
user_config.environment "production"
|
|
199
|
+
user_config.log_requests false
|
|
200
|
+
user_config.quiet
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
Tina4::Log.info("Production server: puma")
|
|
204
|
+
Tina4::Shutdown.setup
|
|
205
|
+
|
|
206
|
+
launcher = Puma::Launcher.new(config)
|
|
207
|
+
launcher.run
|
|
208
|
+
return
|
|
209
|
+
rescue LoadError
|
|
210
|
+
# Puma not installed, fall through to WEBrick
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
Tina4::Log.info("Development server: WEBrick")
|
|
215
|
+
server = Tina4::WebServer.new(app, host: host, port: port)
|
|
216
|
+
server.start
|
|
125
217
|
end
|
|
126
218
|
|
|
127
219
|
# DSL methods for route registration
|
|
@@ -218,6 +310,11 @@ module Tina4
|
|
|
218
310
|
Tina4::Localization.t(key, **options)
|
|
219
311
|
end
|
|
220
312
|
|
|
313
|
+
# Service runner DSL
|
|
314
|
+
def service(name, options = {}, &block)
|
|
315
|
+
Tina4::ServiceRunner.register(name, nil, options, &block)
|
|
316
|
+
end
|
|
317
|
+
|
|
221
318
|
# DI container shortcuts
|
|
222
319
|
def register(name, instance = nil, &block)
|
|
223
320
|
Tina4::Container.register(name, instance, &block)
|
|
@@ -250,9 +347,9 @@ module Tina4
|
|
|
250
347
|
if db_url && !db_url.empty?
|
|
251
348
|
begin
|
|
252
349
|
@database = Tina4::Database.new(db_url)
|
|
253
|
-
Tina4::
|
|
350
|
+
Tina4::Log.info("Database connected: #{db_url.sub(/:[^:@]+@/, ':***@')}")
|
|
254
351
|
rescue => e
|
|
255
|
-
Tina4::
|
|
352
|
+
Tina4::Log.error("Database connection failed: #{e.message}")
|
|
256
353
|
end
|
|
257
354
|
end
|
|
258
355
|
end
|
|
@@ -266,9 +363,9 @@ module Tina4
|
|
|
266
363
|
Dir.glob(File.join(full_dir, "**/*.rb")).sort.each do |file|
|
|
267
364
|
begin
|
|
268
365
|
load file
|
|
269
|
-
Tina4::
|
|
366
|
+
Tina4::Log.debug("Auto-loaded: #{file}")
|
|
270
367
|
rescue => e
|
|
271
|
-
Tina4::
|
|
368
|
+
Tina4::Log.error("Failed to load #{file}: #{e.message}")
|
|
272
369
|
end
|
|
273
370
|
end
|
|
274
371
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
@@ -94,19 +94,33 @@ dependencies:
|
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '3.1'
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
|
-
name:
|
|
97
|
+
name: net-smtp
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
100
|
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '
|
|
102
|
+
version: '0.5'
|
|
103
103
|
type: :runtime
|
|
104
104
|
prerelease: false
|
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '
|
|
109
|
+
version: '0.5'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: net-imap
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0.5'
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0.5'
|
|
110
124
|
- !ruby/object:Gem::Dependency
|
|
111
125
|
name: json
|
|
112
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -237,24 +251,31 @@ description: A lightweight, zero-configuration, Windows-friendly Ruby web framew
|
|
|
237
251
|
email:
|
|
238
252
|
- info@tina4.com
|
|
239
253
|
executables:
|
|
240
|
-
-
|
|
254
|
+
- tina4ruby
|
|
241
255
|
extensions: []
|
|
242
256
|
extra_rdoc_files: []
|
|
243
257
|
files:
|
|
244
258
|
- CHANGELOG.md
|
|
245
259
|
- LICENSE.txt
|
|
246
260
|
- README.md
|
|
247
|
-
- exe/
|
|
261
|
+
- exe/tina4ruby
|
|
248
262
|
- lib/tina4.rb
|
|
263
|
+
- lib/tina4/ai.rb
|
|
249
264
|
- lib/tina4/api.rb
|
|
250
265
|
- lib/tina4/auth.rb
|
|
266
|
+
- lib/tina4/auto_crud.rb
|
|
251
267
|
- lib/tina4/cli.rb
|
|
268
|
+
- lib/tina4/constants.rb
|
|
252
269
|
- lib/tina4/container.rb
|
|
270
|
+
- lib/tina4/cors.rb
|
|
253
271
|
- lib/tina4/crud.rb
|
|
254
272
|
- lib/tina4/database.rb
|
|
273
|
+
- lib/tina4/database/sqlite3_adapter.rb
|
|
255
274
|
- lib/tina4/database_result.rb
|
|
256
275
|
- lib/tina4/debug.rb
|
|
257
276
|
- lib/tina4/dev.rb
|
|
277
|
+
- lib/tina4/dev_admin.rb
|
|
278
|
+
- lib/tina4/dev_mailbox.rb
|
|
258
279
|
- lib/tina4/dev_reload.rb
|
|
259
280
|
- lib/tina4/drivers/firebird_driver.rb
|
|
260
281
|
- lib/tina4/drivers/mssql_driver.rb
|
|
@@ -262,23 +283,53 @@ files:
|
|
|
262
283
|
- lib/tina4/drivers/postgres_driver.rb
|
|
263
284
|
- lib/tina4/drivers/sqlite_driver.rb
|
|
264
285
|
- lib/tina4/env.rb
|
|
286
|
+
- lib/tina4/error_overlay.rb
|
|
287
|
+
- lib/tina4/events.rb
|
|
265
288
|
- lib/tina4/field_types.rb
|
|
289
|
+
- lib/tina4/frond.rb
|
|
290
|
+
- lib/tina4/gallery/auth/meta.json
|
|
291
|
+
- lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb
|
|
292
|
+
- lib/tina4/gallery/database/meta.json
|
|
293
|
+
- lib/tina4/gallery/database/src/routes/api/gallery_db.rb
|
|
294
|
+
- lib/tina4/gallery/error-overlay/meta.json
|
|
295
|
+
- lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb
|
|
296
|
+
- lib/tina4/gallery/orm/meta.json
|
|
297
|
+
- lib/tina4/gallery/orm/src/routes/api/gallery_products.rb
|
|
298
|
+
- lib/tina4/gallery/queue/meta.json
|
|
299
|
+
- lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb
|
|
300
|
+
- lib/tina4/gallery/rest-api/meta.json
|
|
301
|
+
- lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb
|
|
302
|
+
- lib/tina4/gallery/templates/meta.json
|
|
303
|
+
- lib/tina4/gallery/templates/src/routes/gallery_page.rb
|
|
304
|
+
- lib/tina4/gallery/templates/src/templates/gallery_page.twig
|
|
266
305
|
- lib/tina4/graphql.rb
|
|
306
|
+
- lib/tina4/health.rb
|
|
307
|
+
- lib/tina4/html_element.rb
|
|
267
308
|
- lib/tina4/localization.rb
|
|
309
|
+
- lib/tina4/log.rb
|
|
310
|
+
- lib/tina4/messenger.rb
|
|
268
311
|
- lib/tina4/middleware.rb
|
|
269
312
|
- lib/tina4/migration.rb
|
|
270
313
|
- lib/tina4/orm.rb
|
|
271
314
|
- lib/tina4/public/css/tina4.css
|
|
272
315
|
- lib/tina4/public/css/tina4.min.css
|
|
273
|
-
- lib/tina4/public/
|
|
274
|
-
- lib/tina4/public/
|
|
316
|
+
- lib/tina4/public/favicon.ico
|
|
317
|
+
- lib/tina4/public/images/logo.svg
|
|
318
|
+
- lib/tina4/public/images/tina4-logo-icon.webp
|
|
319
|
+
- lib/tina4/public/js/frond.min.js
|
|
320
|
+
- lib/tina4/public/js/tina4-dev-admin.min.js
|
|
321
|
+
- lib/tina4/public/js/tina4.min.js
|
|
322
|
+
- lib/tina4/public/swagger/index.html
|
|
323
|
+
- lib/tina4/public/swagger/oauth2-redirect.html
|
|
275
324
|
- lib/tina4/queue.rb
|
|
276
325
|
- lib/tina4/queue_backends/kafka_backend.rb
|
|
277
326
|
- lib/tina4/queue_backends/lite_backend.rb
|
|
278
327
|
- lib/tina4/queue_backends/rabbitmq_backend.rb
|
|
279
328
|
- lib/tina4/rack_app.rb
|
|
329
|
+
- lib/tina4/rate_limiter.rb
|
|
280
330
|
- lib/tina4/request.rb
|
|
281
331
|
- lib/tina4/response.rb
|
|
332
|
+
- lib/tina4/response_cache.rb
|
|
282
333
|
- lib/tina4/router.rb
|
|
283
334
|
- lib/tina4/scss/tina4css/_alerts.scss
|
|
284
335
|
- lib/tina4/scss/tina4css/_badges.scss
|
|
@@ -298,16 +349,25 @@ files:
|
|
|
298
349
|
- lib/tina4/scss/tina4css/tina4.scss
|
|
299
350
|
- lib/tina4/scss_compiler.rb
|
|
300
351
|
- lib/tina4/seeder.rb
|
|
352
|
+
- lib/tina4/service_runner.rb
|
|
301
353
|
- lib/tina4/session.rb
|
|
302
354
|
- lib/tina4/session_handlers/file_handler.rb
|
|
303
355
|
- lib/tina4/session_handlers/mongo_handler.rb
|
|
304
356
|
- lib/tina4/session_handlers/redis_handler.rb
|
|
357
|
+
- lib/tina4/session_handlers/valkey_handler.rb
|
|
358
|
+
- lib/tina4/shutdown.rb
|
|
359
|
+
- lib/tina4/sql_translation.rb
|
|
305
360
|
- lib/tina4/swagger.rb
|
|
306
361
|
- lib/tina4/template.rb
|
|
307
362
|
- lib/tina4/templates/base.twig
|
|
363
|
+
- lib/tina4/templates/errors/302.twig
|
|
364
|
+
- lib/tina4/templates/errors/401.twig
|
|
308
365
|
- lib/tina4/templates/errors/403.twig
|
|
309
366
|
- lib/tina4/templates/errors/404.twig
|
|
310
367
|
- lib/tina4/templates/errors/500.twig
|
|
368
|
+
- lib/tina4/templates/errors/502.twig
|
|
369
|
+
- lib/tina4/templates/errors/503.twig
|
|
370
|
+
- lib/tina4/templates/errors/base.twig
|
|
311
371
|
- lib/tina4/testing.rb
|
|
312
372
|
- lib/tina4/version.rb
|
|
313
373
|
- lib/tina4/webserver.rb
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tina4 CSS — Lightweight JS components
|
|
3
|
-
* Replaces Bootstrap's JavaScript for: modals, alerts, navbar toggler
|
|
4
|
-
* ~3KB unminified, zero dependencies
|
|
5
|
-
*/
|
|
6
|
-
(function () {
|
|
7
|
-
"use strict";
|
|
8
|
-
|
|
9
|
-
// ── Modals ──────────────────────────────────────────────────
|
|
10
|
-
// Usage: <button data-t4-toggle="modal" data-t4-target="#myModal">Open</button>
|
|
11
|
-
// <button data-t4-dismiss="modal">Close</button>
|
|
12
|
-
// Also supports Bootstrap syntax: data-bs-toggle, data-bs-target, data-bs-dismiss
|
|
13
|
-
|
|
14
|
-
function getModalEl(selector) {
|
|
15
|
-
if (!selector) return null;
|
|
16
|
-
return document.querySelector(selector);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function openModal(modal) {
|
|
20
|
-
if (!modal) return;
|
|
21
|
-
// Create backdrop if not exists
|
|
22
|
-
var backdrop = modal._t4Backdrop;
|
|
23
|
-
if (!backdrop) {
|
|
24
|
-
backdrop = document.createElement("div");
|
|
25
|
-
backdrop.className = "modal-backdrop";
|
|
26
|
-
document.body.appendChild(backdrop);
|
|
27
|
-
modal._t4Backdrop = backdrop;
|
|
28
|
-
backdrop.addEventListener("click", function () {
|
|
29
|
-
closeModal(modal);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
modal.style.display = "block";
|
|
33
|
-
backdrop.style.display = "block";
|
|
34
|
-
// Force reflow then add .show for transition
|
|
35
|
-
void modal.offsetHeight;
|
|
36
|
-
modal.classList.add("show");
|
|
37
|
-
backdrop.classList.add("show");
|
|
38
|
-
document.body.style.overflow = "hidden";
|
|
39
|
-
// Focus trap — focus first focusable element
|
|
40
|
-
var focusable = modal.querySelector("input, select, textarea, button, [tabindex]");
|
|
41
|
-
if (focusable) focusable.focus();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function closeModal(modal) {
|
|
45
|
-
if (!modal) return;
|
|
46
|
-
modal.classList.remove("show");
|
|
47
|
-
var backdrop = modal._t4Backdrop;
|
|
48
|
-
if (backdrop) backdrop.classList.remove("show");
|
|
49
|
-
// Wait for transition
|
|
50
|
-
setTimeout(function () {
|
|
51
|
-
modal.style.display = "none";
|
|
52
|
-
if (backdrop) backdrop.style.display = "none";
|
|
53
|
-
document.body.style.overflow = "";
|
|
54
|
-
}, 150);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Delegated click handler for modal triggers
|
|
58
|
-
document.addEventListener("click", function (e) {
|
|
59
|
-
var trigger = e.target.closest("[data-t4-toggle='modal'], [data-bs-toggle='modal']");
|
|
60
|
-
if (trigger) {
|
|
61
|
-
e.preventDefault();
|
|
62
|
-
var target = trigger.getAttribute("data-t4-target") || trigger.getAttribute("data-bs-target") || trigger.getAttribute("href");
|
|
63
|
-
var modal = getModalEl(target);
|
|
64
|
-
if (modal) openModal(modal);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Dismiss button
|
|
69
|
-
var dismiss = e.target.closest("[data-t4-dismiss='modal'], [data-bs-dismiss='modal'], .btn-close");
|
|
70
|
-
if (dismiss) {
|
|
71
|
-
var modal = dismiss.closest(".modal");
|
|
72
|
-
if (modal) closeModal(modal);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// ESC key closes top modal
|
|
78
|
-
document.addEventListener("keydown", function (e) {
|
|
79
|
-
if (e.key === "Escape") {
|
|
80
|
-
var modals = document.querySelectorAll(".modal.show");
|
|
81
|
-
if (modals.length > 0) closeModal(modals[modals.length - 1]);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// ── Alerts (dismissible) ────────────────────────────────────
|
|
86
|
-
// Usage: <div class="alert alert-danger alert-dismissible">
|
|
87
|
-
// Message <button class="btn-close" data-t4-dismiss="alert">×</button>
|
|
88
|
-
// </div>
|
|
89
|
-
|
|
90
|
-
document.addEventListener("click", function (e) {
|
|
91
|
-
var dismiss = e.target.closest("[data-t4-dismiss='alert'], [data-bs-dismiss='alert']");
|
|
92
|
-
if (dismiss) {
|
|
93
|
-
var alert = dismiss.closest(".alert");
|
|
94
|
-
if (alert) {
|
|
95
|
-
alert.style.opacity = "0";
|
|
96
|
-
setTimeout(function () { alert.remove(); }, 150);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// ── Navbar toggler ──────────────────────────────────────────
|
|
102
|
-
// Usage: <button class="navbar-toggler" data-t4-toggle="collapse" data-t4-target="#navContent">
|
|
103
|
-
// ☰
|
|
104
|
-
// </button>
|
|
105
|
-
// <div class="navbar-collapse collapse" id="navContent">...</div>
|
|
106
|
-
|
|
107
|
-
document.addEventListener("click", function (e) {
|
|
108
|
-
var toggler = e.target.closest("[data-t4-toggle='collapse'], [data-bs-toggle='collapse']");
|
|
109
|
-
if (toggler) {
|
|
110
|
-
e.preventDefault();
|
|
111
|
-
var target = toggler.getAttribute("data-t4-target") || toggler.getAttribute("data-bs-target") || toggler.getAttribute("href");
|
|
112
|
-
var el = document.querySelector(target);
|
|
113
|
-
if (el) {
|
|
114
|
-
el.classList.toggle("show");
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// ── Programmatic API ────────────────────────────────────────
|
|
120
|
-
// window.tina4.modal.open("#myModal")
|
|
121
|
-
// window.tina4.modal.close("#myModal")
|
|
122
|
-
|
|
123
|
-
window.tina4 = window.tina4 || {};
|
|
124
|
-
window.tina4.modal = {
|
|
125
|
-
open: function (selector) {
|
|
126
|
-
var modal = typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
127
|
-
openModal(modal);
|
|
128
|
-
},
|
|
129
|
-
close: function (selector) {
|
|
130
|
-
var modal = typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
131
|
-
closeModal(modal);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
})();
|