openreceive-rails 0.2.1 → 0.2.3

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: 3709b7ea572da6d1a0a259c84f95ea3f5e41ec1fc7dc9dd067a8a77951bd0691
4
- data.tar.gz: 0c42db53e3d8dff9c5796ebc53b15c87b02286c627250be6a2741327d3082403
3
+ metadata.gz: 4fd30ded365e254b6529fc4c006d8ec597a83f659cdf4b60b34127817d7fc995
4
+ data.tar.gz: b272234e0a5eadb74ac2c63a9df71d3af0cc62d290497005af206653a489743d
5
5
  SHA512:
6
- metadata.gz: '0930dafa248e3f22fbc2297fac22a8d14b09ed407c49c08f01cd5de48cb7213f49370644233a74efd45782432a1629a12439a312c4c074f1a9401dcc8ccda51d'
7
- data.tar.gz: 2990f0db5d68c3b8a0fa4c1bace12eb7708f1961894d6bd444cdd593f259aead0249b28ba127e2cc246903ec4517c6f8944ae3a7cde14d4bf58ea6dd7fa65e1f
6
+ metadata.gz: 85bdd9b23bc16d13d4e1b3e4d7bc788cf2987c44431a9c345c9a6f48c63aea11f27e8c8ab7d40b1343e787048a15768eed8baaf40bf60d2e6b6b27fedb1d5d47
7
+ data.tar.gz: 8ed6a9cd303864c971b5b8597e34cbe2e1e6b2cf9e5b1651a38f6183e43f4f69ab1a05af90c364f237b3698432c101c059eaf61bba9738cae692a4aea65ffb93
data/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.3 - 2026-08-25
4
+
5
+ The Ruby gems release in lockstep with the npm workspace version. The full
6
+ release narrative lives in the repository-root
7
+ [CHANGELOG](https://github.com/openreceive/openreceive/blob/master/CHANGELOG.md);
8
+ entries here are scoped to this gem.
9
+
10
+ - The mounted engine inherits `openreceive-server`'s `POST /checkouts` change:
11
+ the response now carries `payment_methods` alongside `checkout` (HTTP
12
+ contract 0.4.1). No configuration change; hosts using `@openreceive/browser`
13
+ see no difference.
14
+
15
+ ## 0.2.2 - 2026-08-25
16
+
17
+ The Ruby gems release in lockstep with the npm workspace version. The full
18
+ release narrative lives in the repository-root
19
+ [CHANGELOG](https://github.com/openreceive/openreceive/blob/master/CHANGELOG.md);
20
+ entries here are scoped to this gem.
21
+
22
+ - **Fixed: the generated migration would not load.** `openreceive:install` wrote
23
+ `class CreateOpenreceiveTables`, but the engine's own acronym inflection makes
24
+ Rails resolve the file name to `CreateOpenReceiveTables`, so
25
+ `bin/rails db:migrate` failed with `NameError` on every install. The template
26
+ declares the class Rails looks for, and a new generator test registers the
27
+ acronym and runs the migration for real.
28
+ - **`nwc-ruby` is now a runtime dependency.** Building the client from `NWC_URI`
29
+ is this gem's DEFAULT wallet path, so installing only `openreceive-rails`
30
+ used to boot fine and then 500 on the first checkout with
31
+ `Install nwc-ruby or configure nwc_client.` `config.nwc_client` remains the
32
+ override for hosts bringing their own client.
33
+ - **Fixed: the boot preflight failed `assets:precompile`.** An image build is a
34
+ production boot with no wallet secrets mounted, so the eager preflight failed
35
+ the build rather than the deploy. Asset builds are now detected
36
+ (`SECRET_KEY_BASE_DUMMY`, or an `assets:precompile`/`clean`/`clobber` rake
37
+ invocation) and skipped with a log line.
38
+ - **Added `config.eager_preflight`** (default `true`) — the supported opt-out
39
+ for any other boot that must come up without wallet secrets. It disables the
40
+ BOOT check only; the wallet is still checked on the first request, and a real
41
+ production boot with no `NWC_URI` still fails closed.
42
+ - The generated migration's `payment_hash` check constraint hoists its adapter
43
+ branch to a local, so the first file a developer opens after running the
44
+ generator reads as ordinary Ruby.
45
+
3
46
  ## 0.2.1 - 2026-08-24
4
47
 
5
48
  The Ruby gems release in lockstep with the npm workspace version. The full
@@ -61,15 +61,19 @@ module OpenReceive
61
61
  # the app actually runs. MySQL's bare REGEXP follows the column's
62
62
  # case-insensitive collation, so its rendering pins case sensitivity
63
63
  # with REGEXP_LIKE's 'c' flag.
64
+ #
65
+ # Rendered as the right-hand side of `hash_check =` at method-body
66
+ # indentation, so the branch reads as ordinary Ruby in the file the
67
+ # developer opens right after running the generator.
64
68
  def payment_hash_check_sql
65
- return %("REGEXP_LIKE(payment_hash, '^[0-9a-f]{64}$', 'c')") if mysql_adapter?
69
+ return %( "REGEXP_LIKE(payment_hash, '^[0-9a-f]{64}$', 'c')") if mysql_adapter?
66
70
 
67
- <<~RUBY.strip
71
+ <<~RUBY.chomp.gsub(/^/, " ")
68
72
  if connection.adapter_name.downcase.include?("postgres")
69
- "payment_hash ~ '^[0-9a-f]{64}$'"
70
- else
71
- "length(payment_hash) = 64 AND payment_hash NOT GLOB '*[^0-9a-f]*'"
72
- end
73
+ "payment_hash ~ '^[0-9a-f]{64}$'"
74
+ else
75
+ "length(payment_hash) = 64 AND payment_hash NOT GLOB '*[^0-9a-f]*'"
76
+ end
73
77
  RUBY
74
78
  end
75
79
 
@@ -4,7 +4,7 @@
4
4
  # durable reconcile gate they share. Same host database, never a second one.
5
5
  #
6
6
  <%= fulfillment_note("# ") %>
7
- class CreateOpenreceiveTables < ActiveRecord::Migration[<%= migration_version %>]
7
+ class CreateOpenReceiveTables < ActiveRecord::Migration[<%= migration_version %>]
8
8
  def change
9
9
  create_table :openreceive_payments do |t|
10
10
  # Your order id, as you passed it.
@@ -54,8 +54,9 @@ class CreateOpenreceiveTables < ActiveRecord::Migration[<%= migration_version %>
54
54
  add_check_constraint :openreceive_payments,
55
55
  "status IN ('pending', 'settled', 'expired', 'failed', 'attention')",
56
56
  name: "openreceive_payments_status_check"
57
- add_check_constraint :openreceive_payments,
58
- <%= payment_hash_check_sql %>,
57
+ hash_check =
58
+ <%= payment_hash_check_sql %>
59
+ add_check_constraint :openreceive_payments, hash_check,
59
60
  name: "openreceive_payments_payment_hash_check"
60
61
 
61
62
  # Which schema generation is installed. The engine refuses to run against a
@@ -36,7 +36,7 @@ module OpenReceive
36
36
  :resolve_checkout, :on_checkout_created,
37
37
  :rate_limit, :rate_limiting, :client_ip, :price_provider,
38
38
  :swap_providers, :price_currencies, :allow_spend_capable_wallet,
39
- :opportunistic_reconcile
39
+ :opportunistic_reconcile, :eager_preflight
40
40
 
41
41
  def initialize
42
42
  @parent_controller = "ActionController::Base"
@@ -78,6 +78,13 @@ module OpenReceive
78
78
  # `bin/rails openreceive:notifications` worker owns scanning), or a Hash
79
79
  # with min_interval_seconds to tune.
80
80
  @opportunistic_reconcile = true
81
+ # The production boot preflight (Engine's after_initialize): build the
82
+ # service, and with it the wallet check, so a missing NWC_URI or a
83
+ # spend-capable wallet stops a deploy instead of the first customer. ON by
84
+ # default. Asset builds are detected and skipped automatically (see
85
+ # OpenReceive.eager_preflight?); set false for any other boot that must
86
+ # come up without wallet secrets.
87
+ @eager_preflight = true
81
88
  end
82
89
 
83
90
  def service
@@ -353,6 +360,8 @@ module OpenReceive
353
360
  end
354
361
  end
355
362
 
363
+ # Rake tasks that are an ASSET BUILD, never a serving boot.
364
+ ASSET_BUILD_TASKS = %w[assets:precompile assets:clean assets:clobber].freeze
356
365
 
357
366
  class << self
358
367
  def configure
@@ -368,6 +377,45 @@ module OpenReceive
368
377
  @configured == true
369
378
  end
370
379
 
380
+ # Whether the engine's production boot preflight should run (see Engine).
381
+ #
382
+ # It must not run during `rails assets:precompile`. That is a production
383
+ # boot by RAILS_ENV, but it happens inside an image build where no wallet
384
+ # secrets are mounted — they arrive at deploy time — so the preflight would
385
+ # fail the BUILD, long before the deploy it exists to protect. Rails' own
386
+ # generated Dockerfile has exactly this shape.
387
+ def eager_preflight?
388
+ preflight_skip_reason.nil?
389
+ end
390
+
391
+ # nil when the boot preflight should run; otherwise the short reason the
392
+ # engine logs, so an operator who expected a fail-closed boot and did not
393
+ # get one can see why in the same log line.
394
+ def preflight_skip_reason
395
+ return "config.eager_preflight = false" unless config.eager_preflight
396
+ return "asset build" if asset_build?
397
+
398
+ nil
399
+ end
400
+
401
+ # An asset build, by the two signals that are actually reliable.
402
+ # `Rails.const_defined?(:Console)`-style sniffing is not: the console
403
+ # constant exists in a serving boot too.
404
+ def asset_build?
405
+ # Rails' own convention for "a production boot with a throwaway secret",
406
+ # set by its generated Dockerfile alongside `rails assets:precompile`.
407
+ return true unless ENV["SECRET_KEY_BASE_DUMMY"].to_s.empty?
408
+
409
+ # The honest test for older/hand-written build shapes: what was actually
410
+ # invoked. `SECRET_KEY_BASE=dummy rails assets:precompile` lands here.
411
+ return false unless defined?(::Rake)
412
+
413
+ ::Rake.application.top_level_tasks.any? { |task| ASSET_BUILD_TASKS.include?(task.to_s) }
414
+ rescue StandardError
415
+ # Rake present but without a usable application: not an asset build.
416
+ false
417
+ end
418
+
371
419
  def config
372
420
  @config ||= Configuration.new
373
421
  end
@@ -17,6 +17,13 @@ module OpenReceive
17
17
  # customer-facing 500s on the first checkout. Skipped when the host never
18
18
  # ran OpenReceive.configure (gem installed, installer not run yet), and
19
19
  # outside production so tests and consoles boot without a live wallet.
20
+ #
21
+ # `rails assets:precompile` is the one production boot that must NOT be
22
+ # preflighted: it runs inside an image build, before any wallet secret is
23
+ # mounted, so checking there fails the build rather than the deploy. It is
24
+ # detected and skipped automatically (OpenReceive.eager_preflight?), and
25
+ # `config.eager_preflight = false` is the explicit lever for any other
26
+ # secretless boot.
20
27
  config.after_initialize do
21
28
  if OpenReceive.configured?
22
29
  if OpenReceive.config.on_paid.equal?(OpenReceive::LOGGING_ON_PAID)
@@ -26,7 +33,17 @@ module OpenReceive
26
33
  "config/initializers/openreceive.rb."
27
34
  )
28
35
  end
29
- OpenReceive.config.service if ::Rails.env.production?
36
+ if ::Rails.env.production?
37
+ skipped = OpenReceive.preflight_skip_reason
38
+ if skipped.nil?
39
+ OpenReceive.config.service
40
+ else
41
+ ::Rails.logger&.info(
42
+ "[openreceive] boot preflight skipped (#{skipped}) — the wallet is " \
43
+ "checked on the first request instead."
44
+ )
45
+ end
46
+ end
30
47
  end
31
48
  end
32
49
  end
@@ -5,6 +5,6 @@ module OpenReceive
5
5
  # top-level `::Rails` framework constant — engine code always references the framework as
6
6
  # `::Rails` to avoid shadowing.
7
7
  module Rails
8
- VERSION = "0.2.1"
8
+ VERSION = "0.2.3"
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openreceive-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenReceive
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.1
18
+ version: 0.2.3
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.2.1
25
+ version: 0.2.3
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: openreceive-server
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - '='
31
31
  - !ruby/object:Gem::Version
32
- version: 0.2.1
32
+ version: 0.2.3
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - '='
38
38
  - !ruby/object:Gem::Version
39
- version: 0.2.1
39
+ version: 0.2.3
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: rails
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +51,26 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '8.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: nwc-ruby
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.2.4
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.2'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.2.4
54
74
  - !ruby/object:Gem::Dependency
55
75
  name: sqlite3
56
76
  requirement: !ruby/object:Gem::Requirement