Commit Graph
39 Commits
Author SHA1 Message Date
selimaj-devandclaude cd81bec938 Write a proper project README with the brand mark
Replaces the minimal AMO-source-submission README with a full project
overview: logo, what Osias actually does, how it works, shipped
features, getting started, project structure, and contributing —
folding the existing build-instructions content in rather than
dropping it, since AMO's source review still depends on it.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HoMzqFw3d93hG6c9xB4thU
2026-09-09 13:46:09 +02:00
selimaj-dev a9a7dc751b Merge pull request #8 from osias-trade/brand/pause-icon
Add the Osias brand mark (pause icon)
2026-09-09 07:35:30 -04:00
selimaj-devandclaude 1193684c29 Add 400x400 profile picture variants and ignore .DS_Store
Two flat-square backgrounds for the pause mark (#1E1912 and #17130F,
matching the site background exactly) sized for the GitHub org avatar
and similar profile contexts — not referenced by the extension
manifest.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HoMzqFw3d93hG6c9xB4thU
2026-09-09 13:34:08 +02:00
selimaj-devandclaude 9ef964892f Add the Osias icon — a pause mark, browser toolbar and store icon
Two uneven vertical bars: reads as a paused instrument first, with a
quieter second reading as a frozen price candle. Chosen over a padlock
mark (the most generic symbol in crypto security) and a wordmark-only
option (still needs a fallback mark for toolbar/favicon contexts) —
see the logo exploration canvas for the full comparison.

WXT auto-discovers public/icon/{16,32,48,96,128}.png by filename
convention and populates manifest.icons at build time — no
wxt.config.ts change needed. osias-icon-512.png and the standalone
SVG are kept alongside for general branding use, not part of the
manifest.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HoMzqFw3d93hG6c9xB4thU
2026-09-09 13:27:08 +02:00
selimaj-devandclaude 891d561aaa Fix AMO submission requirements: data collection permissions, innerHTML lint, source README
- Declare data_collection_permissions in browser_specific_settings.gecko
  (Firefox 140+/AMO validation requirement) to reflect wallet address,
  auth signature, and trading-identity data sent to the backend.
- Replace innerHTML assignments in blur-disable.ts and toast.ts with
  DOM construction (createElementNS/createElement) to clear the AMO
  linter's unsafe-innerHTML warning on content.js.
- Add build instructions to README.md for AMO's source code submission
  requirement, triggered by WXT/Vite's bundling and minification.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HoMzqFw3d93hG6c9xB4thU
