tina4ruby 3.13.97 → 3.13.99

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -0
  3. data/lib/tina4/ai.rb +32 -3
  4. data/lib/tina4/api.rb +5 -0
  5. data/lib/tina4/auto_crud.rb +62 -4
  6. data/lib/tina4/background.rb +112 -31
  7. data/lib/tina4/cache.rb +3 -2
  8. data/lib/tina4/cli.rb +55 -67
  9. data/lib/tina4/database.rb +97 -49
  10. data/lib/tina4/database_adapter.rb +169 -15
  11. data/lib/tina4/dev_admin.rb +137 -9
  12. data/lib/tina4/dispatch_pipeline.rb +145 -4
  13. data/lib/tina4/drivers/firebird_driver.rb +59 -12
  14. data/lib/tina4/drivers/mongodb_driver.rb +98 -14
  15. data/lib/tina4/drivers/mssql_driver.rb +39 -2
  16. data/lib/tina4/drivers/mysql_driver.rb +43 -3
  17. data/lib/tina4/drivers/odbc_driver.rb +36 -2
  18. data/lib/tina4/drivers/postgres_driver.rb +5 -0
  19. data/lib/tina4/drivers/sqlite_driver.rb +11 -1
  20. data/lib/tina4/env.rb +1 -1
  21. data/lib/tina4/error_overlay.rb +43 -49
  22. data/lib/tina4/field_types.rb +33 -16
  23. data/lib/tina4/frond.rb +24 -2
  24. data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +1 -1
  25. data/lib/tina4/gallery/templates/src/templates/gallery_page.twig +1 -1
  26. data/lib/tina4/graphql.rb +2 -2
  27. data/lib/tina4/log.rb +652 -485
  28. data/lib/tina4/mcp.rb +9 -1
  29. data/lib/tina4/messenger.rb +25 -0
  30. data/lib/tina4/middleware.rb +189 -76
  31. data/lib/tina4/migration.rb +47 -15
  32. data/lib/tina4/orm.rb +280 -59
  33. data/lib/tina4/port_takeover.rb +202 -0
  34. data/lib/tina4/public/js/tina4-dev-admin.min.js +23 -19
  35. data/lib/tina4/rack_app.rb +201 -59
  36. data/lib/tina4/realtime.rb +6 -1
  37. data/lib/tina4/request.rb +259 -51
  38. data/lib/tina4/router.rb +20 -2
  39. data/lib/tina4/seeder.rb +68 -19
  40. data/lib/tina4/shutdown.rb +4 -0
  41. data/lib/tina4/sql_translator.rb +115 -86
  42. data/lib/tina4/swagger.rb +19 -3
  43. data/lib/tina4/template.rb +61 -6
  44. data/lib/tina4/test_client.rb +49 -3
  45. data/lib/tina4/testing.rb +16 -11
  46. data/lib/tina4/validator.rb +7 -1
  47. data/lib/tina4/version.rb +1 -1
  48. data/lib/tina4/webserver.rb +28 -40
  49. data/lib/tina4.rb +12 -1
  50. metadata +3 -19
  51. data/lib/tina4/scss/tina4css/_alerts.scss +0 -34
  52. data/lib/tina4/scss/tina4css/_badges.scss +0 -22
  53. data/lib/tina4/scss/tina4css/_buttons.scss +0 -69
  54. data/lib/tina4/scss/tina4css/_cards.scss +0 -49
  55. data/lib/tina4/scss/tina4css/_forms.scss +0 -156
  56. data/lib/tina4/scss/tina4css/_grid.scss +0 -81
  57. data/lib/tina4/scss/tina4css/_modals.scss +0 -84
  58. data/lib/tina4/scss/tina4css/_nav.scss +0 -149
  59. data/lib/tina4/scss/tina4css/_pagination.scss +0 -63
  60. data/lib/tina4/scss/tina4css/_reset.scss +0 -94
  61. data/lib/tina4/scss/tina4css/_tables.scss +0 -54
  62. data/lib/tina4/scss/tina4css/_typography.scss +0 -55
  63. data/lib/tina4/scss/tina4css/_utilities.scss +0 -208
  64. data/lib/tina4/scss/tina4css/_variables.scss +0 -117
  65. data/lib/tina4/scss/tina4css/base.scss +0 -1
  66. data/lib/tina4/scss/tina4css/colors.scss +0 -48
  67. data/lib/tina4/scss/tina4css/tina4.scss +0 -18
