rodauth-tools 0.4.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3229a291fcbbef1fa0f00904dfbb171243f21a9478cf673d33d6f747ed30cbb4
4
- data.tar.gz: 25dff26d7c164d0d8a8409c626c467b5cd3c9b3b64d18771d1ccdfcb8b84c5c4
3
+ metadata.gz: 39d6a88fc0c69fd330a7ad5fbcce20eef2d1069fc317f9e21d28ef286cbea4d8
4
+ data.tar.gz: 30511219eb536cb7d135706866ba497c5f66b89c124baeeab9f2726021c8eeb1
5
5
  SHA512:
6
- metadata.gz: 35506a929bcb7cbd354f08f592331bb6718894f9d0f0331cf337545ce06c4858c1a83ad2ad4aa4af97a9039cd0d1e85004ba8c626d34bb55215032999886e5a8
7
- data.tar.gz: 13f488f19cb2794315dcf1fefb408306e15b994b40c5b03c47e21194a16a11a92e4809733ece96a0cd639af0b7ae71b1256efe9b72bc5ad6b913ea7c5852e868
6
+ metadata.gz: f33049dc3a878378dc0752173c4bbbf3ce66e278947d5e809a86eff788b78b1f58f556d8a77bb1d90c0395557d43bb8b9fdf2c739ab6e4acd906df523dbc1076
7
+ data.tar.gz: 7a7cff39a3a3ca2eed50a16e5daad470d1e39425f1214d81270fe308a253b24e0e15a1b31c7e1a08f84aab38df3c2a049f3a3480e5040353adc83e0cf72fbf78
@@ -1,6 +1,6 @@
1
- # CLAUDE.md
1
+ # AGENTS.md
2
2
 
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
3
+ This file provides guidance to coding agents working in this repository.
4
4
 
5
5
  ## Project Purpose
6
6
 
@@ -11,15 +11,21 @@ Framework-agnostic utilities for Rodauth authentication:
11
11
 
12
12
  **Not a framework adapter.** For Rails integration, use rodauth-rails. This project demonstrates Rodauth's extensibility and provides reference implementations.
13
13
 
14
- **Status:** Experimental learning project. Not published to RubyGems.
14
+ **Status:** Experimental. The gemspec says it plainly — "experimental stuff that may come and go" — so treat the API as unstable. It *is* published to RubyGems (`rodauth-tools`), and at least one production app depends on it, so a breaking change is a real cost to someone: bump the version and write the CHANGELOG entry.
15
15
 
16
- **Recent Refactoring (2025-10):** Namespace changed from `Rodauth::Rack::Generators::Migration` to `Rodauth::Tools::Migration`. This reflects the project's evolution away from being a Rack adapter toward being a collection of framework-agnostic utilities. The migration generator is now deprecated in favor of the `table_guard` feature with `sequel_mode`.
16
+ **Namespace history (2025-10):** Namespace changed from `Rodauth::Rack::Generators::Migration` to `Rodauth::Tools::Migration`. This reflects the project's evolution away from being a Rack adapter toward being a collection of framework-agnostic utilities. The migration generator is now deprecated in favor of the `table_guard` feature with `sequel_mode`.
17
17
 
18
18
  ## Development Commands
19
19
 
