tina4ruby 3.13.37 → 3.13.39
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/README.md +7 -7
- data/lib/tina4/api.rb +43 -1
- data/lib/tina4/auth.rb +118 -7
- data/lib/tina4/cli.rb +110 -2
- data/lib/tina4/database.rb +407 -52
- data/lib/tina4/dev_admin.rb +47 -14
- data/lib/tina4/drivers/sqlite_driver.rb +23 -0
- data/lib/tina4/env.rb +40 -4
- data/lib/tina4/events.rb +54 -8
- data/lib/tina4/field_types.rb +5 -2
- data/lib/tina4/graphql.rb +68 -12
- data/lib/tina4/html_element.rb +55 -7
- data/lib/tina4/log.rb +86 -10
- data/lib/tina4/mcp.rb +35 -8
- data/lib/tina4/messenger.rb +130 -25
- data/lib/tina4/metrics.rb +351 -73
- data/lib/tina4/middleware.rb +136 -13
- data/lib/tina4/migration.rb +113 -24
- data/lib/tina4/orm.rb +196 -32
- data/lib/tina4/query_builder.rb +22 -3
- data/lib/tina4/queue_backends/kafka_backend.rb +39 -2
- data/lib/tina4/rack_app.rb +22 -10
- data/lib/tina4/response.rb +31 -11
- data/lib/tina4/router.rb +34 -4
- data/lib/tina4/seeder.rb +433 -84
- data/lib/tina4/session.rb +94 -17
- data/lib/tina4/version.rb +1 -1
- data/lib/tina4/websocket.rb +458 -21
- data/lib/tina4/wsdl.rb +25 -2
- data/lib/tina4.rb +91 -12
- metadata +6 -47
data/lib/tina4.rb
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# ── Fast JSON: use oj if available, fall back to stdlib json ──────────
|
|
4
|
-
begin
|
|
5
|
-
require "oj"
|
|
6
|
-
Oj.default_options = { mode: :compat, symbol_keys: false }
|
|
7
|
-
rescue LoadError
|
|
8
|
-
# oj not installed — stdlib json is fine
|
|
9
|
-
end
|
|
10
|
-
|
|
11
3
|
# ── Core (always loaded) ──────────────────────────────────────────────
|
|
12
4
|
require_relative "tina4/version"
|
|
13
5
|
require_relative "tina4/constants"
|
|
@@ -108,6 +100,9 @@ module Tina4
|
|
|
108
100
|
autoload :WebSocket, File.expand_path("tina4/websocket", __dir__)
|
|
109
101
|
autoload :WebSocketConnection, File.expand_path("tina4/websocket", __dir__)
|
|
110
102
|
autoload :DevReload, File.expand_path("tina4/websocket", __dir__)
|
|
103
|
+
autoload :WebSocketBackplane, File.expand_path("tina4/websocket_backplane", __dir__)
|
|
104
|
+
autoload :RedisBackplane, File.expand_path("tina4/websocket_backplane", __dir__)
|
|
105
|
+
autoload :NATSBackplane, File.expand_path("tina4/websocket_backplane", __dir__)
|
|
111
106
|
autoload :Testing, File.expand_path("tina4/testing", __dir__)
|
|
112
107
|
autoload :ScssCompiler, File.expand_path("tina4/scss_compiler", __dir__)
|
|
113
108
|
autoload :FakeData, File.expand_path("tina4/seeder", __dir__)
|
|
@@ -188,13 +183,20 @@ module Tina4
|
|
|
188
183
|
# Print banner
|
|
189
184
|
print_banner
|
|
190
185
|
|
|
191
|
-
# Load environment
|
|
186
|
+
# Load environment. Precedence: real-env > .env.local > .env
|
|
187
|
+
# (.env.local loads first, both first-wins, so a real env var always wins).
|
|
192
188
|
Tina4::Env.load_env(root_dir)
|
|
193
189
|
|
|
194
190
|
# Setup debug logging
|
|
195
191
|
Tina4::Log.configure(root_dir)
|
|
196
192
|
Tina4::Log.info("Tina4 Ruby v#{VERSION} initializing...")
|
|
197
193
|
|
|
194
|
+
# Fail-safe dev secret: in dev (and NOT CI/prod) mint a per-machine
|
|
195
|
+
# random TINA4_SECRET into gitignored .env.local if it is blank; in
|
|
196
|
+
# CI/prod with a blank secret, emit the actionable warning. Runs once at
|
|
197
|
+
# boot after env load, before any auth use. Never crashes boot.
|
|
198
|
+
Tina4::Auth.ensure_dev_secret(root_dir)
|
|
199
|
+
|
|
198
200
|
# Setup auth keys
|
|
199
201
|
Tina4::Auth.setup(root_dir)
|
|
200
202
|
|
|
@@ -210,6 +212,10 @@ module Tina4
|
|
|
210
212
|
# Auto-discover routes
|
|
211
213
|
auto_discover(root_dir)
|
|
212
214
|
|
|
215
|
+
# Apply pending DB migrations on startup (non-breaking — see method doc).
|
|
216
|
+
# Runs AFTER route discovery / DB bind, BEFORE serving.
|
|
217
|
+
auto_migrate_on_startup!(root_dir)
|
|
218
|
+
|
|
213
219
|
Tina4::Log.info("Tina4 initialized successfully")
|
|
214
220
|
end
|
|
215
221
|
|
|
@@ -381,9 +387,17 @@ module Tina4
|
|
|
381
387
|
Tina4::Router.group(prefix, auth_handler: auth, &block)
|
|
382
388
|
end
|
|
383
389
|
|
|
384
|
-
# WebSocket route registration
|
|
385
|
-
|
|
386
|
-
|
|
390
|
+
# WebSocket route registration. PUBLIC by default (mirrors GET). Pass
|
|
391
|
+
# secure: true OR chain .secure on the returned route to require a valid JWT
|
|
392
|
+
# on the upgrade.
|
|
393
|
+
def websocket(path, secure: false, &block)
|
|
394
|
+
Tina4::Router.websocket(path, secure: secure, &block)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Register a SECURED WebSocket route — declarative sibling of
|
|
398
|
+
# Tina4.websocket(...).secure, mirroring secure_get/secure_post.
|
|
399
|
+
def secure_websocket(path, &block)
|
|
400
|
+
Tina4::Router.secure_websocket(path, &block)
|
|
387
401
|
end
|
|
388
402
|
|
|
389
403
|
# Middleware hooks
|
|
@@ -438,8 +452,73 @@ module Tina4
|
|
|
438
452
|
Tina4::Container.get(name)
|
|
439
453
|
end
|
|
440
454
|
|
|
455
|
+
# Apply pending DB migrations on startup — NON-BREAKING. Public so it can be
|
|
456
|
+
# called explicitly (and unit-tested) as `Tina4.auto_migrate_on_startup!`.
|
|
457
|
+
#
|
|
458
|
+
# When a migrations/ folder exists (with at least one .sql file) and
|
|
459
|
+
# TINA4_AUTO_MIGRATE is not disabled, pending migrations are applied during
|
|
460
|
+
# boot so the schema is current with no manual `tina4ruby migrate` step. A
|
|
461
|
+
# failure here is logged LOUD and the service STILL starts — a bad migration
|
|
462
|
+
# must never take the backend down. (The explicit `tina4ruby migrate` CLI
|
|
463
|
+
# stays fail-fast so CI still gets a non-zero exit.)
|
|
464
|
+
#
|
|
465
|
+
# Disable with TINA4_AUTO_MIGRATE=false (also 0/no/off) — e.g. multi-instance
|
|
466
|
+
# production that migrates as a separate deploy step (concurrent first-apply
|
|
467
|
+
# can race).
|
|
468
|
+
def auto_migrate_on_startup!(root_dir = Dir.pwd)
|
|
469
|
+
# Gate 1: a migrations folder with at least one .sql file must exist.
|
|
470
|
+
migrations_dir = resolve_startup_migrations_dir(root_dir)
|
|
471
|
+
return unless migrations_dir
|
|
472
|
+
|
|
473
|
+
# Gate 2: TINA4_AUTO_MIGRATE not disabled (default "true"; false/0/no/off off).
|
|
474
|
+
unless Tina4::Env.is_truthy(ENV.fetch("TINA4_AUTO_MIGRATE", "true"))
|
|
475
|
+
Tina4::Log.debug("TINA4_AUTO_MIGRATE is off — skipping startup migrations")
|
|
476
|
+
return
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Gate 3: a database must be resolvable.
|
|
480
|
+
db = Tina4.database
|
|
481
|
+
unless db
|
|
482
|
+
Tina4::Log.debug("Startup migrations skipped (no database configured)")
|
|
483
|
+
return
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
begin
|
|
487
|
+
migration = Tina4::Migration.new(db, migrations_dir: migrations_dir)
|
|
488
|
+
results = migration.run
|
|
489
|
+
applied = Array(results).count { |r| r[:status] == "success" }
|
|
490
|
+
Tina4::Log.info("Applied #{applied} pending migration(s) on startup") if applied.positive?
|
|
491
|
+
# A migration that records as "failed" surfaces in `run`'s results but
|
|
492
|
+
# does NOT raise from the runner; treat a recorded failure as loud-log too.
|
|
493
|
+
if Array(results).any? { |r| r[:status] == "failed" }
|
|
494
|
+
Tina4::Log.error(
|
|
495
|
+
"Startup auto-migration failed — the service is starting anyway. " \
|
|
496
|
+
"Run `tina4ruby migrate` to retry."
|
|
497
|
+
)
|
|
498
|
+
end
|
|
499
|
+
rescue => e
|
|
500
|
+
# NON-BREAKING: never re-raise out of the startup hook.
|
|
501
|
+
Tina4::Log.error(
|
|
502
|
+
"Startup auto-migration failed: #{e.message} — the service is starting " \
|
|
503
|
+
"anyway. Run `tina4ruby migrate` to retry."
|
|
504
|
+
)
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
441
508
|
private
|
|
442
509
|
|
|
510
|
+
# Resolve the migrations directory for startup auto-migration, returning it
|
|
511
|
+
# only when it exists AND contains at least one .sql file. Prefers
|
|
512
|
+
# src/migrations, falls back to migrations/ (mirrors Migration#resolve_migrations_dir).
|
|
513
|
+
def resolve_startup_migrations_dir(root_dir)
|
|
514
|
+
%w[src/migrations migrations].each do |rel|
|
|
515
|
+
dir = File.join(root_dir, rel)
|
|
516
|
+
next unless Dir.exist?(dir)
|
|
517
|
+
return dir unless Dir.glob(File.join(dir, "*.sql")).empty?
|
|
518
|
+
end
|
|
519
|
+
nil
|
|
520
|
+
end
|
|
521
|
+
|
|
443
522
|
# Resolve auth option for route registration
|
|
444
523
|
# :default => use bearer auth (default for POST/PUT/PATCH/DELETE)
|
|
445
524
|
# false => no auth (public route)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.13.
|
|
4
|
+
version: 3.13.39
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -52,20 +52,6 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '6.0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: dotenv
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '3.0'
|
|
62
|
-
type: :runtime
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '3.0'
|
|
69
55
|
- !ruby/object:Gem::Dependency
|
|
70
56
|
name: jwt
|
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,20 +66,6 @@ dependencies:
|
|
|
80
66
|
- - "~>"
|
|
81
67
|
- !ruby/object:Gem::Version
|
|
82
68
|
version: '2.7'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: bcrypt
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '3.1'
|
|
90
|
-
type: :runtime
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - "~>"
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '3.1'
|
|
97
69
|
- !ruby/object:Gem::Dependency
|
|
98
70
|
name: net-smtp
|
|
99
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -136,20 +108,6 @@ dependencies:
|
|
|
136
108
|
- - "~>"
|
|
137
109
|
- !ruby/object:Gem::Version
|
|
138
110
|
version: '2.7'
|
|
139
|
-
- !ruby/object:Gem::Dependency
|
|
140
|
-
name: oj
|
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
|
142
|
-
requirements:
|
|
143
|
-
- - "~>"
|
|
144
|
-
- !ruby/object:Gem::Version
|
|
145
|
-
version: '3.16'
|
|
146
|
-
type: :runtime
|
|
147
|
-
prerelease: false
|
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
-
requirements:
|
|
150
|
-
- - "~>"
|
|
151
|
-
- !ruby/object:Gem::Version
|
|
152
|
-
version: '3.16'
|
|
153
111
|
- !ruby/object:Gem::Dependency
|
|
154
112
|
name: rexml
|
|
155
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -277,8 +235,9 @@ dependencies:
|
|
|
277
235
|
- !ruby/object:Gem::Version
|
|
278
236
|
version: '1.50'
|
|
279
237
|
description: 'TINA4: The Intelligent Native Application 4ramework for Ruby — Simple.
|
|
280
|
-
Fast. Human. Built for AI. Built for you. 54 built-in features,
|
|
281
|
-
|
|
238
|
+
Fast. Human. Built for AI. Built for you. 54 built-in features, minimal dependencies
|
|
239
|
+
(Rack-based; the runtime gems are production-deployment essentials, not framework
|
|
240
|
+
bloat). Full parity with Python, PHP, and Node.js.'
|
|
282
241
|
email:
|
|
283
242
|
- info@tina4.com
|
|
284
243
|
executables:
|
|
@@ -460,5 +419,5 @@ requirements: []
|
|
|
460
419
|
rubygems_version: 3.4.19
|
|
461
420
|
signing_key:
|
|
462
421
|
specification_version: 4
|
|
463
|
-
summary: Tina4 for Ruby — 54 built-in features,
|
|
422
|
+
summary: Tina4 for Ruby — 54 built-in features, minimal dependencies
|
|
464
423
|
test_files: []
|