solana-studio 0.5.0 → 0.5.2

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: d9f198cf717ac69a1a570b082b7ebf76a7d0560e1f863d3410bbc4eeeeca71e5
4
- data.tar.gz: 4bbea890a22fafaba9449bd4aac5483ecfdf3366e694ac9c142c75e898d4435d
3
+ metadata.gz: fa775c67a1f3ae154dabf231c294c86e6a03dc74f2866fcfdab2cb7f8bf9da9b
4
+ data.tar.gz: 6dd4bd255c9ea0d99c8daaeff4a176152226e63a61f36943869f70f3e9a57441
5
5
  SHA512:
6
- metadata.gz: 5becc3ebd6544d5275f1107e1eb9338b47ce5cfeb19e682c9ebdf9bc44e5814f72c3b999f7f4839c1205fd4b9393713dc060edd94264334b999c997c75437a16
7
- data.tar.gz: 90e26c9214ef297a84e43f910bda3d8d22278703672f1eb564a36c83071c6c90717cae87f836b5ba57844b7f1a4ab5b2793c01ec5d16b7cea1cf820eddb1c3dc
6
+ metadata.gz: b52fd18bf1bab93c0a060d5cc135b1e9bc81bdfb5b32b9771251f831ffaaa5653891706927904e5e57a852094c3a4e41a45350e84bcca16f4f30cd9913bdbc55
7
+ data.tar.gz: 701023cfadfee72780409a021e2e2bfa2223cb3366a07659409764f5aa7f4aa1fb2adc961a5b7ba68103fe5263dfa77506f659727c6c315171d63faa4d16f735
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## Unreleased
6
+
7
+ ### Added
8
+ - **The wallet sign-in button, contributed into studio-engine's auth modal** (`app/views/solana_studio/auth/_wallet_credential.html.erb`). Part of the base/bolt-on split: studio-engine plus McRitchie Studio is the template every app is built from, web2 and web3 alike, and this gem plus Turf Monster is the web3 bolt-on. Sign-in is a base concern so the modal stays in the engine; **wallets are not**, so the button moved here. The engine renders whatever resolves at `solana_studio/auth/wallet_credential` and nothing when the path is empty, so bundling this gem IS the registration and a web2 app carries no wallet markup at all. Deliberately NOT solved by giving this gem its own auth modal: that would fork a surface both apps sign in through, which is how the wallet picker reached three drifting copies before it was promoted. The engine keeps both halves of the existing gate (`Studio.auth_method?(:wallet)` and `Studio.feature?(:web3)`) so the hub — which bundles this gem for its signing primitives with web3 off — still renders a web2 sign-in modal.
9
+
10
+ ### Tests
11
+ - `test/auth_credential_test.rb` (7): the partial sits at the path the engine resolves, the click handler consults the modal's age gate, visibility binds to the shared `methodOn('wallet')` toggle, `modal_store` is required with no default, the swap carries the picker's `backTo`/`ageAttested` contract, the brand gradient id is namespaced against collisions, and the mark stays inline rather than becoming a sprockets asset request. Every assertion reads ERB-comment-stripped source, because this file documents its own contract in prose and a bare grep would match the paragraph instead of the code — proven by mutating the gate into a comment and watching it go red.
12
+ - `test/gemspec_test.rb` and `.github/workflows/gem-ci.yml` name the new partial alongside the modal, so a `spec.files` glob that stopped matching it fails at build rather than in a consumer.
13
+
5
14
  ## Unreleased — targets v0.5.0 (minor)
6
15
 
7
16
  Ships the gem's first Rails half, and its first CI. The version number is
data/README.md CHANGED
@@ -177,6 +177,44 @@ attributes, so a host can adopt it before changing its layout.
177
177
  Requires studio-engine's modal host (`Alpine.store('modals')`) and its shared
178
178
  modal blocks. The JS is `solana_studio/network_guard.js` on the asset path.
179
179
 