20
20
  ```bash
21
21
  # Run all tests
22
- bundle exec rspec
22
+ bundle exec rspec # or: bundle exec rake
23
+
24
+ # Tryouts suite (documentation-style tests; auto-discovers try/, NOT run by CI)
25
+ bundle exec try
26
+
27
+ # Lint (config in .rubocop.yml, with .rubocop_todo.yml exclusions)
28
+ bundle exec rubocop lib/ spec/
23
29
 
24
30
  # Interactive console with helpers
25
31
  bin/console
@@ -37,6 +43,14 @@ bin/console
37
43
  - Configurable modes: `:warn`, `:error`, `:silent`, or custom block handler
38
44
  - Demonstrates proper feature lifecycle hooks and configuration DSL
39
45
 
46
+ **lib/rodauth/features/external_identity.rb** - External Rodauth feature
47
+
48
+ - Uses `Rodauth::Feature.define(:external_identity, :ExternalIdentity)` pattern
49
+ - Declares `accounts` columns holding IDs from external services (`external_identity_column :stripe_customer_id`) and generates a reader per column
50
+ - Layer 1 is the bare column plus conflict policy (`external_identity_on_conflict`: `:error`, `:warn`, `:skip`) and column presence checking (`external_identity_check_columns`: `true`, `false`, `:autocreate`)
51
+ - Layer 2 hangs lifecycle callables off the same declaration: `before_create_account`, `formatter`, `validator`, `verifier`, `handshake`
52
+ - Introspection: `external_identity_column_list`, `external_identity_column_config`, `external_identity_status`
53
+
40
54
  **lib/rodauth/features/hmac_secret_guard.rb** - External Rodauth feature
41
55
 
42
56
  - Uses `Rodauth::Feature.define(:hmac_secret_guard, :HmacSecretGuard)` pattern
@@ -72,6 +86,7 @@ bin/console
72
86
  - Keyed format-preserving obfuscation of a 64-bit integer id (4-round Feistel network, HMAC-SHA256 round function)
73
87
  - Pure `Integer <-> 13-char Crockford Base32` bijection; stdlib `openssl` only, independently testable
74
88
  - `decode` returns `nil` on malformed input so callers can pass legacy/foreign values through
89
+
75
90
  **lib/rodauth/secret_guard.rb** - Shared support module (`Rodauth::SecretGuard`)
76
91
 
77
92
  - Kind-parameterized (`:hmac`/`:jwt`) logic behind both secret-guard features
@@ -81,6 +96,12 @@ bin/console
81
96
  - Handles ENV loading (`load_from_env!`), validation (`validate!`), blank/whitespace
82
97
  detection, production detection, and minimum-length enforcement
83
98
 
99
+ **lib/rodauth/table_inspector.rb** - Shared support module (`Rodauth::TableInspector`)
100
+
101
+ - Discovers the tables an enabled feature set requires by inspecting a live Rodauth instance, rather than from a static table
102
+ - `discover_tables(rodauth)` returns `{ accounts_table: "accounts", ... }`; `table_information(rodauth)` adds the owning feature and column list per table
103
+ - This is what backs `table_guard`'s `_table_configuration`, so it is the source of the `*_table` method enumeration described under Hidden Tables below
104
+
84
105
  **lib/rodauth/tools/migration.rb** - Sequel migration generator
85
106
 
86
107
  - Generates database migrations for 19 Rodauth features
@@ -131,6 +152,13 @@ end
131
152
 
132
153
  **Existence Checks (no logger suppression):** The `table_exists?` method matches names against the database's table/view list (`db.tables` + `db.views`) rather than probing each table with a SELECT. An earlier implementation used Sequel's `table_exists?` probe and suppressed the logger around it (clearing/restoring the shared `db.loggers` array) to hide the "no such table" ERROR that Sequel logs before catching internally — but that mutation of shared connection state was not thread-safe. Listing names avoids the failed probe entirely, so no logger suppression (and no shared-state mutation) is needed. Schema-qualified identifiers (a `Sequel::SQL::QualifiedIdentifier` or a `:schema__table` Symbol) are not present in the unqualified list, so they take a separate schema-aware `db.table_exists?` probe path.
133
154
 
155
+ **Cached-Method Backing Visibility:** `auth_cached_method :foo` registers `foo` via `auth_private_methods`, so the backing `_foo` must be defined **private**. Rodauth 2.45.0 audits this at feature-definition time with `private_method_defined?` and warns (`RODAUTH3: raise instead of warn`) when it isn't — a publicly-defined `_foo` trips the audit even though it exists. `_table_configuration` and `_column_requirements` therefore live below the feature's `private` keyword, alongside the equivalent backing methods in `account_id_obfuscation` and `external_identity`.
156
+
157
+ `spec/rodauth/feature_configuration_spec.rb` holds the line. Two things about it are load-bearing, so preserve them when editing:
158
+
159
+ - It **derives** its feature list from `lib/rodauth/features/*.rb` and requires each file. A hardcoded list would leave a new feature silently uncovered — and the require is what makes the audit run at all, since rodauth audits inside `Feature.define` and never sees a feature nothing loaded.
160
+ - Per feature it **re-runs rodauth's own** `def_configuration_methods` with stderr captured and asserts silence, as well as mirroring what that method checks. The re-run cannot drift as upstream tightens the audit and honours `allowed_undefined_configuration_methods` (rodauth's opt-out) for free; the mirrored checks are what name the offending method when it fails.
161
+
134
162
  **Configuration Storage:** Uses instance variables set by `auth_value_method`:
135
163
 
136
164
  - Block configs stored as Procs in `@table_guard_mode`
@@ -232,9 +260,12 @@ Before TemplateInspector, `generate_drop_statements` only dropped dynamically di
232
260
 
233
261
  **RSpec Structure:**
234
262
 
235
- - `spec/spec_helper.rb` - Minimal configuration, loads `rodauth/rack`
263
+ - `spec/spec_helper.rb` - Minimal configuration; requires `rodauth/tools` and `rack/test`. It does **not** require `hmac_secret_guard` or `jwt_secret_guard` — those feature files are not loaded by `rodauth/tools`, so a spec that needs them must require them itself
236
264
  - Feature specs test both behavior and configuration
237
265
  - Migration generator specs verify template output and configuration
266
+ - `spec/rodauth/feature_configuration_spec.rb` - Guards every feature against rodauth's definition-time audit (see Cached-Method Backing Visibility above)
267
+
268
+ **Tryouts:** `try/features/*_try.rb` holds documentation-style tests, run separately from RSpec (`bundle exec try`). Only `external_identity` has one today. CI runs `bundle exec rake`, whose default task is `spec` alone — so **tryouts is not gated**, and it has drifted red: 5 of 50 fail as of 0.4.1. Don't read a red tryouts run as damage you just caused; check against the base branch first.
238
269
 
239
270
  **Console Helpers:**
240
271
 
@@ -246,16 +277,17 @@ Before TemplateInspector, `generate_drop_statements` only dropped dynamically di
246
277
 
247
278
  **docs/rodauth-features-api.md** - Complete reference for feature development DSL methods
248
279
 
249
- **docs/rodauth-internals.rdoc** - Object model explanation:
280
+ **docs/rodauth-integration.md** - Integrating Rodauth into a Rack app, and where this library fits
250
281
 
251
- - `Rodauth::Auth` - Authentication class (where features mix in)
252
- - `Rodauth::Configuration` - Configuration DSL class
253
- - `Rodauth::Feature` - Module subclass for feature definitions
254
- - `Rodauth::FeatureConfiguration` - Configuration module for features
282
+ **docs/sequel-migrations.md** - Migration generator usage
255
283
 
256
284
  **docs/rodauth-mail.md** - Email/SMTP configuration patterns
257
285
 
258
- **DEVELOPMENT.md** - Architectural decisions, standard Rack integration pattern
286
+ **docs/unresolved-bugs.md** - Known defects with analysis, not yet fixed. Read before "fixing" something surprising — it may already be written up here, with the reasoning for why it was left alone
287
+
288
+ **docs/features/** and **docs/examples/** - Per-feature documentation and runnable examples
289
+
290
+ Rodauth's own object model (`Rodauth::Auth`, `Rodauth::Configuration`, `Rodauth::Feature`, `Rodauth::FeatureConfiguration`) is documented upstream in `doc/guides/internals.rdoc` in the rodauth gem.
259
291
 
260
292
  ## Integration Pattern
261
293
 
data/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.1] - 2026-08-10
9
+
10
+ ### Fixed
11
+
12
+ - **`table_guard`: silence rodauth 2.45.0 feature-definition warnings.**
13
+ `_table_configuration` and `_column_requirements` — the backing methods behind
14
+ the `table_configuration` / `column_requirements` `auth_cached_method`
15
+ declarations — were defined publicly. Rodauth registers those via
16
+ `auth_private_methods` and, as of 2.45.0, audits each backing method with
17
+ `private_method_defined?` at feature-definition time, so loading the feature
18
+ printed two `"Bug in Rodauth table_guard feature definition..."` warnings on
19
+ stderr. Both methods moved into the feature's `private` section (matching
20
+ `account_id_obfuscation` and `external_identity`). Upstream marks the warning
21
+ `RODAUTH3: raise instead of warn`, so this would have become a load-time error.
22
+ Added `spec/rodauth/feature_configuration_spec.rb`, which mirrors rodauth's
23
+ audit across all five features so a regression fails the suite.
24
+
25
+ ### Added
26
+
27
+ - **Feature-definition audit coverage** (`spec/rodauth/feature_configuration_spec.rb`).
28
+ The feature list is derived from `lib/rodauth/features/*.rb` rather than
29
+ hand-maintained, so a newly added feature is covered as soon as its file lands
30
+ — and requiring those files is what makes the audit run at all, since rodauth
31
+ audits inside `Feature.define` and never sees a feature nothing requires.
32
+ Alongside the mirrored checks, each feature re-runs rodauth's own
33
+ `def_configuration_methods` with stderr captured and asserts it is silent, so
34
+ the coverage cannot drift as upstream tightens the audit and honours
35
+ `allowed_undefined_configuration_methods` (2.45.0's opt-out) without
36
+ reimplementing it.
37
+
8
38
  ## [0.4.0] - 2026-07-05
9
39
 
10
40
  ### Added
@@ -99,6 +129,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
129
  - Namespace changed from `Rodauth::Rack::Generators::Migration` to `Rodauth::Tools::Migration`
100
130
  - Evolution from Rack adapter to framework-agnostic utilities
101
131
 
132
+ [0.4.1]: https://github.com/delano/rodauth-tools/compare/v0.4.0...v0.4.1
102
133
  [0.4.0]: https://github.com/delano/rodauth-tools/compare/v0.3.1...v0.4.0
103
134
  [0.3.1]: https://github.com/delano/rodauth-tools/compare/v0.3.0...v0.3.1
104
135
  [0.3.0]: https://github.com/delano/rodauth-tools/compare/v0.2.0...v0.3.0
data/Gemfile CHANGED
@@ -28,7 +28,7 @@ group :test do
28
28
  gem 'rqrcode'
29
29
  gem 'sequel-activerecord_connection', '~> 2.0'
30
30
  gem 'sqlite3', '~> 2.9'
31
- gem 'tilt', '~> 2.7'
31
+ gem 'tilt', '~> 2.8'
32
32
  gem 'tryouts', '~> 3.0'
33
33
  gem 'warning'
34
34
  gem 'webauthn' unless RUBY_ENGINE == 'jruby'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rodauth-tools (0.4.0)
4
+ rodauth-tools (0.4.1)
5
5
  dry-inflector (~> 1.1)
6
6
  rodauth (~> 2.41)
7
7
  sequel (~> 5.0)
@@ -9,31 +9,31 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- action_text-trix (2.1.18)
12
+ action_text-trix (2.1.19)
13
13
  railties
14
- actioncable (8.1.3)
15
- actionpack (= 8.1.3)
16
- activesupport (= 8.1.3)
14
+ actioncable (8.1.3.1)
15
+ actionpack (= 8.1.3.1)
16
+ activesupport (= 8.1.3.1)
17
17
  nio4r (~> 2.0)
18
18
  websocket-driver (>= 0.6.1)
19
19
  zeitwerk (~> 2.6)
20
- actionmailbox (8.1.3)
21
- actionpack (= 8.1.3)
22
- activejob (= 8.1.3)
23
- activerecord (= 8.1.3)
24
- activestorage (= 8.1.3)
25
- activesupport (= 8.1.3)
20
+ actionmailbox (8.1.3.1)
21
+ actionpack (= 8.1.3.1)
22
+ activejob (= 8.1.3.1)
23
+ activerecord (= 8.1.3.1)
24
+ activestorage (= 8.1.3.1)
25
+ activesupport (= 8.1.3.1)
26
26
  mail (>= 2.8.0)
27
- actionmailer (8.1.3)
28
- actionpack (= 8.1.3)
29
- actionview (= 8.1.3)
30
- activejob (= 8.1.3)
31
- activesupport (= 8.1.3)
27
+ actionmailer (8.1.3.1)
28
+ actionpack (= 8.1.3.1)
29
+ actionview (= 8.1.3.1)
30
+ activejob (= 8.1.3.1)
31
+ activesupport (= 8.1.3.1)
32
32
  mail (>= 2.8.0)
33
33
  rails-dom-testing (~> 2.2)
34
- actionpack (8.1.3)
35
- actionview (= 8.1.3)
36
- activesupport (= 8.1.3)
34
+ actionpack (8.1.3.1)
35
+ actionview (= 8.1.3.1)
36
+ activesupport (= 8.1.3.1)
37
37
  nokogiri (>= 1.8.5)
38
38
  rack (>= 2.2.4)
39
39
  rack-session (>= 1.0.1)
@@ -41,36 +41,36 @@ GEM
41
41
  rails-dom-testing (~> 2.2)
42
42
  rails-html-sanitizer (~> 1.6)
43
43
  useragent (~> 0.16)
44
- actiontext (8.1.3)
44
+ actiontext (8.1.3.1)
45
45
  action_text-trix (~> 2.1.15)
46
- actionpack (= 8.1.3)
47
- activerecord (= 8.1.3)
48
- activestorage (= 8.1.3)
49
- activesupport (= 8.1.3)
46
+ actionpack (= 8.1.3.1)
47
+ activerecord (= 8.1.3.1)
48
+ activestorage (= 8.1.3.1)
49
+ activesupport (= 8.1.3.1)
50
50
  globalid (>= 0.6.0)
51
51
  nokogiri (>= 1.8.5)
52
- actionview (8.1.3)
53
- activesupport (= 8.1.3)
52
+ actionview (8.1.3.1)
53
+ activesupport (= 8.1.3.1)
54
54
  builder (~> 3.1)
55
55
  erubi (~> 1.11)
56
56
  rails-dom-testing (~> 2.2)
57
57
  rails-html-sanitizer (~> 1.6)
58
- activejob (8.1.3)
59
- activesupport (= 8.1.3)
58
+ activejob (8.1.3.1)
59
+ activesupport (= 8.1.3.1)
60
60
  globalid (>= 0.3.6)
61
- activemodel (8.1.3)
62
- activesupport (= 8.1.3)
63
- activerecord (8.1.3)
64
- activemodel (= 8.1.3)
65
- activesupport (= 8.1.3)
61
+ activemodel (8.1.3.1)
62
+ activesupport (= 8.1.3.1)
63
+ activerecord (8.1.3.1)
64
+ activemodel (= 8.1.3.1)
65
+ activesupport (= 8.1.3.1)
66
66
  timeout (>= 0.4.0)
67
- activestorage (8.1.3)
68
- actionpack (= 8.1.3)
69
- activejob (= 8.1.3)
70
- activerecord (= 8.1.3)
71
- activesupport (= 8.1.3)
67
+ activestorage (8.1.3.1)
68
+ actionpack (= 8.1.3.1)
69
+ activejob (= 8.1.3.1)
70
+ activerecord (= 8.1.3.1)
71
+ activesupport (= 8.1.3.1)
72
72
  marcel (~> 1.0)
73
- activesupport (8.1.3)
73
+ activesupport (8.1.3.1)
74
74
  base64
75
75
  bigdecimal
76
76
  concurrent-ruby (~> 1.0, >= 1.3.1)
@@ -106,21 +106,21 @@ GEM
106
106
  xpath (~> 3.2)
107
107
  cbor (0.5.10.1)
108
108
  chunky_png (1.4.0)
109
- concurrent-ruby (1.3.7)
109
+ concurrent-ruby (1.3.8)
110
110
  connection_pool (3.0.2)
111
111
  cose (1.3.1)
112
112
  cbor (~> 0.5.9)
113
113
  openssl-signature_algorithm (~> 1.0)
114
- crass (1.0.6)
114
+ crass (1.0.7)
115
115
  date (3.5.1)
116
116
  diff-lcs (1.6.2)
117
117
  drb (2.2.3)
118
118
  dry-inflector (1.3.1)
119
- erb (6.0.4)
119
+ erb (6.0.6)
120
120
  erubi (1.13.1)
121
- globalid (1.3.0)
121
+ globalid (1.4.0)
122
122
  activesupport (>= 6.1)
123
- i18n (1.14.8)
123
+ i18n (1.15.2)
124
124
  concurrent-ruby (~> 1.0)
125
125
  io-console (0.8.2)
126
126
  irb (1.18.0)
@@ -128,26 +128,26 @@ GEM
128
128
  prism (>= 1.3.0)
129
129
  rdoc (>= 4.0.0)
130
130
  reline (>= 0.4.2)
131
- json (2.19.9)
131
+ json (2.21.2)
132
132
  jwt (3.2.0)
133
133
  base64
134
- language_server-protocol (3.17.0.5)
134
+ language_server-protocol (3.17.0.6)
135
135
  lint_roller (1.1.0)
136
136
  logger (1.7.0)
137
- loofah (2.25.1)
137
+ loofah (2.25.2)
138
138
  crass (~> 1.0.2)
139
139
  nokogiri (>= 1.12.0)
140
- mail (2.9.0)
140
+ mail (2.9.1)
141
141
  logger
142
142
  mini_mime (>= 0.1.1)
143
143
  net-imap
144
144
  net-pop
145
145
  net-smtp
146
- marcel (1.1.0)
146
+ marcel (1.2.1)
147
147
  matrix (0.4.3)
148
148
  mini_mime (1.1.5)
149
149
  minitest (5.27.0)
150
- net-imap (0.6.4.1)
150
+ net-imap (0.6.6)
151
151
  date
152
152
  net-protocol
153
153
  net-pop (0.1.2)
@@ -170,13 +170,10 @@ GEM
170
170
  racc
171
171
  pastel (0.8.0)
172
172
  tty-color (~> 0.5)
173
- pp (0.6.3)
173
+ pp (0.6.4)
174
174
  prettyprint
175
175
  prettyprint (0.2.0)
176
176
  prism (1.9.0)
177
- psych (5.3.1)
178
- date
179
- stringio
180
177
  public_suffix (7.0.5)
181
178
  racc (1.8.1)
182
179
  rack (3.2.6)
@@ -187,30 +184,30 @@ GEM
187
184
  rack (>= 1.3)
188
185
  rackup (2.3.1)
189
186
  rack (>= 3)
190
- rails (8.1.3)
191
- actioncable (= 8.1.3)
192
- actionmailbox (= 8.1.3)
193
- actionmailer (= 8.1.3)
194
- actionpack (= 8.1.3)
195
- actiontext (= 8.1.3)
196
- actionview (= 8.1.3)
197
- activejob (= 8.1.3)
198
- activemodel (= 8.1.3)
199
- activerecord (= 8.1.3)
200
- activestorage (= 8.1.3)
201
- activesupport (= 8.1.3)
187
+ rails (8.1.3.1)
188
+ actioncable (= 8.1.3.1)
189
+ actionmailbox (= 8.1.3.1)
190
+ actionmailer (= 8.1.3.1)
191
+ actionpack (= 8.1.3.1)
192
+ actiontext (= 8.1.3.1)
193
+ actionview (= 8.1.3.1)
194
+ activejob (= 8.1.3.1)
195
+ activemodel (= 8.1.3.1)
196
+ activerecord (= 8.1.3.1)
197
+ activestorage (= 8.1.3.1)
198
+ activesupport (= 8.1.3.1)
202
199
  bundler (>= 1.15.0)
203
- railties (= 8.1.3)
200
+ railties (= 8.1.3.1)
204
201
  rails-dom-testing (2.3.0)
205
202
  activesupport (>= 5.0.0)
206
203
  minitest
207
204
  nokogiri (>= 1.6)
208
- rails-html-sanitizer (1.7.0)
209
- loofah (~> 2.25)
205
+ rails-html-sanitizer (1.7.1)
206
+ loofah (~> 2.25, >= 2.25.2)
210
207
  nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
211
- railties (8.1.3)
212
- actionpack (= 8.1.3)
213
- activesupport (= 8.1.3)
208
+ railties (8.1.3.1)
209
+ actionpack (= 8.1.3.1)
210
+ activesupport (= 8.1.3.1)
214
211
  irb (~> 1.13)
215
212
  rackup (>= 1.0.0)
216
213
  rake (>= 12.2)
@@ -219,16 +216,21 @@ GEM
219
216
  zeitwerk (~> 2.6)
220
217
  rainbow (3.1.1)
221
218
  rake (13.4.2)
222
- rdoc (7.2.0)
219
+ rbs (4.1.2)
220
+ logger
221
+ prism (>= 1.6.0)
222
+ tsort
223
+ rdoc (8.0.0)
223
224
  erb
224
- psych (>= 4.0.0)
225
+ prism (>= 1.6.0)
226
+ rbs (>= 4.0.0)
225
227
  tsort
226
228
  regexp_parser (2.12.0)
227
229
  reline (0.6.3)
228
230
  io-console (~> 0.5)
229
- roda (3.104.0)
231
+ roda (3.106.0)
230
232
  rack
231
- rodauth (2.44.0)
233
+ rodauth (2.45.0)
232
234
  roda (>= 2.6.0)
233
235
  sequel (>= 4)
234
236
  rotp (6.3.0)
@@ -249,7 +251,7 @@ GEM
249
251
  diff-lcs (>= 1.2.0, < 2.0)
250
252
  rspec-support (~> 3.13.0)
251
253
  rspec-support (3.13.6)
252
- rubocop (1.88.0)
254
+ rubocop (1.88.2)
253
255
  json (~> 2.3)
254
256
  language_server-protocol (~> 3.17.0.2)
255
257
  lint_roller (~> 1.1.0)
@@ -260,7 +262,7 @@ GEM
260
262
  rubocop-ast (>= 1.49.0, < 2.0)
261
263
  ruby-progressbar (~> 1.7)
262
264
  unicode-display_width (>= 2.4.0, < 4.0)
263
- rubocop-ast (1.49.1)
265
+ rubocop-ast (1.50.0)
264
266
  parser (>= 3.3.7.2)
265
267
  prism (~> 1.7)
266
268
  rubocop-rake (0.7.1)
@@ -274,16 +276,15 @@ GEM
274
276
  safety_net_attestation (0.5.0)
275
277
  jwt (>= 2.0, < 4.0)
276
278
  securerandom (0.4.1)
277
- sequel (5.105.0)
279
+ sequel (5.106.0)
278
280
  bigdecimal
279
281
  sequel-activerecord_connection (2.0.1)
280
282
  activerecord (>= 5.1)
281
283
  sequel (~> 5.38)
282
284
  sqlite3 (2.9.5-arm64-darwin)
283
285
  sqlite3 (2.9.5-x86_64-linux-gnu)
284
- stringio (3.2.0)
285
286
  thor (1.5.0)
286
- tilt (2.7.0)
287
+ tilt (2.8.0)
287
288
  timeout (0.6.1)
288
289
  tpm-key_attestation (0.14.1)
289
290
  bindata (~> 2.4)
@@ -318,13 +319,13 @@ GEM
318
319
  openssl (>= 2.2)
319
320
  safety_net_attestation (~> 0.5.0)
320
321
  tpm-key_attestation (~> 0.14.0)
321
- websocket-driver (0.8.0)
322
+ websocket-driver (0.8.2)
322
323
  base64
323
324
  websocket-extensions (>= 0.1.0)
324
325
  websocket-extensions (0.1.5)
325
326
  xpath (3.2.0)
326
327
  nokogiri (~> 1.8)
327
- zeitwerk (2.7.5)
328
+ zeitwerk (2.8.3)
328
329
 
329
330
  PLATFORMS
330
331
  arm64-darwin-25
@@ -349,7 +350,7 @@ DEPENDENCIES
349
350
  rubocop-rspec
350
351
  sequel-activerecord_connection (~> 2.0)
351
352
  sqlite3 (~> 2.9)
352
- tilt (~> 2.7)
353
+ tilt (~> 2.8)
353
354
  tryouts (~> 3.0)
354
355
  warning
355
356
  webauthn
@@ -136,30 +136,6 @@ module Rodauth
136
136
  mode_value != :silent && mode_value != :skip && !mode_value.nil?
137
137
  end
138
138
 
139
- # Internal method called by auth_cached_method :table_configuration
140
- #
141
- # Discovers and returns table configuration. This is called lazily
142
- # per-instance and the result is cached in @table_configuration.
143
- #
144
- # @return [Hash<Symbol, Hash>] Table configuration
145
- def _table_configuration
146
- config = Rodauth::TableInspector.table_information(self)
147
- rodauth_debug("[table_guard] Discovered #{config.size} required tables") if ENV['RODAUTH_DEBUG']
148
- config
149
- end
150
-
151
- # Internal method called by auth_cached_method :column_requirements
152
- #
153
- # Initializes and returns column requirements hash. This is called lazily
154
- # per-instance and the result is cached in @column_requirements.
155
- #
156
- # Structure: { table_name => { column_name => { type:, null:, feature: } } }
157
- #
158
- # @return [Hash<Symbol, Hash<Symbol, Hash>>] Column requirements by table
159
- def _column_requirements
160
- {}
161
- end
162
-
163
139
  # Check required tables and handle based on mode
164
140
  #
165
141
  # This is the main entry point for table validation
@@ -450,6 +426,33 @@ module Rodauth
450
426
 
451
427
  private
452
428
 
429
+ # Backing method for the +table_configuration+ auth_cached_method.
430
+ #
431
+ # Discovers and returns table configuration. This is called lazily
432
+ # per-instance and the result is cached in @table_configuration.
433
+ #
434
+ # Must stay private: rodauth registers it via auth_private_methods and (as
435
+ # of rodauth 2.45.0) warns when the backing method is not defined privately.
436
+ #
437
+ # @return [Hash<Symbol, Hash>] Table configuration
438
+ def _table_configuration
439
+ config = Rodauth::TableInspector.table_information(self)
440
+ rodauth_debug("[table_guard] Discovered #{config.size} required tables") if ENV['RODAUTH_DEBUG']
441
+ config
442
+ end
443
+
444
+ # Backing method for the +column_requirements+ auth_cached_method.
445
+ #
446
+ # Initializes and returns column requirements hash. This is called lazily
447
+ # per-instance and the result is cached in @column_requirements.
448
+ #
449
+ # Structure: { table_name => { column_name => { type:, null:, feature: } } }
450
+ #
451
+ # @return [Hash<Symbol, Hash<Symbol, Hash>>] Column requirements by table
452
+ def _column_requirements
453
+ {}
454
+ end
455
+
453
456
  # Build the set of unqualified table names that currently exist, including
454
457
  # views (which db.tables omits on most adapters but which can legitimately
455
458
  # back a Rodauth table).
@@ -4,6 +4,6 @@
4
4
 
5
5
  module Rodauth
6
6
  module Tools
7
- VERSION = '0.4.0'
7
+ VERSION = '0.4.1'
8
8
  end
9
9
  end
data/package-lock.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "name": "rodauth-tools",
9
9
  "version": "1.0.0",
10
10
  "devDependencies": {
11
- "markdownlint-cli2": "^0.23.0"
11
+ "markdownlint-cli2": "^0.23.2"
12
12
  }
13
13
  },
14
14
  "node_modules/@nodelib/fs.scandir": {
@@ -305,9 +305,9 @@
305
305
  }
306
306
  },
307
307
  "node_modules/globby": {
308
- "version": "16.2.0",
309
- "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz",
310
- "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==",
308
+ "version": "16.2.2",
309
+ "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.2.tgz",
310
+ "integrity": "sha512-NLvV9ubZ6NDsJaOpKPy3cQeJpKi9DcWiyCiFUpJPA0YihRqiE6RWaLUmgNNPr8MgPpLZjnBjSmou7uZBRJv9wA==",
311
311
  "dev": true,
312
312
  "license": "MIT",
313
313
  "dependencies": {
@@ -326,9 +326,9 @@
326
326
  }
327
327
  },
328
328
  "node_modules/ignore": {
329
- "version": "7.0.5",
330
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
331
- "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
329
+ "version": "7.0.6",
330
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz",
331
+ "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==",
332
332
  "dev": true,
333
333
  "license": "MIT",
334
334
  "engines": {
@@ -430,9 +430,9 @@
430
430
  }
431
431
  },
432
432
  "node_modules/js-yaml": {
433
- "version": "5.2.0",
434
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.0.tgz",
435
- "integrity": "sha512-YeLUMlvR4Ou1B119LIaM0r65JvbOBooJDc9yEu0dClb/uSC5P4FrLU8OCCz/HXWvtPoIrR0dRzABTjo1sTN9Bw==",
433
+ "version": "5.2.2",
434
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.2.tgz",
435
+ "integrity": "sha512-dayzUzKkJ1MkuUtZglSebU43utNXH0OWQByK9rKOOuYIO8M5TV1y+n8ALMdG0rdzBnfNkOmZEqrURepb0ejqBw==",
436
436
  "dev": true,
437
437
  "funding": [
438
438
  {
@@ -507,9 +507,9 @@
507
507
  }
508
508
  },
509
509
  "node_modules/markdown-it": {
510
- "version": "14.2.0",
511
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
512
- "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
510
+ "version": "14.3.0",
511
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz",
512
+ "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==",
513
513
  "dev": true,
514
514
  "funding": [
515
515
  {
@@ -524,8 +524,8 @@
524
524
  "license": "MIT",
525
525
  "dependencies": {
526
526
  "argparse": "^2.0.1",
527
- "entities": "^4.4.0",
528
- "linkify-it": "^5.0.1",
527
+ "entities": "^4.5.0",
528
+ "linkify-it": "^5.0.2",
529
529
  "mdurl": "^2.0.0",
530
530
  "punycode.js": "^2.3.1",
531
531
  "uc.micro": "^2.1.0"
@@ -535,9 +535,9 @@
535
535
  }
536
536
  },
537
537
  "node_modules/markdownlint": {
538
- "version": "0.41.0",
539
- "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.41.0.tgz",
540
- "integrity": "sha512-xMUI3ChBuRuxuLF4ENvCZyS8z/+Jly1coUcZwErKLIB3sDj7ojpaTBa1e9YVPhSN4jGEIjYGQCldbTJS/hqS+A==",
538
+ "version": "0.41.1",
539
+ "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.41.1.tgz",
540
+ "integrity": "sha512-qHKeU2E1bdyNAT077go2FVTNXvYcktN5IHtF6XyeD1l0PClxzSp2tUApAV14ORI8DGX4H9bNKZEzelZp4qn8IA==",
541
541
  "dev": true,
542
542
  "license": "MIT",
543
543
  "dependencies": {
@@ -559,18 +559,18 @@
559
559
  }
560
560
  },
561
561
  "node_modules/markdownlint-cli2": {
562
- "version": "0.23.0",
563
- "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.23.0.tgz",
564
- "integrity": "sha512-1nmgQmU/ZTMRVwYCDs7i1HI3zfBISnT2NNRv+9V01oOLZbAtqL+a7tldpPhBWBVBten3FqhMCGV6EUh9McqutQ==",
562
+ "version": "0.23.2",
563
+ "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.23.2.tgz",
564
+ "integrity": "sha512-eUhcnkSpzURo/o4htSqc7LPDszgOOTknhU4eY/sPHvMCLxnTCYscv1gw1/js/idmaZPisv9ECVEIORcllqjTUw==",
565
565
  "dev": true,
566
566
  "license": "MIT",
567
567
  "dependencies": {
568
- "globby": "16.2.0",
569
- "js-yaml": "5.2.0",
568
+ "globby": "16.2.2",
569
+ "js-yaml": "5.2.2",
570
570
  "jsonc-parser": "3.3.1",
571
571
  "jsonpointer": "5.0.1",
572
- "markdown-it": "14.2.0",
573
- "markdownlint": "0.41.0",
572
+ "markdown-it": "14.3.0",
573
+ "markdownlint": "0.41.1",
574
574
  "markdownlint-cli2-formatter-default": "0.0.6",
575
575
  "micromatch": "4.0.8",
576
576
  "smol-toml": "1.7.0"
data/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "version": "1.0.0",
4
4
  "private": true,
5
5
  "devDependencies": {
6
- "markdownlint-cli2": "^0.23.0"
6
+ "markdownlint-cli2": "^0.23.2"
7
7
  },
8
8
  "scripts": {
9
9
  "lint:md": "markdownlint-cli2 '**/*.md' '#node_modules'"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - delano
@@ -65,8 +65,8 @@ files:
65
65
  - ".pre-commit-config.yaml"
66
66
  - ".rubocop.yml"
67
67
  - ".rubocop_todo.yml"
68
+ - AGENTS.md
68
69
  - CHANGELOG.md
69
- - CLAUDE.md
70
70
  - CODE_OF_CONDUCT.md
71
71
  - CONTRIBUTING.md
72
72
  - Gemfile
@@ -133,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
133
  - !ruby/object:Gem::Version
134
134
  version: '0'
135
135
  requirements: []
136
- rubygems_version: 3.7.2
136
+ rubygems_version: 3.6.9
137
137
  specification_version: 4
138
138
  summary: Framework-agnostic Rodauth tools
139
139
  test_files: []