data/lib/tina4.rb CHANGED
@@ -388,7 +388,7 @@ module Tina4
388
388
  reset = is_tty ? "\e[0m" : ""
389
389
 
390
390
  is_debug = Tina4::Env.is_truthy(ENV["TINA4_DEBUG"])
391
- log_level = (ENV["TINA4_LOG_LEVEL"] || "[TINA4_LOG_ALL]").upcase
391
+ log_level = (ENV["TINA4_LOG_LEVEL"] || "ALL").upcase
392
392
  display = (host == "0.0.0.0" || host == "::") ? "localhost" : host
393
393
 
394
394
  # Auto-detect server name if not provided
@@ -456,6 +456,17 @@ module Tina4
456
456
  # Setup auth keys
457
457
  Tina4::Auth.setup(root_dir)
458
458
 
459
+ # Auto-attach CSRF protection when TINA4_CSRF is enabled (OFF by default).
460
+ # Mirrors the Python master's attach_csrf_from_env -- the env flag is the
461
+ # switch; unset means no CSRF gate. Idempotent, so a re-init is safe.
462
+ Tina4::CsrfMiddleware.attach_from_env
463
+
464
+ # Security headers: register in the default chain UNCONDITIONALLY
465
+ # (secure-by-default, SECHDR-DEC-01). Unlike CSRF this needs no opt-in -- a
466
+ # default app ships X-Frame-Options/X-Content-Type-Options/CSP/etc. with no
467
+ # code change. HSTS stays HTTPS-only. Idempotent.
468
+ Tina4::SecurityHeadersMiddleware.attach
469
+
459
470
  # Load translations
460
471
  Tina4::Localization.load(root_dir)
461
472
 
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.97
4
+ version: 3.13.99
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-08-07 00:00:00.000000000 Z
11
+ date: 2026-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -398,6 +398,7 @@ files:
398
398
  - lib/tina4/mqtt_message.rb
399
399
  - lib/tina4/orm.rb
400
400
  - lib/tina4/plan.rb
401
+ - lib/tina4/port_takeover.rb
401
402
  - lib/tina4/project_index.rb
402
403
  - lib/tina4/public/__feedback/widget.js
403
404
  - lib/tina4/public/css/tina4.css
@@ -434,23 +435,6 @@ files:
434
435
  - lib/tina4/response.rb
435
436
  - lib/tina4/response_cache.rb
436
437
  - lib/tina4/router.rb
437
- - lib/tina4/scss/tina4css/_alerts.scss
438
- - lib/tina4/scss/tina4css/_badges.scss
439
- - lib/tina4/scss/tina4css/_buttons.scss
440
- - lib/tina4/scss/tina4css/_cards.scss
441
- - lib/tina4/scss/tina4css/_forms.scss
442
- - lib/tina4/scss/tina4css/_grid.scss
443
- - lib/tina4/scss/tina4css/_modals.scss
444
- - lib/tina4/scss/tina4css/_nav.scss
445
- - lib/tina4/scss/tina4css/_pagination.scss
446
- - lib/tina4/scss/tina4css/_reset.scss
447
- - lib/tina4/scss/tina4css/_tables.scss
448
- - lib/tina4/scss/tina4css/_typography.scss
449
- - lib/tina4/scss/tina4css/_utilities.scss
450
- - lib/tina4/scss/tina4css/_variables.scss
451
- - lib/tina4/scss/tina4css/base.scss
452
- - lib/tina4/scss/tina4css/colors.scss
453
- - lib/tina4/scss/tina4css/tina4.scss
454
438
  - lib/tina4/seeder.rb