180
+ ### Wallet sign-in button (the credential slot)
181
+
182
+ studio-engine owns the sign-in modal, because every app in the ecosystem signs
183
+ people in and most of them are web2. This gem owns the **wallet button** inside
184
+ it, because only a web3 app has wallets.
185
+
186
+ There is **nothing to wire up.** The engine's auth modal looks for a partial at
187
+ one fixed path and renders whatever it finds:
188
+
189
+ solana_studio/auth/_wallet_credential
190
+
191
+ Bundling this gem puts that partial on the host's view path, so the button
192
+ appears. An app that does not bundle it finds nothing and renders nothing — no
193
+ wallet markup ships to a newsletter app, and no `render` call has to be deleted
194
+ to keep it out.
195
+
196
+ The engine asks two questions and needs both answered yes:
197
+
198
+ | Question | Answered by | Where |
199
+ |---|---|---|
200
+ | Does this app *want* wallet sign-in? | `Studio.auth_method?(:wallet)` and `Studio.feature?(:web3)` | the host's `config/initializers/studio.rb` |
201
+ | Is there a layer that *implements* it? | this partial resolving on the view path | bundling this gem |
202
+
203
+ Both matter. McRitchie Studio bundles this gem for the Ruby signing primitives
204
+ while shipping web3 **off**, so the partial is present and the button is
205
+ correctly absent. And an app that declares `:wallet` but forgets the gem gets no
206
+ button rather than a missing-partial error in front of someone signing in.
207
+
208
+ The partial renders inside the modal's own Alpine scope and borrows three
209
+ members from it — `methodOn('wallet')` for visibility, `attested()` for the
210
+ legal-age gate, and `props.submitting` for the disabled state. It takes one
211
+ required local, `modal_store`, which the engine passes.
212
+
213
+ Why a contributed button and not a second auth modal: Turf Monster wants Google
214
+ plus magic-link plus wallet, McRitchie Studio wants Google plus magic-link. A
215
+ forked modal would put a surface both apps sign in through into two files, which
216
+ is how the wallet picker reached three copies before it was promoted.
217
+
180
218
  ## Dependencies
181
219
 
182
220
  - `ed25519` (~> 1.3) — Ed25519 signing
