better_auth-sinatra 0.8.0 → 0.10.0
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 +5 -0
- data/README.md +33 -6
- data/lib/better_auth/sinatra/extension.rb +1 -1
- data/lib/better_auth/sinatra/helpers.rb +23 -15
- data/lib/better_auth/sinatra/migration.rb +21 -227
- data/lib/better_auth/sinatra/mounted_app.rb +12 -11
- data/lib/better_auth/sinatra/tasks.rb +41 -5
- data/lib/better_auth/sinatra/version.rb +1 -1
- data/lib/better_auth/sinatra.rb +19 -2
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c1354b443fe041ddaa63d80da87d5386dd88128ff7b0fdce339b4ec123751e4e
|
|
4
|
+
data.tar.gz: 38c93a00515742217abe673835752acc65465e6c207904d1219c605f94409ad4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 674b03f0268f4ed4b07f4d66c0ac348645d3506a7787e0593cd1e33ffdc8a20c5b045e701c998621c7d15ce006c520ec07cc538c4cbfe03fd03263b41b63eaae
|
|
7
|
+
data.tar.gz: 4c13b0fdec4ec941beef0786b353abaee4b9ec56d5a952af91414e0a65e108f4adb7ea6b8c1801024ad66da789cb5e978b319eb7bc99a445ff0f962b8db980e2
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.10.0 - 2026-05-21
|
|
6
|
+
|
|
7
|
+
- Removed obsolete helper wiring and expanded mounted app, migration, and routing coverage.
|
|
8
|
+
- Updated Sinatra docs for current mounting and integration behavior.
|
|
9
|
+
|
|
5
10
|
## 0.7.0 - 2026-05-05
|
|
6
11
|
|
|
7
12
|
- Fixed auth dispatch when Rack splits mounted paths across `SCRIPT_NAME` and `PATH_INFO`.
|
data/README.md
CHANGED
|
@@ -44,6 +44,10 @@ cannot be `/`, because that would capture every Sinatra route before the app can
|
|
|
44
44
|
handle it. The core app still owns routes such as `/ok`, `/sign-up/email`,
|
|
45
45
|
`/sign-in/email`, and plugin endpoints.
|
|
46
46
|
|
|
47
|
+
Call `better_auth` once per Sinatra app class. Registering it more than once is
|
|
48
|
+
treated as a configuration error because each Rack mount must delegate to one
|
|
49
|
+
core Better Auth instance.
|
|
50
|
+
|
|
47
51
|
`better_auth at:` sets the path prefix that Better Auth uses as its core
|
|
48
52
|
`base_path`. The adapter supports two common Rack mount patterns:
|
|
49
53
|
|
|
@@ -58,7 +62,10 @@ When using reverse proxies, `Rack::URLMap`, or another parent app, make sure the
|
|
|
58
62
|
`PATH_INFO` visible to Sinatra still aligns with the configured auth prefix.
|
|
59
63
|
`SCRIPT_NAME` handling depends on the Rack server and mount stack, so verify
|
|
60
64
|
redirect URLs and cookie paths in integration tests when mounting below a
|
|
61
|
-
sub-path.
|
|
65
|
+
sub-path. If the public auth URL includes a parent mount prefix, set
|
|
66
|
+
`config.base_url` to that public URL, for example `https://app.example/api/auth`;
|
|
67
|
+
core URL inference uses the configured Better Auth base path and cannot infer
|
|
68
|
+
every parent Rack mount layout from Sinatra alone.
|
|
62
69
|
|
|
63
70
|
## Helpers
|
|
64
71
|
|
|
@@ -91,11 +98,27 @@ Available tasks:
|
|
|
91
98
|
rake better_auth:install
|
|
92
99
|
rake better_auth:generate:migration
|
|
93
100
|
rake better_auth:migrate
|
|
101
|
+
rake better_auth:migrate:status
|
|
102
|
+
rake better_auth:doctor
|
|
94
103
|
rake better_auth:routes
|
|
95
104
|
```
|
|
96
105
|
|
|
97
106
|
`better_auth:install` creates `config/better_auth.rb`. SQL migrations are
|
|
98
|
-
generated under `db/better_auth/migrate`.
|
|
107
|
+
generated under `db/better_auth/migrate`. When a SQL adapter is configured,
|
|
108
|
+
generation introspects the current database and emits only missing Better Auth
|
|
109
|
+
tables, columns, and indexes.
|
|
110
|
+
|
|
111
|
+
Migration and route tasks load Better Auth configuration from
|
|
112
|
+
`config/better_auth.rb` by default. Set `BETTER_AUTH_CONFIG` (or the
|
|
113
|
+
OpenAuth-compatible `OPEN_AUTH_CONFIG`) to a shared config file if your app keeps
|
|
114
|
+
Better Auth setup elsewhere:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
BETTER_AUTH_CONFIG=config/auth/better_auth.rb rake better_auth:generate:migration
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The migration tasks fail when no config file is found, so generated SQL cannot
|
|
121
|
+
silently omit app plugins or custom schema options.
|
|
99
122
|
|
|
100
123
|
## Database Notes
|
|
101
124
|
|
|
@@ -103,10 +126,14 @@ Sinatra does not include a Rails-style database layer or migration command.
|
|
|
103
126
|
This adapter uses Better Auth core SQL adapters for migrations. Set
|
|
104
127
|
`BETTER_AUTH_DIALECT=postgres`, `mysql`, or `sqlite` when generating SQL.
|
|
105
128
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
129
|
+
The migration runner delegates SQL rendering and execution behavior to the core
|
|
130
|
+
Better Auth SQL migration layer. It handles multiple statements, quoted strings,
|
|
131
|
+
and PostgreSQL dollar-quoted blocks; DDL rollback behavior still depends on the
|
|
132
|
+
database, so back up production data before migrating.
|
|
133
|
+
|
|
134
|
+
Exhaustive adapter behavior for PostgreSQL, MySQL, SQLite, and other database
|
|
135
|
+
families is covered in the core `better_auth` package. This Sinatra package only
|
|
136
|
+
smoke-tests that its configuration and Rake tasks delegate to those core paths.
|
|
110
137
|
|
|
111
138
|
ActiveRecord-backed Sinatra migrations are not supported yet. Apps that already
|
|
112
139
|
use `sinatra-activerecord` can still configure Better Auth manually, but the v1
|
|
@@ -16,7 +16,7 @@ module BetterAuth
|
|
|
16
16
|
"better_auth mount path cannot be '/' (it would capture every request). " \
|
|
17
17
|
"Use a prefix such as #{BetterAuth::Configuration::DEFAULT_BASE_PATH.inspect}."
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
raise ArgumentError, "better_auth is already configured for this app" if respond_to?(:better_auth_auth)
|
|
20
20
|
|
|
21
21
|
config = BetterAuth::Sinatra.configuration.copy
|
|
22
22
|
yield config if block_given?
|
|
@@ -54,26 +54,34 @@ module BetterAuth
|
|
|
54
54
|
def resolve_better_auth_session
|
|
55
55
|
auth = better_auth_auth
|
|
56
56
|
result = auth.api.get_session(
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
request: Rack::Request.new(request.env),
|
|
58
|
+
method: "GET",
|
|
59
|
+
as_response: true
|
|
59
60
|
)
|
|
61
|
+
return resolve_better_auth_response(result) if result.respond_to?(:headers) && result.respond_to?(:body)
|
|
62
|
+
|
|
60
63
|
apply_better_auth_response_headers(result[:headers] || result["headers"] || {})
|
|
61
64
|
result[:response] || result["response"]
|
|
62
65
|
end
|
|
63
66
|
|
|
64
|
-
def
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
def resolve_better_auth_response(response)
|
|
68
|
+
apply_better_auth_response_headers(response.headers || {})
|
|
69
|
+
body = response.body.respond_to?(:join) ? response.body.join : response.body.to_s
|
|
70
|
+
payload = body.empty? ? nil : JSON.parse(body)
|
|
71
|
+
raise_better_auth_response_error(response, payload) if response.status.to_i >= 400
|
|
72
|
+
|
|
73
|
+
payload
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def raise_better_auth_response_error(response, payload)
|
|
77
|
+
payload = payload.is_a?(Hash) ? payload : {}
|
|
78
|
+
status = BetterAuth::APIError::STATUS_CODES.key(response.status.to_i) || "INTERNAL_SERVER_ERROR"
|
|
79
|
+
raise BetterAuth::APIError.new(
|
|
80
|
+
status,
|
|
81
|
+
message: payload["message"],
|
|
82
|
+
code: payload["code"],
|
|
83
|
+
headers: response.headers || {}
|
|
84
|
+
)
|
|
77
85
|
end
|
|
78
86
|
|
|
79
87
|
def apply_better_auth_response_headers(headers)
|
|
@@ -1,250 +1,44 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "better_auth/sql_migration"
|
|
4
4
|
|
|
5
5
|
module BetterAuth
|
|
6
6
|
module Sinatra
|
|
7
7
|
module Migration
|
|
8
|
-
DEFAULT_MIGRATIONS_PATH =
|
|
9
|
-
MISSING_MIGRATIONS_TABLE_MESSAGES =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/table .* doesn't exist/i,
|
|
13
|
-
/undefined table/i,
|
|
14
|
-
/invalid object name/i
|
|
15
|
-
].freeze
|
|
16
|
-
|
|
17
|
-
class UnsupportedAdapterError < StandardError; end
|
|
8
|
+
DEFAULT_MIGRATIONS_PATH = BetterAuth::SQLMigration::DEFAULT_MIGRATIONS_PATH
|
|
9
|
+
MISSING_MIGRATIONS_TABLE_MESSAGES = BetterAuth::SQLMigration::MISSING_MIGRATIONS_TABLE_MESSAGES
|
|
10
|
+
UnsupportedAdapterError = BetterAuth::SQLMigration::UnsupportedAdapterError
|
|
11
|
+
GENERATOR = "better_auth-sinatra"
|
|
18
12
|
|
|
19
13
|
module_function
|
|
20
14
|
|
|
21
15
|
def render(options, dialect:)
|
|
22
|
-
dialect
|
|
23
|
-
config = configuration_for(options)
|
|
24
|
-
statements = BetterAuth::Schema::SQL.create_statements(config, dialect: dialect)
|
|
25
|
-
[
|
|
26
|
-
"-- Generated by better_auth-sinatra",
|
|
27
|
-
"-- Dialect: #{dialect}",
|
|
28
|
-
"",
|
|
29
|
-
statements.join("\n\n"),
|
|
30
|
-
""
|
|
31
|
-
].join("\n")
|
|
16
|
+
BetterAuth::SQLMigration.render(options, dialect: dialect, generator: GENERATOR)
|
|
32
17
|
end
|
|
33
18
|
|
|
34
|
-
def generate(options, dialect:, migrations_path: DEFAULT_MIGRATIONS_PATH, timestamp: Time.now.utc.strftime("%Y%m%d%H%M%S"))
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
19
|
+
def generate(options, dialect:, migrations_path: DEFAULT_MIGRATIONS_PATH, timestamp: Time.now.utc.strftime("%Y%m%d%H%M%S"), connection: nil)
|
|
20
|
+
BetterAuth::SQLMigration.generate(
|
|
21
|
+
options,
|
|
22
|
+
dialect: dialect,
|
|
23
|
+
generator: GENERATOR,
|
|
24
|
+
migrations_path: migrations_path,
|
|
25
|
+
timestamp: timestamp,
|
|
26
|
+
connection: connection
|
|
27
|
+
)
|
|
42
28
|
end
|
|
43
29
|
|
|
44
30
|
def migrate(auth_or_options, migrations_path: DEFAULT_MIGRATIONS_PATH)
|
|
45
|
-
|
|
46
|
-
adapter = auth.context.adapter
|
|
47
|
-
unless adapter.respond_to?(:dialect) && adapter.respond_to?(:connection)
|
|
48
|
-
raise UnsupportedAdapterError, "better_auth-sinatra migrations require core SQL adapters with connection and dialect support"
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
connection = adapter.connection
|
|
52
|
-
dialect = normalize_dialect(adapter.dialect)
|
|
53
|
-
files = Dir[File.join(migrations_path, "*.sql")].sort
|
|
54
|
-
ensure_schema_migrations!(connection, dialect)
|
|
55
|
-
applied = applied_migrations(connection, dialect)
|
|
56
|
-
|
|
57
|
-
files.reject { |file| applied.include?(File.basename(file)) }.each do |file|
|
|
58
|
-
execute_sql(connection, File.read(file))
|
|
59
|
-
record_migration(connection, dialect, File.basename(file))
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def configuration_for(options)
|
|
64
|
-
return options.options if options.is_a?(BetterAuth::Auth)
|
|
65
|
-
return options if options.is_a?(BetterAuth::Configuration)
|
|
66
|
-
|
|
67
|
-
BetterAuth::Configuration.new(options)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def auth_for(value)
|
|
71
|
-
return value if value.is_a?(BetterAuth::Auth)
|
|
72
|
-
|
|
73
|
-
BetterAuth.auth(value)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def ensure_schema_migrations!(connection, dialect)
|
|
77
|
-
sql = case dialect
|
|
78
|
-
when :postgres, :sqlite
|
|
79
|
-
%(CREATE TABLE IF NOT EXISTS #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} text PRIMARY KEY);)
|
|
80
|
-
when :mysql
|
|
81
|
-
%(CREATE TABLE IF NOT EXISTS #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} varchar(191) PRIMARY KEY) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;)
|
|
82
|
-
when :mssql
|
|
83
|
-
%(IF OBJECT_ID(N'#{quote("better_auth_schema_migrations", dialect)}', N'U') IS NULL CREATE TABLE #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} varchar(255) PRIMARY KEY);)
|
|
84
|
-
else
|
|
85
|
-
raise UnsupportedAdapterError, "Unsupported SQL dialect for better_auth-sinatra migrations: #{dialect}"
|
|
86
|
-
end
|
|
87
|
-
execute_sql(connection, sql)
|
|
31
|
+
BetterAuth::SQLMigration.migrate(auth_or_options, migrations_path: migrations_path)
|
|
88
32
|
end
|
|
89
33
|
|
|
90
|
-
def
|
|
91
|
-
|
|
92
|
-
Array(rows).map { |row| row["version"] || row[:version] }
|
|
93
|
-
rescue UnsupportedAdapterError
|
|
94
|
-
raise
|
|
95
|
-
rescue => error
|
|
96
|
-
raise error unless missing_schema_migrations_table?(error)
|
|
97
|
-
|
|
98
|
-
[]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def record_migration(connection, dialect, version)
|
|
102
|
-
sql = "INSERT INTO #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)}) VALUES (#{literal(version)});"
|
|
103
|
-
execute_sql(connection, sql)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def execute_sql(connection, sql)
|
|
107
|
-
statements(sql).each_with_object([]) do |statement, results|
|
|
108
|
-
result =
|
|
109
|
-
if connection.respond_to?(:exec)
|
|
110
|
-
connection.exec(statement)
|
|
111
|
-
elsif connection.respond_to?(:execute)
|
|
112
|
-
connection.execute(statement)
|
|
113
|
-
elsif connection.respond_to?(:query)
|
|
114
|
-
connection.query(statement)
|
|
115
|
-
else
|
|
116
|
-
raise UnsupportedAdapterError, "SQL connection does not support exec, execute, or query"
|
|
117
|
-
end
|
|
118
|
-
results.concat(result.to_a) if result.respond_to?(:to_a)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def statements(sql)
|
|
123
|
-
normalized = sql.to_s.gsub("\r\n", "\n").strip
|
|
124
|
-
return [] if normalized.empty?
|
|
125
|
-
|
|
126
|
-
split_sql_statements(normalized)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def split_sql_statements(sql)
|
|
130
|
-
output = []
|
|
131
|
-
buffer = +""
|
|
132
|
-
index = 0
|
|
133
|
-
quote = nil
|
|
134
|
-
line_comment = false
|
|
135
|
-
block_comment = false
|
|
136
|
-
dollar_tag = nil
|
|
137
|
-
|
|
138
|
-
while index < sql.length
|
|
139
|
-
state = {
|
|
140
|
-
quote: quote,
|
|
141
|
-
line_comment: line_comment,
|
|
142
|
-
block_comment: block_comment,
|
|
143
|
-
dollar_tag: dollar_tag
|
|
144
|
-
}
|
|
145
|
-
index, quote, line_comment, block_comment, dollar_tag = scan_sql_character(sql, buffer, index, state, output)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
tail = buffer.strip
|
|
149
|
-
output << tail unless tail.empty?
|
|
150
|
-
output
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def scan_sql_character(sql, buffer, index, state, output)
|
|
154
|
-
char = sql[index]
|
|
155
|
-
next_char = sql[index + 1]
|
|
156
|
-
quote = state[:quote]
|
|
157
|
-
line_comment = state[:line_comment]
|
|
158
|
-
block_comment = state[:block_comment]
|
|
159
|
-
dollar_tag = state[:dollar_tag]
|
|
160
|
-
|
|
161
|
-
return scan_line_comment(buffer, index, char) + [quote, false, block_comment, dollar_tag] if line_comment && char == "\n"
|
|
162
|
-
return scan_line_comment(buffer, index, char) + [quote, true, block_comment, dollar_tag] if line_comment
|
|
163
|
-
return scan_block_comment(buffer, index, char, next_char, quote, line_comment, dollar_tag) if block_comment
|
|
164
|
-
return scan_dollar_quote(sql, buffer, index, char, quote, line_comment, block_comment, dollar_tag) if dollar_tag
|
|
165
|
-
return scan_quoted_string(sql, buffer, index, char, quote, line_comment, block_comment, dollar_tag) if quote
|
|
166
|
-
return [index + 2, quote, true, block_comment, dollar_tag].tap { buffer << char << next_char } if char == "-" && next_char == "-"
|
|
167
|
-
return [index + 2, quote, line_comment, true, dollar_tag].tap { buffer << char << next_char } if char == "/" && next_char == "*"
|
|
168
|
-
|
|
169
|
-
tag = dollar_quote_tag_at(sql, index)
|
|
170
|
-
return [index + tag.length, quote, line_comment, block_comment, tag].tap { buffer << tag } if tag
|
|
171
|
-
return [index + 1, char, line_comment, block_comment, dollar_tag].tap { buffer << char } if char == "'" || char == "\""
|
|
172
|
-
|
|
173
|
-
if char == ";"
|
|
174
|
-
statement = buffer.strip
|
|
175
|
-
output << statement unless statement.empty?
|
|
176
|
-
buffer.clear
|
|
177
|
-
return [index + 1, quote, line_comment, block_comment, dollar_tag]
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
buffer << char
|
|
181
|
-
[index + 1, quote, line_comment, block_comment, dollar_tag]
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def scan_line_comment(buffer, index, char)
|
|
185
|
-
buffer << char
|
|
186
|
-
[index + 1]
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def scan_block_comment(buffer, index, char, next_char, quote, line_comment, dollar_tag)
|
|
190
|
-
buffer << char
|
|
191
|
-
if char == "*" && next_char == "/"
|
|
192
|
-
buffer << next_char
|
|
193
|
-
[index + 2, quote, line_comment, false, dollar_tag]
|
|
194
|
-
else
|
|
195
|
-
[index + 1, quote, line_comment, true, dollar_tag]
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def scan_dollar_quote(sql, buffer, index, char, quote, line_comment, block_comment, dollar_tag)
|
|
200
|
-
if sql[index, dollar_tag.length] == dollar_tag
|
|
201
|
-
buffer << dollar_tag
|
|
202
|
-
[index + dollar_tag.length, quote, line_comment, block_comment, nil]
|
|
203
|
-
else
|
|
204
|
-
buffer << char
|
|
205
|
-
[index + 1, quote, line_comment, block_comment, dollar_tag]
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def scan_quoted_string(sql, buffer, index, char, quote, line_comment, block_comment, dollar_tag)
|
|
210
|
-
buffer << char
|
|
211
|
-
if char == quote && sql[index + 1] == quote
|
|
212
|
-
buffer << sql[index + 1]
|
|
213
|
-
[index + 2, quote, line_comment, block_comment, dollar_tag]
|
|
214
|
-
elsif char == quote
|
|
215
|
-
[index + 1, nil, line_comment, block_comment, dollar_tag]
|
|
216
|
-
else
|
|
217
|
-
[index + 1, quote, line_comment, block_comment, dollar_tag]
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def dollar_quote_tag_at(sql, index)
|
|
222
|
-
match = sql[index..]&.match(/\A\$[A-Za-z_][A-Za-z0-9_]*\$|\A\$\$/)
|
|
223
|
-
match&.[](0)
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def missing_schema_migrations_table?(error)
|
|
227
|
-
message = error.message.to_s
|
|
228
|
-
MISSING_MIGRATIONS_TABLE_MESSAGES.any? { |pattern| message.match?(pattern) }
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def quote(identifier, dialect)
|
|
232
|
-
BetterAuth::Schema::SQL.quote(identifier, dialect)
|
|
233
|
-
end
|
|
34
|
+
def method_missing(name, *args, **kwargs, &block)
|
|
35
|
+
return BetterAuth::SQLMigration.public_send(name, *args, **kwargs, &block) if BetterAuth::SQLMigration.respond_to?(name)
|
|
234
36
|
|
|
235
|
-
|
|
236
|
-
"'#{value.to_s.gsub("'", "''")}'"
|
|
37
|
+
super
|
|
237
38
|
end
|
|
238
39
|
|
|
239
|
-
def
|
|
240
|
-
|
|
241
|
-
when "postgresql"
|
|
242
|
-
:postgres
|
|
243
|
-
when "sqlite3"
|
|
244
|
-
:sqlite
|
|
245
|
-
else
|
|
246
|
-
value.to_sym
|
|
247
|
-
end
|
|
40
|
+
def respond_to_missing?(name, include_private = false)
|
|
41
|
+
BetterAuth::SQLMigration.respond_to?(name, include_private) || super
|
|
248
42
|
end
|
|
249
43
|
end
|
|
250
44
|
end
|
|
@@ -29,7 +29,7 @@ module BetterAuth
|
|
|
29
29
|
def mount_matches?(env)
|
|
30
30
|
return false if @mount_path == "/"
|
|
31
31
|
|
|
32
|
-
path_info = normalize_path(env["PATH_INFO"])
|
|
32
|
+
path_info = normalize_path(env["PATH_INFO"], trim: true)
|
|
33
33
|
return true if path_info == @mount_path || path_info.start_with?("#{@mount_path}/")
|
|
34
34
|
|
|
35
35
|
full = full_request_path(env)
|
|
@@ -39,33 +39,34 @@ module BetterAuth
|
|
|
39
39
|
def full_request_path(env)
|
|
40
40
|
script = env.fetch("SCRIPT_NAME", "").to_s
|
|
41
41
|
path = env.fetch("PATH_INFO", "").to_s
|
|
42
|
-
normalize_path("#{script}#{path}")
|
|
42
|
+
normalize_path("#{script}#{path}", trim: true)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def mounted_path_info(env)
|
|
46
|
-
path_info = normalize_path(env["PATH_INFO"])
|
|
47
|
-
|
|
46
|
+
path_info = normalize_path(env["PATH_INFO"], trim: false)
|
|
47
|
+
comparable_path = normalize_path(env["PATH_INFO"], trim: true)
|
|
48
|
+
return path_info if comparable_path == @mount_path || comparable_path.start_with?("#{@mount_path}/")
|
|
48
49
|
|
|
49
|
-
script_name = normalize_path(env["SCRIPT_NAME"])
|
|
50
|
+
script_name = normalize_path(env["SCRIPT_NAME"], trim: true)
|
|
50
51
|
prefix = (script_name == "/") ? @mount_path : script_name
|
|
51
|
-
return path_info if
|
|
52
|
+
return path_info if comparable_path == prefix || comparable_path.start_with?("#{prefix}/")
|
|
52
53
|
|
|
53
|
-
normalize_path("#{prefix}/#{path_info.delete_prefix("/")}")
|
|
54
|
+
normalize_path("#{prefix}/#{path_info.delete_prefix("/")}", trim: false)
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def shared_mount_rewrite?(env, rewritten_path)
|
|
57
|
-
script_name = normalize_path(env["SCRIPT_NAME"])
|
|
58
|
-
original_path = normalize_path(env["PATH_INFO"])
|
|
58
|
+
script_name = normalize_path(env["SCRIPT_NAME"], trim: true)
|
|
59
|
+
original_path = normalize_path(env["PATH_INFO"], trim: true)
|
|
59
60
|
script_name != "/" &&
|
|
60
61
|
!original_path.start_with?("#{@mount_path}/") &&
|
|
61
62
|
rewritten_path.start_with?("#{@mount_path}/")
|
|
62
63
|
end
|
|
63
64
|
|
|
64
|
-
def normalize_path(path)
|
|
65
|
+
def normalize_path(path, trim: true)
|
|
65
66
|
normalized = path.to_s
|
|
66
67
|
normalized = "/#{normalized}" unless normalized.start_with?("/")
|
|
67
68
|
normalized = normalized.squeeze("/")
|
|
68
|
-
normalized = normalized.delete_suffix("/")
|
|
69
|
+
normalized = normalized.delete_suffix("/") if trim && normalized != "/"
|
|
69
70
|
normalized.empty? ? "/" : normalized
|
|
70
71
|
end
|
|
71
72
|
end
|
|
@@ -22,23 +22,59 @@ namespace :better_auth do
|
|
|
22
22
|
namespace :generate do
|
|
23
23
|
desc "Create the Better Auth SQL migration"
|
|
24
24
|
task :migration do
|
|
25
|
-
BetterAuth::Sinatra.load_app_config
|
|
25
|
+
BetterAuth::Sinatra.load_app_config!
|
|
26
26
|
dialect = BetterAuth::Sinatra::Migration.normalize_dialect(BetterAuth::Env.get("BETTER_AUTH_DIALECT") || BetterAuth::Env.get("BETTER_AUTH_DATABASE_DIALECT") || "postgres")
|
|
27
27
|
config = BetterAuth::Sinatra.migration_configuration
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
adapter = begin
|
|
29
|
+
BetterAuth::Sinatra.auth.context.adapter
|
|
30
|
+
rescue
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
connection = if adapter&.respond_to?(:connection) && adapter.respond_to?(:dialect) && BetterAuth::Sinatra::Migration.normalize_dialect(adapter.dialect) == dialect
|
|
34
|
+
adapter.connection
|
|
35
|
+
end
|
|
36
|
+
path = BetterAuth::Sinatra::Migration.generate(config, dialect: dialect, connection: connection)
|
|
37
|
+
puts(path ? "create #{path}" : "no migrations needed")
|
|
30
38
|
end
|
|
31
39
|
end
|
|
32
40
|
|
|
33
41
|
desc "Run pending Better Auth SQL migrations"
|
|
34
42
|
task :migrate do
|
|
35
|
-
BetterAuth::Sinatra.load_app_config
|
|
43
|
+
BetterAuth::Sinatra.load_app_config!
|
|
36
44
|
BetterAuth::Sinatra::Migration.migrate(BetterAuth::Sinatra.auth)
|
|
37
45
|
end
|
|
38
46
|
|
|
47
|
+
namespace :migrate do
|
|
48
|
+
desc "Print pending Better Auth SQL migration status"
|
|
49
|
+
task :status do
|
|
50
|
+
BetterAuth::Sinatra.load_app_config!
|
|
51
|
+
auth = BetterAuth::Sinatra.auth
|
|
52
|
+
adapter = auth.context.adapter
|
|
53
|
+
unless adapter.respond_to?(:connection) && adapter.respond_to?(:dialect)
|
|
54
|
+
raise BetterAuth::Sinatra::Migration::UnsupportedAdapterError, "Better Auth SQL migrations require core SQL adapters with connection and dialect support"
|
|
55
|
+
end
|
|
56
|
+
plan = BetterAuth::Sinatra::Migration.plan(auth.options, connection: adapter.connection, dialect: adapter.dialect)
|
|
57
|
+
if plan.empty?
|
|
58
|
+
puts "No migrations needed."
|
|
59
|
+
else
|
|
60
|
+
plan.to_create.each { |change| puts "create table #{change.table_name}" }
|
|
61
|
+
plan.to_add.each { |change| puts "add #{change.fields.keys.join(", ")} to #{change.table_name}" }
|
|
62
|
+
plan.to_index.each { |change| puts "create index #{change.name}" }
|
|
63
|
+
plan.warnings.each { |warning| puts "warning: #{warning}" }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
desc "Check Better Auth configuration and schema health"
|
|
69
|
+
task :doctor do
|
|
70
|
+
BetterAuth::Sinatra.load_app_config!
|
|
71
|
+
exit_code = BetterAuth::Doctor.print(BetterAuth::Doctor.check(BetterAuth::Sinatra.migration_configuration), stdout: $stdout, stderr: $stderr)
|
|
72
|
+
abort if exit_code != 0
|
|
73
|
+
end
|
|
74
|
+
|
|
39
75
|
desc "Print Better Auth Sinatra mount information"
|
|
40
76
|
task :routes do
|
|
41
|
-
BetterAuth::Sinatra.load_app_config
|
|
77
|
+
BetterAuth::Sinatra.load_app_config!
|
|
42
78
|
mount_path = BetterAuth::Sinatra.configuration.base_path
|
|
43
79
|
puts "#{mount_path}/* -> BetterAuth.auth"
|
|
44
80
|
puts "Core routes are handled by Better Auth; use the OpenAPI plugin or HTTP API docs for endpoint details."
|
data/lib/better_auth/sinatra.rb
CHANGED
|
@@ -45,8 +45,25 @@ module BetterAuth
|
|
|
45
45
|
BetterAuth::Configuration.new(options)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def
|
|
49
|
-
|
|
48
|
+
def app_config_path(path = nil)
|
|
49
|
+
path || BetterAuth::Env.get("BETTER_AUTH_CONFIG") || "config/better_auth.rb"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def load_app_config(path = nil)
|
|
53
|
+
config_path = app_config_path(path)
|
|
54
|
+
return false unless File.exist?(config_path)
|
|
55
|
+
|
|
56
|
+
load config_path
|
|
57
|
+
true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def load_app_config!(path = nil)
|
|
61
|
+
config_path = app_config_path(path)
|
|
62
|
+
return true if load_app_config(config_path)
|
|
63
|
+
|
|
64
|
+
raise ArgumentError,
|
|
65
|
+
"Better Auth Sinatra config not found at #{config_path.inspect}. " \
|
|
66
|
+
"Run `rake better_auth:install` or set BETTER_AUTH_CONFIG to a shared config file."
|
|
50
67
|
end
|
|
51
68
|
|
|
52
69
|
def default_config_template
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: better_auth-sinatra
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sebastian Sala
|
|
@@ -134,14 +134,14 @@ files:
|
|
|
134
134
|
- lib/better_auth/sinatra/tasks.rb
|
|
135
135
|
- lib/better_auth/sinatra/version.rb
|
|
136
136
|
- lib/better_auth_sinatra.rb
|
|
137
|
-
homepage: https://github.com/sebasxsala/better-auth
|
|
137
|
+
homepage: https://github.com/sebasxsala/better-auth-rb
|
|
138
138
|
licenses:
|
|
139
139
|
- MIT
|
|
140
140
|
metadata:
|
|
141
|
-
homepage_uri: https://github.com/sebasxsala/better-auth
|
|
142
|
-
source_code_uri: https://github.com/sebasxsala/better-auth
|
|
143
|
-
changelog_uri: https://github.com/sebasxsala/better-auth/blob/main/packages/better_auth-sinatra/CHANGELOG.md
|
|
144
|
-
bug_tracker_uri: https://github.com/sebasxsala/better-auth/issues
|
|
141
|
+
homepage_uri: https://github.com/sebasxsala/better-auth-rb
|
|
142
|
+
source_code_uri: https://github.com/sebasxsala/better-auth-rb
|
|
143
|
+
changelog_uri: https://github.com/sebasxsala/better-auth-rb/blob/main/packages/better_auth-sinatra/CHANGELOG.md
|
|
144
|
+
bug_tracker_uri: https://github.com/sebasxsala/better-auth-rb/issues
|
|
145
145
|
rdoc_options: []
|
|
146
146
|
require_paths:
|
|
147
147
|
- lib
|