Refactor logging in event handling and message processing to use trace-level logs, enhancing clarity and consistency across the application. Update web application structure to utilize Svelte and remove unused React components, streamlining the project. Additionally, clean up .gitignore and update package dependencies for improved performance.
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (l *Listener) HandleEvent(msg []byte) (err error) {
|
func (l *Listener) HandleEvent(msg []byte) (err error) {
|
||||||
|
log.D.F("handling event: %s", msg)
|
||||||
// decode the envelope
|
// decode the envelope
|
||||||
env := eventenvelope.NewSubmission()
|
env := eventenvelope.NewSubmission()
|
||||||
if msg, err = env.Unmarshal(msg); chk.E(err) {
|
if msg, err = env.Unmarshal(msg); chk.E(err) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func (l *Listener) HandleMessage(msg []byte, remote string) {
|
|||||||
if len(msgPreview) > 150 {
|
if len(msgPreview) > 150 {
|
||||||
msgPreview = msgPreview[:150] + "..."
|
msgPreview = msgPreview[:150] + "..."
|
||||||
}
|
}
|
||||||
log.D.F("%s processing message (len=%d): %s", remote, len(msg), msgPreview)
|
// log.D.F("%s processing message (len=%d): %s", remote, len(msg), msgPreview)
|
||||||
|
|
||||||
l.msgCount++
|
l.msgCount++
|
||||||
var err error
|
var err error
|
||||||
@@ -28,55 +28,69 @@ func (l *Listener) HandleMessage(msg []byte, remote string) {
|
|||||||
|
|
||||||
// Attempt to identify the envelope type
|
// Attempt to identify the envelope type
|
||||||
if t, rem, err = envelopes.Identify(msg); err != nil {
|
if t, rem, err = envelopes.Identify(msg); err != nil {
|
||||||
log.E.F("%s envelope identification FAILED (len=%d): %v", remote, len(msg), err)
|
log.E.F(
|
||||||
log.D.F("%s malformed message content: %q", remote, msgPreview)
|
"%s envelope identification FAILED (len=%d): %v", remote, len(msg),
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
log.T.F("%s malformed message content: %q", remote, msgPreview)
|
||||||
chk.E(err)
|
chk.E(err)
|
||||||
// Send error notice to client
|
// Send error notice to client
|
||||||
if noticeErr := noticeenvelope.NewFrom("malformed message: " + err.Error()).Write(l); noticeErr != nil {
|
if noticeErr := noticeenvelope.NewFrom("malformed message: " + err.Error()).Write(l); noticeErr != nil {
|
||||||
log.E.F("%s failed to send malformed message notice: %v", remote, noticeErr)
|
log.E.F(
|
||||||
|
"%s failed to send malformed message notice: %v", remote,
|
||||||
|
noticeErr,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.D.F("%s identified envelope type: %s (payload_len=%d)", remote, t, len(rem))
|
log.T.F(
|
||||||
|
"%s identified envelope type: %s (payload_len=%d)", remote, t, len(rem),
|
||||||
|
)
|
||||||
|
|
||||||
// Process the identified envelope type
|
// Process the identified envelope type
|
||||||
switch t {
|
switch t {
|
||||||
case eventenvelope.L:
|
case eventenvelope.L:
|
||||||
log.D.F("%s processing EVENT envelope", remote)
|
log.T.F("%s processing EVENT envelope", remote)
|
||||||
l.eventCount++
|
l.eventCount++
|
||||||
err = l.HandleEvent(rem)
|
err = l.HandleEvent(rem)
|
||||||
case reqenvelope.L:
|
case reqenvelope.L:
|
||||||
log.D.F("%s processing REQ envelope", remote)
|
log.T.F("%s processing REQ envelope", remote)
|
||||||
l.reqCount++
|
l.reqCount++
|
||||||
err = l.HandleReq(rem)
|
err = l.HandleReq(rem)
|
||||||
case closeenvelope.L:
|
case closeenvelope.L:
|
||||||
log.D.F("%s processing CLOSE envelope", remote)
|
log.T.F("%s processing CLOSE envelope", remote)
|
||||||
err = l.HandleClose(rem)
|
err = l.HandleClose(rem)
|
||||||
case authenvelope.L:
|
case authenvelope.L:
|
||||||
log.D.F("%s processing AUTH envelope", remote)
|
log.T.F("%s processing AUTH envelope", remote)
|
||||||
err = l.HandleAuth(rem)
|
err = l.HandleAuth(rem)
|
||||||
case countenvelope.L:
|
case countenvelope.L:
|
||||||
log.D.F("%s processing COUNT envelope", remote)
|
log.T.F("%s processing COUNT envelope", remote)
|
||||||
err = l.HandleCount(rem)
|
err = l.HandleCount(rem)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unknown envelope type %s", t)
|
err = fmt.Errorf("unknown envelope type %s", t)
|
||||||
log.E.F("%s unknown envelope type: %s (payload: %q)", remote, t, string(rem))
|
log.E.F(
|
||||||
|
"%s unknown envelope type: %s (payload: %q)", remote, t,
|
||||||
|
string(rem),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle any processing errors
|
// Handle any processing errors
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.E.F("%s message processing FAILED (type=%s): %v", remote, t, err)
|
log.E.F("%s message processing FAILED (type=%s): %v", remote, t, err)
|
||||||
log.D.F("%s error context - original message: %q", remote, msgPreview)
|
log.T.F("%s error context - original message: %q", remote, msgPreview)
|
||||||
|
|
||||||
// Send error notice to client
|
// Send error notice to client
|
||||||
noticeMsg := fmt.Sprintf("%s: %s", t, err.Error())
|
noticeMsg := fmt.Sprintf("%s: %s", t, err.Error())
|
||||||
if noticeErr := noticeenvelope.NewFrom(noticeMsg).Write(l); noticeErr != nil {
|
if noticeErr := noticeenvelope.NewFrom(noticeMsg).Write(l); noticeErr != nil {
|
||||||
log.E.F("%s failed to send error notice after %s processing failure: %v", remote, t, noticeErr)
|
log.E.F(
|
||||||
|
"%s failed to send error notice after %s processing failure: %v",
|
||||||
|
remote, t, noticeErr,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.D.F("%s sent error notice for %s processing failure", remote, t)
|
log.T.F("%s sent error notice for %s processing failure", remote, t)
|
||||||
} else {
|
} else {
|
||||||
log.D.F("%s message processing SUCCESS (type=%s)", remote, t)
|
log.T.F("%s message processing SUCCESS (type=%s)", remote, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,13 +29,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (l *Listener) HandleReq(msg []byte) (err error) {
|
func (l *Listener) HandleReq(msg []byte) (err error) {
|
||||||
log.D.F("HandleReq: START processing from %s", l.remote)
|
log.D.F("handling REQ: %s", msg)
|
||||||
|
log.T.F("HandleReq: START processing from %s", l.remote)
|
||||||
// var rem []byte
|
// var rem []byte
|
||||||
env := reqenvelope.New()
|
env := reqenvelope.New()
|
||||||
if _, err = env.Unmarshal(msg); chk.E(err) {
|
if _, err = env.Unmarshal(msg); chk.E(err) {
|
||||||
return normalize.Error.Errorf(err.Error())
|
return normalize.Error.Errorf(err.Error())
|
||||||
}
|
}
|
||||||
log.D.C(func() string { return fmt.Sprintf("REQ sub=%s filters=%d", env.Subscription, len(*env.Filters)) })
|
log.T.C(
|
||||||
|
func() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"REQ sub=%s filters=%d", env.Subscription, len(*env.Filters),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
// send a challenge to the client to auth if an ACL is active
|
// send a challenge to the client to auth if an ACL is active
|
||||||
if acl.Registry.Active.Load() != "none" {
|
if acl.Registry.Active.Load() != "none" {
|
||||||
if err = authenvelope.NewChallengeWith(l.challenge.Load()).
|
if err = authenvelope.NewChallengeWith(l.challenge.Load()).
|
||||||
@@ -100,9 +107,15 @@ func (l *Listener) HandleReq(msg []byte) (err error) {
|
|||||||
if f.Until != nil {
|
if f.Until != nil {
|
||||||
until = f.Until.Int()
|
until = f.Until.Int()
|
||||||
}
|
}
|
||||||
log.D.C(func() string {
|
log.T.C(
|
||||||
return fmt.Sprintf("REQ %s filter: kinds.len=%d authors.len=%d ids.len=%d d=%q limit=%v since=%v until=%v", env.Subscription, kindsLen, authorsLen, idsLen, dtag, lim, since, until)
|
func() string {
|
||||||
})
|
return fmt.Sprintf(
|
||||||
|
"REQ %s filter: kinds.len=%d authors.len=%d ids.len=%d d=%q limit=%v since=%v until=%v",
|
||||||
|
env.Subscription, kindsLen, authorsLen, idsLen, dtag,
|
||||||
|
lim, since, until,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if f != nil && pointers.Present(f.Limit) {
|
if f != nil && pointers.Present(f.Limit) {
|
||||||
if *f.Limit == 0 {
|
if *f.Limit == 0 {
|
||||||
@@ -229,7 +242,7 @@ privCheck:
|
|||||||
events = tmp
|
events = tmp
|
||||||
seen := make(map[string]struct{})
|
seen := make(map[string]struct{})
|
||||||
for _, ev := range events {
|
for _, ev := range events {
|
||||||
log.D.C(
|
log.T.C(
|
||||||
func() string {
|
func() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"REQ %s: sending EVENT id=%s kind=%d", env.Subscription,
|
"REQ %s: sending EVENT id=%s kind=%d", env.Subscription,
|
||||||
@@ -256,7 +269,7 @@ privCheck:
|
|||||||
}
|
}
|
||||||
// write the EOSE to signal to the client that all events found have been
|
// write the EOSE to signal to the client that all events found have been
|
||||||
// sent.
|
// sent.
|
||||||
log.D.F("sending EOSE to %s", l.remote)
|
log.T.F("sending EOSE to %s", l.remote)
|
||||||
if err = eoseenvelope.NewFrom(env.Subscription).
|
if err = eoseenvelope.NewFrom(env.Subscription).
|
||||||
Write(l); chk.E(err) {
|
Write(l); chk.E(err) {
|
||||||
return
|
return
|
||||||
@@ -264,7 +277,7 @@ privCheck:
|
|||||||
// if the query was for just Ids, we know there can't be any more results,
|
// if the query was for just Ids, we know there can't be any more results,
|
||||||
// so cancel the subscription.
|
// so cancel the subscription.
|
||||||
cancel := true
|
cancel := true
|
||||||
log.D.F(
|
log.T.F(
|
||||||
"REQ %s: computing cancel/subscription; events_sent=%d",
|
"REQ %s: computing cancel/subscription; events_sent=%d",
|
||||||
env.Subscription, len(events),
|
env.Subscription, len(events),
|
||||||
)
|
)
|
||||||
@@ -318,6 +331,6 @@ privCheck:
|
|||||||
} else {
|
} else {
|
||||||
// suppress server-sent CLOSED; client will close subscription if desired
|
// suppress server-sent CLOSED; client will close subscription if desired
|
||||||
}
|
}
|
||||||
log.D.F("HandleReq: COMPLETED processing from %s", l.remote)
|
log.T.F("HandleReq: COMPLETED processing from %s", l.remote)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ func (s *Server) Pinger(
|
|||||||
|
|
||||||
pingCancel()
|
pingCancel()
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.D.F("pinger context cancelled after %d pings", pingCount)
|
log.T.F("pinger context cancelled after %d pings", pingCount)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ type Listener struct {
|
|||||||
authedPubkey atomic.Bytes
|
authedPubkey atomic.Bytes
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
// Diagnostics: per-connection counters
|
// Diagnostics: per-connection counters
|
||||||
msgCount int
|
msgCount int
|
||||||
reqCount int
|
reqCount int
|
||||||
eventCount int
|
eventCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctx returns the listener's context, but creates a new context for each operation
|
// Ctx returns the listener's context, but creates a new context for each operation
|
||||||
@@ -41,7 +41,9 @@ func (l *Listener) Write(p []byte) (n int, err error) {
|
|||||||
if len(preview) > 200 {
|
if len(preview) > 200 {
|
||||||
preview = preview[:200] + "..."
|
preview = preview[:200] + "..."
|
||||||
}
|
}
|
||||||
log.D.F("ws->%s attempting write: len=%d preview=%q", l.remote, msgLen, preview)
|
log.T.F(
|
||||||
|
"ws->%s attempting write: len=%d preview=%q", l.remote, msgLen, preview,
|
||||||
|
)
|
||||||
|
|
||||||
// Use a separate context with timeout for writes to prevent race conditions
|
// Use a separate context with timeout for writes to prevent race conditions
|
||||||
// where the main connection context gets cancelled while writing events
|
// where the main connection context gets cancelled while writing events
|
||||||
@@ -57,17 +59,25 @@ func (l *Listener) Write(p []byte) (n int, err error) {
|
|||||||
totalDuration := time.Since(start)
|
totalDuration := time.Since(start)
|
||||||
|
|
||||||
// Log detailed failure information
|
// Log detailed failure information
|
||||||
log.E.F("ws->%s WRITE FAILED: len=%d duration=%v write_duration=%v error=%v preview=%q",
|
log.E.F(
|
||||||
l.remote, msgLen, totalDuration, writeDuration, err, preview)
|
"ws->%s WRITE FAILED: len=%d duration=%v write_duration=%v error=%v preview=%q",
|
||||||
|
l.remote, msgLen, totalDuration, writeDuration, err, preview,
|
||||||
|
)
|
||||||
|
|
||||||
// Check if this is a context timeout
|
// Check if this is a context timeout
|
||||||
if writeCtx.Err() != nil {
|
if writeCtx.Err() != nil {
|
||||||
log.E.F("ws->%s write timeout after %v (limit=%v)", l.remote, writeDuration, DefaultWriteTimeout)
|
log.E.F(
|
||||||
|
"ws->%s write timeout after %v (limit=%v)", l.remote,
|
||||||
|
writeDuration, DefaultWriteTimeout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check connection state
|
// Check connection state
|
||||||
if l.conn != nil {
|
if l.conn != nil {
|
||||||
log.D.F("ws->%s connection state during failure: remote_addr=%v", l.remote, l.req.RemoteAddr)
|
log.T.F(
|
||||||
|
"ws->%s connection state during failure: remote_addr=%v",
|
||||||
|
l.remote, l.req.RemoteAddr,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
chk.E(err) // Still call the original error handler
|
chk.E(err) // Still call the original error handler
|
||||||
@@ -79,12 +89,17 @@ func (l *Listener) Write(p []byte) (n int, err error) {
|
|||||||
totalDuration := time.Since(start)
|
totalDuration := time.Since(start)
|
||||||
n = msgLen
|
n = msgLen
|
||||||
|
|
||||||
log.D.F("ws->%s WRITE SUCCESS: len=%d duration=%v write_duration=%v",
|
log.T.F(
|
||||||
l.remote, n, totalDuration, writeDuration)
|
"ws->%s WRITE SUCCESS: len=%d duration=%v write_duration=%v",
|
||||||
|
l.remote, n, totalDuration, writeDuration,
|
||||||
|
)
|
||||||
|
|
||||||
// Log slow writes for performance diagnostics
|
// Log slow writes for performance diagnostics
|
||||||
if writeDuration > time.Millisecond*100 {
|
if writeDuration > time.Millisecond*100 {
|
||||||
log.D.F("ws->%s SLOW WRITE detected: %v (>100ms) len=%d", l.remote, writeDuration, n)
|
log.T.F(
|
||||||
|
"ws->%s SLOW WRITE detected: %v (>100ms) len=%d", l.remote,
|
||||||
|
writeDuration, n,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
41
app/web/.gitignore
vendored
41
app/web/.gitignore
vendored
@@ -1,30 +1,11 @@
|
|||||||
# Dependencies
|
node_modules/
|
||||||
node_modules
|
dist/
|
||||||
.pnp
|
.vite/
|
||||||
.pnp.js
|
.tanstack/
|
||||||
|
.idea/
|
||||||
# Bun
|
.DS_Store
|
||||||
.bunfig.toml
|
npm-debug.log*
|
||||||
bun.lockb
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
# Build directories
|
pnpm-debug.log*
|
||||||
build
|
/.idea/
|
||||||
|
|
||||||
# Cache and logs
|
|
||||||
.cache
|
|
||||||
.temp
|
|
||||||
.log
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Environment variables
|
|
||||||
.env
|
|
||||||
.env.local
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
# Orly Web Application
|
|
||||||
|
|
||||||
This is a React web application that uses Bun for building and bundling, and is automatically embedded into the Go binary when built.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- [Bun](https://bun.sh/) - JavaScript runtime and toolkit
|
|
||||||
- Go 1.16+ (for embedding functionality)
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
There are two ways to develop the web app:
|
|
||||||
|
|
||||||
1) Standalone (recommended for hot reload)
|
|
||||||
- Start the Go relay with the embedded web UI disabled so the React app can run on its own dev server with HMR.
|
|
||||||
- Configure the relay via environment variables:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# In another shell at repo root
|
|
||||||
export ORLY_WEB_DISABLE=true
|
|
||||||
# Optional: if you want same-origin URLs, you can set a proxy target and access the relay on the same port
|
|
||||||
# export ORLY_WEB_DEV_PROXY_URL=http://localhost:5173
|
|
||||||
|
|
||||||
# Start the relay as usual
|
|
||||||
go run .
|
|
||||||
```
|
|
||||||
|
|
||||||
- Then start the React dev server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd app/web
|
|
||||||
bun install
|
|
||||||
bun dev
|
|
||||||
```
|
|
||||||
|
|
||||||
When ORLY_WEB_DISABLE=true is set, the Go server still serves the API and websocket endpoints and sends permissive CORS headers, so the dev server can access them cross-origin. If ORLY_WEB_DEV_PROXY_URL is set, the Go server will reverse-proxy non-/api paths to the dev server so you can use the same origin.
|
|
||||||
|
|
||||||
2) Embedded (no hot reload)
|
|
||||||
- Build the web app and run the Go server with defaults:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd app/web
|
|
||||||
bun install
|
|
||||||
bun run build
|
|
||||||
cd ../../
|
|
||||||
go run .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
The React application needs to be built before compiling the Go binary to ensure that the embedded files are available:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build the React application
|
|
||||||
cd app/web
|
|
||||||
bun install
|
|
||||||
bun run build
|
|
||||||
|
|
||||||
# Build the Go binary from project root
|
|
||||||
cd ../../
|
|
||||||
go build
|
|
||||||
```
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
1. The React application is built to the `app/web/dist` directory
|
|
||||||
2. The Go embed directive in `app/web.go` embeds these files into the binary
|
|
||||||
3. When the server runs, it serves the embedded React app at the root path
|
|
||||||
|
|
||||||
## Build Automation
|
|
||||||
|
|
||||||
You can create a shell script to automate the build process:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
# build.sh
|
|
||||||
echo "Building React app..."
|
|
||||||
cd app/web
|
|
||||||
bun install
|
|
||||||
bun run build
|
|
||||||
|
|
||||||
echo "Building Go binary..."
|
|
||||||
cd ../../
|
|
||||||
go build
|
|
||||||
|
|
||||||
echo "Build complete!"
|
|
||||||
```
|
|
||||||
|
|
||||||
Make it executable with `chmod +x build.sh` and run with `./build.sh`.
|
|
||||||
183
app/web/bun.lock
183
app/web/bun.lock
@@ -2,44 +2,189 @@
|
|||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "orly-web",
|
"name": "svelte-app",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.2.0",
|
"sirv-cli": "^2.0.0",
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-json-pretty": "^2.2.0",
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "latest",
|
"@rollup/plugin-commonjs": "^24.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
||||||
|
"@rollup/plugin-terser": "^0.4.0",
|
||||||
|
"rollup": "^3.15.0",
|
||||||
|
"rollup-plugin-css-only": "^4.3.0",
|
||||||
|
"rollup-plugin-livereload": "^2.0.0",
|
||||||
|
"rollup-plugin-svelte": "^7.1.2",
|
||||||
|
"svelte": "^3.55.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
"@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ=="],
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
|
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="],
|
"@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="],
|
||||||
|
|
||||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||||
|
|
||||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||||
|
|
||||||
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
|
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
|
||||||
|
|
||||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
"@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@24.1.0", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "glob": "^8.0.3", "is-reference": "1.2.1", "magic-string": "^0.27.0" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0" }, "optionalPeers": ["rollup"] }, "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ=="],
|
||||||
|
|
||||||
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
|
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@15.3.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA=="],
|
||||||
|
|
||||||
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
|
"@rollup/plugin-terser": ["@rollup/plugin-terser@0.4.4", "", { "dependencies": { "serialize-javascript": "^6.0.1", "smob": "^1.0.0", "terser": "^5.17.4" }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A=="],
|
||||||
|
|
||||||
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
|
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||||
|
|
||||||
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|
||||||
"react-json-pretty": ["react-json-pretty@2.2.0", "", { "dependencies": { "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=15.0", "react-dom": ">=15.0" } }, "sha512-3UMzlAXkJ4R8S4vmkRKtvJHTewG4/rn1Q18n0zqdu/ipZbUPLVZD+QwC7uVcD/IAY3s8iNVHlgR2dMzIUS0n1A=="],
|
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
||||||
|
|
||||||
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="],
|
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||||
|
|
||||||
|
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
|
|
||||||
|
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||||
|
|
||||||
|
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||||
|
|
||||||
|
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||||
|
|
||||||
|
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||||
|
|
||||||
|
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||||
|
|
||||||
|
"commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
|
||||||
|
|
||||||
|
"commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="],
|
||||||
|
|
||||||
|
"console-clear": ["console-clear@1.1.1", "", {}, "sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ=="],
|
||||||
|
|
||||||
|
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
|
||||||
|
|
||||||
|
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||||
|
|
||||||
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
|
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
||||||
|
|
||||||
|
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
|
"get-port": ["get-port@3.2.0", "", {}, "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg=="],
|
||||||
|
|
||||||
|
"glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
|
||||||
|
|
||||||
|
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
|
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||||
|
|
||||||
|
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
|
||||||
|
|
||||||
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||||
|
|
||||||
|
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
|
||||||
|
|
||||||
|
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||||
|
|
||||||
|
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||||
|
|
||||||
|
"is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="],
|
||||||
|
|
||||||
|
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||||
|
|
||||||
|
"is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="],
|
||||||
|
|
||||||
|
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||||
|
|
||||||
|
"livereload": ["livereload@0.9.3", "", { "dependencies": { "chokidar": "^3.5.0", "livereload-js": "^3.3.1", "opts": ">= 1.2.0", "ws": "^7.4.3" }, "bin": { "livereload": "bin/livereload.js" } }, "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw=="],
|
||||||
|
|
||||||
|
"livereload-js": ["livereload-js@3.4.1", "", {}, "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g=="],
|
||||||
|
|
||||||
|
"local-access": ["local-access@1.1.0", "", {}, "sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw=="],
|
||||||
|
|
||||||
|
"magic-string": ["magic-string@0.27.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.13" } }, "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA=="],
|
||||||
|
|
||||||
|
"minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
|
||||||
|
|
||||||
|
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
|
||||||
|
|
||||||
|
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
||||||
|
|
||||||
|
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||||
|
|
||||||
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
|
"opts": ["opts@2.0.2", "", {}, "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg=="],
|
||||||
|
|
||||||
|
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||||
|
|
||||||
|
"randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="],
|
||||||
|
|
||||||
|
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||||
|
|
||||||
|
"resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
|
||||||
|
|
||||||
|
"resolve.exports": ["resolve.exports@2.0.3", "", {}, "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A=="],
|
||||||
|
|
||||||
|
"rollup": ["rollup@3.29.5", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w=="],
|
||||||
|
|
||||||
|
"rollup-plugin-css-only": ["rollup-plugin-css-only@4.5.5", "", { "dependencies": { "@rollup/pluginutils": "5" }, "peerDependencies": { "rollup": "<5" } }, "sha512-O2m2Sj8qsAtjUVqZyGTDXJypaOFFNV4knz8OlS6wJBws6XEICIiLsXmI56SbQEmWDqYU5TgRgWmslGj4THofJQ=="],
|
||||||
|
|
||||||
|
"rollup-plugin-livereload": ["rollup-plugin-livereload@2.0.5", "", { "dependencies": { "livereload": "^0.9.1" } }, "sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA=="],
|
||||||
|
|
||||||
|
"rollup-plugin-svelte": ["rollup-plugin-svelte@7.2.3", "", { "dependencies": { "@rollup/pluginutils": "^4.1.0", "resolve.exports": "^2.0.0" }, "peerDependencies": { "rollup": ">=2.0.0", "svelte": ">=3.5.0" } }, "sha512-LlniP+h00DfM+E4eav/Kk8uGjgPUjGIBfrAS/IxQvsuFdqSM0Y2sXf31AdxuIGSW9GsmocDqOfaxR5QNno/Tgw=="],
|
||||||
|
|
||||||
|
"sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
|
||||||
|
|
||||||
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
|
"semiver": ["semiver@1.1.0", "", {}, "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg=="],
|
||||||
|
|
||||||
|
"serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="],
|
||||||
|
|
||||||
|
"sirv": ["sirv@2.0.4", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ=="],
|
||||||
|
|
||||||
|
"sirv-cli": ["sirv-cli@2.0.2", "", { "dependencies": { "console-clear": "^1.1.0", "get-port": "^3.2.0", "kleur": "^4.1.4", "local-access": "^1.0.1", "sade": "^1.6.0", "semiver": "^1.0.0", "sirv": "^2.0.0", "tinydate": "^1.0.0" }, "bin": { "sirv": "bin.js" } }, "sha512-OtSJDwxsF1NWHc7ps3Sa0s+dPtP15iQNJzfKVz+MxkEo3z72mCD+yu30ct79rPr0CaV1HXSOBp+MIY5uIhHZ1A=="],
|
||||||
|
|
||||||
|
"smob": ["smob@1.5.0", "", {}, "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig=="],
|
||||||
|
|
||||||
|
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||||
|
|
||||||
|
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
|
||||||
|
|
||||||
|
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||||
|
|
||||||
|
"svelte": ["svelte@3.59.2", "", {}, "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA=="],
|
||||||
|
|
||||||
|
"terser": ["terser@5.44.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w=="],
|
||||||
|
|
||||||
|
"tinydate": ["tinydate@1.3.0", "", {}, "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w=="],
|
||||||
|
|
||||||
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
|
|
||||||
|
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
|
||||||
|
|
||||||
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
|
"ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
||||||
|
|
||||||
|
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"rollup-plugin-svelte/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="],
|
||||||
|
|
||||||
|
"rollup-plugin-svelte/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
161
app/web/dist/index-kk1m7jg4.js
vendored
161
app/web/dist/index-kk1m7jg4.js
vendored
File diff suppressed because one or more lines are too long
1
app/web/dist/index-q4cwd1fy.css
vendored
1
app/web/dist/index-q4cwd1fy.css
vendored
File diff suppressed because one or more lines are too long
40
app/web/dist/index.html
vendored
40
app/web/dist/index.html
vendored
@@ -1,30 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Nostr Relay</title>
|
<title>Next Orly</title>
|
||||||
|
<link rel="icon" href="/favicon.png" type="image/png" />
|
||||||
<link rel="stylesheet" crossorigin href="./index-q4cwd1fy.css"><script type="module" crossorigin src="./index-kk1m7jg4.js"></script></head>
|
<link rel="stylesheet" href="/bundle.css" />
|
||||||
<body>
|
</head>
|
||||||
<script>
|
<body>
|
||||||
// Apply system theme preference immediately to avoid flash of wrong theme
|
<div id="app"></div>
|
||||||
function applyTheme(isDark) {
|
<script src="/bundle.js"></script>
|
||||||
document.body.classList.remove('bg-white', 'bg-gray-900');
|
</body>
|
||||||
document.body.classList.add(isDark ? 'bg-gray-900' : 'bg-white');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set initial theme
|
|
||||||
applyTheme(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
||||||
|
|
||||||
// Listen for theme changes
|
|
||||||
if (window.matchMedia) {
|
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
|
||||||
applyTheme(e.matches);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div id="root"></div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
112
app/web/dist/tailwind.min.css
vendored
112
app/web/dist/tailwind.min.css
vendored
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
Local Tailwind CSS (minimal subset for this UI)
|
|
||||||
Note: This file includes just the utilities used by the app to keep size small.
|
|
||||||
You can replace this with a full Tailwind build if desired.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Preflight-like resets (very minimal) */
|
|
||||||
*,::before,::after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}
|
|
||||||
html,body,#root{height:100%}
|
|
||||||
html{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,Noto Sans,\"Apple Color Emoji\",\"Segoe UI Emoji\"}
|
|
||||||
body{margin:0}
|
|
||||||
button,input{font:inherit;color:inherit}
|
|
||||||
img{display:block;max-width:100%;height:auto}
|
|
||||||
|
|
||||||
/* Layout */
|
|
||||||
.sticky{position:sticky}.relative{position:relative}.absolute{position:absolute}
|
|
||||||
.top-0{top:0}.left-0{left:0}.inset-0{top:0;right:0;bottom:0;left:0}
|
|
||||||
.z-50{z-index:50}.z-10{z-index:10}
|
|
||||||
.block{display:block}.flex{display:flex}
|
|
||||||
.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}
|
|
||||||
.flex-grow{flex-grow:1}.shrink-0{flex-shrink:0}
|
|
||||||
.overflow-hidden{overflow:hidden}
|
|
||||||
|
|
||||||
/* Sizing */
|
|
||||||
.w-full{width:100%}.w-auto{width:auto}.w-16{width:4rem}
|
|
||||||
.h-full{height:100%}.h-16{height:4rem}
|
|
||||||
.aspect-square{aspect-ratio:1/1}
|
|
||||||
.max-w-3xl{max-width:48rem}
|
|
||||||
|
|
||||||
/* Spacing */
|
|
||||||
.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-6{padding:1.5rem}
|
|
||||||
.px-2{padding-left:.5rem;padding-right:.5rem}
|
|
||||||
.mr-0{margin-right:0}.mr-2{margin-right:.5rem}
|
|
||||||
.mt-2{margin-top:.5rem}.mt-5{margin-top:1.25rem}
|
|
||||||
.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}
|
|
||||||
.mx-auto{margin-left:auto;margin-right:auto}
|
|
||||||
|
|
||||||
/* Borders & Radius */
|
|
||||||
.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}
|
|
||||||
.border-0{border-width:0}.border-2{border-width:2px}
|
|
||||||
.border-white{border-color:#fff}
|
|
||||||
.border{border-width:1px}.border-gray-300{border-color:#d1d5db}.border-gray-600{border-color:#4b5563}
|
|
||||||
.border-red-500{border-color:#ef4444}.border-red-700{border-color:#b91c1c}
|
|
||||||
|
|
||||||
/* Colors / Backgrounds */
|
|
||||||
.bg-white{background-color:#fff}
|
|
||||||
.bg-gray-100{background-color:#f3f4f6}
|
|
||||||
.bg-gray-200{background-color:#e5e7eb}
|
|
||||||
.bg-gray-300{background-color:#d1d5db}
|
|
||||||
.bg-gray-600{background-color:#4b5563}
|
|
||||||
.bg-gray-700{background-color:#374151}
|
|
||||||
.bg-gray-800{background-color:#1f2937}
|
|
||||||
.bg-gray-900{background-color:#111827}
|
|
||||||
.bg-blue-500{background-color:#3b82f6}
|
|
||||||
.bg-blue-600{background-color:#2563eb}.hover\:bg-blue-700:hover{background-color:#1d4ed8}
|
|
||||||
.hover\:bg-blue-600:hover{background-color:#2563eb}
|
|
||||||
.bg-red-600{background-color:#dc2626}.hover\:bg-red-700:hover{background-color:#b91c1c}
|
|
||||||
.bg-cyan-100{background-color:#cffafe}
|
|
||||||
.bg-green-100{background-color:#d1fae5}
|
|
||||||
.bg-red-100{background-color:#fee2e2}
|
|
||||||
.bg-red-50{background-color:#fef2f2}
|
|
||||||
.bg-green-900{background-color:#064e3b}
|
|
||||||
.bg-red-900{background-color:#7f1d1d}
|
|
||||||
.bg-cyan-900{background-color:#164e63}
|
|
||||||
.bg-cover{background-size:cover}.bg-center{background-position:center}
|
|
||||||
.bg-transparent{background-color:transparent}
|
|
||||||
|
|
||||||
/* Text */
|
|
||||||
.text-left{text-align:left}
|
|
||||||
.text-white{color:#fff}
|
|
||||||
.text-gray-300{color:#d1d5db}
|
|
||||||
.text-gray-500{color:#6b7280}.hover\:text-gray-800:hover{color:#1f2937}
|
|
||||||
.hover\:text-gray-100:hover{color:#f3f4f6}
|
|
||||||
.text-gray-700{color:#374151}
|
|
||||||
.text-gray-800{color:#1f2937}
|
|
||||||
.text-gray-900{color:#111827}
|
|
||||||
.text-gray-100{color:#f3f4f6}
|
|
||||||
.text-green-800{color:#065f46}
|
|
||||||
.text-green-100{color:#dcfce7}
|
|
||||||
.text-red-800{color:#991b1b}
|
|
||||||
.text-red-200{color:#fecaca}
|
|
||||||
.text-red-100{color:#fee2e2}
|
|
||||||
.text-cyan-800{color:#155e75}
|
|
||||||
.text-cyan-100{color:#cffafe}
|
|
||||||
.text-base{font-size:1rem;line-height:1.5rem}
|
|
||||||
.text-lg{font-size:1.125rem;line-height:1.75rem}
|
|
||||||
.text-2xl{font-size:1.5rem;line-height:2rem}
|
|
||||||
.font-bold{font-weight:700}
|
|
||||||
|
|
||||||
/* Opacity */
|
|
||||||
.opacity-70{opacity:.7}
|
|
||||||
|
|
||||||
/* Effects */
|
|
||||||
.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px -1px rgba(0,0,0,0.1);box-shadow:var(--tw-shadow)}
|
|
||||||
|
|
||||||
/* Cursor */
|
|
||||||
.cursor-pointer{cursor:pointer}
|
|
||||||
|
|
||||||
/* Box model */
|
|
||||||
.box-border{box-sizing:border-box}
|
|
||||||
|
|
||||||
/* Utilities */
|
|
||||||
.hover\:bg-transparent:hover{background-color:transparent}
|
|
||||||
.hover\:bg-gray-200:hover{background-color:#e5e7eb}
|
|
||||||
.hover\:bg-gray-600:hover{background-color:#4b5563}
|
|
||||||
.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}
|
|
||||||
.focus\:ring-blue-200:focus{--tw-ring-color:rgba(191, 219, 254, var(--tw-ring-opacity))}
|
|
||||||
.focus\:ring-blue-500:focus{--tw-ring-color:rgba(59, 130, 246, var(--tw-ring-opacity))}
|
|
||||||
.disabled\:opacity-50:disabled{opacity:.5}
|
|
||||||
.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}
|
|
||||||
|
|
||||||
/* Height for avatar images in header already inherit from container */
|
|
||||||
@@ -1,19 +1,24 @@
|
|||||||
{
|
{
|
||||||
"name": "orly-web",
|
"name": "svelte-app",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun --hot --port 5173 public/dev.html",
|
"build": "rollup -c",
|
||||||
"build": "rm -rf dist && bun build ./public/index.html --outdir ./dist --minify --splitting && cp -r public/tailwind.min.css dist/",
|
"dev": "rollup -c -w",
|
||||||
"preview": "bun x serve dist"
|
"start": "sirv public --no-clear"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-json-pretty": "^2.2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "latest"
|
"@rollup/plugin-commonjs": "^24.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
||||||
|
"@rollup/plugin-terser": "^0.4.0",
|
||||||
|
"rollup": "^3.15.0",
|
||||||
|
"rollup-plugin-css-only": "^4.3.0",
|
||||||
|
"rollup-plugin-livereload": "^2.0.0",
|
||||||
|
"rollup-plugin-svelte": "^7.1.2",
|
||||||
|
"svelte": "^3.55.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sirv-cli": "^2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Nostr Relay (Dev)</title>
|
|
||||||
<link rel="stylesheet" href="tailwind.min.css" />
|
|
||||||
</head>
|
|
||||||
<body class="bg-white">
|
|
||||||
<div id="root"></div>
|
|
||||||
<script type="module" src="/src/index.jsx"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,30 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset='utf-8'>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||||
<title>Nostr Relay</title>
|
|
||||||
<link rel="stylesheet" href="tailwind.min.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script>
|
|
||||||
// Apply system theme preference immediately to avoid flash of wrong theme
|
|
||||||
function applyTheme(isDark) {
|
|
||||||
document.body.classList.remove('bg-white', 'bg-gray-900');
|
|
||||||
document.body.classList.add(isDark ? 'bg-gray-900' : 'bg-white');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set initial theme
|
<title>Svelte app</title>
|
||||||
applyTheme(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
||||||
|
|
||||||
// Listen for theme changes
|
<link rel='icon' type='image/png' href='/orly.png'>
|
||||||
if (window.matchMedia) {
|
<link rel='stylesheet' href='/global.css'>
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
<link rel='stylesheet' href='/build/bundle.css'>
|
||||||
applyTheme(e.matches);
|
|
||||||
});
|
<script defer src='/build/bundle.js'></script>
|
||||||
}
|
</head>
|
||||||
</script>
|
|
||||||
<div id="root"></div>
|
<body>
|
||||||
<script type="module" src="/src/index.jsx"></script>
|
</body>
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
112
app/web/public/tailwind.min.css
vendored
112
app/web/public/tailwind.min.css
vendored
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
Local Tailwind CSS (minimal subset for this UI)
|
|
||||||
Note: This file includes just the utilities used by the app to keep size small.
|
|
||||||
You can replace this with a full Tailwind build if desired.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Preflight-like resets (very minimal) */
|
|
||||||
*,::before,::after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}
|
|
||||||
html,body,#root{height:100%}
|
|
||||||
html{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,Noto Sans,\"Apple Color Emoji\",\"Segoe UI Emoji\"}
|
|
||||||
body{margin:0}
|
|
||||||
button,input{font:inherit;color:inherit}
|
|
||||||
img{display:block;max-width:100%;height:auto}
|
|
||||||
|
|
||||||
/* Layout */
|
|
||||||
.sticky{position:sticky}.relative{position:relative}.absolute{position:absolute}
|
|
||||||
.top-0{top:0}.left-0{left:0}.inset-0{top:0;right:0;bottom:0;left:0}
|
|
||||||
.z-50{z-index:50}.z-10{z-index:10}
|
|
||||||
.block{display:block}.flex{display:flex}
|
|
||||||
.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}
|
|
||||||
.flex-grow{flex-grow:1}.shrink-0{flex-shrink:0}
|
|
||||||
.overflow-hidden{overflow:hidden}
|
|
||||||
|
|
||||||
/* Sizing */
|
|
||||||
.w-full{width:100%}.w-auto{width:auto}.w-16{width:4rem}
|
|
||||||
.h-full{height:100%}.h-16{height:4rem}
|
|
||||||
.aspect-square{aspect-ratio:1/1}
|
|
||||||
.max-w-3xl{max-width:48rem}
|
|
||||||
|
|
||||||
/* Spacing */
|
|
||||||
.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-6{padding:1.5rem}
|
|
||||||
.px-2{padding-left:.5rem;padding-right:.5rem}
|
|
||||||
.mr-0{margin-right:0}.mr-2{margin-right:.5rem}
|
|
||||||
.mt-2{margin-top:.5rem}.mt-5{margin-top:1.25rem}
|
|
||||||
.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}
|
|
||||||
.mx-auto{margin-left:auto;margin-right:auto}
|
|
||||||
|
|
||||||
/* Borders & Radius */
|
|
||||||
.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}
|
|
||||||
.border-0{border-width:0}.border-2{border-width:2px}
|
|
||||||
.border-white{border-color:#fff}
|
|
||||||
.border{border-width:1px}.border-gray-300{border-color:#d1d5db}.border-gray-600{border-color:#4b5563}
|
|
||||||
.border-red-500{border-color:#ef4444}.border-red-700{border-color:#b91c1c}
|
|
||||||
|
|
||||||
/* Colors / Backgrounds */
|
|
||||||
.bg-white{background-color:#fff}
|
|
||||||
.bg-gray-100{background-color:#f3f4f6}
|
|
||||||
.bg-gray-200{background-color:#e5e7eb}
|
|
||||||
.bg-gray-300{background-color:#d1d5db}
|
|
||||||
.bg-gray-600{background-color:#4b5563}
|
|
||||||
.bg-gray-700{background-color:#374151}
|
|
||||||
.bg-gray-800{background-color:#1f2937}
|
|
||||||
.bg-gray-900{background-color:#111827}
|
|
||||||
.bg-blue-500{background-color:#3b82f6}
|
|
||||||
.bg-blue-600{background-color:#2563eb}.hover\:bg-blue-700:hover{background-color:#1d4ed8}
|
|
||||||
.hover\:bg-blue-600:hover{background-color:#2563eb}
|
|
||||||
.bg-red-600{background-color:#dc2626}.hover\:bg-red-700:hover{background-color:#b91c1c}
|
|
||||||
.bg-cyan-100{background-color:#cffafe}
|
|
||||||
.bg-green-100{background-color:#d1fae5}
|
|
||||||
.bg-red-100{background-color:#fee2e2}
|
|
||||||
.bg-red-50{background-color:#fef2f2}
|
|
||||||
.bg-green-900{background-color:#064e3b}
|
|
||||||
.bg-red-900{background-color:#7f1d1d}
|
|
||||||
.bg-cyan-900{background-color:#164e63}
|
|
||||||
.bg-cover{background-size:cover}.bg-center{background-position:center}
|
|
||||||
.bg-transparent{background-color:transparent}
|
|
||||||
|
|
||||||
/* Text */
|
|
||||||
.text-left{text-align:left}
|
|
||||||
.text-white{color:#fff}
|
|
||||||
.text-gray-300{color:#d1d5db}
|
|
||||||
.text-gray-500{color:#6b7280}.hover\:text-gray-800:hover{color:#1f2937}
|
|
||||||
.hover\:text-gray-100:hover{color:#f3f4f6}
|
|
||||||
.text-gray-700{color:#374151}
|
|
||||||
.text-gray-800{color:#1f2937}
|
|
||||||
.text-gray-900{color:#111827}
|
|
||||||
.text-gray-100{color:#f3f4f6}
|
|
||||||
.text-green-800{color:#065f46}
|
|
||||||
.text-green-100{color:#dcfce7}
|
|
||||||
.text-red-800{color:#991b1b}
|
|
||||||
.text-red-200{color:#fecaca}
|
|
||||||
.text-red-100{color:#fee2e2}
|
|
||||||
.text-cyan-800{color:#155e75}
|
|
||||||
.text-cyan-100{color:#cffafe}
|
|
||||||
.text-base{font-size:1rem;line-height:1.5rem}
|
|
||||||
.text-lg{font-size:1.125rem;line-height:1.75rem}
|
|
||||||
.text-2xl{font-size:1.5rem;line-height:2rem}
|
|
||||||
.font-bold{font-weight:700}
|
|
||||||
|
|
||||||
/* Opacity */
|
|
||||||
.opacity-70{opacity:.7}
|
|
||||||
|
|
||||||
/* Effects */
|
|
||||||
.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px -1px rgba(0,0,0,0.1);box-shadow:var(--tw-shadow)}
|
|
||||||
|
|
||||||
/* Cursor */
|
|
||||||
.cursor-pointer{cursor:pointer}
|
|
||||||
|
|
||||||
/* Box model */
|
|
||||||
.box-border{box-sizing:border-box}
|
|
||||||
|
|
||||||
/* Utilities */
|
|
||||||
.hover\:bg-transparent:hover{background-color:transparent}
|
|
||||||
.hover\:bg-gray-200:hover{background-color:#e5e7eb}
|
|
||||||
.hover\:bg-gray-600:hover{background-color:#4b5563}
|
|
||||||
.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}
|
|
||||||
.focus\:ring-blue-200:focus{--tw-ring-color:rgba(191, 219, 254, var(--tw-ring-opacity))}
|
|
||||||
.focus\:ring-blue-500:focus{--tw-ring-color:rgba(59, 130, 246, var(--tw-ring-opacity))}
|
|
||||||
.disabled\:opacity-50:disabled{opacity:.5}
|
|
||||||
.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}
|
|
||||||
|
|
||||||
/* Height for avatar images in header already inherit from container */
|
|
||||||
2299
app/web/src/App.jsx
2299
app/web/src/App.jsx
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
|
||||||
import App from './App';
|
|
||||||
import './styles.css';
|
|
||||||
|
|
||||||
const root = createRoot(document.getElementById('root'));
|
|
||||||
root.render(
|
|
||||||
<React.StrictMode>
|
|
||||||
<App />
|
|
||||||
</React.StrictMode>
|
|
||||||
);
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
background: #f9f9f9;
|
|
||||||
padding: 30px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-top: 20px; /* Reduced space since header is now sticky */
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
input, textarea {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: #007cba;
|
|
||||||
color: white;
|
|
||||||
padding: 12px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background: #005a87;
|
|
||||||
}
|
|
||||||
|
|
||||||
.danger-button {
|
|
||||||
background: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.danger-button:hover {
|
|
||||||
background: #c82333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.success {
|
|
||||||
background: #d4edda;
|
|
||||||
color: #155724;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
background: #f8d7da;
|
|
||||||
color: #721c24;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
background: #d1ecf1;
|
|
||||||
color: #0c5460;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-panel {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
z-index: 1000;
|
|
||||||
height: 60px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 0 0 12px;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-left {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-center {
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-logo {
|
|
||||||
height: 100%;
|
|
||||||
aspect-ratio: 1 / 1;
|
|
||||||
width: auto;
|
|
||||||
border-radius: 0;
|
|
||||||
object-fit: cover;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-avatar {
|
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
|
||||||
border-radius: 50%;
|
|
||||||
object-fit: cover;
|
|
||||||
border: 2px solid white;
|
|
||||||
margin-right: 10px;
|
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-profile {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.2em;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-name {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1em;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-banner {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: -1;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logout-button {
|
|
||||||
background: transparent;
|
|
||||||
color: #6c757d;
|
|
||||||
border: none;
|
|
||||||
font-size: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 48px;
|
|
||||||
height: 100%;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logout-button:hover {
|
|
||||||
background: transparent;
|
|
||||||
color: #343a40;
|
|
||||||
}
|
|
||||||
@@ -236,7 +236,7 @@ func (f *Follows) startSubscriptions(ctx context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
urls := f.adminRelays()
|
urls := f.adminRelays()
|
||||||
log.I.S(urls)
|
// log.I.S(urls)
|
||||||
if len(urls) == 0 {
|
if len(urls) == 0 {
|
||||||
log.W.F("follows syncer: no admin relays found in DB (kind 10002) and no bootstrap relays configured")
|
log.W.F("follows syncer: no admin relays found in DB (kind 10002) and no bootstrap relays configured")
|
||||||
return
|
return
|
||||||
@@ -274,11 +274,16 @@ func (f *Follows) startSubscriptions(ctx context.Context) {
|
|||||||
log.W.F("follows syncer: dial %s failed: %v", u, err)
|
log.W.F("follows syncer: dial %s failed: %v", u, err)
|
||||||
|
|
||||||
// Handle different types of errors
|
// Handle different types of errors
|
||||||
if strings.Contains(err.Error(), "response status code 101 but got 403") {
|
if strings.Contains(
|
||||||
|
err.Error(), "response status code 101 but got 403",
|
||||||
|
) {
|
||||||
// 403 means the relay is not accepting connections from us
|
// 403 means the relay is not accepting connections from us
|
||||||
// Forbidden is the meaning, usually used to indicate either the IP or user is blocked
|
// Forbidden is the meaning, usually used to indicate either the IP or user is blocked
|
||||||
// But we should still retry after a longer delay
|
// But we should still retry after a longer delay
|
||||||
log.W.F("follows syncer: relay %s returned 403, will retry after longer delay", u)
|
log.W.F(
|
||||||
|
"follows syncer: relay %s returned 403, will retry after longer delay",
|
||||||
|
u,
|
||||||
|
)
|
||||||
timer := time.NewTimer(5 * time.Minute) // Wait 5 minutes before retrying 403 errors
|
timer := time.NewTimer(5 * time.Minute) // Wait 5 minutes before retrying 403 errors
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -286,12 +291,20 @@ func (f *Follows) startSubscriptions(ctx context.Context) {
|
|||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
} else if strings.Contains(err.Error(), "timeout") || strings.Contains(err.Error(), "connection refused") {
|
} else if strings.Contains(
|
||||||
|
err.Error(), "timeout",
|
||||||
|
) || strings.Contains(err.Error(), "connection refused") {
|
||||||
// Network issues, retry with normal backoff
|
// Network issues, retry with normal backoff
|
||||||
log.W.F("follows syncer: network issue with %s, retrying in %v", u, backoff)
|
log.W.F(
|
||||||
|
"follows syncer: network issue with %s, retrying in %v",
|
||||||
|
u, backoff,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// Other errors, retry with normal backoff
|
// Other errors, retry with normal backoff
|
||||||
log.W.F("follows syncer: connection error with %s, retrying in %v", u, backoff)
|
log.W.F(
|
||||||
|
"follows syncer: connection error with %s, retrying in %v",
|
||||||
|
u, backoff,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
timer := time.NewTimer(backoff)
|
timer := time.NewTimer(backoff)
|
||||||
@@ -306,7 +319,7 @@ func (f *Follows) startSubscriptions(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
backoff = time.Second
|
backoff = time.Second
|
||||||
log.I.F("follows syncer: successfully connected to %s", u)
|
log.T.F("follows syncer: successfully connected to %s", u)
|
||||||
|
|
||||||
// send REQ for kind 3 (follow lists), kind 10002 (relay lists), and all events from follows
|
// send REQ for kind 3 (follow lists), kind 10002 (relay lists), and all events from follows
|
||||||
ff := &filter.S{}
|
ff := &filter.S{}
|
||||||
@@ -332,11 +345,16 @@ func (f *Follows) startSubscriptions(ctx context.Context) {
|
|||||||
if err = c.Write(
|
if err = c.Write(
|
||||||
ctx, websocket.MessageText, req.Marshal(nil),
|
ctx, websocket.MessageText, req.Marshal(nil),
|
||||||
); chk.E(err) {
|
); chk.E(err) {
|
||||||
log.W.F("follows syncer: failed to send REQ to %s: %v", u, err)
|
log.W.F(
|
||||||
|
"follows syncer: failed to send REQ to %s: %v", u, err,
|
||||||
|
)
|
||||||
_ = c.Close(websocket.StatusInternalError, "write failed")
|
_ = c.Close(websocket.StatusInternalError, "write failed")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.I.F("follows syncer: sent REQ to %s for kind 3, 10002, and all events (last 30 days) from followed users", u)
|
log.T.F(
|
||||||
|
"follows syncer: sent REQ to %s for kind 3, 10002, and all events (last 30 days) from followed users",
|
||||||
|
u,
|
||||||
|
)
|
||||||
// read loop
|
// read loop
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -368,17 +386,24 @@ func (f *Follows) startSubscriptions(ctx context.Context) {
|
|||||||
// Process events based on kind
|
// Process events based on kind
|
||||||
switch res.Event.Kind {
|
switch res.Event.Kind {
|
||||||
case kind.FollowList.K:
|
case kind.FollowList.K:
|
||||||
log.I.F("follows syncer: received kind 3 (follow list) event from %s on relay %s",
|
log.T.F(
|
||||||
hex.EncodeToString(res.Event.Pubkey), u)
|
"follows syncer: received kind 3 (follow list) event from %s on relay %s",
|
||||||
|
hex.EncodeToString(res.Event.Pubkey), u,
|
||||||
|
)
|
||||||
// Extract followed pubkeys from 'p' tags in kind 3 events
|
// Extract followed pubkeys from 'p' tags in kind 3 events
|
||||||
f.extractFollowedPubkeys(res.Event)
|
f.extractFollowedPubkeys(res.Event)
|
||||||
case kind.RelayListMetadata.K:
|
case kind.RelayListMetadata.K:
|
||||||
log.I.F("follows syncer: received kind 10002 (relay list) event from %s on relay %s",
|
log.T.F(
|
||||||
hex.EncodeToString(res.Event.Pubkey), u)
|
"follows syncer: received kind 10002 (relay list) event from %s on relay %s",
|
||||||
|
hex.EncodeToString(res.Event.Pubkey), u,
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
// Log all other events from followed users
|
// Log all other events from followed users
|
||||||
log.I.F("follows syncer: received kind %d event from %s on relay %s",
|
log.T.F(
|
||||||
res.Event.Kind, hex.EncodeToString(res.Event.Pubkey), u)
|
"follows syncer: received kind %d event from %s on relay %s",
|
||||||
|
res.Event.Kind,
|
||||||
|
hex.EncodeToString(res.Event.Pubkey), u,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err = f.D.SaveEvent(
|
if _, _, err = f.D.SaveEvent(
|
||||||
@@ -488,7 +513,10 @@ func (f *Follows) AddFollow(pub []byte) {
|
|||||||
b := make([]byte, len(pub))
|
b := make([]byte, len(pub))
|
||||||
copy(b, pub)
|
copy(b, pub)
|
||||||
f.follows = append(f.follows, b)
|
f.follows = append(f.follows, b)
|
||||||
log.I.F("follows syncer: added new followed pubkey: %s", hex.EncodeToString(pub))
|
log.I.F(
|
||||||
|
"follows syncer: added new followed pubkey: %s",
|
||||||
|
hex.EncodeToString(pub),
|
||||||
|
)
|
||||||
// notify syncer if initialized
|
// notify syncer if initialized
|
||||||
if f.updated != nil {
|
if f.updated != nil {
|
||||||
select {
|
select {
|
||||||
|
|||||||
Reference in New Issue
Block a user