455
439
  - lib/tina4/service.rb
456
440
  - lib/tina4/service_runner.rb
@@ -1,34 +0,0 @@
1
- // Tina4 CSS Framework - Alerts
2
- // -------------------------------
3
-
4
- .alert {
5
- position: relative;
6
- padding: 0.75rem 1rem;
7
- margin-bottom: 1rem;
8
- border: 1px solid transparent;
9
- border-radius: $border-radius;
10
- }
11
-
12
- @each $name, $color in $theme-colors {
13
- .alert-#{$name} {
14
- color: darken($color, 25%);
15
- background-color: lighten($color, 35%);
16
- border-color: lighten($color, 25%);
17
- }
18
- }
19
-
20
- .alert-dismissible {
21
- padding-right: 3rem;
22
- .btn-close {
23
- position: absolute;
24
- top: 0;
25
- right: 0;
26
- padding: 0.9375rem 1rem;
27
- background: transparent;
28
- border: 0;
29
- cursor: pointer;
30
- color: inherit;
31
- opacity: 0.5;
32
- &:hover { opacity: 0.75; }
33
- }
34
- }
@@ -1,22 +0,0 @@
1
- // Tina4 CSS Framework - Badges
2
- // -------------------------------
3
-
4
- .badge {
5
- display: inline-block;
6
- padding: 0.25em 0.65em;
7
- font-size: 0.75em;
8
- font-weight: $font-weight-bold;
9
- line-height: 1;
10
- color: $white;
11
- text-align: center;
12
- white-space: nowrap;
13
- vertical-align: baseline;
14
- border-radius: $border-radius-pill;
15
- }
16
-
17
- @each $name, $color in $theme-colors {
18
- .badge-#{$name} {
19
- color: if($name == "light" or $name == "warning", $dark, $white);
20
- background-color: $color;
21
- }
22
- }
@@ -1,69 +0,0 @@
1
- // Tina4 CSS Framework - Buttons
2
- // --------------------------------
3
-
4
- .btn {
5
- display: inline-block;
6
- font-weight: $font-weight-normal;
7
- line-height: $line-height-base;
8
- color: $body-color;
9
- text-align: center;
10
- vertical-align: middle;
11
- cursor: pointer;
12
- user-select: none;
13
- background-color: transparent;
14
- border: 1px solid transparent;
15
- padding: 0.375rem 0.75rem;
16
- font-size: $font-size-base;
17
- border-radius: $border-radius;
18
- transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
19
- text-decoration: none;
20
-
21
- &:disabled, &.disabled {
22
- pointer-events: none;
23
- opacity: 0.65;
24
- }
25
- }
26
-
27
- // Solid buttons
28
- @each $name, $color in $theme-colors {
29
- $text: if($name == "light" or $name == "warning", $dark, $white);
30
- .btn-#{$name} {
31
- color: $text;
32
- background-color: $color;
33
- border-color: $color;
34
- &:hover {
35
- background-color: darken($color, 8%);
36
- border-color: darken($color, 10%);
37
- }
38
- }
39
- }
40
-
41
- // Outline buttons
42
- @each $name, $color in $theme-colors {
43
- .btn-outline-#{$name} {
44
- color: $color;
45
- border-color: $color;
46
- background-color: transparent;
47
- &:hover {
48
- color: if($name == "light" or $name == "warning", $dark, $white);
49
- background-color: $color;
50
- }
51
- }
52
- }
53
-
54
- .btn-sm {
55
- padding: 0.25rem 0.5rem;
56
- font-size: $font-size-sm;
57
- border-radius: $border-radius-sm;
58
- }
59
-
60
- .btn-lg {
61
- padding: 0.5rem 1rem;
62
- font-size: $font-size-lg;
63
- border-radius: $border-radius-lg;
64
- }
65
-
66
- .btn-block {
67
- display: block;
68
- width: 100%;
69
- }
@@ -1,49 +0,0 @@
1
- // Tina4 CSS Framework - Cards
2
- // ------------------------------
3
-
4
- .card {
5
- position: relative;
6
- display: flex;
7
- flex-direction: column;
8
- min-width: 0;
9
- word-wrap: break-word;
10
- background-color: $white;
11
- background-clip: border-box;
12
- border: 1px solid rgba($black, 0.125);
13
- border-radius: $border-radius-lg;
14
- }
15
-
16
- .card-header {
17
- padding: 0.75rem 1rem;
18
- margin-bottom: 0;
19
- background-color: rgba($black, 0.03);
20
- border-bottom: 1px solid rgba($black, 0.125);
21
- &:first-child { border-radius: calc($border-radius-lg - 1px) calc($border-radius-lg - 1px) 0 0; }
22
- }
23
-
24
- .card-body {
25
- flex: 1 1 auto;
26
- padding: 1rem;
27
- }
28
-
29
- .card-footer {
30
- padding: 0.75rem 1rem;
31
- background-color: rgba($black, 0.03);
32
- border-top: 1px solid rgba($black, 0.125);
33
- &:last-child { border-radius: 0 0 calc($border-radius-lg - 1px) calc($border-radius-lg - 1px); }
34
- }
35
-
36
- .card-title {
37
- margin-bottom: 0.5rem;
38
- font-weight: $font-weight-bold;
39
- }
40
-
41
- .card-text:last-child {
42
- margin-bottom: 0;
43
- }
44
-
45
- .card-img-top {
46
- width: 100%;
47
- border-top-left-radius: calc($border-radius-lg - 1px);
48
- border-top-right-radius: calc($border-radius-lg - 1px);
49
- }
@@ -1,156 +0,0 @@
1
- // Tina4 CSS Framework - Forms
2
- // ------------------------------
3
-
4
- .form-group {
5
- margin-bottom: 1rem;
6
- }
7
-
8
- .form-label {
9
- display: inline-block;
10
- margin-bottom: 0.5rem;
11
- font-weight: $font-weight-bold;
12
- }
13
-
14
- .form-control {
15
- display: block;
16
- width: 100%;
17
- padding: 0.375rem 0.75rem;
18
- font-size: $font-size-base;
19
- font-weight: $font-weight-normal;
20
- line-height: $line-height-base;
21
- color: $body-color;
22
- background-color: $white;
23
- background-clip: padding-box;
24
- border: 1px solid #ced4da;
25
- border-radius: $border-radius;
26
- transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
27
- appearance: none;
28
-
29
- &:focus {
30
- color: $body-color;
31
- background-color: $white;
32
- border-color: lighten($primary, 25%);
33
- outline: 0;
34
- box-shadow: 0 0 0 0.2rem rgba($primary, 0.25);
35
- }
36
-
37
- &::placeholder {
38
- color: $muted;
39
- opacity: 1;
40
- }
41
-
42
- &:disabled {
43
- background-color: $light;
44
- opacity: 1;
45
- }
46
- }
47
-
48
- textarea.form-control {
49
- min-height: calc(1.5em + 0.75rem + 2px);
50
- }
51
-
52
- .form-select {
53
- display: block;
54
- width: 100%;
55
- padding: 0.375rem 2.25rem 0.375rem 0.75rem;
56
- font-size: $font-size-base;
57
- font-weight: $font-weight-normal;
58
- line-height: $line-height-base;
59
- color: $body-color;
60
- background-color: $white;
61
- border: 1px solid #ced4da;
62
- border-radius: $border-radius;
63
- transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
64
- appearance: none;
65
-
66
- &:focus {
67
- border-color: lighten($primary, 25%);
68
- outline: 0;
69
- box-shadow: 0 0 0 0.2rem rgba($primary, 0.25);
70
- }
71
- }
72
-
73
- // Checkboxes and radios
74
- .form-check {
75
- display: block;
76
- min-height: $line-height-base * 1rem;
77
- padding-left: 1.5em;
78
- margin-bottom: 0.125rem;
79
- }
80
-
81
- .form-check-input {
82
- float: left;
83
- width: 1em;
84
- height: 1em;
85
- margin-left: -1.5em;
86
- margin-top: 0.25em;
87
- appearance: none;
88
- background-color: $white;
89
- border: 1px solid rgba($black, 0.25);
90
- &[type="checkbox"] { border-radius: 0.25em; }
91
- &[type="radio"] { border-radius: 50%; }
92
- &:checked { background-color: $primary; border-color: $primary; }
93
- &:focus { border-color: lighten($primary, 25%); outline: 0; box-shadow: 0 0 0 0.2rem rgba($primary, 0.25); }
94
- }
95
-
96
- .form-check-label { cursor: pointer; }
97
-
98
- // Validation
99
- .is-valid {
100
- border-color: $success !important;
101
- &:focus {
102
- box-shadow: 0 0 0 0.2rem rgba($success, 0.25) !important;
103
- }
104
- }
105
-
106
- .is-invalid {
107
- border-color: $danger !important;
108
- &:focus {
109
- box-shadow: 0 0 0 0.2rem rgba($danger, 0.25) !important;
110
- }
111
- }
112
-
113
- .valid-feedback,
114
- .invalid-feedback {
115
- display: none;
116
- width: 100%;
117
- margin-top: 0.25rem;
118
- font-size: 0.875em;
119
- }
120
- .valid-feedback { color: $success; }
121
- .invalid-feedback { color: $danger; }
122
-
123
- .is-valid ~ .valid-feedback,
124
- .is-invalid ~ .invalid-feedback {
125
- display: block;
126
- }
127
-
128
- // Input group
129
- .input-group {
130
- position: relative;
131
- display: flex;
132
- flex-wrap: wrap;
133
- align-items: stretch;
134
- width: 100%;
135
- > .form-control,
136
- > .form-select {
137
- position: relative;
138
- flex: 1 1 auto;
139
- width: 1%;
140
- min-width: 0;
141
- }
142
- }
143
-
144
- .input-group-text {
145
- display: flex;
146
- align-items: center;
147
- padding: 0.375rem 0.75rem;
148
- font-size: $font-size-base;
149
- line-height: $line-height-base;
150
- color: $body-color;
151
- text-align: center;
152
- white-space: nowrap;
153
- background-color: $light;
154
- border: 1px solid #ced4da;
155
- border-radius: $border-radius;
156
- }
@@ -1,81 +0,0 @@
1
- // Tina4 CSS Framework - 12-Column Flexbox Grid
2
- // -----------------------------------------------
3
-
4
- .container,
5
- .container-fluid {
6
- width: 100%;
7
- padding-right: calc($grid-gutter / 2);
8
- padding-left: calc($grid-gutter / 2);
9
- margin-right: auto;
10
- margin-left: auto;
11
- }
12
-
13
- @each $bp, $max-width in $container-max-widths {
14
- @media (min-width: map-get($breakpoints, $bp)) {
15
- .container {
16
- max-width: $max-width;
17
- }
18
- }
19
- }
20
-
21
- .row {
22
- display: flex;
23
- flex-wrap: wrap;
24
- margin-right: calc($grid-gutter / -2);
25
- margin-left: calc($grid-gutter / -2);
26
- > * {
27
- flex-shrink: 0;
28
- width: 100%;
29
- max-width: 100%;
30
- padding-right: calc($grid-gutter / 2);
31
- padding-left: calc($grid-gutter / 2);
32
- }
33
- }
34
-
35
- .col {
36
- flex: 1 0 0%;
37
- }
38
-
39
- // Generate base columns
40
- @for $i from 1 through $grid-columns {
41
- .col-#{$i} {
42
- flex: 0 0 auto;
43
- width: percentage($i / $grid-columns);
44
- }
45
- }
46
- @each $i in 1, 2, 3, 4 {
47
- .offset-#{$i} {
48
- margin-left: percentage($i / $grid-columns);
49
- }
50
- }
51
- .offset-0 { margin-left: 0; }
52
-
53
- // Responsive columns (core breakpoints only for size)
54
- $grid-breakpoints: (sm, md, lg, xl);
55
-
56
- @each $bp in $grid-breakpoints {
57
- $min-width: map-get($breakpoints, $bp);
58
- @media (min-width: $min-width) {
59
- .col-#{$bp} {
60
- flex: 1 0 0%;
61
- }
62
- @for $i from 1 through $grid-columns {
63
- .col-#{$bp}-#{$i} {
64
- flex: 0 0 auto;
65
- width: percentage($i / $grid-columns);
66
- }
67
- }
68
- .offset-#{$bp}-0 { margin-left: 0; }
69
- }
70
- }
71
-
72
- // Row alignment
73
- .justify-start { justify-content: flex-start; }
74
- .justify-center { justify-content: center; }
75
- .justify-end { justify-content: flex-end; }
76
- .justify-between { justify-content: space-between; }
77
- .justify-around { justify-content: space-around; }
78
-
79
- .align-start { align-items: flex-start; }
80
- .align-center { align-items: center; }
81
- .align-end { align-items: flex-end; }
@@ -1,84 +0,0 @@
1
- // Tina4 CSS Framework - Modals
2
- // -------------------------------
3
-
4
- .modal {
5
- position: fixed;
6
- top: 0;
7
- left: 0;
8
- z-index: $zindex-modal;
9
- display: none;
10
- width: 100%;
11
- height: 100%;
12
- overflow-x: hidden;
13
- overflow-y: auto;
14
- outline: 0;
15
-
16
- &.show { display: block; }
17
- }
18
-
19
- .modal-dialog {
20
- position: relative;
21
- width: auto;
22
- margin: 1.75rem auto;
23
- max-width: 500px;
24
- }
25
-
26
- .modal-sm { max-width: 300px; }
27
- .modal-lg { max-width: 800px; }
28
-
29
- .modal-content {
30
- position: relative;
31
- display: flex;
32
- flex-direction: column;
33
- width: 100%;
34
- pointer-events: auto;
35
- background-color: $white;
36
- background-clip: padding-box;
37
- border: 1px solid rgba($black, 0.2);
38
- border-radius: $border-radius-lg;
39
- box-shadow: $shadow;
40
- outline: 0;
41
- }
42
-
43
- .modal-header {
44
- display: flex;
45
- flex-shrink: 0;
46
- align-items: center;
47
- justify-content: space-between;
48
- padding: 1rem;
49
- border-bottom: 1px solid rgba($black, 0.1);
50
- }
51
-
52
- .modal-title {
53
- margin-bottom: 0;
54
- font-weight: $font-weight-bold;
55
- }
56
-
57
- .modal-body {
58
- position: relative;
59
- flex: 1 1 auto;
60
- padding: 1rem;
61
- }
62
-
63
- .modal-footer {
64
- display: flex;
65
- flex-shrink: 0;
66
- flex-wrap: wrap;
67
- align-items: center;
68
- justify-content: flex-end;
69
- padding: 0.75rem;
70
- border-top: 1px solid rgba($black, 0.1);
71
- gap: 0.5rem;
72
- }
73
-
74
- .modal-backdrop {
75
- position: fixed;
76
- top: 0;
77
- left: 0;
78
- z-index: $zindex-backdrop;
79
- width: 100vw;
80
- height: 100vh;
81
- background-color: rgba($black, 0.5);
82
- display: none;
83
- &.show { display: block; }
84
- }