tina4ruby 3.13.147 → 3.13.148

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9a60268ad13cea010f5fc994563e37b77d62c93bf73a67d075cd8086b4fa431
4
- data.tar.gz: 740402d29d856535fe82468ce329ea754760a180f24436b22ae36f1d16fc25b8
3
+ metadata.gz: 5f81aa317ab408c5f85fa182149d2bddf74f76a6dbe0d07eab1346335f2feb18
4
+ data.tar.gz: a877a9d71c42570d719c721427d164581919c15e235e17d366891a5337a7920c
5
5
  SHA512:
6
- metadata.gz: 0a63f77fa42d0b2dfb1ce82a6c600c0b83b3336a68826302e27179dd92eb0bb79d57f0d4b5c183b279178d0d600fbac33a4f97ae0a1c415cae09cab3e2eaa2c5
7
- data.tar.gz: 6bbd112086e7b380d4a9748ae96192fba1721b17bd7b57cff1a682e60c062c308b817e5053ee3d1fb7293f1a27e9f448857a526f1d4fd7fe72889308bbf56643
6
+ metadata.gz: 4da03de83c10544ac690ce24d6b951b6ba688fab57fb01cb4cf5a630d1e1d41dd5fbab7397538a2910708409c3fb6fea74285ce84fd74559fb883d83303b66d6
7
+ data.tar.gz: cb21b614d729b774a1d9ec16ada8674cab6663e675a370ed7cb8b3f588b3c038036ba0d43bedcf764f1ab673b117df005e30063d50612ce8ace479300104d127
data/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ number means the same thing everywhere.
6
6
  **The authoritative release notes for every shipped version live in the documentation:**
7
7
  https://tina4.com/ruby/36-releases
8
8
 
9
+ ## 3.13.148 — 2026-10-05
10
+
11
+ ### Session
12
+ - An anonymous request stores no session — a request that never reads or writes session state no longer emits a `Set-Cookie` or persists an empty session record (cross-framework fix, at parity across Python, PHP, Ruby, Node.js).
13
+
14
+ ### AI skills
15
+ - `tina4-developer-ruby` skill `updated_for_version` bumped to this release.
16
+
9
17
  ## 3.13.147 — 2026-10-05
10
18
 
11
19
  ### Dev MCP tools (fixes #271)
@@ -649,12 +649,11 @@ module Tina4
649
649
  # renamed through TINA4_SESSION_NAME, so the auto-Set-Cookie would be
650
650
  # needlessly re-emitted on every request that already carries the renamed
651
651
  # cookie. Parity with Python's core/server._init_session cookie_prefix.
652
- sid = sess.id
653
652
  cookie_prefix = "#{Tina4::Session.cookie_name}="
654
653
  cookie_val = (ctx.env["HTTP_COOKIE"] || "").split(";").map(&:strip)
655
654
  .find { |part| part.start_with?(cookie_prefix) }
656
655
  &.slice(cookie_prefix.length..)
657
- if sid && sid != cookie_val
656
+ if session_needs_cookie?(sess, cookie_val)
658
657
  # Route through Session#cookie_header rather than hand-writing the
659
658
  # header, so TINA4_SESSION_SECURE / _SAMESITE / _HTTPONLY / _NAME / _TTL
660
659
  # are all honoured and Secure reflects the request scheme. The old
@@ -666,6 +665,19 @@ module Tina4
666
665
  [status, headers, body_parts]
667
666
  end
668
667
 
668
+ # Whether the response must carry a session cookie: the session has an id the
669
+ # request did not already send, and it is not a fresh one. A fresh session
670
+ # (minted for this request and never written: a route that only read it, or
671
+ # the replacement for a cookie the store does not know) was not stored, so a
672
+ # cookie for it would name nothing - the next request could not resume it and
673
+ # would be handed another one.
674
+ def session_needs_cookie?(sess, cookie_val)
675
+ sid = sess.id
676
+ return false unless sid && sid != cookie_val
677
+
678
+ !(sess.respond_to?(:fresh?) && sess.fresh?)
679
+ end
680
+
669
681
  # Milliseconds since the request entered the pipeline.
670
682
  def elapsed_ms(ctx)
671
683
  ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - ctx.started_at) * 1000).round(3)
data/lib/tina4/session.rb CHANGED
@@ -217,7 +217,7 @@ module Tina4
217
217
  # false) therefore still no-ops, exactly as before; a modified session of
218
218
  # any kind still writes.
219
219
  def save
220
- return true unless @id && (@modified || @stored)
220
+ return true if @id.nil? || fresh?
221
221
 
222
222
  record = @data
223
223
  if @stored
@@ -247,6 +247,17 @@ module Tina4
247
247
  end
248
248
  end
249
249
 
250
+ # Whether this session is only an id: nothing has stored it and it holds no
251
+ # data. Such a session has no record and needs no cookie, so #save writes
252
+ # nothing for it and the dispatcher sends no cookie for it. It stops being
253
+ # fresh when something is stored in it. Calls that mark a session changed
254
+ # without leaving anything in it (deleting a key it never had, #clear,
255
+ # #regenerate on an empty session) leave it fresh: a record with no data is
256
+ # not a session.
257
+ def fresh?
258
+ !@stored && @data.empty?
259
+ end
260
+
250
261
  # Destroy the current session. ENDS the session: the stored record is
251
262
  # removed and the id is CLEARED (@id = nil), so a later set()+save() with no
252
263
  # new #start has no id to persist under and cannot RESURRECT the just-
data/lib/tina4/version.rb CHANGED
@@ -7,5 +7,5 @@
7
7
 
8
8
 
9
9
  module Tina4
10
- VERSION = "3.13.147"
10
+ VERSION = "3.13.148"
11
11
  end
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.147
4
+ version: 3.13.148
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-10-05 00:00:00.000000000 Z
11
+ date: 2026-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3