v0.1.0
2026-09-09 12:20:31 +02:00
selimaj-devandclaude cd56cf60cd Clean up CLAUDE.md: cut changelog narrative, fix stale sections
Removed decorative status narration ("used to have a mock toggle, removed
once...") and strikethrough'd resolved non-goals in favor of describing
current state directly. Kept the genuine postmortems intact (Firefox
CustomEvent Xray bug, accountChanged double-fire bug, buy/sell wrapper
gotcha) since those actively prevent regressions.

Also fixed the "Visual treatment for v1" section, which still described
the old filter: blur() approach — now documents the backdrop-filter fix
from earlier this session and explicitly warns against reintroducing
filter/opacity on the container. Documented the ping/pong keepalive in
both the wire-protocol spec and "Backend connection".

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013qK4zsF5ogU7cjRVL3AQZ2
2026-09-09 03:26:17 +02:00
selimaj-dev abdc0c9fca Merge pull request #7 from osias-trade/fix/blur-icon-and-ws-keepalive
Fix blurred lock icon overlay; add WS ping keepalive
2026-09-08 21:09:15 -04:00
selimaj-devandclaude c87f86f82e Send a ping every 20s to keep the WS connection (and MV3 worker) alive
Backend now replies with {"type":"pong"}. See backend commit for the full
rationale: a MV3 background service worker can be idle-killed after ~30s
with no activity reaching its own message handlers, and a disconnect while
a lockout is active used to reset the visible lock state on reconnect
(fixed backend-side) — this keepalive addresses the other half by making
that disconnect much less likely to happen in the first place.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013qK4zsF5ogU7cjRVL3AQZ2
2026-09-09 03:03:51 +02:00
selimaj-devandclaude 1222baadee Fix lock icon getting blurred with its container, tune overlay look
filter/opacity on the container recomposited its whole subtree
(including the lock icon appended as a child) as one filtered unit, so
the icon's own filter:none/opacity:1 couldn't opt it back out. Switch
to backdrop-filter on the overlay instead, which only blurs what's
painted behind it, leaving the icon crisp with no need to reparent the
site's own React-owned DOM.

Also lighten the blur (pixelated on small pills) in favor of
grayscale/brightness doing the "disabled" signaling, and size the
overlay 4px larger on every side than a flush inset:0.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013qK4zsF5ogU7cjRVL3AQZ2
2026-09-09 02:30:44 +02:00
selimaj-dev 705945bf25 Merge pull request #6 from osias-trade/popup/redesign-and-settings-errors
Redesign popup UI, surface settings errors on main screen
2026-09-08 07:22:02 -04:00
selimaj-devandclaude 9a774a38d4 Redesign popup UI, rename thresholds panel to Settings, surface errors on main screen
UX changes:
- Settings load/save errors now surface as a dismissible banner on the
  main popup screen, not only inside the collapsed panel. Settings are
  fetched eagerly (like lock state/connection status already were)
  instead of lazily on first expand, so a load failure is visible
  immediately.
- The "Adjust loss thresholds" toggle/panel is renamed to "Settings"
  (with "Loss thresholds" as a subsection heading, since that's the
  only setting today), and gains a "Done" affordance to collapse it
  back rather than only being expandable.
- Lock status is now the visual hero (a bordered status card with an
  icon), rather than one item in a flat list alongside connection
  status and account actions.

Visual changes:
- style.css rewritten around CSS custom-property design tokens
  (spacing/radius/font-size scale, semantic colors) with explicit
  light and dark palettes, instead of hardcoded hex colors reused
  as-is across both color schemes.
- Popup widened 280px -> 320px for breathing room; card-based grouping
  (status, settings) replaces the previous flat stack of sections.

No wire-protocol or messaging-contract changes.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tn7uDYjTuZEbLPwpEiSCUw
2026-09-08 13:20:05 +02:00
selimaj-devandclaude 5cfb0f0b53 Remove stale CLAUDE.md note about an already-merged PR
The "not merged yet" branch-workflow paragraph got reintroduced by a
merge from a stale local branch (PR #4) that hadn't been rebased since
before PR #2 actually merged. That PR (and everything after it,
including production) has long since landed.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tn7uDYjTuZEbLPwpEiSCUw
2026-09-08 12:40:10 +02:00
selimaj-dev 0634a006a3 Merge pull request #5 from nexa-sol/rename/osias
Rename project from Nexa to Osias
2026-09-08 06:35:26 -04:00
selimaj-devandclaude 59157c7e76 Rename project from Nexa to Osias
Renames the npm package (nexa-extension -> osias-extension), the
extension manifest name and Firefox gecko id
([email protected]), the internal runtime message-type
namespace and storage keys ('nexa:...' -> 'osias:...'), the
NexaMessage type, and all remaining Nexa branding in source comments,
UI copy, and CLAUDE.md to match the new osias.trade domain and the
osias-trade GitHub org.

No wire-protocol changes — purely internal naming plus user-facing
strings.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tn7uDYjTuZEbLPwpEiSCUw
2026-09-08 12:32:53 +02:00
selimaj-dev 3164f3d4eb Merge pull request #4 from nexa-sol/feat/real-wallet-auth-and-backend-connection
Note open PR #2 and branch workflow in CLAUDE.md
2026-09-08 06:15:11 -04:00
selimaj-dev ca66c2e1b3 Merge pull request #3 from nexa-sol/feat/prod-backend-and-settings-panel
Real settings panel + connect to production backend
2026-09-08 06:08:13 -04:00
selimaj-devandclaude e3d1e45843 Fix @ alias not resolving inside wxt.config.ts
The @/ path alias is only wired up for the app bundle via WXT's
generated tsconfig; wxt.config.ts itself runs outside that resolution,
so the aliased import of BACKEND_HTTP_URL failed there. Use a relative
import instead.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tn7uDYjTuZEbLPwpEiSCUw
2026-09-08 12:07:21 +02:00
selimaj-devandclaude bee164ebf9 Fix WebSocket URL scheme and drop stale dev-only CSP override
BACKEND_WS_URL was set to https://, but new WebSocket() requires a
ws://wss:// scheme and throws a SyntaxError otherwise. Also removes
the Firefox-only CSP override that worked around Firefox upgrading a
plaintext ws:// dev connection to wss:// — now that the backend is
real wss:// behind TLS, there's nothing left to upgrade.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tn7uDYjTuZEbLPwpEiSCUw
2026-09-08 12:02:44 +02:00
selimaj-dev 3cc150508d Using osias backend 2026-09-08 11:57:59 +02:00
selimaj-devandclaude 7f8270a048 Replace threshold placeholder link with a real settings panel
Adds a "Loss thresholds" panel to the popup backed by the backend's
new GET/PATCH /me/settings endpoints, converting between the wire's
fractional percentages and whole-number form inputs only at that
boundary.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RTorFQXMR9ZQtCKcMTXLHp
2026-09-08 02:38:46 +02:00
selimaj-devandclaude 84fdc36edb Note open PR #2 and branch workflow in CLAUDE.md
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 15:44:54 +02:00
selimaj-dev ac421196e9 Merge pull request #2 from nexa-sol/feat/real-wallet-auth-and-backend-connection
Real Phantom wallet auth and live backend connection
2026-09-07 09:42:37 -04:00
selimaj-devandclaude d5e93ffcbb Bring CLAUDE.md up to date with everything built this session
Documents the React popup port (missing entirely before -- including
the tsconfig jsx flag gotcha), and fixes several stale references
left over from earlier edits: backend-client.ts's storeSessionToken
-> storeSession(token, walletAddress) rename, wallet-auth.ts's newer
requestWalletDisconnect()/requestAccountSwitch() helpers, and a
duplicated/outdated description of the wallet-connected re-auth gate
that still described the "any token" check after it was replaced
with a wallet-address comparison.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 14:08:21 +02:00
selimaj-devandclaude 8d104ef3cf Fix duplicate signing; make account switching an explicit action
Root cause of "requires a lot of signs, not just a single one":
inject.ts wired Phantom's own accountChanged provider event to
auto-trigger re-auth, but calling connect() ourselves also fires that
same event -- so a normal silent reconnect raced its own
event-triggered handler, producing two competing "wallet connected"
reports that each independently asked Phantom to sign a fresh nonce.

Removed that event wiring entirely (onWalletEvent, EVENT_CHANNEL) --
inject.ts now only responds to our own explicit calls, never reacts
to unsolicited provider events. Per feedback, account switching isn't
something that should be inferred from a Phantom event anyway; it's
now its own explicit feature: a "Switch account" button in the popup
(nexa:switch-account) that tells the content script to disconnect and
immediately reconnect, so Phantom's connect UI reflects whichever
account is currently active there.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 14:02:11 +02:00
selimaj-devandclaude b93a9c6f10 Support Phantom account switching and add sign-out
Wires Phantom's own accountChanged/disconnect provider events
(inject.ts) so switching accounts or disconnecting directly in
Phantom's UI is detected, not just our own connect/sign calls --
relayed as unsolicited postMessage events (relay.ts's onWalletEvent)
since they aren't a response to any request we made.

Adds a "Sign out" button in the popup (nexa:sign-out) that clears the
stored session, force-closes the WS connection via a new
ws-client.ts disconnect() (distinct from reconnectNow() -- it also
suppresses auto-reconnect until a new wallet connects), and asks the
content script to call provider.disconnect(), which revokes
Phantom's trust for the origin so the next silent connect correctly
fails until the user reconnects.

Fixes a real bug this surfaced: the existing "skip re-auth if a
session token exists" check in background.ts only checked for *any*
token, so switching Phantom accounts would have silently kept
authenticating as the old wallet. Session storage now tracks which
wallet it belongs to (backend-client.ts's storeSession(token,
walletAddress)) so the handler can tell "already signed in" apart
from "signed in as a different wallet than the one that just
connected."

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 13:48:05 +02:00
selimaj-devandclaude 9f06a83b64 Fix Firefox silently upgrading ws:// to wss:// against the dev backend
Firefox's implicit default extension-pages CSP includes
upgrade-insecure-requests, which rewrites the WS client's plain
ws://localhost:8080/ws connection to wss:// -- which nothing is
listening on, since the local dev backend has no TLS (deliberately;
see backend/CLAUDE.md). Symptom was silent: a CSP console message
about the upgrade, then a failed connection with no other signal.

Declaring an explicit content_security_policy.extension_pages in
wxt.config.ts (otherwise identical to Firefox's own default) replaces
the implicit one and drops the upgrade directive. Gated to
browser === 'firefox' since Chrome doesn't have this behavior and its
MV3 CSP can't be loosened this way regardless.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 13:17:02 +02:00
selimaj-devandclaude 3bb1c2f0c8 Skip re-signing when a session token already exists
A content script reports 'wallet-connected' on every page load (it
always tries a silent onlyIfTrusted connect first), and the handler
was unconditionally running the full nonce/sign/verify cycle every
time. signMessage() shows a fresh Phantom approval popup on every
call, unlike connect() which is silent once trusted -- so this meant
a new signature prompt on every single axiom.trade page load, caught
during manual testing ("signing appears every time").

Now the handler checks for an existing valid session token first and
only re-authenticates when there isn't one.

Confirmed end-to-end against real Phantom on Zen: connect -> sign ->
verify -> session token stored, via the wallet-auth debug logs.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 13:08:18 +02:00
selimaj-devandclaude 140616a3e4 Fix wallet bridge on Firefox: use postMessage instead of CustomEvent
Manual testing on Zen/Firefox surfaced "Uncaught Error: Permission
denied to access property 'id'" the moment the isolated-world relay
dispatched a CustomEvent to the world:'MAIN' injected script. That's
a Firefox-specific Xray-wrapper restriction: a CustomEvent's `detail`
object created in one world can't have its properties read from the
other, even though the event itself fires fine. Chromium doesn't
enforce this, which is why it wasn't caught until testing on the
actual target browser (Zen).

Switched both sides of the bridge (wallet-bridge/inject.ts,
wallet-bridge/relay.ts) to window.postMessage with a `channel` field
and same-window source check, since postMessage structured-clones
its payload across the boundary correctly on both browsers -- the
same approach Phantom's own inpage<->content-script bridge uses.

Also added [nexa/...]-prefixed console.debug breadcrumbs through the
wallet-connect/wallet-bridge/wallet-auth chain, since diagnosing this
without them (previous commit shipped none) took several rounds of
"nothing happened" back and forth.

Still not fully verified end-to-end against live Phantom -- the
crash is fixed, but a full connect -> sign -> verify round trip
hasn't been confirmed yet. See CLAUDE.md.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 12:59:04 +02:00
selimaj-devandclaude 56a2ff9930 Replace stub wallet keypair with real Phantom sign-in
Auth now goes through an actual connected Solana wallet instead of a
locally-generated ed25519 keypair. Phantom's window.solana provider
is only reachable from a page's own JS world, not an isolated-world
content script, so this adds a second world:'MAIN' content script
(wallet-bridge.content.ts + wallet-bridge/inject.ts) that talks to
window.solana directly and relays to the isolated world via window
CustomEvents (wallet-bridge/relay.ts), matched by request id.

wallet-connect.ts orchestrates: try a silent onlyIfTrusted connect on
load; if that fails, show an on-page banner (wallet-bridge/banner.ts)
whose click handler is what actually calls connect() -- Phantom
requires a real user gesture for the approval popup on a first-ever
connect, which a click relayed from the extension popup wouldn't
count as by the time it reaches the wallet.

background/wallet-auth.ts runs the REST auth flow (nonce -> ask the
tab's content script to sign it -> verify -> store session token)
once a wallet reports connected. ws-client.ts no longer force-retries
with a known-bad token on auth failure; it calls onAuthExpired
instead (which clears the token and prompts a silent wallet
reconnect) and exposes reconnectNow() so background.ts can
short-circuit the backoff wait once a fresh token exists.

identity.ts and its tweetnacl dependency are gone -- no more stub
signer.

Untested against real Phantom (no browser automation available this
session) -- flagged in CLAUDE.md as needing manual verification,
along with a note that world:'MAIN' needs Firefox 128+.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 12:20:17 +02:00
selimaj-devandclaude 58e32caa5c Port popup to React; fix backend port colliding with Vite dev server
Popup is now a real React app (App.tsx/main.tsx via createRoot),
wired through @wxt-dev/module-react. tsconfig.json needed an explicit
jsx: "react-jsx" -- WXT's generated .wxt/tsconfig.json doesn't set
it, so tsc --noEmit failed on JSX syntax even though the Vite build
itself was fine.

Root cause of the actually-reported bug (blank popup, predating the
React port too): the backend defaulted to port 3000, the same port
WXT's dev server uses for this extension. With both running, the
popup's script tags pointed at the Vite dev server but the backend
answered instead, so main.tsx never loaded -- "View Page Source"
showed raw unbundled dev-mode HTML pointing at localhost:3000.
Backend now binds :8080 (see backend commit), and
BACKEND_HTTP_URL/BACKEND_WS_URL + host_permissions here follow it.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 11:56:05 +02:00
selimaj-devandclaude 3302a78536 Update CLAUDE.md: real backend connection replaces the mock lock toggle
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 09:11:53 +02:00
selimaj-devandclaude 3b6054f2f0 Connect to the real Nexa backend, replacing the mock lock toggle
Adds the wire-protocol WebSocket client (ws-client.ts) and the REST
auth flow (backend-client.ts) against the now-live backend, using a
locally-generated ed25519 keypair (identity.ts) as a stand-in wallet
signer until real wallet-extension integration is built.

lock-state.ts's setLockState is now applyLockState, called only by
the WS client on an incoming lock_state message -- the backend is
the sole source of truth for lock state, so there's no other writer
anymore. The popup's dev mock controls are replaced with a live
connection-status + lock-state display.

Verified end-to-end against the real backend (nonce -> verify -> /me
-> ws lock_state) using the same tweetnacl/bs58 libs shipped in the
extension.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
2026-09-07 09:10:18 +02:00
selimaj-devandclaude 5643eebde7 Fold spec docs into CLAUDE.md
Consolidate NEXA_SPEC.md and NEXA_PROTOCOL_SPEC.md into CLAUDE.md as the
single source of truth, updating the behavioral notes to reflect what
live debugging on axiom.trade actually found (rather than the original
spec's assumptions) and adding the backend WebSocket wire contract.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CHESr7MTKG5Dc3mRPvWPn7
2026-09-06 12:49:29 +02:00
selimaj-dev 41c6f232fe Fix sell on noob 2026-09-06 12:32:09 +02:00
selimaj-dev 0099a6b753 Fix sell 2026-09-06 12:28:38 +02:00
selimaj-dev 9362c9ac80 Lesss gooo claude 2026-09-06 11:44:59 +02:00
selimaj-dev 477db87363 Merge pull request #1 from nexa-sol/spec-and-claude
Add SPEC and CLAUDE.md
2026-09-05 22:43:26 -04:00
selimaj-dev 68686f7b18 Spec and claude 2026-09-06 04:41:40 +02:00
selimaj-dev bc7c769802 Initial commit 2026-09-06 04:27:03 +02:00