@@ -0,0 +1,71 @@
1
+ <%#
2
+ The Solana credential button for studio-engine's SIGN-IN modal.
3
+
4
+ This is the gem half of the engine's CREDENTIAL SLOT seam. The auth modal is a
5
+ BASE modal: every app in the ecosystem signs people in, and most of them are
6
+ web2, so the modal itself stays in studio-engine and is never forked. What
7
+ varies is which credentials it offers. Google and magic-link are implemented by
8
+ the base template and render from the engine directly. Wallet is implemented
9
+ HERE, by the web3 bolt-on, and reaches the modal by being on the view path.
10
+
11
+ The engine renders this at a fixed path and only when it resolves:
12
+
13
+ solana_studio/auth/_wallet_credential
14
+
15
+ So an app that does not bundle this gem finds nothing, renders nothing, and
16
+ carries no wallet markup at all. An app that does bundle it gets the button
17
+ with no configuration and no registration call. Presence IS the wiring.
18
+
19
+ WHY A PARTIAL AND NOT A COPY OF THE MODAL. Turf Monster wants Google plus
20
+ magic-link plus wallet; McRitchie Studio wants Google plus magic-link. Solving
21
+ that by giving the gem its own auth modal would fork a surface both apps sign
22
+ in through, and the two copies would drift the way the wallet picker drifted
23
+ into three copies before it was promoted. One modal, one contributed button.
24
+
25
+ SCOPE — this renders INSIDE the engine auth modal's root x-data, so these
26
+ members are in scope and are the seam's contract:
27
+
28
+ methodOn(m) whether credential m should show. Reads props.methods per key
29
+ and falls back to the app's own Studio.auth_method? default,
30
+ which for wallet is auth_method?(:wallet) AND feature?(:web3).
31
+ attested() the legal-age gate. Returns false and paints the error when
32
+ the app requires attestation and the box is unticked. Every
33
+ credential CTA in the modal calls it first; skipping it here
34
+ would make wallet the one way around the gate.
35
+
36
+ THE HANDLER IS INLINE, not a method on a nested x-data, and that is deliberate.
37
+ A child x-data would reach attested() through Alpine's prototypal scope merge,
38
+ which works but is subtle enough that a later reader could "simplify" the
39
+ nesting away and silently drop the age gate. An expression in the attribute
40
+ reads the enclosing scope directly, with nothing to get wrong.
41
+
42
+ Locals:
43
+ modal_store Alpine store name backing the modal. The engine's real host
44
+ uses "modals"; the living style guide mounts a page-scoped host
45
+ and passes "dsModals". Required, no default, because a wrong
46
+ store name fails as a dead button rather than as an error.
47
+ %>
48
+ <% modal_store = local_assigns.fetch(:modal_store) %>
49
+ <%# The picker this opens is the wallet-connect modal. backTo returns the user
50
+ here if they back out of the brand list, and ageAttested carries the gate
51
+ they already passed so the picker does not ask a second time. %>
52
+ <button type="button"
53
+ @click="attested() && $store.<%= modal_store %>.swap('wallet-connect', { backTo: 'auth', ageAttested: true })"
54
+ x-show="methodOn('wallet')"
55
+ :disabled="!!props.submitting"
56
+ class="btn btn-neutral btn-lg w-full gap-3 mb-3 disabled:cursor-wait">
57
+ <%# The Solana wordmark, inline rather than an asset request: this gem ships no
58
+ image and a host that had to precompile one would get a silent 404 on a
59
+ sprockets app. The gradient id is namespaced so two Solana marks on one
60
+ page cannot collide. %>
61
+ <svg width="18" height="14" viewBox="0 0 397 311" fill="none" x-show="props.submitting !== 'wallet'" aria-hidden="true">
62
+ <defs><linearGradient id="solana-studio-auth-grad" x1="361" y1="-9" x2="153" y2="389" gradientUnits="userSpaceOnUse">
63
+ <stop offset="0" stop-color="#00FFA3"/><stop offset="1" stop-color="#DC1FFF"/>
64
+ </linearGradient></defs>
65
+ <path d="M65 234c2-2 6-4 9-4h317c6 0 9 7 5 11l-63 63c-2 2-6 4-9 4H6c-6 0-9-7-5-11l64-63z" fill="url(#solana-studio-auth-grad)"/>
66
+ <path d="M65 4c2-2 6-4 9-4h317c6 0 9 7 5 11l-63 63c-2 2-6 4-9 4H6c-6 0-9-7-5-11L65 4z" fill="url(#solana-studio-auth-grad)"/>
67
+ <path d="M333 119c-2-2-6-4-9-4H7c-6 0-9 7-5 11l63 63c2 2 6 4 9 4h317c6 0 9-7 5-11l-63-63z" fill="url(#solana-studio-auth-grad)"/>
68
+ </svg>
69
+ <span x-show="props.submitting === 'wallet'" class="spinner" aria-hidden="true"></span>
70
+ <span x-text="props.submitting === 'wallet' ? 'Connecting…' : 'Solana'"></span>
71
+ </button>
@@ -16,5 +16,5 @@ module SolanaStudio
16
16
  # through the normal cycle. Splitting the version out is the same shape
17
17
  # studio-engine already uses (lib/studio/version.rb) and hands each file back
18
18
  # to its real owner: this one to the release, the gemspec to the PR.
19
- VERSION = "0.5.0"
19
+ VERSION = "0.5.2"
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solana-studio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McRitchie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-21 00:00:00.000000000 Z
11
+ date: 2026-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ed25519
@@ -38,6 +38,7 @@ files:
38
38
  - LICENSE
39
39
  - README.md
40
40
  - app/assets/javascripts/solana_studio/network_guard.js
41
+ - app/views/solana_studio/auth/_wallet_credential.html.erb
41
42
  - app/views/solana_studio/modals/_network_mismatch.html.erb
42
43
  - lib/solana-studio.rb
43
44
  - lib/solana/auth_verifier.rb