mirror of
https://github.com/cf-sonr/radar.git
synced 2026-01-12 02:59:13 +00:00
feat: implement account, profile, network, and activity management
This commit is contained in:
13
Makefile
Normal file
13
Makefile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
generate:
|
||||||
|
@gum spin --show-error --title "(1/3) Running templ generate" -- sh -c "templ generate"
|
||||||
|
@gum log --level info --time kitchen "[GENERATE] Completed templ generate successfully."
|
||||||
|
|
||||||
|
assets:
|
||||||
|
@gum spin --show-error --title "(2/3) Running workers-assets-gen" -- sh -c "go run github.com/syumai/workers/cmd/workers-assets-gen -mode=go"
|
||||||
|
@gum log --level info --time kitchen "[GENERATE] Completed workers-assets-gen successfully."
|
||||||
|
|
||||||
|
build: generate assets
|
||||||
|
@GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o ./build/app.wasm .
|
||||||
|
@gum log --level info --time kitchen "[BUILD] Completed Go WASM Build successfully."
|
||||||
|
|
||||||
|
|
||||||
69
config/config.go
Normal file
69
config/config.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/syumai/workers/cloudflare"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Cache CacheSettings `json:"cache"` // Added Cache configuration
|
||||||
|
Sonr NetworkParams `json:"network"`
|
||||||
|
DefaultExpiry time.Duration `json:"expiry"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkParams struct {
|
||||||
|
SonrChainID string `json:"sonr_chain_id"`
|
||||||
|
SonrAPIURL string `json:"sonr_api_url"`
|
||||||
|
SonrRPCURL string `json:"sonr_rpc_url"`
|
||||||
|
IPFSGateway string `json:"ipfs_gateway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheSettings defines the configuration for Cloudflare cache
|
||||||
|
type CacheSettings struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
DefaultMaxAge int `json:"default_max_age"`
|
||||||
|
BypassHeader string `json:"bypass_header"`
|
||||||
|
BypassValue string `json:"bypass_value"`
|
||||||
|
CacheableStatusCodes []int `json:"cacheable_status_codes"`
|
||||||
|
CacheableContentTypes []string `json:"cacheable_content_types"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Get() Config {
|
||||||
|
cache := CacheSettings{
|
||||||
|
Enabled: true,
|
||||||
|
DefaultMaxAge: 60, // 1 minute by default
|
||||||
|
BypassHeader: "X-Cache-Bypass",
|
||||||
|
BypassValue: "true",
|
||||||
|
CacheableStatusCodes: []int{
|
||||||
|
200, 301, 302,
|
||||||
|
},
|
||||||
|
CacheableContentTypes: []string{
|
||||||
|
"text/html",
|
||||||
|
"text/css",
|
||||||
|
"text/javascript",
|
||||||
|
"application/javascript",
|
||||||
|
"application/json",
|
||||||
|
"image/jpeg",
|
||||||
|
"image/png",
|
||||||
|
"image/gif",
|
||||||
|
"image/webp",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sonr := NetworkParams{
|
||||||
|
SonrChainID: cloudflare.Getenv("SONR_CHAIN_ID"),
|
||||||
|
SonrAPIURL: cloudflare.Getenv("SONR_API_URL"),
|
||||||
|
SonrRPCURL: cloudflare.Getenv("SONR_RPC_URL"),
|
||||||
|
IPFSGateway: cloudflare.Getenv("IPFS_GATEWAY"),
|
||||||
|
}
|
||||||
|
c := Config{
|
||||||
|
Sonr: sonr,
|
||||||
|
Cache: cache,
|
||||||
|
DefaultExpiry: time.Hour * 1,
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
28
config/routes.go
Normal file
28
config/routes.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/sonr-io/motr/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ╭────────────────────────────────────────────────╮
|
||||||
|
// │ HTTP Routes │
|
||||||
|
// ╰────────────────────────────────────────────────╯
|
||||||
|
|
||||||
|
func RegisterViews(e *echo.Echo) {
|
||||||
|
e.GET("/", handlers.RenderHomePage)
|
||||||
|
e.GET("/login", handlers.RenderLoginPage)
|
||||||
|
e.GET("/register", handlers.RenderRegisterPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterPartials(e *echo.Echo) {
|
||||||
|
e.POST("/login/:handle/check", handlers.HandleLoginCheck)
|
||||||
|
e.POST("/login/:handle/finish", handlers.HandleLoginFinish)
|
||||||
|
e.POST("/register/:handle", handlers.HandleRegisterStart)
|
||||||
|
e.POST("/register/:handle/check", handlers.HandleRegisterCheck)
|
||||||
|
e.POST("/register/:handle/finish", handlers.HandleRegisterFinish)
|
||||||
|
e.POST("/status", handlers.HandleStatusCheck)
|
||||||
|
}
|
||||||
40
handlers/auth_handler.go
Normal file
40
handlers/auth_handler.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/sonr-io/motr/pkg/render"
|
||||||
|
"github.com/sonr-io/motr/ui/login"
|
||||||
|
"github.com/sonr-io/motr/ui/register"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleLoginCheck(c echo.Context) error {
|
||||||
|
return render.Component(c, login.LoginView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleLoginInitial(c echo.Context) error {
|
||||||
|
return render.Component(c, login.LoginView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleLoginFinish(c echo.Context) error {
|
||||||
|
return render.Component(c, login.LoginView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleLoginStart(c echo.Context) error {
|
||||||
|
return render.Component(c, login.LoginView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleRegisterInitial(c echo.Context) error {
|
||||||
|
return render.Component(c, register.RegisterView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleRegisterCheck(c echo.Context) error {
|
||||||
|
return render.Component(c, register.RegisterView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleRegisterFinish(c echo.Context) error {
|
||||||
|
return render.Component(c, register.RegisterView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleRegisterStart(c echo.Context) error {
|
||||||
|
return render.Component(c, register.RegisterView())
|
||||||
|
}
|
||||||
4
handlers/form_handler.go
Normal file
4
handlers/form_handler.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package handlers
|
||||||
24
handlers/page_handler.go
Normal file
24
handlers/page_handler.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/sonr-io/motr/ui/register"
|
||||||
|
"github.com/sonr-io/motr/pkg/render"
|
||||||
|
"github.com/sonr-io/motr/ui/home"
|
||||||
|
"github.com/sonr-io/motr/ui/login"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RenderHomePage(c echo.Context) error {
|
||||||
|
return render.Component(c, home.HomeView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderLoginPage(c echo.Context) error {
|
||||||
|
return render.Component(c, login.LoginView())
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderRegisterPage(c echo.Context) error {
|
||||||
|
return render.Component(c, register.RegisterView())
|
||||||
|
}
|
||||||
38
handlers/status_handler.go
Normal file
38
handlers/status_handler.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StatusCheck is a struct that represents the status of the application
|
||||||
|
type StatusCheck struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Services []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
} `json:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleStatusCheck is a handler that checks the status of the application
|
||||||
|
func HandleStatusCheck(c echo.Context) error {
|
||||||
|
return c.JSON(200, StatusCheck{
|
||||||
|
Ok: true,
|
||||||
|
Services: []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "IPFS",
|
||||||
|
Ok: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "IBC",
|
||||||
|
Ok: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Sonr",
|
||||||
|
Ok: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
35
internal/api/client.go
Normal file
35
internal/api/client.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/syumai/workers/cloudflare/fetch"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response interface {
|
||||||
|
UnmarshalJSON(data []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client interface {
|
||||||
|
MarketAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
fc *fetch.Client
|
||||||
|
ctx context.Context
|
||||||
|
MarketAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(ctx context.Context) *client {
|
||||||
|
fc := fetch.NewClient()
|
||||||
|
c := &client{
|
||||||
|
fc: fc,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
marketAPI := NewMarketAPI(c, ctx)
|
||||||
|
c.MarketAPI = marketAPI
|
||||||
|
return c
|
||||||
|
}
|
||||||
117
internal/api/market.go
Normal file
117
internal/api/market.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
kCryptoAPIURL = "https://api.alternative.me"
|
||||||
|
kCryptoAPIListings = "/v2/listings"
|
||||||
|
kCryptoAPITickers = "/v2/ticker"
|
||||||
|
kCryptoAPIGlobal = "/v2/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarketAPI interface {
|
||||||
|
Listings(symbol string) (*ListingsResponse, error)
|
||||||
|
Ticker(symbol string) (*TickersResponse, error)
|
||||||
|
GlobalMarket() (*GlobalMarketResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type marketAPI struct {
|
||||||
|
client *client
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMarketAPI(c *client, ctx context.Context) *marketAPI {
|
||||||
|
return &marketAPI{
|
||||||
|
client: c,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *marketAPI) Listings(symbol string) (*ListingsResponse, error) {
|
||||||
|
r := buildRequest(m.ctx, fmt.Sprintf("%s/%s", kCryptoAPIListings, symbol))
|
||||||
|
v := &ListingsResponse{}
|
||||||
|
err := doFetch(m.client.fc, r, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *marketAPI) Ticker(symbol string) (*TickersResponse, error) {
|
||||||
|
r := buildRequest(m.ctx, fmt.Sprintf("%s/%s", kCryptoAPITickers, symbol))
|
||||||
|
v := &TickersResponse{}
|
||||||
|
err := doFetch(m.client.fc, r, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *marketAPI) GlobalMarket() (*GlobalMarketResponse, error) {
|
||||||
|
r := buildRequest(m.ctx, kCryptoAPIGlobal)
|
||||||
|
v := &GlobalMarketResponse{}
|
||||||
|
err := doFetch(m.client.fc, r, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListingsResponse struct {
|
||||||
|
Data []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
WebsiteSlug string `json:"website_slug"`
|
||||||
|
} `json:"data"`
|
||||||
|
Metadata struct {
|
||||||
|
Timestamp int `json:"timestamp"`
|
||||||
|
NumCryptocurrencies int `json:"num_cryptocurrencies"`
|
||||||
|
Error any `json:"error"`
|
||||||
|
} `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ListingsResponse) UnmarshalJSON(data []byte) error {
|
||||||
|
return json.Unmarshal(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TickersResponse struct {
|
||||||
|
Data []struct {
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Price struct {
|
||||||
|
USD float64 `json:"USD"`
|
||||||
|
} `json:"price"`
|
||||||
|
} `json:"data"`
|
||||||
|
Metadata struct {
|
||||||
|
Timestamp int `json:"timestamp"`
|
||||||
|
Error any `json:"error"`
|
||||||
|
} `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *TickersResponse) UnmarshalJSON(data []byte) error {
|
||||||
|
return json.Unmarshal(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GlobalMarketResponse struct {
|
||||||
|
Data []struct {
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Price struct {
|
||||||
|
USD float64 `json:"USD"`
|
||||||
|
} `json:"price"`
|
||||||
|
} `json:"data"`
|
||||||
|
Metadata struct {
|
||||||
|
Timestamp int `json:"timestamp"`
|
||||||
|
Error any `json:"error"`
|
||||||
|
} `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GlobalMarketResponse) UnmarshalJSON(data []byte) error {
|
||||||
|
return json.Unmarshal(data, r)
|
||||||
|
}
|
||||||
43
internal/api/utils.go
Normal file
43
internal/api/utils.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/syumai/workers/cloudflare/fetch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildRequest(c context.Context, url string) *fetch.Request {
|
||||||
|
r, err := fetch.NewRequest(c, http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0")
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func doFetch(c *fetch.Client, r *fetch.Request, v Response) error {
|
||||||
|
resp, err := c.Do(r, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("request failed: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close() // Ensure body is always closed
|
||||||
|
|
||||||
|
// Check for non-200 status codes
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directly decode JSON into the response struct
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
|
||||||
|
return fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
31
internal/db/activity/db.go
Normal file
31
internal/db/activity/db.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package activity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBTX interface {
|
||||||
|
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||||
|
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||||
|
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db DBTX) *Queries {
|
||||||
|
return &Queries{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queries struct {
|
||||||
|
db DBTX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||||
|
return &Queries{
|
||||||
|
db: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
99
internal/db/activity/models.go
Normal file
99
internal/db/activity/models.go
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package activity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Activity struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
AccountID string `json:"account_id"`
|
||||||
|
TxHash sql.NullString `json:"tx_hash"`
|
||||||
|
TxType string `json:"tx_type"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Amount sql.NullString `json:"amount"`
|
||||||
|
Fee sql.NullString `json:"fee"`
|
||||||
|
GasUsed sql.NullInt64 `json:"gas_used"`
|
||||||
|
GasWanted sql.NullInt64 `json:"gas_wanted"`
|
||||||
|
Memo sql.NullString `json:"memo"`
|
||||||
|
BlockHeight sql.NullInt64 `json:"block_height"`
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
RawLog sql.NullString `json:"raw_log"`
|
||||||
|
Error sql.NullString `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CryptoListing struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
ApiID string `json:"api_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
WebsiteSlug string `json:"website_slug"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FearGreedIndex struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Value int64 `json:"value"`
|
||||||
|
ValueClassification string `json:"value_classification"`
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
TimeUntilUpdate sql.NullString `json:"time_until_update"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GlobalMarket struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
TotalMarketCapUsd sql.NullFloat64 `json:"total_market_cap_usd"`
|
||||||
|
Total24hVolumeUsd sql.NullFloat64 `json:"total_24h_volume_usd"`
|
||||||
|
BitcoinPercentageOfMarketCap sql.NullFloat64 `json:"bitcoin_percentage_of_market_cap"`
|
||||||
|
ActiveCurrencies sql.NullInt64 `json:"active_currencies"`
|
||||||
|
ActiveAssets sql.NullInt64 `json:"active_assets"`
|
||||||
|
ActiveMarkets sql.NullInt64 `json:"active_markets"`
|
||||||
|
LastUpdated time.Time `json:"last_updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Health struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
EndpointUrl string `json:"endpoint_url"`
|
||||||
|
EndpointType string `json:"endpoint_type"`
|
||||||
|
ChainID sql.NullString `json:"chain_id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
ResponseTimeMs sql.NullInt64 `json:"response_time_ms"`
|
||||||
|
LastChecked time.Time `json:"last_checked"`
|
||||||
|
NextCheck sql.NullTime `json:"next_check"`
|
||||||
|
FailureCount int64 `json:"failure_count"`
|
||||||
|
SuccessCount int64 `json:"success_count"`
|
||||||
|
ResponseData sql.NullString `json:"response_data"`
|
||||||
|
ErrorMessage sql.NullString `json:"error_message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description sql.NullString `json:"description"`
|
||||||
|
ChainID string `json:"chain_id"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
OwnerAddress string `json:"owner_address"`
|
||||||
|
Metadata sql.NullString `json:"metadata"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
BlockHeight int64 `json:"block_height"`
|
||||||
|
}
|
||||||
63
internal/db/activity/querier.go
Normal file
63
internal/db/activity/querier.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package activity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Querier interface {
|
||||||
|
GetActivityByID(ctx context.Context, id string) (Activity, error)
|
||||||
|
GetActivityByTxHash(ctx context.Context, txHash sql.NullString) (Activity, error)
|
||||||
|
GetCryptoListingByApiID(ctx context.Context, apiID string) (CryptoListing, error)
|
||||||
|
GetCryptoListingByID(ctx context.Context, id string) (CryptoListing, error)
|
||||||
|
GetCryptoListingBySymbol(ctx context.Context, symbol string) (CryptoListing, error)
|
||||||
|
GetCryptoListingByWebsiteSlug(ctx context.Context, websiteSlug string) (CryptoListing, error)
|
||||||
|
GetFearGreedIndexByID(ctx context.Context, id string) (FearGreedIndex, error)
|
||||||
|
GetGlobalMarketByID(ctx context.Context, id string) (GlobalMarket, error)
|
||||||
|
GetHealthByEndpoint(ctx context.Context, endpointUrl string) (Health, error)
|
||||||
|
GetHealthByID(ctx context.Context, id string) (Health, error)
|
||||||
|
GetLatestFearGreedIndex(ctx context.Context) (FearGreedIndex, error)
|
||||||
|
GetLatestGlobalMarket(ctx context.Context) (GlobalMarket, error)
|
||||||
|
GetServiceByAddress(ctx context.Context, address string) (Service, error)
|
||||||
|
GetServiceByChainAndAddress(ctx context.Context, arg GetServiceByChainAndAddressParams) (Service, error)
|
||||||
|
GetServiceByID(ctx context.Context, id string) (Service, error)
|
||||||
|
// ACTIVITY QUERIES
|
||||||
|
InsertActivity(ctx context.Context, arg InsertActivityParams) (Activity, error)
|
||||||
|
// CRYPTO LISTINGS QUERIES (NEW)
|
||||||
|
InsertCryptoListing(ctx context.Context, arg InsertCryptoListingParams) (CryptoListing, error)
|
||||||
|
// FEAR AND GREED INDEX QUERIES (NEW)
|
||||||
|
InsertFearGreedIndex(ctx context.Context, arg InsertFearGreedIndexParams) (FearGreedIndex, error)
|
||||||
|
InsertGlobalMarket(ctx context.Context, arg InsertGlobalMarketParams) (GlobalMarket, error)
|
||||||
|
// HEALTH QUERIES
|
||||||
|
InsertHealth(ctx context.Context, arg InsertHealthParams) (Health, error)
|
||||||
|
InsertService(ctx context.Context, arg InsertServiceParams) (Service, error)
|
||||||
|
ListActivitiesByAccount(ctx context.Context, arg ListActivitiesByAccountParams) ([]Activity, error)
|
||||||
|
ListActivitiesByStatus(ctx context.Context, arg ListActivitiesByStatusParams) ([]Activity, error)
|
||||||
|
ListActivitiesByType(ctx context.Context, arg ListActivitiesByTypeParams) ([]Activity, error)
|
||||||
|
ListCryptoListings(ctx context.Context, arg ListCryptoListingsParams) ([]CryptoListing, error)
|
||||||
|
ListFearGreedIndexHistory(ctx context.Context, arg ListFearGreedIndexHistoryParams) ([]FearGreedIndex, error)
|
||||||
|
ListGlobalMarketHistory(ctx context.Context, arg ListGlobalMarketHistoryParams) ([]GlobalMarket, error)
|
||||||
|
ListHealthByChain(ctx context.Context, arg ListHealthByChainParams) ([]Health, error)
|
||||||
|
ListHealthByStatus(ctx context.Context, arg ListHealthByStatusParams) ([]Health, error)
|
||||||
|
ListHealthChecksNeedingUpdate(ctx context.Context, limit int64) ([]Health, error)
|
||||||
|
ListServicesByChain(ctx context.Context, arg ListServicesByChainParams) ([]Service, error)
|
||||||
|
ListServicesByOwner(ctx context.Context, arg ListServicesByOwnerParams) ([]Service, error)
|
||||||
|
SoftDeleteActivity(ctx context.Context, id string) error
|
||||||
|
SoftDeleteCryptoListing(ctx context.Context, id string) error
|
||||||
|
SoftDeleteFearGreedIndex(ctx context.Context, id string) error
|
||||||
|
SoftDeleteGlobalMarket(ctx context.Context, id string) error
|
||||||
|
SoftDeleteHealth(ctx context.Context, id string) error
|
||||||
|
SoftDeleteService(ctx context.Context, id string) error
|
||||||
|
UpdateActivityStatus(ctx context.Context, arg UpdateActivityStatusParams) (Activity, error)
|
||||||
|
UpdateCryptoListing(ctx context.Context, arg UpdateCryptoListingParams) (CryptoListing, error)
|
||||||
|
UpdateFearGreedIndex(ctx context.Context, arg UpdateFearGreedIndexParams) (FearGreedIndex, error)
|
||||||
|
UpdateGlobalMarket(ctx context.Context, arg UpdateGlobalMarketParams) (GlobalMarket, error)
|
||||||
|
UpdateHealthCheck(ctx context.Context, arg UpdateHealthCheckParams) (Health, error)
|
||||||
|
UpdateService(ctx context.Context, arg UpdateServiceParams) (Service, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Querier = (*Queries)(nil)
|
||||||
338
internal/db/activity/query.sql
Normal file
338
internal/db/activity/query.sql
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
-- name: InsertService :one
|
||||||
|
INSERT INTO services (
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
chain_id,
|
||||||
|
address,
|
||||||
|
owner_address,
|
||||||
|
metadata,
|
||||||
|
status,
|
||||||
|
block_height
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetServiceByID :one
|
||||||
|
SELECT * FROM services
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetServiceByAddress :one
|
||||||
|
SELECT * FROM services
|
||||||
|
WHERE address = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetServiceByChainAndAddress :one
|
||||||
|
SELECT * FROM services
|
||||||
|
WHERE chain_id = ? AND address = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListServicesByChain :many
|
||||||
|
SELECT * FROM services
|
||||||
|
WHERE chain_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY name ASC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: ListServicesByOwner :many
|
||||||
|
SELECT * FROM services
|
||||||
|
WHERE owner_address = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: UpdateService :one
|
||||||
|
UPDATE services
|
||||||
|
SET
|
||||||
|
name = ?,
|
||||||
|
description = ?,
|
||||||
|
owner_address = ?,
|
||||||
|
metadata = ?,
|
||||||
|
status = ?,
|
||||||
|
block_height = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteService :exec
|
||||||
|
UPDATE services
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- ACTIVITY QUERIES
|
||||||
|
-- name: InsertActivity :one
|
||||||
|
INSERT INTO activities (
|
||||||
|
account_id,
|
||||||
|
tx_hash,
|
||||||
|
tx_type,
|
||||||
|
status,
|
||||||
|
amount,
|
||||||
|
fee,
|
||||||
|
gas_used,
|
||||||
|
gas_wanted,
|
||||||
|
memo,
|
||||||
|
block_height,
|
||||||
|
timestamp,
|
||||||
|
raw_log,
|
||||||
|
error
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetActivityByID :one
|
||||||
|
SELECT * FROM activities
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetActivityByTxHash :one
|
||||||
|
SELECT * FROM activities
|
||||||
|
WHERE tx_hash = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListActivitiesByAccount :many
|
||||||
|
SELECT * FROM activities
|
||||||
|
WHERE account_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: ListActivitiesByType :many
|
||||||
|
SELECT * FROM activities
|
||||||
|
WHERE tx_type = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: ListActivitiesByStatus :many
|
||||||
|
SELECT * FROM activities
|
||||||
|
WHERE status = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: UpdateActivityStatus :one
|
||||||
|
UPDATE activities
|
||||||
|
SET
|
||||||
|
status = ?,
|
||||||
|
tx_hash = ?,
|
||||||
|
block_height = ?,
|
||||||
|
gas_used = ?,
|
||||||
|
raw_log = ?,
|
||||||
|
error = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteActivity :exec
|
||||||
|
UPDATE activities
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- HEALTH QUERIES
|
||||||
|
-- name: InsertHealth :one
|
||||||
|
INSERT INTO health (
|
||||||
|
endpoint_url,
|
||||||
|
endpoint_type,
|
||||||
|
chain_id,
|
||||||
|
status,
|
||||||
|
response_time_ms,
|
||||||
|
last_checked,
|
||||||
|
next_check,
|
||||||
|
failure_count,
|
||||||
|
success_count,
|
||||||
|
response_data,
|
||||||
|
error_message
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetHealthByID :one
|
||||||
|
SELECT * FROM health
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetHealthByEndpoint :one
|
||||||
|
SELECT * FROM health
|
||||||
|
WHERE endpoint_url = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY last_checked DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListHealthByChain :many
|
||||||
|
SELECT * FROM health
|
||||||
|
WHERE chain_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY last_checked DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: ListHealthByStatus :many
|
||||||
|
SELECT * FROM health
|
||||||
|
WHERE status = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY last_checked DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: ListHealthChecksNeedingUpdate :many
|
||||||
|
SELECT * FROM health
|
||||||
|
WHERE next_check <= CURRENT_TIMESTAMP AND deleted_at IS NULL
|
||||||
|
ORDER BY next_check ASC
|
||||||
|
LIMIT ?;
|
||||||
|
|
||||||
|
-- name: UpdateHealthCheck :one
|
||||||
|
UPDATE health
|
||||||
|
SET
|
||||||
|
status = ?,
|
||||||
|
response_time_ms = ?,
|
||||||
|
last_checked = CURRENT_TIMESTAMP,
|
||||||
|
next_check = ?,
|
||||||
|
failure_count = CASE WHEN status = 'failed' THEN failure_count + 1 ELSE failure_count END,
|
||||||
|
success_count = CASE WHEN status = 'success' THEN success_count + 1 ELSE success_count END,
|
||||||
|
response_data = ?,
|
||||||
|
error_message = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteHealth :exec
|
||||||
|
UPDATE health
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: GetGlobalMarketByID :one
|
||||||
|
SELECT * FROM global_market
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetLatestGlobalMarket :one
|
||||||
|
SELECT * FROM global_market
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY last_updated DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListGlobalMarketHistory :many
|
||||||
|
SELECT * FROM global_market
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY last_updated DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: UpdateGlobalMarket :one
|
||||||
|
UPDATE global_market
|
||||||
|
SET
|
||||||
|
total_market_cap_usd = ?,
|
||||||
|
total_24h_volume_usd = ?,
|
||||||
|
bitcoin_percentage_of_market_cap = ?,
|
||||||
|
active_currencies = ?,
|
||||||
|
active_assets = ?,
|
||||||
|
active_markets = ?,
|
||||||
|
last_updated = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteGlobalMarket :exec
|
||||||
|
UPDATE global_market
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- FEAR AND GREED INDEX QUERIES (NEW)
|
||||||
|
-- name: InsertFearGreedIndex :one
|
||||||
|
INSERT INTO fear_greed_index (
|
||||||
|
value,
|
||||||
|
value_classification,
|
||||||
|
timestamp,
|
||||||
|
time_until_update
|
||||||
|
) VALUES (?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetFearGreedIndexByID :one
|
||||||
|
SELECT * FROM fear_greed_index
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetLatestFearGreedIndex :one
|
||||||
|
SELECT * FROM fear_greed_index
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListFearGreedIndexHistory :many
|
||||||
|
SELECT * FROM fear_greed_index
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: UpdateFearGreedIndex :one
|
||||||
|
UPDATE fear_greed_index
|
||||||
|
SET
|
||||||
|
value = ?,
|
||||||
|
value_classification = ?,
|
||||||
|
timestamp = ?,
|
||||||
|
time_until_update = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: InsertGlobalMarket :one
|
||||||
|
INSERT INTO global_market (
|
||||||
|
total_market_cap_usd,
|
||||||
|
total_24h_volume_usd,
|
||||||
|
bitcoin_percentage_of_market_cap,
|
||||||
|
active_currencies,
|
||||||
|
active_assets,
|
||||||
|
active_markets,
|
||||||
|
last_updated
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: SoftDeleteFearGreedIndex :exec
|
||||||
|
UPDATE fear_greed_index
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- CRYPTO LISTINGS QUERIES (NEW)
|
||||||
|
-- name: InsertCryptoListing :one
|
||||||
|
INSERT INTO crypto_listings (
|
||||||
|
api_id,
|
||||||
|
name,
|
||||||
|
symbol,
|
||||||
|
website_slug
|
||||||
|
) VALUES (?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetCryptoListingByID :one
|
||||||
|
SELECT * FROM crypto_listings
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetCryptoListingByApiID :one
|
||||||
|
SELECT * FROM crypto_listings
|
||||||
|
WHERE api_id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetCryptoListingBySymbol :one
|
||||||
|
SELECT * FROM crypto_listings
|
||||||
|
WHERE symbol = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetCryptoListingByWebsiteSlug :one
|
||||||
|
SELECT * FROM crypto_listings
|
||||||
|
WHERE website_slug = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListCryptoListings :many
|
||||||
|
SELECT * FROM crypto_listings
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY name ASC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: UpdateCryptoListing :one
|
||||||
|
UPDATE crypto_listings
|
||||||
|
SET
|
||||||
|
name = ?,
|
||||||
|
symbol = ?,
|
||||||
|
website_slug = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteCryptoListing :exec
|
||||||
|
UPDATE crypto_listings
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
1640
internal/db/activity/query.sql.go
Normal file
1640
internal/db/activity/query.sql.go
Normal file
File diff suppressed because it is too large
Load Diff
136
internal/db/activity/schema.sql
Normal file
136
internal/db/activity/schema.sql
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
|
||||||
|
-- Service for Service Records sourced on chain
|
||||||
|
CREATE TABLE services (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
chain_id TEXT NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
owner_address TEXT NOT NULL,
|
||||||
|
metadata TEXT CHECK(json_valid(metadata)),
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
block_height INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (chain_id) REFERENCES assets(chain_id),
|
||||||
|
UNIQUE(chain_id, address)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Activity table for basic transaction broadcast activity
|
||||||
|
CREATE TABLE activities (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
account_id TEXT NOT NULL,
|
||||||
|
tx_hash TEXT,
|
||||||
|
tx_type TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
amount TEXT,
|
||||||
|
fee TEXT,
|
||||||
|
gas_used INTEGER,
|
||||||
|
gas_wanted INTEGER,
|
||||||
|
memo TEXT,
|
||||||
|
block_height INTEGER,
|
||||||
|
timestamp TIMESTAMP NOT NULL,
|
||||||
|
raw_log TEXT,
|
||||||
|
error TEXT,
|
||||||
|
FOREIGN KEY (account_id) REFERENCES accounts(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Health table for scheduled checks for API endpoints
|
||||||
|
CREATE TABLE health (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
endpoint_url TEXT NOT NULL,
|
||||||
|
endpoint_type TEXT NOT NULL,
|
||||||
|
chain_id TEXT,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
response_time_ms INTEGER,
|
||||||
|
last_checked TIMESTAMP NOT NULL,
|
||||||
|
next_check TIMESTAMP,
|
||||||
|
failure_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
success_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
response_data TEXT,
|
||||||
|
error_message TEXT,
|
||||||
|
FOREIGN KEY (chain_id) REFERENCES assets(chain_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Global market data from Alternative.me API
|
||||||
|
CREATE TABLE global_market (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
total_market_cap_usd REAL,
|
||||||
|
total_24h_volume_usd REAL,
|
||||||
|
bitcoin_percentage_of_market_cap REAL,
|
||||||
|
active_currencies INTEGER,
|
||||||
|
active_assets INTEGER,
|
||||||
|
active_markets INTEGER,
|
||||||
|
last_updated TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Fear and Greed Index data from Alternative.me
|
||||||
|
CREATE TABLE fear_greed_index (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
value INTEGER NOT NULL,
|
||||||
|
value_classification TEXT NOT NULL,
|
||||||
|
timestamp TIMESTAMP NOT NULL,
|
||||||
|
time_until_update TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Listings data from Alternative.me API
|
||||||
|
CREATE TABLE crypto_listings (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
api_id TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
symbol TEXT NOT NULL,
|
||||||
|
website_slug TEXT NOT NULL,
|
||||||
|
UNIQUE(api_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE INDEX idx_services_name ON services(name);
|
||||||
|
CREATE INDEX idx_services_chain_id ON services(chain_id);
|
||||||
|
CREATE INDEX idx_services_address ON services(address);
|
||||||
|
CREATE INDEX idx_services_owner_address ON services(owner_address);
|
||||||
|
CREATE INDEX idx_services_status ON services(status);
|
||||||
|
CREATE INDEX idx_services_deleted_at ON services(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_activities_account_id ON activities(account_id);
|
||||||
|
CREATE INDEX idx_activities_tx_hash ON activities(tx_hash);
|
||||||
|
CREATE INDEX idx_activities_tx_type ON activities(tx_type);
|
||||||
|
CREATE INDEX idx_activities_status ON activities(status);
|
||||||
|
CREATE INDEX idx_activities_timestamp ON activities(timestamp);
|
||||||
|
CREATE INDEX idx_activities_block_height ON activities(block_height);
|
||||||
|
CREATE INDEX idx_activities_deleted_at ON activities(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_health_endpoint_url ON health(endpoint_url);
|
||||||
|
CREATE INDEX idx_health_endpoint_type ON health(endpoint_type);
|
||||||
|
CREATE INDEX idx_health_chain_id ON health(chain_id);
|
||||||
|
CREATE INDEX idx_health_status ON health(status);
|
||||||
|
CREATE INDEX idx_health_last_checked ON health(last_checked);
|
||||||
|
CREATE INDEX idx_health_next_check ON health(next_check);
|
||||||
|
CREATE INDEX idx_health_deleted_at ON health(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_global_market_last_updated ON global_market(last_updated);
|
||||||
|
CREATE INDEX idx_global_market_deleted_at ON global_market(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_fear_greed_index_timestamp ON fear_greed_index(timestamp);
|
||||||
|
CREATE INDEX idx_fear_greed_index_value ON fear_greed_index(value);
|
||||||
|
CREATE INDEX idx_fear_greed_index_deleted_at ON fear_greed_index(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_crypto_listings_api_id ON crypto_listings(api_id);
|
||||||
|
CREATE INDEX idx_crypto_listings_symbol ON crypto_listings(symbol);
|
||||||
|
CREATE INDEX idx_crypto_listings_website_slug ON crypto_listings(website_slug);
|
||||||
|
CREATE INDEX idx_crypto_listings_deleted_at ON crypto_listings(deleted_at);
|
||||||
31
internal/db/network/db.go
Normal file
31
internal/db/network/db.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBTX interface {
|
||||||
|
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||||
|
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||||
|
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db DBTX) *Queries {
|
||||||
|
return &Queries{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queries struct {
|
||||||
|
db DBTX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||||
|
return &Queries{
|
||||||
|
db: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
96
internal/db/network/models.go
Normal file
96
internal/db/network/models.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Asset struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Decimals int64 `json:"decimals"`
|
||||||
|
ChainID string `json:"chain_id"`
|
||||||
|
Channel string `json:"channel"`
|
||||||
|
AssetType string `json:"asset_type"`
|
||||||
|
CoingeckoID sql.NullString `json:"coingecko_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Blockchain struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
ChainName string `json:"chain_name"`
|
||||||
|
ChainIDCosmos sql.NullString `json:"chain_id_cosmos"`
|
||||||
|
ChainIDEvm sql.NullString `json:"chain_id_evm"`
|
||||||
|
ApiName sql.NullString `json:"api_name"`
|
||||||
|
BechAccountPrefix sql.NullString `json:"bech_account_prefix"`
|
||||||
|
BechValidatorPrefix sql.NullString `json:"bech_validator_prefix"`
|
||||||
|
MainAssetSymbol sql.NullString `json:"main_asset_symbol"`
|
||||||
|
MainAssetDenom sql.NullString `json:"main_asset_denom"`
|
||||||
|
StakingAssetSymbol sql.NullString `json:"staking_asset_symbol"`
|
||||||
|
StakingAssetDenom sql.NullString `json:"staking_asset_denom"`
|
||||||
|
IsStakeEnabled bool `json:"is_stake_enabled"`
|
||||||
|
ChainImage sql.NullString `json:"chain_image"`
|
||||||
|
MainAssetImage sql.NullString `json:"main_asset_image"`
|
||||||
|
StakingAssetImage sql.NullString `json:"staking_asset_image"`
|
||||||
|
ChainType string `json:"chain_type"`
|
||||||
|
IsSupportMobileWallet bool `json:"is_support_mobile_wallet"`
|
||||||
|
IsSupportExtensionWallet bool `json:"is_support_extension_wallet"`
|
||||||
|
IsSupportErc20 bool `json:"is_support_erc20"`
|
||||||
|
DescriptionEn sql.NullString `json:"description_en"`
|
||||||
|
DescriptionKo sql.NullString `json:"description_ko"`
|
||||||
|
DescriptionJa sql.NullString `json:"description_ja"`
|
||||||
|
OriginGenesisTime sql.NullTime `json:"origin_genesis_time"`
|
||||||
|
AccountType string `json:"account_type"`
|
||||||
|
BtcStaking sql.NullString `json:"btc_staking"`
|
||||||
|
CosmosFeeInfo sql.NullString `json:"cosmos_fee_info"`
|
||||||
|
EvmFeeInfo sql.NullString `json:"evm_fee_info"`
|
||||||
|
LcdEndpoint sql.NullString `json:"lcd_endpoint"`
|
||||||
|
GrpcEndpoint sql.NullString `json:"grpc_endpoint"`
|
||||||
|
EvmRpcEndpoint sql.NullString `json:"evm_rpc_endpoint"`
|
||||||
|
Explorer sql.NullString `json:"explorer"`
|
||||||
|
About sql.NullString `json:"about"`
|
||||||
|
Forum sql.NullString `json:"forum"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Price struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
AssetID string `json:"asset_id"`
|
||||||
|
PriceUsd sql.NullFloat64 `json:"price_usd"`
|
||||||
|
PriceBtc sql.NullFloat64 `json:"price_btc"`
|
||||||
|
Volume24hUsd sql.NullFloat64 `json:"volume_24h_usd"`
|
||||||
|
MarketCapUsd sql.NullFloat64 `json:"market_cap_usd"`
|
||||||
|
AvailableSupply sql.NullFloat64 `json:"available_supply"`
|
||||||
|
TotalSupply sql.NullFloat64 `json:"total_supply"`
|
||||||
|
MaxSupply sql.NullFloat64 `json:"max_supply"`
|
||||||
|
PercentChange1h sql.NullFloat64 `json:"percent_change_1h"`
|
||||||
|
PercentChange24h sql.NullFloat64 `json:"percent_change_24h"`
|
||||||
|
PercentChange7d sql.NullFloat64 `json:"percent_change_7d"`
|
||||||
|
Rank sql.NullInt64 `json:"rank"`
|
||||||
|
LastUpdated time.Time `json:"last_updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PriceConversion struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
PriceID string `json:"price_id"`
|
||||||
|
CurrencyCode string `json:"currency_code"`
|
||||||
|
Price sql.NullFloat64 `json:"price"`
|
||||||
|
Volume24h sql.NullFloat64 `json:"volume_24h"`
|
||||||
|
MarketCap sql.NullFloat64 `json:"market_cap"`
|
||||||
|
LastUpdated time.Time `json:"last_updated"`
|
||||||
|
}
|
||||||
64
internal/db/network/querier.go
Normal file
64
internal/db/network/querier.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Querier interface {
|
||||||
|
CountBlockchainsByChainType(ctx context.Context, dollar_1 sql.NullString) (int64, error)
|
||||||
|
GetAssetByChainAndSymbol(ctx context.Context, arg GetAssetByChainAndSymbolParams) (Asset, error)
|
||||||
|
GetAssetByID(ctx context.Context, id string) (Asset, error)
|
||||||
|
GetAssetBySymbol(ctx context.Context, symbol string) (Asset, error)
|
||||||
|
GetAssetWithLatestPrice(ctx context.Context, id string) (GetAssetWithLatestPriceRow, error)
|
||||||
|
GetBlockchainByChainName(ctx context.Context, chainName string) (Blockchain, error)
|
||||||
|
GetBlockchainByCosmosChainID(ctx context.Context, chainIDCosmos sql.NullString) (Blockchain, error)
|
||||||
|
GetBlockchainByEvmChainID(ctx context.Context, chainIDEvm sql.NullString) (Blockchain, error)
|
||||||
|
GetBlockchainByID(ctx context.Context, id string) (Blockchain, error)
|
||||||
|
GetBlockchainEndpoints(ctx context.Context, id string) (GetBlockchainEndpointsRow, error)
|
||||||
|
GetBlockchainExplorer(ctx context.Context, id string) (GetBlockchainExplorerRow, error)
|
||||||
|
GetBlockchainWithAssetInfo(ctx context.Context, id string) (GetBlockchainWithAssetInfoRow, error)
|
||||||
|
GetPriceByAssetID(ctx context.Context, assetID string) (Price, error)
|
||||||
|
GetPriceByID(ctx context.Context, id string) (Price, error)
|
||||||
|
GetPriceConversionByCurrency(ctx context.Context, arg GetPriceConversionByCurrencyParams) (PriceConversion, error)
|
||||||
|
GetPriceConversionByID(ctx context.Context, id string) (PriceConversion, error)
|
||||||
|
GetPriceConversionsByPriceID(ctx context.Context, priceID string) ([]PriceConversion, error)
|
||||||
|
// ASSET QUERIES
|
||||||
|
InsertAsset(ctx context.Context, arg InsertAssetParams) (Asset, error)
|
||||||
|
// BLOCKCHAIN QUERIES
|
||||||
|
InsertBlockchain(ctx context.Context, arg InsertBlockchainParams) (Blockchain, error)
|
||||||
|
// PRICE QUERIES (UPDATED)
|
||||||
|
InsertPrice(ctx context.Context, arg InsertPriceParams) (Price, error)
|
||||||
|
// PRICE CONVERSION QUERIES (NEW)
|
||||||
|
InsertPriceConversion(ctx context.Context, arg InsertPriceConversionParams) (PriceConversion, error)
|
||||||
|
ListAllBlockchains(ctx context.Context) ([]Blockchain, error)
|
||||||
|
ListAssetsByChain(ctx context.Context, chainID string) ([]Asset, error)
|
||||||
|
ListAssetsWithLatestPrices(ctx context.Context, arg ListAssetsWithLatestPricesParams) ([]ListAssetsWithLatestPricesRow, error)
|
||||||
|
ListBlockchainsByChainType(ctx context.Context, dollar_1 sql.NullString) ([]Blockchain, error)
|
||||||
|
ListBlockchainsWithAssetInfo(ctx context.Context, arg ListBlockchainsWithAssetInfoParams) ([]ListBlockchainsWithAssetInfoRow, error)
|
||||||
|
ListBlockchainsWithERC20Support(ctx context.Context) ([]Blockchain, error)
|
||||||
|
ListBlockchainsWithExtensionSupport(ctx context.Context) ([]Blockchain, error)
|
||||||
|
ListBlockchainsWithMobileSupport(ctx context.Context) ([]Blockchain, error)
|
||||||
|
ListBlockchainsWithStaking(ctx context.Context) ([]Blockchain, error)
|
||||||
|
ListPriceHistoryByAssetID(ctx context.Context, arg ListPriceHistoryByAssetIDParams) ([]Price, error)
|
||||||
|
SearchBlockchains(ctx context.Context, arg SearchBlockchainsParams) ([]Blockchain, error)
|
||||||
|
SoftDeleteAsset(ctx context.Context, id string) error
|
||||||
|
SoftDeleteBlockchain(ctx context.Context, id string) error
|
||||||
|
SoftDeletePriceConversion(ctx context.Context, id string) error
|
||||||
|
UpdateAsset(ctx context.Context, arg UpdateAssetParams) (Asset, error)
|
||||||
|
UpdateBlockchain(ctx context.Context, arg UpdateBlockchainParams) (Blockchain, error)
|
||||||
|
UpdateBlockchainDescriptions(ctx context.Context, arg UpdateBlockchainDescriptionsParams) (Blockchain, error)
|
||||||
|
UpdateBlockchainEndpoints(ctx context.Context, arg UpdateBlockchainEndpointsParams) (Blockchain, error)
|
||||||
|
UpdateBlockchainExplorer(ctx context.Context, arg UpdateBlockchainExplorerParams) (Blockchain, error)
|
||||||
|
UpdateBlockchainFeeInfo(ctx context.Context, arg UpdateBlockchainFeeInfoParams) (Blockchain, error)
|
||||||
|
UpdateBlockchainImages(ctx context.Context, arg UpdateBlockchainImagesParams) (Blockchain, error)
|
||||||
|
UpdateBlockchainSocialLinks(ctx context.Context, arg UpdateBlockchainSocialLinksParams) (Blockchain, error)
|
||||||
|
UpdatePrice(ctx context.Context, arg UpdatePriceParams) (Price, error)
|
||||||
|
UpdatePriceConversion(ctx context.Context, arg UpdatePriceConversionParams) (PriceConversion, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Querier = (*Queries)(nil)
|
||||||
453
internal/db/network/query.sql
Normal file
453
internal/db/network/query.sql
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
-- ASSET QUERIES
|
||||||
|
-- name: InsertAsset :one
|
||||||
|
INSERT INTO assets (
|
||||||
|
name,
|
||||||
|
symbol,
|
||||||
|
decimals,
|
||||||
|
chain_id,
|
||||||
|
channel,
|
||||||
|
asset_type,
|
||||||
|
coingecko_id
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetAssetByID :one
|
||||||
|
SELECT * FROM assets
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAssetBySymbol :one
|
||||||
|
SELECT * FROM assets
|
||||||
|
WHERE symbol = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAssetByChainAndSymbol :one
|
||||||
|
SELECT * FROM assets
|
||||||
|
WHERE chain_id = ? AND symbol = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListAssetsByChain :many
|
||||||
|
SELECT * FROM assets
|
||||||
|
WHERE chain_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY symbol ASC;
|
||||||
|
|
||||||
|
-- name: UpdateAsset :one
|
||||||
|
UPDATE assets
|
||||||
|
SET
|
||||||
|
name = ?,
|
||||||
|
decimals = ?,
|
||||||
|
channel = ?,
|
||||||
|
asset_type = ?,
|
||||||
|
coingecko_id = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteAsset :exec
|
||||||
|
UPDATE assets
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- PRICE QUERIES (UPDATED)
|
||||||
|
-- name: InsertPrice :one
|
||||||
|
INSERT INTO prices (
|
||||||
|
asset_id,
|
||||||
|
price_usd,
|
||||||
|
price_btc,
|
||||||
|
volume_24h_usd,
|
||||||
|
market_cap_usd,
|
||||||
|
available_supply,
|
||||||
|
total_supply,
|
||||||
|
max_supply,
|
||||||
|
percent_change_1h,
|
||||||
|
percent_change_24h,
|
||||||
|
percent_change_7d,
|
||||||
|
rank,
|
||||||
|
last_updated
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetPriceByAssetID :one
|
||||||
|
SELECT * FROM prices
|
||||||
|
WHERE asset_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY last_updated DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetPriceByID :one
|
||||||
|
SELECT * FROM prices
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListPriceHistoryByAssetID :many
|
||||||
|
SELECT * FROM prices
|
||||||
|
WHERE asset_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY last_updated DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: GetAssetWithLatestPrice :one
|
||||||
|
SELECT a.*, p.price_usd, p.price_btc, p.volume_24h_usd, p.market_cap_usd,
|
||||||
|
p.available_supply, p.total_supply, p.max_supply,
|
||||||
|
p.percent_change_1h, p.percent_change_24h, p.percent_change_7d,
|
||||||
|
p.rank, p.last_updated
|
||||||
|
FROM assets a
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT p1.*
|
||||||
|
FROM prices p1
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT asset_id, MAX(last_updated) as max_date
|
||||||
|
FROM prices
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
GROUP BY asset_id
|
||||||
|
) p2 ON p1.asset_id = p2.asset_id AND p1.last_updated = p2.max_date
|
||||||
|
WHERE p1.deleted_at IS NULL
|
||||||
|
) p ON a.id = p.asset_id
|
||||||
|
WHERE a.id = ? AND a.deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListAssetsWithLatestPrices :many
|
||||||
|
SELECT a.*, p.price_usd, p.price_btc, p.volume_24h_usd, p.market_cap_usd,
|
||||||
|
p.available_supply, p.total_supply, p.max_supply,
|
||||||
|
p.percent_change_1h, p.percent_change_24h, p.percent_change_7d,
|
||||||
|
p.rank, p.last_updated
|
||||||
|
FROM assets a
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT p1.*
|
||||||
|
FROM prices p1
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT asset_id, MAX(last_updated) as max_date
|
||||||
|
FROM prices
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
GROUP BY asset_id
|
||||||
|
) p2 ON p1.asset_id = p2.asset_id AND p1.last_updated = p2.max_date
|
||||||
|
WHERE p1.deleted_at IS NULL
|
||||||
|
) p ON a.id = p.asset_id
|
||||||
|
WHERE a.deleted_at IS NULL
|
||||||
|
ORDER BY p.rank ASC, a.symbol ASC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: UpdatePrice :one
|
||||||
|
UPDATE prices
|
||||||
|
SET
|
||||||
|
price_usd = ?,
|
||||||
|
price_btc = ?,
|
||||||
|
volume_24h_usd = ?,
|
||||||
|
market_cap_usd = ?,
|
||||||
|
available_supply = ?,
|
||||||
|
total_supply = ?,
|
||||||
|
max_supply = ?,
|
||||||
|
percent_change_1h = ?,
|
||||||
|
percent_change_24h = ?,
|
||||||
|
percent_change_7d = ?,
|
||||||
|
rank = ?,
|
||||||
|
last_updated = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- PRICE CONVERSION QUERIES (NEW)
|
||||||
|
-- name: InsertPriceConversion :one
|
||||||
|
INSERT INTO price_conversions (
|
||||||
|
price_id,
|
||||||
|
currency_code,
|
||||||
|
price,
|
||||||
|
volume_24h,
|
||||||
|
market_cap,
|
||||||
|
last_updated
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetPriceConversionByID :one
|
||||||
|
SELECT * FROM price_conversions
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetPriceConversionsByPriceID :many
|
||||||
|
SELECT * FROM price_conversions
|
||||||
|
WHERE price_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY currency_code ASC;
|
||||||
|
|
||||||
|
-- name: GetPriceConversionByCurrency :one
|
||||||
|
SELECT * FROM price_conversions
|
||||||
|
WHERE price_id = ? AND currency_code = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: UpdatePriceConversion :one
|
||||||
|
UPDATE price_conversions
|
||||||
|
SET
|
||||||
|
price = ?,
|
||||||
|
volume_24h = ?,
|
||||||
|
market_cap = ?,
|
||||||
|
last_updated = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeletePriceConversion :exec
|
||||||
|
UPDATE price_conversions
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- BLOCKCHAIN QUERIES
|
||||||
|
-- name: InsertBlockchain :one
|
||||||
|
INSERT INTO blockchains (
|
||||||
|
id,
|
||||||
|
chain_name,
|
||||||
|
chain_id_cosmos,
|
||||||
|
chain_id_evm,
|
||||||
|
api_name,
|
||||||
|
bech_account_prefix,
|
||||||
|
bech_validator_prefix,
|
||||||
|
main_asset_symbol,
|
||||||
|
main_asset_denom,
|
||||||
|
staking_asset_symbol,
|
||||||
|
staking_asset_denom,
|
||||||
|
is_stake_enabled,
|
||||||
|
chain_image,
|
||||||
|
main_asset_image,
|
||||||
|
staking_asset_image,
|
||||||
|
chain_type,
|
||||||
|
is_support_mobile_wallet,
|
||||||
|
is_support_extension_wallet,
|
||||||
|
is_support_erc20,
|
||||||
|
description_en,
|
||||||
|
description_ko,
|
||||||
|
description_ja,
|
||||||
|
origin_genesis_time,
|
||||||
|
account_type,
|
||||||
|
btc_staking,
|
||||||
|
cosmos_fee_info,
|
||||||
|
evm_fee_info,
|
||||||
|
lcd_endpoint,
|
||||||
|
grpc_endpoint,
|
||||||
|
evm_rpc_endpoint,
|
||||||
|
explorer,
|
||||||
|
about,
|
||||||
|
forum
|
||||||
|
) VALUES (
|
||||||
|
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||||
|
)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetBlockchainByID :one
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetBlockchainByChainName :one
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE chain_name = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetBlockchainByCosmosChainID :one
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE chain_id_cosmos = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetBlockchainByEvmChainID :one
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE chain_id_evm = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListAllBlockchains :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC;
|
||||||
|
|
||||||
|
-- name: ListBlockchainsByChainType :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE chain_type LIKE '%' || ? || '%' AND deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC;
|
||||||
|
|
||||||
|
-- name: ListBlockchainsWithStaking :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE is_stake_enabled = 1 AND deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC;
|
||||||
|
|
||||||
|
-- name: ListBlockchainsWithMobileSupport :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE is_support_mobile_wallet = 1 AND deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC;
|
||||||
|
|
||||||
|
-- name: ListBlockchainsWithExtensionSupport :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE is_support_extension_wallet = 1 AND deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC;
|
||||||
|
|
||||||
|
-- name: ListBlockchainsWithERC20Support :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE is_support_erc20 = 1 AND deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchain :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
chain_name = ?,
|
||||||
|
chain_id_cosmos = ?,
|
||||||
|
chain_id_evm = ?,
|
||||||
|
api_name = ?,
|
||||||
|
bech_account_prefix = ?,
|
||||||
|
bech_validator_prefix = ?,
|
||||||
|
main_asset_symbol = ?,
|
||||||
|
main_asset_denom = ?,
|
||||||
|
staking_asset_symbol = ?,
|
||||||
|
staking_asset_denom = ?,
|
||||||
|
is_stake_enabled = ?,
|
||||||
|
chain_image = ?,
|
||||||
|
main_asset_image = ?,
|
||||||
|
staking_asset_image = ?,
|
||||||
|
chain_type = ?,
|
||||||
|
is_support_mobile_wallet = ?,
|
||||||
|
is_support_extension_wallet = ?,
|
||||||
|
is_support_erc20 = ?,
|
||||||
|
description_en = ?,
|
||||||
|
description_ko = ?,
|
||||||
|
description_ja = ?,
|
||||||
|
origin_genesis_time = ?,
|
||||||
|
account_type = ?,
|
||||||
|
btc_staking = ?,
|
||||||
|
cosmos_fee_info = ?,
|
||||||
|
evm_fee_info = ?,
|
||||||
|
lcd_endpoint = ?,
|
||||||
|
grpc_endpoint = ?,
|
||||||
|
evm_rpc_endpoint = ?,
|
||||||
|
explorer = ?,
|
||||||
|
about = ?,
|
||||||
|
forum = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchainEndpoints :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
lcd_endpoint = ?,
|
||||||
|
grpc_endpoint = ?,
|
||||||
|
evm_rpc_endpoint = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchainExplorer :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
explorer = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchainFeeInfo :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
cosmos_fee_info = ?,
|
||||||
|
evm_fee_info = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchainImages :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
chain_image = ?,
|
||||||
|
main_asset_image = ?,
|
||||||
|
staking_asset_image = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchainDescriptions :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
description_en = ?,
|
||||||
|
description_ko = ?,
|
||||||
|
description_ja = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateBlockchainSocialLinks :one
|
||||||
|
UPDATE blockchains
|
||||||
|
SET
|
||||||
|
about = ?,
|
||||||
|
forum = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteBlockchain :exec
|
||||||
|
UPDATE blockchains
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- name: GetBlockchainWithAssetInfo :one
|
||||||
|
SELECT b.*, a.id as asset_id, a.symbol, a.decimals, p.price_usd, p.price_btc
|
||||||
|
FROM blockchains b
|
||||||
|
LEFT JOIN assets a ON b.main_asset_symbol = a.symbol
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT p1.*
|
||||||
|
FROM prices p1
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT asset_id, MAX(last_updated) as max_date
|
||||||
|
FROM prices
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
GROUP BY asset_id
|
||||||
|
) p2 ON p1.asset_id = p2.asset_id AND p1.last_updated = p2.max_date
|
||||||
|
WHERE p1.deleted_at IS NULL
|
||||||
|
) p ON a.id = p.asset_id
|
||||||
|
WHERE b.id = ? AND b.deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListBlockchainsWithAssetInfo :many
|
||||||
|
SELECT b.*, a.id as asset_id, a.symbol, a.decimals, p.price_usd, p.price_btc
|
||||||
|
FROM blockchains b
|
||||||
|
LEFT JOIN assets a ON b.main_asset_symbol = a.symbol
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT p1.*
|
||||||
|
FROM prices p1
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT asset_id, MAX(last_updated) as max_date
|
||||||
|
FROM prices
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
GROUP BY asset_id
|
||||||
|
) p2 ON p1.asset_id = p2.asset_id AND p1.last_updated = p2.max_date
|
||||||
|
WHERE p1.deleted_at IS NULL
|
||||||
|
) p ON a.id = p.asset_id
|
||||||
|
WHERE b.deleted_at IS NULL
|
||||||
|
ORDER BY b.chain_name ASC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: SearchBlockchains :many
|
||||||
|
SELECT * FROM blockchains
|
||||||
|
WHERE (
|
||||||
|
chain_name LIKE '%' || ? || '%' OR
|
||||||
|
main_asset_symbol LIKE '%' || ? || '%' OR
|
||||||
|
staking_asset_symbol LIKE '%' || ? || '%' OR
|
||||||
|
description_en LIKE '%' || ? || '%'
|
||||||
|
) AND deleted_at IS NULL
|
||||||
|
ORDER BY chain_name ASC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- name: CountBlockchainsByChainType :one
|
||||||
|
SELECT COUNT(*) as count FROM blockchains
|
||||||
|
WHERE chain_type LIKE '%' || ? || '%' AND deleted_at IS NULL;
|
||||||
|
|
||||||
|
-- name: GetBlockchainEndpoints :one
|
||||||
|
SELECT id, chain_name, lcd_endpoint, grpc_endpoint, evm_rpc_endpoint
|
||||||
|
FROM blockchains
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetBlockchainExplorer :one
|
||||||
|
SELECT id, chain_name, explorer
|
||||||
|
FROM blockchains
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
2583
internal/db/network/query.sql.go
Normal file
2583
internal/db/network/query.sql.go
Normal file
File diff suppressed because it is too large
Load Diff
139
internal/db/network/schema.sql
Normal file
139
internal/db/network/schema.sql
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
-- Assets represent tokens and coins
|
||||||
|
CREATE TABLE assets (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
symbol TEXT NOT NULL,
|
||||||
|
decimals INTEGER NOT NULL CHECK(decimals >= 0),
|
||||||
|
chain_id TEXT NOT NULL,
|
||||||
|
channel TEXT NOT NULL,
|
||||||
|
asset_type TEXT NOT NULL,
|
||||||
|
coingecko_id TEXT,
|
||||||
|
UNIQUE(chain_id, symbol)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Prices entity based on the Alternative.me API for crypto prices
|
||||||
|
CREATE TABLE prices (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
asset_id TEXT NOT NULL,
|
||||||
|
price_usd REAL,
|
||||||
|
price_btc REAL,
|
||||||
|
volume_24h_usd REAL,
|
||||||
|
market_cap_usd REAL,
|
||||||
|
available_supply REAL,
|
||||||
|
total_supply REAL,
|
||||||
|
max_supply REAL,
|
||||||
|
percent_change_1h REAL,
|
||||||
|
percent_change_24h REAL,
|
||||||
|
percent_change_7d REAL,
|
||||||
|
rank INTEGER,
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
FOREIGN KEY (asset_id) REFERENCES assets(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Currency conversion rates for crypto prices
|
||||||
|
CREATE TABLE price_conversions (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
price_id TEXT NOT NULL,
|
||||||
|
currency_code TEXT NOT NULL,
|
||||||
|
price REAL,
|
||||||
|
volume_24h REAL,
|
||||||
|
market_cap REAL,
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
FOREIGN KEY (price_id) REFERENCES prices(id),
|
||||||
|
UNIQUE(price_id, currency_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Blockchains table to store chain configuration parameters
|
||||||
|
CREATE TABLE blockchains (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
|
||||||
|
-- Basic chain information
|
||||||
|
chain_name TEXT NOT NULL,
|
||||||
|
chain_id_cosmos TEXT,
|
||||||
|
chain_id_evm TEXT,
|
||||||
|
api_name TEXT,
|
||||||
|
bech_account_prefix TEXT,
|
||||||
|
bech_validator_prefix TEXT,
|
||||||
|
|
||||||
|
-- Chain assets
|
||||||
|
main_asset_symbol TEXT,
|
||||||
|
main_asset_denom TEXT,
|
||||||
|
staking_asset_symbol TEXT,
|
||||||
|
staking_asset_denom TEXT,
|
||||||
|
is_stake_enabled BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_stake_enabled IN (0,1)),
|
||||||
|
|
||||||
|
-- Chain images
|
||||||
|
chain_image TEXT,
|
||||||
|
main_asset_image TEXT,
|
||||||
|
staking_asset_image TEXT,
|
||||||
|
|
||||||
|
-- Chain types and features
|
||||||
|
chain_type TEXT NOT NULL CHECK(json_valid(chain_type)),
|
||||||
|
is_support_mobile_wallet BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_support_mobile_wallet IN (0,1)),
|
||||||
|
is_support_extension_wallet BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_support_extension_wallet IN (0,1)),
|
||||||
|
is_support_erc20 BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_support_erc20 IN (0,1)),
|
||||||
|
|
||||||
|
-- Descriptions in multiple languages
|
||||||
|
description_en TEXT,
|
||||||
|
description_ko TEXT,
|
||||||
|
description_ja TEXT,
|
||||||
|
|
||||||
|
-- Genesis information
|
||||||
|
origin_genesis_time TIMESTAMP,
|
||||||
|
|
||||||
|
-- Account types configuration
|
||||||
|
account_type TEXT NOT NULL CHECK(json_valid(account_type)),
|
||||||
|
|
||||||
|
-- BTC staking specific
|
||||||
|
btc_staking TEXT CHECK(json_valid(btc_staking)),
|
||||||
|
|
||||||
|
-- Cosmos fee information
|
||||||
|
cosmos_fee_info TEXT CHECK(json_valid(cosmos_fee_info)),
|
||||||
|
|
||||||
|
-- EVM fee information
|
||||||
|
evm_fee_info TEXT CHECK(json_valid(evm_fee_info)),
|
||||||
|
|
||||||
|
-- Endpoints
|
||||||
|
lcd_endpoint TEXT CHECK(json_valid(lcd_endpoint)),
|
||||||
|
grpc_endpoint TEXT CHECK(json_valid(grpc_endpoint)),
|
||||||
|
evm_rpc_endpoint TEXT CHECK(json_valid(evm_rpc_endpoint)),
|
||||||
|
|
||||||
|
-- Explorer information
|
||||||
|
explorer TEXT CHECK(json_valid(explorer)),
|
||||||
|
|
||||||
|
-- Social and documentation links
|
||||||
|
about TEXT CHECK(json_valid(about)),
|
||||||
|
forum TEXT CHECK(json_valid(forum))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Add all necessary indexes
|
||||||
|
CREATE INDEX idx_assets_symbol ON assets(symbol);
|
||||||
|
CREATE INDEX idx_assets_chain_id ON assets(chain_id);
|
||||||
|
CREATE INDEX idx_assets_deleted_at ON assets(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_prices_asset_id ON prices(asset_id);
|
||||||
|
CREATE INDEX idx_prices_rank ON prices(rank);
|
||||||
|
CREATE INDEX idx_prices_last_updated ON prices(last_updated);
|
||||||
|
CREATE INDEX idx_prices_deleted_at ON prices(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_price_conversions_price_id ON price_conversions(price_id);
|
||||||
|
CREATE INDEX idx_price_conversions_currency_code ON price_conversions(currency_code);
|
||||||
|
CREATE INDEX idx_price_conversions_deleted_at ON price_conversions(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_blockchains_chain_name ON blockchains(chain_name);
|
||||||
|
CREATE INDEX idx_blockchains_chain_id_cosmos ON blockchains(chain_id_cosmos);
|
||||||
|
CREATE INDEX idx_blockchains_chain_id_evm ON blockchains(chain_id_evm);
|
||||||
|
CREATE INDEX idx_blockchains_main_asset_symbol ON blockchains(main_asset_symbol);
|
||||||
|
CREATE INDEX idx_blockchains_deleted_at ON blockchains(deleted_at);
|
||||||
34
internal/db/sqlc.yaml
Normal file
34
internal/db/sqlc.yaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
version: "2"
|
||||||
|
sql:
|
||||||
|
# Activity DB - User to User Interactions
|
||||||
|
- engine: "sqlite"
|
||||||
|
queries: "./activity/query.sql"
|
||||||
|
schema: "./activity/schema.sql"
|
||||||
|
gen:
|
||||||
|
go:
|
||||||
|
emit_interface: true
|
||||||
|
emit_json_tags: true
|
||||||
|
package: "activity"
|
||||||
|
out: "./activity"
|
||||||
|
|
||||||
|
# Network DB - Blockchain Parameters and Asset Metadata
|
||||||
|
- engine: "sqlite"
|
||||||
|
queries: "./network/query.sql"
|
||||||
|
schema: "./network/schema.sql"
|
||||||
|
gen:
|
||||||
|
go:
|
||||||
|
emit_interface: true
|
||||||
|
emit_json_tags: true
|
||||||
|
package: "network"
|
||||||
|
out: "./network"
|
||||||
|
|
||||||
|
# Users DB - Accounts, Profiles, and Vault Metadata
|
||||||
|
- engine: "sqlite"
|
||||||
|
queries: "./users/query.sql"
|
||||||
|
schema: "./users/schema.sql"
|
||||||
|
gen:
|
||||||
|
go:
|
||||||
|
emit_interface: true
|
||||||
|
emit_json_tags: true
|
||||||
|
package: "users"
|
||||||
|
out: "./users"
|
||||||
31
internal/db/users/db.go
Normal file
31
internal/db/users/db.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBTX interface {
|
||||||
|
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||||
|
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||||
|
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db DBTX) *Queries {
|
||||||
|
return &Queries{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queries struct {
|
||||||
|
db DBTX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||||
|
return &Queries{
|
||||||
|
db: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
68
internal/db/users/models.go
Normal file
68
internal/db/users/models.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Number int64 `json:"number"`
|
||||||
|
Sequence int64 `json:"sequence"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
ChainID string `json:"chain_id"`
|
||||||
|
BlockCreated int64 `json:"block_created"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Handle string `json:"handle"`
|
||||||
|
IsSubsidiary bool `json:"is_subsidiary"`
|
||||||
|
IsValidator bool `json:"is_validator"`
|
||||||
|
IsDelegator bool `json:"is_delegator"`
|
||||||
|
IsAccountable bool `json:"is_accountable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Credential struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Handle string `json:"handle"`
|
||||||
|
CredentialID string `json:"credential_id"`
|
||||||
|
AuthenticatorAttachment string `json:"authenticator_attachment"`
|
||||||
|
Origin string `json:"origin"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Transports string `json:"transports"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Profile struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Handle string `json:"handle"`
|
||||||
|
Origin string `json:"origin"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Vault struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `json:"deleted_at"`
|
||||||
|
Handle string `json:"handle"`
|
||||||
|
Origin string `json:"origin"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Cid string `json:"cid"`
|
||||||
|
Config string `json:"config"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
RedirectUri string `json:"redirect_uri"`
|
||||||
|
}
|
||||||
53
internal/db/users/querier.go
Normal file
53
internal/db/users/querier.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Querier interface {
|
||||||
|
CheckHandleExists(ctx context.Context, handle string) (bool, error)
|
||||||
|
GetAccountByAddress(ctx context.Context, address string) (Account, error)
|
||||||
|
GetAccountByController(ctx context.Context, controller string) (Account, error)
|
||||||
|
GetAccountByID(ctx context.Context, id string) (Account, error)
|
||||||
|
GetAccountByNumber(ctx context.Context, number int64) (Account, error)
|
||||||
|
GetAccountByPublicKey(ctx context.Context, publicKey string) (Account, error)
|
||||||
|
GetAccountBySequence(ctx context.Context, sequence int64) (Account, error)
|
||||||
|
GetAccountsByChainID(ctx context.Context, chainID string) ([]Account, error)
|
||||||
|
GetAccountsByController(ctx context.Context, controller string) ([]Account, error)
|
||||||
|
GetAccountsByHandle(ctx context.Context, handle string) ([]Account, error)
|
||||||
|
GetAccountsByLabel(ctx context.Context, label string) ([]Account, error)
|
||||||
|
GetCredentialByID(ctx context.Context, credentialID string) (Credential, error)
|
||||||
|
GetCredentialsByHandle(ctx context.Context, handle string) ([]Credential, error)
|
||||||
|
GetProfileByAddress(ctx context.Context, address string) (Profile, error)
|
||||||
|
GetProfileByHandle(ctx context.Context, handle string) (Profile, error)
|
||||||
|
GetProfileByID(ctx context.Context, id string) (Profile, error)
|
||||||
|
GetVaultByID(ctx context.Context, id string) (Vault, error)
|
||||||
|
GetVaultConfigByCID(ctx context.Context, cid string) (Vault, error)
|
||||||
|
GetVaultRedirectURIBySessionID(ctx context.Context, sessionID string) (string, error)
|
||||||
|
GetVaultsByHandle(ctx context.Context, handle string) ([]Vault, error)
|
||||||
|
// ACCOUNT QUERIES
|
||||||
|
InsertAccount(ctx context.Context, arg InsertAccountParams) (Account, error)
|
||||||
|
// CREDENTIAL QUERIES
|
||||||
|
InsertCredential(ctx context.Context, arg InsertCredentialParams) (Credential, error)
|
||||||
|
// PROFILE QUERIES
|
||||||
|
InsertProfile(ctx context.Context, arg InsertProfileParams) (Profile, error)
|
||||||
|
// VAULT QUERIES
|
||||||
|
InsertVault(ctx context.Context, arg InsertVaultParams) (Vault, error)
|
||||||
|
ListDelegatorAccounts(ctx context.Context) ([]Account, error)
|
||||||
|
ListProfiles(ctx context.Context, arg ListProfilesParams) ([]Profile, error)
|
||||||
|
ListValidatorAccounts(ctx context.Context) ([]Account, error)
|
||||||
|
SoftDeleteAccount(ctx context.Context, id string) error
|
||||||
|
SoftDeleteCredential(ctx context.Context, credentialID string) error
|
||||||
|
SoftDeleteProfile(ctx context.Context, address string) error
|
||||||
|
SoftDeleteVault(ctx context.Context, id string) error
|
||||||
|
UpdateAccountLabel(ctx context.Context, arg UpdateAccountLabelParams) (Account, error)
|
||||||
|
UpdateAccountSequence(ctx context.Context, arg UpdateAccountSequenceParams) (Account, error)
|
||||||
|
UpdateProfile(ctx context.Context, arg UpdateProfileParams) (Profile, error)
|
||||||
|
UpdateVault(ctx context.Context, arg UpdateVaultParams) (Vault, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Querier = (*Queries)(nil)
|
||||||
234
internal/db/users/query.sql
Normal file
234
internal/db/users/query.sql
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
-- PROFILE QUERIES
|
||||||
|
-- name: InsertProfile :one
|
||||||
|
INSERT INTO profiles (
|
||||||
|
address,
|
||||||
|
handle,
|
||||||
|
origin,
|
||||||
|
name
|
||||||
|
) VALUES (?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetProfileByID :one
|
||||||
|
SELECT * FROM profiles
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetProfileByAddress :one
|
||||||
|
SELECT * FROM profiles
|
||||||
|
WHERE address = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetProfileByHandle :one
|
||||||
|
SELECT * FROM profiles
|
||||||
|
WHERE handle = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: CheckHandleExists :one
|
||||||
|
SELECT COUNT(*) > 0 as handle_exists FROM profiles
|
||||||
|
WHERE handle = ?
|
||||||
|
AND deleted_at IS NULL;
|
||||||
|
|
||||||
|
-- name: UpdateProfile :one
|
||||||
|
UPDATE profiles
|
||||||
|
SET
|
||||||
|
name = ?,
|
||||||
|
handle = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE address = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteProfile :exec
|
||||||
|
UPDATE profiles
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE address = ?;
|
||||||
|
|
||||||
|
-- name: ListProfiles :many
|
||||||
|
SELECT * FROM profiles
|
||||||
|
WHERE deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT ? OFFSET ?;
|
||||||
|
|
||||||
|
-- VAULT QUERIES
|
||||||
|
-- name: InsertVault :one
|
||||||
|
INSERT INTO vaults (
|
||||||
|
handle,
|
||||||
|
origin,
|
||||||
|
address,
|
||||||
|
cid,
|
||||||
|
config,
|
||||||
|
session_id,
|
||||||
|
redirect_uri
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetVaultByID :one
|
||||||
|
SELECT * FROM vaults
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetVaultsByHandle :many
|
||||||
|
SELECT * FROM vaults
|
||||||
|
WHERE handle = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: GetVaultConfigByCID :one
|
||||||
|
SELECT * FROM vaults
|
||||||
|
WHERE cid = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetVaultRedirectURIBySessionID :one
|
||||||
|
SELECT redirect_uri FROM vaults
|
||||||
|
WHERE session_id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: UpdateVault :one
|
||||||
|
UPDATE vaults
|
||||||
|
SET
|
||||||
|
config = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteVault :exec
|
||||||
|
UPDATE vaults
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- ACCOUNT QUERIES
|
||||||
|
-- name: InsertAccount :one
|
||||||
|
INSERT INTO accounts (
|
||||||
|
number,
|
||||||
|
sequence,
|
||||||
|
address,
|
||||||
|
public_key,
|
||||||
|
chain_id,
|
||||||
|
block_created,
|
||||||
|
controller,
|
||||||
|
label,
|
||||||
|
is_subsidiary,
|
||||||
|
is_validator,
|
||||||
|
is_delegator,
|
||||||
|
is_accountable
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetAccountByID :one
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE id = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAccountByAddress :one
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE address = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAccountsByHandle :many
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE handle = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: GetAccountByController :one
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE controller = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAccountByPublicKey :one
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE public_key = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAccountByNumber :one
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE number = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAccountBySequence :one
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE sequence = ? AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAccountsByChainID :many
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE chain_id = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY sequence DESC;
|
||||||
|
|
||||||
|
-- name: GetAccountsByController :many
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE controller = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: GetAccountsByLabel :many
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE label = ? AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: UpdateAccountSequence :one
|
||||||
|
UPDATE accounts
|
||||||
|
SET
|
||||||
|
sequence = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE address = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateAccountLabel :one
|
||||||
|
UPDATE accounts
|
||||||
|
SET
|
||||||
|
label = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: SoftDeleteAccount :exec
|
||||||
|
UPDATE accounts
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?;
|
||||||
|
|
||||||
|
-- name: ListValidatorAccounts :many
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE is_validator = 1
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: ListDelegatorAccounts :many
|
||||||
|
SELECT * FROM accounts
|
||||||
|
WHERE is_delegator = 1
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- CREDENTIAL QUERIES
|
||||||
|
-- name: InsertCredential :one
|
||||||
|
INSERT INTO credentials (
|
||||||
|
handle,
|
||||||
|
credential_id,
|
||||||
|
authenticator_attachment,
|
||||||
|
origin,
|
||||||
|
type,
|
||||||
|
transports
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetCredentialsByHandle :many
|
||||||
|
SELECT * FROM credentials
|
||||||
|
WHERE handle = ?
|
||||||
|
AND deleted_at IS NULL;
|
||||||
|
|
||||||
|
-- name: GetCredentialByID :one
|
||||||
|
SELECT * FROM credentials
|
||||||
|
WHERE credential_id = ?
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: SoftDeleteCredential :exec
|
||||||
|
UPDATE credentials
|
||||||
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE credential_id = ?;
|
||||||
|
|
||||||
1177
internal/db/users/query.sql.go
Normal file
1177
internal/db/users/query.sql.go
Normal file
File diff suppressed because it is too large
Load Diff
81
internal/db/users/schema.sql
Normal file
81
internal/db/users/schema.sql
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
-- Credentials store WebAuthn credentials
|
||||||
|
CREATE TABLE credentials (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
handle TEXT NOT NULL,
|
||||||
|
credential_id TEXT NOT NULL UNIQUE,
|
||||||
|
authenticator_attachment TEXT NOT NULL,
|
||||||
|
origin TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
transports TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Accounts represent blockchain accounts
|
||||||
|
CREATE TABLE accounts (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
number INTEGER NOT NULL,
|
||||||
|
sequence INTEGER NOT NULL DEFAULT 0,
|
||||||
|
address TEXT NOT NULL UNIQUE,
|
||||||
|
public_key TEXT NOT NULL CHECK(json_valid(public_key)),
|
||||||
|
chain_id TEXT NOT NULL,
|
||||||
|
block_created INTEGER NOT NULL,
|
||||||
|
controller TEXT NOT NULL,
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
handle TEXT NOT NULL,
|
||||||
|
is_subsidiary BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_subsidiary IN (0,1)),
|
||||||
|
is_validator BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_validator IN (0,1)),
|
||||||
|
is_delegator BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_delegator IN (0,1)),
|
||||||
|
is_accountable BOOLEAN NOT NULL DEFAULT TRUE CHECK(is_accountable IN (0,1))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Profiles represent user identities
|
||||||
|
CREATE TABLE profiles (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
handle TEXT NOT NULL UNIQUE,
|
||||||
|
origin TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
UNIQUE(address, origin)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Vaults store encrypted data
|
||||||
|
CREATE TABLE vaults (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
handle TEXT NOT NULL,
|
||||||
|
origin TEXT NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
cid TEXT NOT NULL UNIQUE,
|
||||||
|
config TEXT NOT NULL CHECK(json_valid(config)),
|
||||||
|
session_id TEXT NOT NULL,
|
||||||
|
redirect_uri TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_credentials_handle ON credentials(handle);
|
||||||
|
CREATE INDEX idx_credentials_origin ON credentials(origin);
|
||||||
|
CREATE INDEX idx_credentials_deleted_at ON credentials(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_accounts_address ON accounts(address);
|
||||||
|
CREATE INDEX idx_accounts_chain_id ON accounts(chain_id);
|
||||||
|
CREATE INDEX idx_accounts_block_created ON accounts(block_created);
|
||||||
|
CREATE INDEX idx_accounts_label ON accounts(label);
|
||||||
|
CREATE INDEX idx_accounts_controller ON accounts(controller);
|
||||||
|
CREATE INDEX idx_accounts_deleted_at ON accounts(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_profiles_handle ON profiles(handle);
|
||||||
|
CREATE INDEX idx_profiles_address ON profiles(address);
|
||||||
|
CREATE INDEX idx_profiles_deleted_at ON profiles(deleted_at);
|
||||||
|
|
||||||
|
CREATE INDEX idx_vaults_handle ON vaults(handle);
|
||||||
|
CREATE INDEX idx_vaults_session_id ON vaults(session_id);
|
||||||
|
CREATE INDEX idx_vaults_deleted_at ON vaults(deleted_at);
|
||||||
1
internal/jobs/cron.go
Normal file
1
internal/jobs/cron.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package jobs
|
||||||
12
internal/jobs/events.go
Normal file
12
internal/jobs/events.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
type EventTrigger string
|
||||||
|
|
||||||
|
var (
|
||||||
|
EventTriggerMinute = EventTrigger("0 * * * * *") // Every minute (with seconds)
|
||||||
|
EventTriggerHourly = EventTrigger("0 */1 * * *") // Every hour at minute 0
|
||||||
|
EventTriggerDaily = EventTrigger("0 0 0 * * *") // Every day at 00:00:00
|
||||||
|
EventTriggerWeekly = EventTrigger("0 0 0 * * 0") // Every Sunday at 00:00:00
|
||||||
|
EventTriggerMonthly = EventTrigger("0 0 0 1 * *") // First day of every month at 00:00:00
|
||||||
|
EventTriggerYearly = EventTrigger("0 0 0 1 1 *") // January 1st every year at 00:00:00
|
||||||
|
)
|
||||||
1
internal/jobs/tasks.go
Normal file
1
internal/jobs/tasks.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package jobs
|
||||||
97
internal/meta/metadata.templ
Normal file
97
internal/meta/metadata.templ
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package meta
|
||||||
|
|
||||||
|
import "github.com/labstack/echo/v4"
|
||||||
|
|
||||||
|
func GetMetadata(c echo.Context) Metadata {
|
||||||
|
return DefaultMetadata()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMetaComponent(c echo.Context) templ.Component {
|
||||||
|
return MetaComponent(GetMetadata(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultMetadata() Metadata {
|
||||||
|
return Metadata{
|
||||||
|
Title: "Motr",
|
||||||
|
Author: "Sonr",
|
||||||
|
Favicon: "https://cdn.sonr.id/favicon.png",
|
||||||
|
Robots: "index, follow",
|
||||||
|
Googlebot: "index, follow",
|
||||||
|
Google: "nositelinkssearchbox",
|
||||||
|
Description: "Sonr is a decentralized social network that allows you to create your own personalized digital identity.",
|
||||||
|
Keywords: "Sonr, social network, decentralized, identity, decentralized social network, decentralized identity, self-sovereign identity, self-sovereign, self-sovereign social network, self-sovereign identity network, sso, sso network, sso identity, sso social network, digital identity, digital social network",
|
||||||
|
CanonicalURL: "https://sonr.io",
|
||||||
|
OGImage: "https://cdn.sonr.id/og.png",
|
||||||
|
OGURL: "https://sonr.io",
|
||||||
|
OGSiteName: "Sonr",
|
||||||
|
TwitterSite: "@sonr_io",
|
||||||
|
TwitterCreator: "@sonr_io",
|
||||||
|
TwitterImage: "https://cdn.sonr.id/og.png",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Title string
|
||||||
|
Author string
|
||||||
|
Favicon string
|
||||||
|
Robots string
|
||||||
|
Googlebot string
|
||||||
|
Google string
|
||||||
|
Description string
|
||||||
|
Keywords string
|
||||||
|
CanonicalURL string
|
||||||
|
OGImage string
|
||||||
|
OGURL string
|
||||||
|
OGSiteName string
|
||||||
|
TwitterSite string
|
||||||
|
TwitterCreator string
|
||||||
|
TwitterImage string
|
||||||
|
}
|
||||||
|
|
||||||
|
templ DefaultMetaComponent() {
|
||||||
|
<title>Motr</title>
|
||||||
|
<link rel="icon" type="image/png" href="https://cdn.sonr.id/favicon.png"/>
|
||||||
|
<meta name="description" content="Sonr is a decentralized social network that allows you to create your own personalized digital identity."/>
|
||||||
|
<meta name="keywords" content="Sonr, social network, decentralized, identity, decentralized social network, decentralized identity, self-sovereign identity, self-sovereign, self-sovereign social network, self-sovereign identity network, sso, sso network, sso identity, sso social network, digital identity, digital social network"/>
|
||||||
|
<meta name="author" content="Sonr"/>
|
||||||
|
<meta name="robots" content="index, follow"/>
|
||||||
|
<meta name="googlebot" content="index, follow"/>
|
||||||
|
<meta name="google" content="nositelinkssearchbox"/>
|
||||||
|
<meta property="og:title" content="Motr"/>
|
||||||
|
<meta property="og:description" content="Sonr is a decentralized social network that allows you to create your own personalized digital identity."/>
|
||||||
|
<meta property="og:image" content="https://cdn.sonr.id/og.png"/>
|
||||||
|
<meta property="og:url" content="https://sonr.io"/>
|
||||||
|
<meta property="og:site_name" content="Sonr"/>
|
||||||
|
<meta property="og:type" content="website"/>
|
||||||
|
<meta property="og:locale" content="en_US"/>
|
||||||
|
<meta name="twitter:card" content="summary_large_image"/>
|
||||||
|
<meta name="twitter:site" content="@sonr_io"/>
|
||||||
|
<meta name="twitter:creator" content="@sonr_io"/>
|
||||||
|
<meta name="twitter:title" content="Motr"/>
|
||||||
|
<meta name="twitter:description" content="Sonr is a decentralized social network that allows you to create your own personalized digital identity."/>
|
||||||
|
<meta name="twitter:image" content="https://cdn.sonr.id/og.png"/>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ MetaComponent(m Metadata) {
|
||||||
|
<title>{ m.Title }</title>
|
||||||
|
<link rel="icon" type="image/png" href={ m.Favicon }/>
|
||||||
|
<meta name="description" content={ m.Description }/>
|
||||||
|
<meta name="keywords" content={ m.Keywords }/>
|
||||||
|
<meta name="author" content={ m.Author }/>
|
||||||
|
<meta name="robots" content={ m.Robots }/>
|
||||||
|
<meta name="googlebot" content={ m.Googlebot }/>
|
||||||
|
<meta name="google" content={ m.Google }/>
|
||||||
|
<meta property="og:title" content={ m.Title }/>
|
||||||
|
<meta property="og:description" content={ m.Description }/>
|
||||||
|
<meta property="og:image" content={ m.OGImage }/>
|
||||||
|
<meta property="og:url" content={ m.OGURL }/>
|
||||||
|
<meta property="og:site_name" content={ m.OGSiteName }/>
|
||||||
|
<meta property="og:type" content="website"/>
|
||||||
|
<meta property="og:locale" content="en_US"/>
|
||||||
|
<meta name="twitter:card" content="summary_large_image"/>
|
||||||
|
<meta name="twitter:site" content={ m.TwitterSite }/>
|
||||||
|
<meta name="twitter:creator" content={ m.TwitterCreator }/>
|
||||||
|
<meta name="twitter:title" content={ m.Title }/>
|
||||||
|
<meta name="twitter:description" content={ m.Description }/>
|
||||||
|
<meta name="twitter:image" content={ m.TwitterImage }/>
|
||||||
|
}
|
||||||
351
internal/meta/metadata_templ.go
Normal file
351
internal/meta/metadata_templ.go
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package meta
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "github.com/labstack/echo/v4"
|
||||||
|
|
||||||
|
func GetMetadata(c echo.Context) Metadata {
|
||||||
|
return DefaultMetadata()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMetaComponent(c echo.Context) templ.Component {
|
||||||
|
return MetaComponent(GetMetadata(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultMetadata() Metadata {
|
||||||
|
return Metadata{
|
||||||
|
Title: "Motr",
|
||||||
|
Author: "Sonr",
|
||||||
|
Favicon: "https://cdn.sonr.id/favicon.png",
|
||||||
|
Robots: "index, follow",
|
||||||
|
Googlebot: "index, follow",
|
||||||
|
Google: "nositelinkssearchbox",
|
||||||
|
Description: "Sonr is a decentralized social network that allows you to create your own personalized digital identity.",
|
||||||
|
Keywords: "Sonr, social network, decentralized, identity, decentralized social network, decentralized identity, self-sovereign identity, self-sovereign, self-sovereign social network, self-sovereign identity network, sso, sso network, sso identity, sso social network, digital identity, digital social network",
|
||||||
|
CanonicalURL: "https://sonr.io",
|
||||||
|
OGImage: "https://cdn.sonr.id/og.png",
|
||||||
|
OGURL: "https://sonr.io",
|
||||||
|
OGSiteName: "Sonr",
|
||||||
|
TwitterSite: "@sonr_io",
|
||||||
|
TwitterCreator: "@sonr_io",
|
||||||
|
TwitterImage: "https://cdn.sonr.id/og.png",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Title string
|
||||||
|
Author string
|
||||||
|
Favicon string
|
||||||
|
Robots string
|
||||||
|
Googlebot string
|
||||||
|
Google string
|
||||||
|
Description string
|
||||||
|
Keywords string
|
||||||
|
CanonicalURL string
|
||||||
|
OGImage string
|
||||||
|
OGURL string
|
||||||
|
OGSiteName string
|
||||||
|
TwitterSite string
|
||||||
|
TwitterCreator string
|
||||||
|
TwitterImage string
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultMetaComponent() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<title>Motr</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn.sonr.id/favicon.png\"><meta name=\"description\" content=\"Sonr is a decentralized social network that allows you to create your own personalized digital identity.\"><meta name=\"keywords\" content=\"Sonr, social network, decentralized, identity, decentralized social network, decentralized identity, self-sovereign identity, self-sovereign, self-sovereign social network, self-sovereign identity network, sso, sso network, sso identity, sso social network, digital identity, digital social network\"><meta name=\"author\" content=\"Sonr\"><meta name=\"robots\" content=\"index, follow\"><meta name=\"googlebot\" content=\"index, follow\"><meta name=\"google\" content=\"nositelinkssearchbox\"><meta property=\"og:title\" content=\"Motr\"><meta property=\"og:description\" content=\"Sonr is a decentralized social network that allows you to create your own personalized digital identity.\"><meta property=\"og:image\" content=\"https://cdn.sonr.id/og.png\"><meta property=\"og:url\" content=\"https://sonr.io\"><meta property=\"og:site_name\" content=\"Sonr\"><meta property=\"og:type\" content=\"website\"><meta property=\"og:locale\" content=\"en_US\"><meta name=\"twitter:card\" content=\"summary_large_image\"><meta name=\"twitter:site\" content=\"@sonr_io\"><meta name=\"twitter:creator\" content=\"@sonr_io\"><meta name=\"twitter:title\" content=\"Motr\"><meta name=\"twitter:description\" content=\"Sonr is a decentralized social network that allows you to create your own personalized digital identity.\"><meta name=\"twitter:image\" content=\"https://cdn.sonr.id/og.png\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func MetaComponent(m Metadata) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var2 == nil {
|
||||||
|
templ_7745c5c3_Var2 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<title>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(m.Title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 76, Col: 17}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</title><link rel=\"icon\" type=\"image/png\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var4 string
|
||||||
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(m.Favicon)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 77, Col: 51}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"><meta name=\"description\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(m.Description)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 78, Col: 49}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\"><meta name=\"keywords\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(m.Keywords)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 79, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\"><meta name=\"author\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(m.Author)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 80, Col: 39}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\"><meta name=\"robots\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var8 string
|
||||||
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(m.Robots)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 81, Col: 39}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\"><meta name=\"googlebot\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(m.Googlebot)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 82, Col: 45}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\"><meta name=\"google\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var10 string
|
||||||
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(m.Google)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 83, Col: 39}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\"><meta property=\"og:title\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var11 string
|
||||||
|
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(m.Title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 84, Col: 44}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\"><meta property=\"og:description\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var12 string
|
||||||
|
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(m.Description)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 85, Col: 56}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\"><meta property=\"og:image\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var13 string
|
||||||
|
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(m.OGImage)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 86, Col: 46}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"><meta property=\"og:url\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var14 string
|
||||||
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(m.OGURL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 87, Col: 42}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\"><meta property=\"og:site_name\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var15 string
|
||||||
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(m.OGSiteName)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 88, Col: 53}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\"><meta property=\"og:type\" content=\"website\"><meta property=\"og:locale\" content=\"en_US\"><meta name=\"twitter:card\" content=\"summary_large_image\"><meta name=\"twitter:site\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var16 string
|
||||||
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(m.TwitterSite)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 92, Col: 50}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\"><meta name=\"twitter:creator\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var17 string
|
||||||
|
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(m.TwitterCreator)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 93, Col: 56}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\"><meta name=\"twitter:title\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var18 string
|
||||||
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(m.Title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 94, Col: 45}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\"><meta name=\"twitter:description\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var19 string
|
||||||
|
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(m.Description)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 95, Col: 57}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\"><meta name=\"twitter:image\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var20 string
|
||||||
|
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(m.TwitterImage)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/meta/metadata.templ`, Line: 96, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
internal/migrations/001_accounts_table.down.sql
Normal file
1
internal/migrations/001_accounts_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE accounts;
|
||||||
30
internal/migrations/001_accounts_table.up.sql
Normal file
30
internal/migrations/001_accounts_table.up.sql
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
-- Accounts represent blockchain accounts
|
||||||
|
CREATE TABLE accounts (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
number INTEGER NOT NULL,
|
||||||
|
sequence INTEGER NOT NULL DEFAULT 0,
|
||||||
|
address TEXT NOT NULL UNIQUE,
|
||||||
|
public_key TEXT NOT NULL CHECK(json_valid(public_key)),
|
||||||
|
chain_id TEXT NOT NULL,
|
||||||
|
block_created INTEGER NOT NULL,
|
||||||
|
controller TEXT NOT NULL,
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
handle TEXT NOT NULL,
|
||||||
|
is_subsidiary BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_subsidiary IN (0,1)),
|
||||||
|
is_validator BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_validator IN (0,1)),
|
||||||
|
is_delegator BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_delegator IN (0,1)),
|
||||||
|
is_accountable BOOLEAN NOT NULL DEFAULT TRUE CHECK(is_accountable IN (0,1))
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE INDEX idx_accounts_address ON accounts(address);
|
||||||
|
CREATE INDEX idx_accounts_chain_id ON accounts(chain_id);
|
||||||
|
CREATE INDEX idx_accounts_block_created ON accounts(block_created);
|
||||||
|
CREATE INDEX idx_accounts_label ON accounts(label);
|
||||||
|
CREATE INDEX idx_accounts_controller ON accounts(controller);
|
||||||
|
CREATE INDEX idx_accounts_deleted_at ON accounts(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/002_credentials_table.down.sql
Normal file
1
internal/migrations/002_credentials_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE credentials;
|
||||||
19
internal/migrations/002_credentials_table.up.sql
Normal file
19
internal/migrations/002_credentials_table.up.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- Credentials store WebAuthn credentials
|
||||||
|
CREATE TABLE credentials (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
handle TEXT NOT NULL,
|
||||||
|
credential_id TEXT NOT NULL UNIQUE,
|
||||||
|
authenticator_attachment TEXT NOT NULL,
|
||||||
|
origin TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
transports TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_credentials_handle ON credentials(handle);
|
||||||
|
CREATE INDEX idx_credentials_origin ON credentials(origin);
|
||||||
|
CREATE INDEX idx_credentials_deleted_at ON credentials(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/003_profiles_table.down.sql
Normal file
1
internal/migrations/003_profiles_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE profiles;
|
||||||
18
internal/migrations/003_profiles_table.up.sql
Normal file
18
internal/migrations/003_profiles_table.up.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- Profiles represent user identities
|
||||||
|
CREATE TABLE profiles (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
handle TEXT NOT NULL UNIQUE,
|
||||||
|
origin TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
UNIQUE(address, origin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_profiles_handle ON profiles(handle);
|
||||||
|
CREATE INDEX idx_profiles_address ON profiles(address);
|
||||||
|
CREATE INDEX idx_profiles_deleted_at ON profiles(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/004_vaults_table.down.sql
Normal file
1
internal/migrations/004_vaults_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE vaults;
|
||||||
19
internal/migrations/004_vaults_table.up.sql
Normal file
19
internal/migrations/004_vaults_table.up.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- Vaults store encrypted data
|
||||||
|
CREATE TABLE vaults (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
handle TEXT NOT NULL,
|
||||||
|
origin TEXT NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
cid TEXT NOT NULL UNIQUE,
|
||||||
|
config TEXT NOT NULL CHECK(json_valid(config)),
|
||||||
|
session_id TEXT NOT NULL,
|
||||||
|
redirect_uri TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE INDEX idx_vaults_handle ON vaults(handle);
|
||||||
|
CREATE INDEX idx_vaults_session_id ON vaults(session_id);
|
||||||
|
CREATE INDEX idx_vaults_deleted_at ON vaults(deleted_at)
|
||||||
1
internal/migrations/005_assets_table.down.sql
Normal file
1
internal/migrations/005_assets_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE assets;
|
||||||
21
internal/migrations/005_assets_table.up.sql
Normal file
21
internal/migrations/005_assets_table.up.sql
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-- Assets represent tokens and coins
|
||||||
|
CREATE TABLE assets (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
symbol TEXT NOT NULL,
|
||||||
|
decimals INTEGER NOT NULL CHECK(decimals >= 0),
|
||||||
|
chain_id TEXT NOT NULL,
|
||||||
|
channel TEXT NOT NULL,
|
||||||
|
asset_type TEXT NOT NULL,
|
||||||
|
coingecko_id TEXT,
|
||||||
|
UNIQUE(chain_id, symbol)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_assets_symbol ON assets(symbol);
|
||||||
|
CREATE INDEX idx_assets_chain_id ON assets(chain_id);
|
||||||
|
CREATE INDEX idx_assets_deleted_at ON assets(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/006_prices_table.down.sql
Normal file
1
internal/migrations/006_prices_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE prices;
|
||||||
28
internal/migrations/006_prices_table.up.sql
Normal file
28
internal/migrations/006_prices_table.up.sql
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-- Prices entity based on the Alternative.me API for crypto prices
|
||||||
|
CREATE TABLE prices (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
asset_id TEXT NOT NULL,
|
||||||
|
price_usd REAL,
|
||||||
|
price_btc REAL,
|
||||||
|
volume_24h_usd REAL,
|
||||||
|
market_cap_usd REAL,
|
||||||
|
available_supply REAL,
|
||||||
|
total_supply REAL,
|
||||||
|
max_supply REAL,
|
||||||
|
percent_change_1h REAL,
|
||||||
|
percent_change_24h REAL,
|
||||||
|
percent_change_7d REAL,
|
||||||
|
rank INTEGER,
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
FOREIGN KEY (asset_id) REFERENCES assets(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_prices_asset_id ON prices(asset_id);
|
||||||
|
CREATE INDEX idx_prices_rank ON prices(rank);
|
||||||
|
CREATE INDEX idx_prices_last_updated ON prices(last_updated);
|
||||||
|
CREATE INDEX idx_prices_deleted_at ON prices(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/007_price_conversions_table.down.sql
Normal file
1
internal/migrations/007_price_conversions_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE price_conversions;
|
||||||
21
internal/migrations/007_price_conversions_table.up.sql
Normal file
21
internal/migrations/007_price_conversions_table.up.sql
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-- Currency conversion rates for crypto prices
|
||||||
|
CREATE TABLE price_conversions (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
price_id TEXT NOT NULL,
|
||||||
|
currency_code TEXT NOT NULL,
|
||||||
|
price REAL,
|
||||||
|
volume_24h REAL,
|
||||||
|
market_cap REAL,
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
FOREIGN KEY (price_id) REFERENCES prices(id),
|
||||||
|
UNIQUE(price_id, currency_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_price_conversions_price_id ON price_conversions(price_id);
|
||||||
|
CREATE INDEX idx_price_conversions_currency_code ON price_conversions(currency_code);
|
||||||
|
CREATE INDEX idx_price_conversions_deleted_at ON price_conversions(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/008_blockchains_table.down.sql
Normal file
1
internal/migrations/008_blockchains_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE blockchains;
|
||||||
71
internal/migrations/008_blockchains_table.up.sql
Normal file
71
internal/migrations/008_blockchains_table.up.sql
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
-- Blockchains table to store chain configuration parameters
|
||||||
|
CREATE TABLE blockchains (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
|
||||||
|
-- Basic chain information
|
||||||
|
chain_name TEXT NOT NULL,
|
||||||
|
chain_id_cosmos TEXT,
|
||||||
|
chain_id_evm TEXT,
|
||||||
|
api_name TEXT,
|
||||||
|
bech_account_prefix TEXT,
|
||||||
|
bech_validator_prefix TEXT,
|
||||||
|
|
||||||
|
-- Chain assets
|
||||||
|
main_asset_symbol TEXT,
|
||||||
|
main_asset_denom TEXT,
|
||||||
|
staking_asset_symbol TEXT,
|
||||||
|
staking_asset_denom TEXT,
|
||||||
|
is_stake_enabled BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_stake_enabled IN (0,1)),
|
||||||
|
|
||||||
|
-- Chain images
|
||||||
|
chain_image TEXT,
|
||||||
|
main_asset_image TEXT,
|
||||||
|
staking_asset_image TEXT,
|
||||||
|
|
||||||
|
-- Chain types and features
|
||||||
|
chain_type TEXT NOT NULL CHECK(json_valid(chain_type)),
|
||||||
|
is_support_mobile_wallet BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_support_mobile_wallet IN (0,1)),
|
||||||
|
is_support_extension_wallet BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_support_extension_wallet IN (0,1)),
|
||||||
|
is_support_erc20 BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_support_erc20 IN (0,1)),
|
||||||
|
|
||||||
|
-- Descriptions in multiple languages
|
||||||
|
description_en TEXT,
|
||||||
|
description_ko TEXT,
|
||||||
|
description_ja TEXT,
|
||||||
|
|
||||||
|
-- Genesis information
|
||||||
|
origin_genesis_time TIMESTAMP,
|
||||||
|
|
||||||
|
-- Account types configuration
|
||||||
|
account_type TEXT NOT NULL CHECK(json_valid(account_type)),
|
||||||
|
|
||||||
|
-- BTC staking specific
|
||||||
|
btc_staking TEXT CHECK(json_valid(btc_staking)),
|
||||||
|
|
||||||
|
-- Cosmos fee information
|
||||||
|
cosmos_fee_info TEXT CHECK(json_valid(cosmos_fee_info)),
|
||||||
|
|
||||||
|
-- EVM fee information
|
||||||
|
evm_fee_info TEXT CHECK(json_valid(evm_fee_info)),
|
||||||
|
|
||||||
|
-- Endpoints
|
||||||
|
lcd_endpoint TEXT CHECK(json_valid(lcd_endpoint)),
|
||||||
|
grpc_endpoint TEXT CHECK(json_valid(grpc_endpoint)),
|
||||||
|
evm_rpc_endpoint TEXT CHECK(json_valid(evm_rpc_endpoint)),
|
||||||
|
|
||||||
|
-- Explorer information
|
||||||
|
explorer TEXT CHECK(json_valid(explorer)),
|
||||||
|
|
||||||
|
-- Social and documentation links
|
||||||
|
about TEXT CHECK(json_valid(about)),
|
||||||
|
forum TEXT CHECK(json_valid(forum))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_blockchains_chain_name ON blockchains(chain_name);
|
||||||
|
CREATE INDEX idx_blockchains_chain_id_cosmos ON blockchains(chain_id_cosmos);
|
||||||
|
CREATE INDEX idx_blockchains_chain_id_evm ON blockchains(chain_id_evm);
|
||||||
|
CREATE INDEX idx_blockchains_main_asset_symbol ON blockchains(main_asset_symbol);
|
||||||
|
CREATE INDEX idx_blockchains_deleted_at ON blockchains(deleted_at);
|
||||||
1
internal/migrations/009_services_table.down.sql
Normal file
1
internal/migrations/009_services_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE services;
|
||||||
24
internal/migrations/009_services_table.up.sql
Normal file
24
internal/migrations/009_services_table.up.sql
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
-- Service for Service Records sourced on chain
|
||||||
|
CREATE TABLE services (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
chain_id TEXT NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
owner_address TEXT NOT NULL,
|
||||||
|
metadata TEXT CHECK(json_valid(metadata)),
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
block_height INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (chain_id) REFERENCES assets(chain_id),
|
||||||
|
UNIQUE(chain_id, address)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_services_name ON services(name);
|
||||||
|
CREATE INDEX idx_services_chain_id ON services(chain_id);
|
||||||
|
CREATE INDEX idx_services_address ON services(address);
|
||||||
|
CREATE INDEX idx_services_owner_address ON services(owner_address);
|
||||||
|
CREATE INDEX idx_services_status ON services(status);
|
||||||
|
CREATE INDEX idx_services_deleted_at ON services(deleted_at);
|
||||||
1
internal/migrations/010_activities_table.down.sql
Normal file
1
internal/migrations/010_activities_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE activities;
|
||||||
32
internal/migrations/010_activities_table.up.sql
Normal file
32
internal/migrations/010_activities_table.up.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
-- Activity table for basic transaction broadcast activity
|
||||||
|
CREATE TABLE activities (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
account_id TEXT NOT NULL,
|
||||||
|
tx_hash TEXT,
|
||||||
|
tx_type TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
amount TEXT,
|
||||||
|
fee TEXT,
|
||||||
|
gas_used INTEGER,
|
||||||
|
gas_wanted INTEGER,
|
||||||
|
memo TEXT,
|
||||||
|
block_height INTEGER,
|
||||||
|
timestamp TIMESTAMP NOT NULL,
|
||||||
|
raw_log TEXT,
|
||||||
|
error TEXT,
|
||||||
|
FOREIGN KEY (account_id) REFERENCES accounts(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_activities_account_id ON activities(account_id);
|
||||||
|
CREATE INDEX idx_activities_tx_hash ON activities(tx_hash);
|
||||||
|
CREATE INDEX idx_activities_tx_type ON activities(tx_type);
|
||||||
|
CREATE INDEX idx_activities_status ON activities(status);
|
||||||
|
CREATE INDEX idx_activities_timestamp ON activities(timestamp);
|
||||||
|
CREATE INDEX idx_activities_block_height ON activities(block_height);
|
||||||
|
CREATE INDEX idx_activities_deleted_at ON activities(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/011_health_table.down.sql
Normal file
1
internal/migrations/011_health_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE health;
|
||||||
28
internal/migrations/011_health_table.up.sql
Normal file
28
internal/migrations/011_health_table.up.sql
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-- Health table for scheduled checks for API endpoints
|
||||||
|
CREATE TABLE health (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
endpoint_url TEXT NOT NULL,
|
||||||
|
endpoint_type TEXT NOT NULL,
|
||||||
|
chain_id TEXT,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
response_time_ms INTEGER,
|
||||||
|
last_checked TIMESTAMP NOT NULL,
|
||||||
|
next_check TIMESTAMP,
|
||||||
|
failure_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
success_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
response_data TEXT,
|
||||||
|
error_message TEXT,
|
||||||
|
FOREIGN KEY (chain_id) REFERENCES assets(chain_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_health_endpoint_url ON health(endpoint_url);
|
||||||
|
CREATE INDEX idx_health_endpoint_type ON health(endpoint_type);
|
||||||
|
CREATE INDEX idx_health_chain_id ON health(chain_id);
|
||||||
|
CREATE INDEX idx_health_status ON health(status);
|
||||||
|
CREATE INDEX idx_health_last_checked ON health(last_checked);
|
||||||
|
CREATE INDEX idx_health_next_check ON health(next_check);
|
||||||
|
CREATE INDEX idx_health_deleted_at ON health(deleted_at);
|
||||||
|
|
||||||
1
internal/migrations/012_global_market_table.down.sql
Normal file
1
internal/migrations/012_global_market_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE global_market;
|
||||||
19
internal/migrations/012_global_market_table.up.sql
Normal file
19
internal/migrations/012_global_market_table.up.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- Global market data from Alternative.me API
|
||||||
|
CREATE TABLE global_market (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
total_market_cap_usd REAL,
|
||||||
|
total_24h_volume_usd REAL,
|
||||||
|
bitcoin_percentage_of_market_cap REAL,
|
||||||
|
active_currencies INTEGER,
|
||||||
|
active_assets INTEGER,
|
||||||
|
active_markets INTEGER,
|
||||||
|
last_updated TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_global_market_last_updated ON global_market(last_updated);
|
||||||
|
CREATE INDEX idx_global_market_deleted_at ON global_market(deleted_at);
|
||||||
|
|
||||||
|
|
||||||
1
internal/migrations/013_fear_greed_index_table.down.sql
Normal file
1
internal/migrations/013_fear_greed_index_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE fear_greed_index;
|
||||||
15
internal/migrations/013_fear_greed_index_table.up.sql
Normal file
15
internal/migrations/013_fear_greed_index_table.up.sql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-- Fear and Greed Index data from Alternative.me
|
||||||
|
CREATE TABLE fear_greed_index (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
value INTEGER NOT NULL,
|
||||||
|
value_classification TEXT NOT NULL,
|
||||||
|
timestamp TIMESTAMP NOT NULL,
|
||||||
|
time_until_update TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_fear_greed_index_timestamp ON fear_greed_index(timestamp);
|
||||||
|
CREATE INDEX idx_fear_greed_index_value ON fear_greed_index(value);
|
||||||
|
CREATE INDEX idx_fear_greed_index_deleted_at ON fear_greed_index(deleted_at);
|
||||||
1
internal/migrations/014_crypto_listings_table.down.sql
Normal file
1
internal/migrations/014_crypto_listings_table.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE crypto_listings;
|
||||||
18
internal/migrations/014_crypto_listings_table.up.sql
Normal file
18
internal/migrations/014_crypto_listings_table.up.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- Listings data from Alternative.me API
|
||||||
|
CREATE TABLE crypto_listings (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP,
|
||||||
|
api_id TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
symbol TEXT NOT NULL,
|
||||||
|
website_slug TEXT NOT NULL,
|
||||||
|
UNIQUE(api_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE INDEX idx_crypto_listings_api_id ON crypto_listings(api_id);
|
||||||
|
CREATE INDEX idx_crypto_listings_symbol ON crypto_listings(symbol);
|
||||||
|
CREATE INDEX idx_crypto_listings_website_slug ON crypto_listings(website_slug);
|
||||||
|
CREATE INDEX idx_crypto_listings_deleted_at ON crypto_listings(deleted_at);
|
||||||
200
internal/migrations/Taskfile.yml
Normal file
200
internal/migrations/Taskfile.yml
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
# yaml-language-server: $schema=https://taskfile.dev/schema.json
|
||||||
|
version: "3"
|
||||||
|
silent: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- task: migrate
|
||||||
|
|
||||||
|
initialize:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:accounts:up
|
||||||
|
- task: migrate:credentials:up
|
||||||
|
- task: migrate:profiles:up
|
||||||
|
- task: migrate:vaults:up
|
||||||
|
- task: migrate:assets:up
|
||||||
|
- task: migrate:prices:up
|
||||||
|
- task: migrate:price_conversions:up
|
||||||
|
- task: migrate:blockchains:up
|
||||||
|
- task: migrate:services:up
|
||||||
|
- task: migrate:activities:up
|
||||||
|
- task: migrate:health:up
|
||||||
|
- task: migrate:global_market:up
|
||||||
|
- task: migrate:fear_greed_index:up
|
||||||
|
- task: migrate:crypto_listings:up
|
||||||
|
|
||||||
|
migrate:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:accounts
|
||||||
|
- task: migrate:credentials
|
||||||
|
- task: migrate:profiles
|
||||||
|
- task: migrate:vaults
|
||||||
|
- task: migrate:assets
|
||||||
|
- task: migrate:prices
|
||||||
|
- task: migrate:price_conversions
|
||||||
|
- task: migrate:blockchains
|
||||||
|
- task: migrate:services
|
||||||
|
- task: migrate:activities
|
||||||
|
- task: migrate:health
|
||||||
|
- task: migrate:global_market
|
||||||
|
- task: migrate:fear_greed_index
|
||||||
|
- task: migrate:crypto_listings
|
||||||
|
|
||||||
|
# ---------------
|
||||||
|
# Main Tasks
|
||||||
|
# ---------------
|
||||||
|
migrate:accounts:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:accounts:down
|
||||||
|
- task: migrate:accounts:up
|
||||||
|
|
||||||
|
migrate:accounts:up:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 001_accounts_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:accounts:down:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 001_accounts_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:credentials:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:credentials:down
|
||||||
|
- task: migrate:credentials:up
|
||||||
|
|
||||||
|
migrate:credentials:up:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 002_credentials_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:credentials:down:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 002_credentials_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:profiles:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:profiles:down
|
||||||
|
- task: migrate:profiles:up
|
||||||
|
|
||||||
|
migrate:profiles:up:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 003_profiles_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:profiles:down:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 003_profiles_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:vaults:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:vaults:down
|
||||||
|
- task: migrate:vaults:up
|
||||||
|
|
||||||
|
migrate:vaults:down:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 004_vaults_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:vaults:up:
|
||||||
|
cmd: wrangler d1 execute USERS_DB --file 004_vaults_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:assets:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:assets:down
|
||||||
|
- task: migrate:assets:up
|
||||||
|
|
||||||
|
migrate:assets:up:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 005_assets_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:assets:down:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 005_assets_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:prices:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:prices:down
|
||||||
|
- task: migrate:prices:up
|
||||||
|
|
||||||
|
migrate:prices:up:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 006_prices_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:prices:down:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 006_prices_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:price_conversions:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:price_conversions:down
|
||||||
|
- task: migrate:price_conversions:up
|
||||||
|
|
||||||
|
migrate:price_conversions:up:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 007_price_conversions_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:price_conversions:down:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 007_price_conversions_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:blockchains:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:blockchains:down
|
||||||
|
- task: migrate:blockchains:up
|
||||||
|
|
||||||
|
migrate:blockchains:up:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 008_blockchains_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:blockchains:down:
|
||||||
|
cmd: wrangler d1 execute NETWORK_DB --file 008_blockchains_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:services:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:services:down
|
||||||
|
- task: migrate:services:up
|
||||||
|
|
||||||
|
migrate:services:up:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 009_services_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:services:down:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 009_services_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:activities:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:activities:down
|
||||||
|
- task: migrate:activities:up
|
||||||
|
|
||||||
|
migrate:activities:up:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 010_activities_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:activities:down:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 010_activities_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:health:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:health:down
|
||||||
|
- task: migrate:health:up
|
||||||
|
|
||||||
|
migrate:health:up:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 011_health_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:health:down:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 011_health_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:global_market:
|
||||||
|
cmds:
|
||||||
|
- task: global_market:down
|
||||||
|
- task: global_market:up
|
||||||
|
|
||||||
|
migrate:global_market:up:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 012_global_market_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:global_market:down:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 012_global_market_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:fear_greed_index:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:fear_greed_index:down
|
||||||
|
- task: migrate:fear_greed_index:up
|
||||||
|
|
||||||
|
migrate:fear_greed_index:up:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 013_fear_greed_index_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:fear_greed_index:down:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 013_fear_greed_index_table.down.sql --remote -y
|
||||||
|
|
||||||
|
migrate:crypto_listings:
|
||||||
|
cmds:
|
||||||
|
- task: migrate:crypto_listings:down
|
||||||
|
- task: migrate:crypto_listings:up
|
||||||
|
|
||||||
|
migrate:crypto_listings:up:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 014_crypto_listings_table.up.sql --remote -y
|
||||||
|
|
||||||
|
migrate:crypto_listings:down:
|
||||||
|
cmd: wrangler d1 execute ACTIVITY_DB --file 014_crypto_listings_table.down.sql --remote -y
|
||||||
|
|
||||||
6
internal/migrations/node_modules/.cache/wrangler/wrangler-account.json
generated
vendored
Normal file
6
internal/migrations/node_modules/.cache/wrangler/wrangler-account.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"id": "eb37925850388bca807b7fab964c12bb",
|
||||||
|
"name": "Sonr"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
internal/migrations/node_modules/.mf/cf.json
generated
vendored
Normal file
1
internal/migrations/node_modules/.mf/cf.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"clientTcpRtt":8,"requestHeaderNames":{},"httpProtocol":"HTTP/1.1","tlsCipher":"AEAD-AES256-GCM-SHA384","continent":"NA","asn":701,"clientAcceptEncoding":"br, gzip, deflate","verifiedBotCategory":"","country":"US","region":"Virginia","tlsClientCiphersSha1":"kXrN3VEKDdzz2cPKTQaKzpxVTxQ=","tlsClientAuth":{"certIssuerDNLegacy":"","certIssuerSKI":"","certSubjectDNRFC2253":"","certSubjectDNLegacy":"","certFingerprintSHA256":"","certNotBefore":"","certSKI":"","certSerial":"","certIssuerDN":"","certVerified":"NONE","certNotAfter":"","certSubjectDN":"","certPresented":"0","certRevoked":"0","certIssuerSerial":"","certIssuerDNRFC2253":"","certFingerprintSHA1":""},"tlsClientRandom":"KHkBe8nH4XNP9wnNS5nCDWBpe+Ha+8+BUuP0iev0P7Q=","tlsExportedAuthenticator":{"clientFinished":"c71857a631b6612f8bdfda376b597ddb0ccf62688fc7f50086006daba82f54c412501557ccfce73754bc550a1e09a6b9","clientHandshake":"8d0a2b64f7b6d0d1c2a77d7535feca90c9703a46c457b4951670146a8b5e2fe89357c6d8666c4e7f864e6814e7bb1d0f","serverHandshake":"429ef59250f50d719b076c2efdf97ecd5d1a50c15fdf979df5894d078793865ff44c7680213365147c44daedbc92bec6","serverFinished":"6e46d6694b01edbbc7d5daa9316565f17fb3a626713c96286d07487a7ddb7482aea03a84971fc74231d848d2f037af41"},"tlsClientHelloLength":"383","colo":"IAD","timezone":"America/New_York","longitude":"-77.53900","latitude":"39.01800","edgeRequestKeepAliveStatus":1,"requestPriority":"","postalCode":"20147","city":"Ashburn","tlsVersion":"TLSv1.3","regionCode":"VA","asOrganization":"Verizon Fios","metroCode":"511","tlsClientExtensionsSha1Le":"u4wtEMFQBY18l3BzHAvORm+KGRw=","tlsClientExtensionsSha1":"1eY97BUYYO8vDaTfHQywB1pcNdM=","botManagement":{"corporateProxy":false,"verifiedBot":false,"jsDetection":{"passed":false},"staticResource":false,"detectionIds":{},"score":99}}
|
||||||
64
internal/migrations/wrangler.toml
Normal file
64
internal/migrations/wrangler.toml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# Top-level configuration
|
||||||
|
name = "motr-worker"
|
||||||
|
main = "worker.mjs"
|
||||||
|
compatibility_date = "2025-04-14"
|
||||||
|
|
||||||
|
routes = [
|
||||||
|
{ pattern = "sonr.id", custom_domain = true },
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
command = "devbox run build:worker"
|
||||||
|
|
||||||
|
[dev]
|
||||||
|
port = 6969
|
||||||
|
|
||||||
|
[observability]
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[triggers]
|
||||||
|
crons = ["0 */1 * * *"]
|
||||||
|
|
||||||
|
[[d1_databases]]
|
||||||
|
binding = "ACTIVITY_DB"
|
||||||
|
database_name = "motr-activity"
|
||||||
|
database_id = "a7ccb4bb-c529-4f42-8029-92564a3aecb8"
|
||||||
|
|
||||||
|
[[d1_databases]]
|
||||||
|
binding = "NETWORK_DB"
|
||||||
|
database_name = "motr-network"
|
||||||
|
database_id = "acb75499-3502-4052-9604-263a913e077a"
|
||||||
|
|
||||||
|
[[d1_databases]]
|
||||||
|
binding = "USERS_DB"
|
||||||
|
database_name = "motr-users"
|
||||||
|
database_id = "8ed4d399-5932-419c-b92f-9c20d7a36ad2"
|
||||||
|
|
||||||
|
[[kv_namespaces]]
|
||||||
|
binding = "SESSIONS_KV"
|
||||||
|
id = "ea5de66fcfc14b5eba170395e29432ee"
|
||||||
|
|
||||||
|
[[kv_namespaces]]
|
||||||
|
binding = "HANDLES_KV"
|
||||||
|
id = "271d47087a8842b2aac5ee79cf7bb203"
|
||||||
|
|
||||||
|
[[r2_buckets]]
|
||||||
|
binding = 'PROFILES'
|
||||||
|
bucket_name = 'profiles'
|
||||||
|
|
||||||
|
[vars]
|
||||||
|
SONR_CHAIN_ID = 'sonr-testnet-1'
|
||||||
|
IPFS_GATEWAY = 'https://ipfs.sonr.land'
|
||||||
|
SONR_API_URL = 'https://api.sonr.land'
|
||||||
|
SONR_RPC_URL = 'https://rpc.sonr.land'
|
||||||
|
SONR_GRPC_URL = 'https://grpc.sonr.land'
|
||||||
|
MATRIX_SERVER = 'https://bm.chat'
|
||||||
|
MOTR_GATEWAY = 'https://sonr.id'
|
||||||
|
MOTR_VAULT = 'https://did.run'
|
||||||
|
|
||||||
|
[durable_objects]
|
||||||
|
bindings = [{name = "VAULT", class_name = "Vault"}]
|
||||||
|
|
||||||
|
[[migrations]]
|
||||||
|
tag = "v1" # Should be unique for each entry
|
||||||
|
new_classes = ["Vault"] # List the classes that should be created
|
||||||
20
internal/ui/charts/area_chart.templ
Normal file
20
internal/ui/charts/area_chart.templ
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package charts
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type DateValue struct {
|
||||||
|
Date string
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
||||||
|
templ AreaChart(data []DateValue) {
|
||||||
|
for _, d := range data {
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ d.Date }</span>
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ fmt.Sprintf("%d", d.Value) }</span>
|
||||||
|
</div>
|
||||||
|
<div class="h-1 bg-gray-200 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
75
internal/ui/charts/area_chart_templ.go
Normal file
75
internal/ui/charts/area_chart_templ.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package charts
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type DateValue struct {
|
||||||
|
Date string
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
||||||
|
func AreaChart(data []DateValue) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
for _, d := range data {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"flex flex-col\"><div class=\"flex justify-between\"><span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(d.Date)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/area_chart.templ`, Line: 14, Col: 61}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</span> <span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", d.Value))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/area_chart.templ`, Line: 15, Col: 81}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span></div><div class=\"h-1 bg-gray-200 rounded-full\"></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
21
internal/ui/charts/bar_chart.templ
Normal file
21
internal/ui/charts/bar_chart.templ
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package charts
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type KeyValue struct {
|
||||||
|
Key string
|
||||||
|
Value int
|
||||||
|
Color string
|
||||||
|
}
|
||||||
|
|
||||||
|
templ BarChart(data []KeyValue) {
|
||||||
|
for _, d := range data {
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ d.Key }</span>
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ fmt.Sprintf("%d", d.Value) }</span>
|
||||||
|
</div>
|
||||||
|
<div class="h-1 bg-gray-200 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
76
internal/ui/charts/bar_chart_templ.go
Normal file
76
internal/ui/charts/bar_chart_templ.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package charts
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type KeyValue struct {
|
||||||
|
Key string
|
||||||
|
Value int
|
||||||
|
Color string
|
||||||
|
}
|
||||||
|
|
||||||
|
func BarChart(data []KeyValue) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
for _, d := range data {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"flex flex-col\"><div class=\"flex justify-between\"><span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(d.Key)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/bar_chart.templ`, Line: 15, Col: 60}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</span> <span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", d.Value))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/bar_chart.templ`, Line: 16, Col: 81}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span></div><div class=\"h-1 bg-gray-200 rounded-full\"></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
106
internal/ui/charts/candle_chart.templ
Normal file
106
internal/ui/charts/candle_chart.templ
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package charts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CandleData struct {
|
||||||
|
Open float64
|
||||||
|
Close float64
|
||||||
|
High float64
|
||||||
|
Low float64
|
||||||
|
Date time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// D3 script handle for deduplication
|
||||||
|
var d3Handle = templ.NewOnceHandle()
|
||||||
|
|
||||||
|
// D3 component for loading D3.js
|
||||||
|
templ D3() {
|
||||||
|
@d3Handle.Once() {
|
||||||
|
<script type="module">
|
||||||
|
|
||||||
|
window.d3 = d3;
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CandleChart component
|
||||||
|
templ CandleChart(data []CandleData) {
|
||||||
|
@D3()
|
||||||
|
<div id="candleChart" class="@container relative">
|
||||||
|
<div
|
||||||
|
class="relative h-72 w-full"
|
||||||
|
style="--marginTop: 10px; --marginRight: 60px; --marginBottom: 56px; --marginLeft: 30px;"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<script type="module">
|
||||||
|
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
|
||||||
|
// Convert Go data to JavaScript
|
||||||
|
|
||||||
|
// Declare the chart dimensions and margins.
|
||||||
|
const width = 640;
|
||||||
|
const height = 400;
|
||||||
|
const marginTop = 20;
|
||||||
|
const marginRight = 20;
|
||||||
|
const marginBottom = 30;
|
||||||
|
const marginLeft = 40;
|
||||||
|
|
||||||
|
// Declare the x (horizontal position) scale.
|
||||||
|
const x = d3.scaleUtc()
|
||||||
|
.domain([new Date("2023-01-01"), new Date("2024-01-01")])
|
||||||
|
.range([marginLeft, width - marginRight]);
|
||||||
|
|
||||||
|
// Declare the y (vertical position) scale.
|
||||||
|
const y = d3.scaleLinear()
|
||||||
|
.domain([0, 100])
|
||||||
|
.range([height - marginBottom, marginTop]);
|
||||||
|
|
||||||
|
// Create the SVG container.
|
||||||
|
const svg = d3.create("svg")
|
||||||
|
.attr("width", width)
|
||||||
|
.attr("height", height);
|
||||||
|
|
||||||
|
// Add the x-axis.
|
||||||
|
svg.append("g")
|
||||||
|
.attr("transform", `translate(0,${height - marginBottom})`)
|
||||||
|
.call(d3.axisBottom(x));
|
||||||
|
|
||||||
|
// Add the y-axis.
|
||||||
|
svg.append("g")
|
||||||
|
.attr("transform", `translate(${marginLeft},0)`)
|
||||||
|
.call(d3.axisLeft(y));
|
||||||
|
|
||||||
|
// Append the SVG element.
|
||||||
|
container.append(svg.node());
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatDataForJS converts the Go data structure to a JavaScript-compatible JSON string
|
||||||
|
func formatDataForJS(data []CandleData) string {
|
||||||
|
type jsData struct {
|
||||||
|
Date string `json:"date"`
|
||||||
|
Open float64 `json:"open"`
|
||||||
|
Close float64 `json:"close"`
|
||||||
|
High float64 `json:"high"`
|
||||||
|
Low float64 `json:"low"`
|
||||||
|
}
|
||||||
|
|
||||||
|
jsDataArray := make([]jsData, len(data))
|
||||||
|
for i, d := range data {
|
||||||
|
jsDataArray[i] = jsData{
|
||||||
|
Date: d.Date.Format(time.RFC3339),
|
||||||
|
Open: d.Open,
|
||||||
|
Close: d.Close,
|
||||||
|
High: d.High,
|
||||||
|
Low: d.Low,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(jsDataArray)
|
||||||
|
if err != nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
return string(jsonBytes)
|
||||||
|
}
|
||||||
137
internal/ui/charts/candle_chart_templ.go
Normal file
137
internal/ui/charts/candle_chart_templ.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package charts
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CandleData struct {
|
||||||
|
Open float64
|
||||||
|
Close float64
|
||||||
|
High float64
|
||||||
|
Low float64
|
||||||
|
Date time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// D3 script handle for deduplication
|
||||||
|
var d3Handle = templ.NewOnceHandle()
|
||||||
|
|
||||||
|
// D3 component for loading D3.js
|
||||||
|
func D3() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<script type=\"module\">\n \n window.d3 = d3;\n </script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = d3Handle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CandleChart component
|
||||||
|
func CandleChart(data []CandleData) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var3 == nil {
|
||||||
|
templ_7745c5c3_Var3 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = D3().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div id=\"candleChart\" class=\"@container relative\"><div class=\"relative h-72 w-full\" style=\"--marginTop: 10px; --marginRight: 60px; --marginBottom: 56px; --marginLeft: 30px;\"></div></div><script type=\"module\">\n\t import * as d3 from \"https://cdn.jsdelivr.net/npm/d3@7/+esm\";\n // Convert Go data to JavaScript\n \n // Declare the chart dimensions and margins.\n const width = 640;\n const height = 400;\n const marginTop = 20;\n const marginRight = 20;\n const marginBottom = 30;\n const marginLeft = 40;\n\n // Declare the x (horizontal position) scale.\n const x = d3.scaleUtc()\n .domain([new Date(\"2023-01-01\"), new Date(\"2024-01-01\")])\n .range([marginLeft, width - marginRight]);\n\n // Declare the y (vertical position) scale.\n const y = d3.scaleLinear()\n .domain([0, 100])\n .range([height - marginBottom, marginTop]);\n\n // Create the SVG container.\n const svg = d3.create(\"svg\")\n .attr(\"width\", width)\n .attr(\"height\", height);\n\n // Add the x-axis.\n svg.append(\"g\")\n .attr(\"transform\", `translate(0,${height - marginBottom})`)\n .call(d3.axisBottom(x));\n\n // Add the y-axis.\n svg.append(\"g\")\n .attr(\"transform\", `translate(${marginLeft},0)`)\n .call(d3.axisLeft(y));\n\n // Append the SVG element.\n container.append(svg.node()); \n </script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatDataForJS converts the Go data structure to a JavaScript-compatible JSON string
|
||||||
|
func formatDataForJS(data []CandleData) string {
|
||||||
|
type jsData struct {
|
||||||
|
Date string `json:"date"`
|
||||||
|
Open float64 `json:"open"`
|
||||||
|
Close float64 `json:"close"`
|
||||||
|
High float64 `json:"high"`
|
||||||
|
Low float64 `json:"low"`
|
||||||
|
}
|
||||||
|
|
||||||
|
jsDataArray := make([]jsData, len(data))
|
||||||
|
for i, d := range data {
|
||||||
|
jsDataArray[i] = jsData{
|
||||||
|
Date: d.Date.Format(time.RFC3339),
|
||||||
|
Open: d.Open,
|
||||||
|
Close: d.Close,
|
||||||
|
High: d.High,
|
||||||
|
Low: d.Low,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(jsDataArray)
|
||||||
|
if err != nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
return string(jsonBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
15
internal/ui/charts/line_chart.templ
Normal file
15
internal/ui/charts/line_chart.templ
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package charts
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
templ LineChart(data []DateValue) {
|
||||||
|
for _, d := range data {
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ d.Date }</span>
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ fmt.Sprintf("%d", d.Value) }</span>
|
||||||
|
</div>
|
||||||
|
<div class="h-1 bg-gray-200 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
70
internal/ui/charts/line_chart_templ.go
Normal file
70
internal/ui/charts/line_chart_templ.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package charts
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func LineChart(data []DateValue) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
for _, d := range data {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"flex flex-col\"><div class=\"flex justify-between\"><span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(d.Date)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/line_chart.templ`, Line: 9, Col: 61}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</span> <span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", d.Value))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/line_chart.templ`, Line: 10, Col: 81}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span></div><div class=\"h-1 bg-gray-200 rounded-full\"></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
22
internal/ui/charts/pie_chart.templ
Normal file
22
internal/ui/charts/pie_chart.templ
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package charts
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type CategoryValue struct {
|
||||||
|
Category string
|
||||||
|
Value int
|
||||||
|
ColorFrom string
|
||||||
|
ColorTo string
|
||||||
|
}
|
||||||
|
|
||||||
|
templ PieChart(data []CategoryValue) {
|
||||||
|
for _, d := range data {
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ d.Category }</span>
|
||||||
|
<span class="text-sm font-medium text-gray-900">${ fmt.Sprintf("%d", d.Value) }</span>
|
||||||
|
</div>
|
||||||
|
<div class="h-1 bg-gray-200 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
77
internal/ui/charts/pie_chart_templ.go
Normal file
77
internal/ui/charts/pie_chart_templ.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package charts
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type CategoryValue struct {
|
||||||
|
Category string
|
||||||
|
Value int
|
||||||
|
ColorFrom string
|
||||||
|
ColorTo string
|
||||||
|
}
|
||||||
|
|
||||||
|
func PieChart(data []CategoryValue) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
for _, d := range data {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"flex flex-col\"><div class=\"flex justify-between\"><span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 string
|
||||||
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(d.Category)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/pie_chart.templ`, Line: 16, Col: 65}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</span> <span class=\"text-sm font-medium text-gray-900\">$")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", d.Value))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/charts/pie_chart.templ`, Line: 17, Col: 81}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span></div><div class=\"h-1 bg-gray-200 rounded-full\"></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
113
internal/ui/layout.templ
Normal file
113
internal/ui/layout.templ
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
// Body is a component that renders the body tag
|
||||||
|
templ Body() {
|
||||||
|
<body>
|
||||||
|
{ children... }
|
||||||
|
</body>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head is a component that renders the head of the document
|
||||||
|
templ Head() {
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
@ApexCharts()
|
||||||
|
@Helia()
|
||||||
|
@Dexie()
|
||||||
|
@Htmx()
|
||||||
|
@Tailwind()
|
||||||
|
@Shoelace()
|
||||||
|
@DefaultStyles()
|
||||||
|
{ children... }
|
||||||
|
</head>
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML is a component that renders the html tag
|
||||||
|
templ HTML() {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
{ children... }
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns is a component that renders a responsive flex container that stacks on mobile
|
||||||
|
templ Columns() {
|
||||||
|
<div class="flex flex-col h-full w-full gap-4 md:gap-6 md:flex-row md:flex-wrap">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container is a component that renders a full screen container
|
||||||
|
templ Container() {
|
||||||
|
<div id="container" class="flex fixed inset-0 z-[99] w-screen min-h-screen">
|
||||||
|
<div class="relative flex flex-wrap items-center w-full min-h-full px-4 py-6 sm:px-6 md:px-8">
|
||||||
|
<div class="relative w-full max-w-screen-lg mx-auto">
|
||||||
|
<div class="flex flex-col items-center justify-center min-h-full gap-4">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tailwind css dependencies
|
||||||
|
templ Tailwind() {
|
||||||
|
@tailwindHandle.Once() {
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav is a component that renders the navigation bar
|
||||||
|
templ Nav() {
|
||||||
|
<nav class="absolute inset-x-0 top-0 z-[100] flex h-16 w-full items-center justify-between px-4 py-4 sm:px-6 md:px-8">
|
||||||
|
{ children... }
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavCTA is a component that renders a call to action button
|
||||||
|
templ NavCTA(href string, text string) {
|
||||||
|
<sl-button type="primary" href={ href }>{ text }</sl-button>
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavItem is a component that renders a navigation item
|
||||||
|
templ NavItem(href string, text string) {
|
||||||
|
<sl-button type="text" href={ href }>{ text }</sl-button>
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavLogo is a component that renders a logo
|
||||||
|
templ NavLogo(title string) {
|
||||||
|
<a href="/" class="flex items-center justify-center gap-1.5 px-2 py-2">
|
||||||
|
{ children... }
|
||||||
|
<span class="text-xl font-bold pb-1.5">{ title }</span>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavLeft is a component that renders the left side of the navigation bar
|
||||||
|
templ NavLeft() {
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ NavRight() {
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rows is a component that renders a responsive flex container that wraps on mobile
|
||||||
|
templ Rows() {
|
||||||
|
<div class="flex flex-col w-full gap-3 sm:flex-row sm:flex-wrap sm:gap-4">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ Separator(text string) {
|
||||||
|
<div class="relative py-6">
|
||||||
|
<div class="absolute inset-0 flex items-center"><span class="w-full border-t"></span></div>
|
||||||
|
<div class="relative flex justify-center text-xs uppercase">
|
||||||
|
<span class="px-2 text-neutral-500">{ text }</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
633
internal/ui/layout_templ.go
Normal file
633
internal/ui/layout_templ.go
Normal file
@@ -0,0 +1,633 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package ui
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
// Body is a component that renders the body tag
|
||||||
|
func Body() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<body>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</body>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head is a component that renders the head of the document
|
||||||
|
func Head() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var2 == nil {
|
||||||
|
templ_7745c5c3_Var2 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = ApexCharts().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = Helia().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = Dexie().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = Htmx().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = Tailwind().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = Shoelace().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = DefaultStyles().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</head>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML is a component that renders the html tag
|
||||||
|
func HTML() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var3 == nil {
|
||||||
|
templ_7745c5c3_Var3 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<!doctype html><html lang=\"en\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var3.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns is a component that renders a responsive flex container that stacks on mobile
|
||||||
|
func Columns() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var4 == nil {
|
||||||
|
templ_7745c5c3_Var4 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"flex flex-col h-full w-full gap-4 md:gap-6 md:flex-row md:flex-wrap\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var4.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container is a component that renders a full screen container
|
||||||
|
func Container() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var5 == nil {
|
||||||
|
templ_7745c5c3_Var5 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div id=\"container\" class=\"flex fixed inset-0 z-[99] w-screen min-h-screen\"><div class=\"relative flex flex-wrap items-center w-full min-h-full px-4 py-6 sm:px-6 md:px-8\"><div class=\"relative w-full max-w-screen-lg mx-auto\"><div class=\"flex flex-col items-center justify-center min-h-full gap-4\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var5.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div></div></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tailwind css dependencies
|
||||||
|
func Tailwind() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var6 == nil {
|
||||||
|
templ_7745c5c3_Var6 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<script src=\"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4\"></script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = tailwindHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav is a component that renders the navigation bar
|
||||||
|
func Nav() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var8 == nil {
|
||||||
|
templ_7745c5c3_Var8 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<nav class=\"absolute inset-x-0 top-0 z-[100] flex h-16 w-full items-center justify-between px-4 py-4 sm:px-6 md:px-8\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var8.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</nav>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavCTA is a component that renders a call to action button
|
||||||
|
func NavCTA(href string, text string) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var9 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var9 == nil {
|
||||||
|
templ_7745c5c3_Var9 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<sl-button type=\"primary\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var10 string
|
||||||
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(href)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/layout.templ`, Line: 70, Col: 38}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var11 string
|
||||||
|
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/layout.templ`, Line: 70, Col: 47}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</sl-button>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavItem is a component that renders a navigation item
|
||||||
|
func NavItem(href string, text string) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var12 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var12 == nil {
|
||||||
|
templ_7745c5c3_Var12 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<sl-button type=\"text\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var13 string
|
||||||
|
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(href)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/layout.templ`, Line: 75, Col: 35}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var14 string
|
||||||
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/layout.templ`, Line: 75, Col: 44}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</sl-button>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavLogo is a component that renders a logo
|
||||||
|
func NavLogo(title string) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var15 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var15 == nil {
|
||||||
|
templ_7745c5c3_Var15 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<a href=\"/\" class=\"flex items-center justify-center gap-1.5 px-2 py-2\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var15.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<span class=\"text-xl font-bold pb-1.5\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var16 string
|
||||||
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/layout.templ`, Line: 82, Col: 48}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</span></a>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavLeft is a component that renders the left side of the navigation bar
|
||||||
|
func NavLeft() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var17 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var17 == nil {
|
||||||
|
templ_7745c5c3_Var17 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<div class=\"flex items-center gap-4\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var17.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NavRight() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var18 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var18 == nil {
|
||||||
|
templ_7745c5c3_Var18 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<div class=\"flex items-center gap-4\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var18.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rows is a component that renders a responsive flex container that wraps on mobile
|
||||||
|
func Rows() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var19 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var19 == nil {
|
||||||
|
templ_7745c5c3_Var19 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<div class=\"flex flex-col w-full gap-3 sm:flex-row sm:flex-wrap sm:gap-4\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_Var19.Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Separator(text string) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var20 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var20 == nil {
|
||||||
|
templ_7745c5c3_Var20 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<div class=\"relative py-6\"><div class=\"absolute inset-0 flex items-center\"><span class=\"w-full border-t\"></span></div><div class=\"relative flex justify-center text-xs uppercase\"><span class=\"px-2 text-neutral-500\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var21 string
|
||||||
|
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(text)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/layout.templ`, Line: 110, Col: 45}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</span></div></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
139
internal/ui/providers.templ
Normal file
139
internal/ui/providers.templ
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var (
|
||||||
|
apexChartsHandle = templ.NewOnceHandle()
|
||||||
|
d3Handle = templ.NewOnceHandle()
|
||||||
|
dexieHandle = templ.NewOnceHandle()
|
||||||
|
heliaHandle = templ.NewOnceHandle()
|
||||||
|
htmxHandle = templ.NewOnceHandle()
|
||||||
|
tailwindHandle = templ.NewOnceHandle()
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApexCharts is a component that renders the ApexCharts.js library
|
||||||
|
templ ApexCharts() {
|
||||||
|
@apexChartsHandle.Once() {
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// d3 is a component that renders the D3.js library
|
||||||
|
templ D3() {
|
||||||
|
@d3Handle.Once() {
|
||||||
|
<script type="module">
|
||||||
|
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dexie is a component that renders the Dexie.js library
|
||||||
|
templ Dexie() {
|
||||||
|
@dexieHandle.Once() {
|
||||||
|
<script src={ jsDelivrURL("dexie", "4.0.10", "dist/dexie.min.js") }></script>
|
||||||
|
<script src={ jsDelivrURL("dexie-export-import", "4.1.4", "dist/dexie-export-import.min.js") }></script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In package deps
|
||||||
|
templ Helia() {
|
||||||
|
@heliaHandle.Once() {
|
||||||
|
<script src="https://unpkg.com/@helia/unixfs/dist/index.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/blockstore-core/dist/index.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/datastore-core/dist/index.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/helia/dist/index.min.js"></script>
|
||||||
|
<script>
|
||||||
|
// Time formatting helper
|
||||||
|
function ms2TimeString(a) {
|
||||||
|
const k = a % 1e3
|
||||||
|
const s = a / 1e3 % 60 | 0
|
||||||
|
const m = a / 6e4 % 60 | 0
|
||||||
|
const h = a / 36e5 % 24 | 0
|
||||||
|
|
||||||
|
return (h ? (h < 10 ? '0' + h : h) + ':' : '00:') +
|
||||||
|
(m < 10 ? 0 : '') + m + ':' +
|
||||||
|
(s < 10 ? 0 : '') + s + ':' +
|
||||||
|
(k < 100 ? k < 10 ? '00' : 0 : '') + k
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log management
|
||||||
|
const getLogLineEl = (msg) => {
|
||||||
|
const logLine = document.createElement('span')
|
||||||
|
logLine.innerHTML = `${ms2TimeString(performance.now())} - ${msg}`
|
||||||
|
return logLine
|
||||||
|
}
|
||||||
|
|
||||||
|
const addToLog = (msg) => {
|
||||||
|
const logEl = document.getElementById('runningLog')
|
||||||
|
if (logEl) {
|
||||||
|
logEl.appendChild(getLogLineEl(msg))
|
||||||
|
logEl.appendChild(document.createElement('br'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peer management
|
||||||
|
window.discoveredPeers = new Map()
|
||||||
|
const updateConnectedPeers = () => {
|
||||||
|
if (!window.helia || !window.helia.libp2p) return
|
||||||
|
|
||||||
|
const peers = window.helia.libp2p.getPeers()
|
||||||
|
const connectedPeerCountEl = document.getElementById('connectedPeerCount')
|
||||||
|
const connectedPeersListEl = document.getElementById('connectedPeersList')
|
||||||
|
|
||||||
|
if (connectedPeerCountEl) {
|
||||||
|
connectedPeerCountEl.innerHTML = peers.length
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectedPeersListEl) {
|
||||||
|
connectedPeersListEl.innerHTML = ''
|
||||||
|
|
||||||
|
for (const peer of peers) {
|
||||||
|
const peerEl = document.createElement('li')
|
||||||
|
peerEl.innerText = peer.toString()
|
||||||
|
connectedPeersListEl.appendChild(peerEl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateDiscoveredPeers = () => {
|
||||||
|
const discoveredPeerCountEl = document.getElementById('discoveredPeerCount')
|
||||||
|
if (discoveredPeerCountEl) {
|
||||||
|
discoveredPeerCountEl.innerHTML = window.discoveredPeers.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Helia node instantiation
|
||||||
|
let heliaInstance = null
|
||||||
|
window.instantiateHeliaNode = async () => {
|
||||||
|
// application-specific data lives in the datastore
|
||||||
|
const datastore = new DatastoreCore.MemoryDatastore()
|
||||||
|
const blockstore = new BlockstoreCore.MemoryBlockstore()
|
||||||
|
|
||||||
|
if (heliaInstance != null) {
|
||||||
|
return heliaInstance
|
||||||
|
}
|
||||||
|
heliaInstance = await Helia.createHelia({
|
||||||
|
datastore,
|
||||||
|
blockstore
|
||||||
|
})
|
||||||
|
addToLog('Created Helia instance')
|
||||||
|
return heliaInstance
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Htmx is a component that renders the Htmx.js library
|
||||||
|
templ Htmx() {
|
||||||
|
@htmxHandle.Once() {
|
||||||
|
<script src={ jsDelivrURL("htmx.org", "1.9.12", "dist/htmx.min.js") }></script>
|
||||||
|
<script src={ jsDelivrURL("htmx-ext-include-vals", "2.0.0", "include-vals.min.js") }></script>
|
||||||
|
<script src={ jsDelivrURL("htmx-ext-path-params", "2.0.0", "path-params.min.js") }></script>
|
||||||
|
<script src={ jsDelivrURL("htmx-ext-alpine-morph", "2.0.0", "alpine-morph.min.js") }></script>
|
||||||
|
<script src={ jsDelivrURL("htmx-ext-sse", "2.2.2", "sse.min.js") }></script>
|
||||||
|
<script src={ jsDelivrURL("htmx-ext-ws", "2.0.2", "ws.min.js") }></script>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsDelivrURL returns the URL of a package on jsDelivr
|
||||||
|
func jsDelivrURL(pkg string, version string, path string) string {
|
||||||
|
return fmt.Sprintf("https://cdn.jsdelivr.net/npm/%s/%s/%s", pkg, version, path)
|
||||||
|
}
|
||||||
371
internal/ui/providers_templ.go
Normal file
371
internal/ui/providers_templ.go
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package ui
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var (
|
||||||
|
apexChartsHandle = templ.NewOnceHandle()
|
||||||
|
d3Handle = templ.NewOnceHandle()
|
||||||
|
dexieHandle = templ.NewOnceHandle()
|
||||||
|
heliaHandle = templ.NewOnceHandle()
|
||||||
|
htmxHandle = templ.NewOnceHandle()
|
||||||
|
tailwindHandle = templ.NewOnceHandle()
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApexCharts is a component that renders the ApexCharts.js library
|
||||||
|
func ApexCharts() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<script src=\"https://cdn.jsdelivr.net/npm/apexcharts\"></script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = apexChartsHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// d3 is a component that renders the D3.js library
|
||||||
|
func D3() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var3 == nil {
|
||||||
|
templ_7745c5c3_Var3 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<script type=\"module\">\n import * as d3 from \"https://cdn.jsdelivr.net/npm/d3@7/+esm\";\n\t </script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = d3Handle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// dexie is a component that renders the Dexie.js library
|
||||||
|
func Dexie() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var5 == nil {
|
||||||
|
templ_7745c5c3_Var5 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("dexie", "4.0.10", "dist/dexie.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 33, Col: 67}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"></script> <script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var8 string
|
||||||
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("dexie-export-import", "4.1.4", "dist/dexie-export-import.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 34, Col: 94}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\"></script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = dexieHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// In package deps
|
||||||
|
func Helia() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var9 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var9 == nil {
|
||||||
|
templ_7745c5c3_Var9 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var10 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<script src=\"https://unpkg.com/@helia/unixfs/dist/index.min.js\"></script> <script src=\"https://unpkg.com/blockstore-core/dist/index.min.js\"></script> <script src=\"https://unpkg.com/datastore-core/dist/index.min.js\"></script> <script src=\"https://unpkg.com/helia/dist/index.min.js\"></script> <script>\n // Time formatting helper\n function ms2TimeString(a) {\n const k = a % 1e3\n const s = a / 1e3 % 60 | 0\n const m = a / 6e4 % 60 | 0\n const h = a / 36e5 % 24 | 0\n\n return (h ? (h < 10 ? '0' + h : h) + ':' : '00:') +\n (m < 10 ? 0 : '') + m + ':' +\n (s < 10 ? 0 : '') + s + ':' +\n (k < 100 ? k < 10 ? '00' : 0 : '') + k\n }\n\n // Log management\n const getLogLineEl = (msg) => {\n const logLine = document.createElement('span')\n logLine.innerHTML = `${ms2TimeString(performance.now())} - ${msg}`\n return logLine\n }\n \n const addToLog = (msg) => {\n const logEl = document.getElementById('runningLog')\n if (logEl) {\n logEl.appendChild(getLogLineEl(msg))\n logEl.appendChild(document.createElement('br'))\n }\n }\n\n // Peer management\n window.discoveredPeers = new Map()\n const updateConnectedPeers = () => {\n if (!window.helia || !window.helia.libp2p) return\n \n const peers = window.helia.libp2p.getPeers()\n const connectedPeerCountEl = document.getElementById('connectedPeerCount')\n const connectedPeersListEl = document.getElementById('connectedPeersList')\n \n if (connectedPeerCountEl) {\n connectedPeerCountEl.innerHTML = peers.length\n }\n \n if (connectedPeersListEl) {\n connectedPeersListEl.innerHTML = ''\n \n for (const peer of peers) {\n const peerEl = document.createElement('li')\n peerEl.innerText = peer.toString()\n connectedPeersListEl.appendChild(peerEl)\n }\n }\n }\n const updateDiscoveredPeers = () => {\n const discoveredPeerCountEl = document.getElementById('discoveredPeerCount')\n if (discoveredPeerCountEl) {\n discoveredPeerCountEl.innerHTML = window.discoveredPeers.size\n }\n }\n // Helia node instantiation\n let heliaInstance = null\n window.instantiateHeliaNode = async () => {\n // application-specific data lives in the datastore\n const datastore = new DatastoreCore.MemoryDatastore()\n const blockstore = new BlockstoreCore.MemoryBlockstore()\n\n if (heliaInstance != null) {\n return heliaInstance\n }\n heliaInstance = await Helia.createHelia({\n datastore,\n blockstore\n })\n addToLog('Created Helia instance')\n return heliaInstance\n }\n </script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = heliaHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var10), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Htmx is a component that renders the Htmx.js library
|
||||||
|
func Htmx() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var11 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var11 == nil {
|
||||||
|
templ_7745c5c3_Var11 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var12 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var13 string
|
||||||
|
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("htmx.org", "1.9.12", "dist/htmx.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 127, Col: 69}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\"></script> <script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var14 string
|
||||||
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("htmx-ext-include-vals", "2.0.0", "include-vals.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 128, Col: 84}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\"></script> <script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var15 string
|
||||||
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("htmx-ext-path-params", "2.0.0", "path-params.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 129, Col: 82}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\"></script> <script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var16 string
|
||||||
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("htmx-ext-alpine-morph", "2.0.0", "alpine-morph.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 130, Col: 84}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\"></script> <script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var17 string
|
||||||
|
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("htmx-ext-sse", "2.2.2", "sse.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 131, Col: 66}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\"></script> <script src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var18 string
|
||||||
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(jsDelivrURL("htmx-ext-ws", "2.0.2", "ws.min.js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/ui/providers.templ`, Line: 132, Col: 64}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"></script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = htmxHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var12), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsDelivrURL returns the URL of a package on jsDelivr
|
||||||
|
func jsDelivrURL(pkg string, version string, path string) string {
|
||||||
|
return fmt.Sprintf("https://cdn.jsdelivr.net/npm/%s/%s/%s", pkg, version, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
54
internal/ui/styles.templ
Normal file
54
internal/ui/styles.templ
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
templ DefaultStyles() {
|
||||||
|
<style>
|
||||||
|
@theme {
|
||||||
|
--color-primary: #17c2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-out {
|
||||||
|
to { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-from-right {
|
||||||
|
from { transform: translateX(90px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-to-left {
|
||||||
|
to { transform: translateX(-90px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-it {
|
||||||
|
view-transition-name: slide-it;
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(slide-it) {
|
||||||
|
animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
|
||||||
|
600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
|
||||||
|
}
|
||||||
|
::view-transition-new(slide-it) {
|
||||||
|
animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
|
||||||
|
600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shoelace dependencies
|
||||||
|
templ Shoelace() {
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
media="(prefers-color-scheme:light)"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/sonr-shoelace/cdn/themes/light.css"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
media="(prefers-color-scheme:dark)"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/sonr-shoelace/cdn/themes/dark.css"
|
||||||
|
onload="document.documentElement.classList.add('sl-theme-dark');"
|
||||||
|
/>
|
||||||
|
<script type="module" src="https://cdn.jsdelivr.net/npm/sonr-shoelace/cdn/shoelace-autoloader.js"></script>
|
||||||
|
}
|
||||||
70
internal/ui/styles_templ.go
Normal file
70
internal/ui/styles_templ.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// Code generated by templ - DO NOT EDIT.
|
||||||
|
|
||||||
|
// templ: version: v0.3.857
|
||||||
|
package ui
|
||||||
|
|
||||||
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||||
|
|
||||||
|
import "github.com/a-h/templ"
|
||||||
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
|
func DefaultStyles() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var1 == nil {
|
||||||
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<style>\n\t @theme {\n --color-primary: #17c2ff;\n }\n\n \t\t@keyframes fade-in {\n \t\tfrom { opacity: 0; }\n \t\t}\n\n \t\t@keyframes fade-out {\n \t\tto { opacity: 0; }\n \t\t}\n\n \t\t@keyframes slide-from-right {\n \t\tfrom { transform: translateX(90px); }\n \t\t}\n\n \t\t@keyframes slide-to-left {\n \t\tto { transform: translateX(-90px); }\n \t\t}\n\n \t\t.slide-it {\n \t\tview-transition-name: slide-it;\n \t\t}\n\n \t\t::view-transition-old(slide-it) {\n \t\tanimation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,\n \t\t600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;\n \t\t}\n \t\t::view-transition-new(slide-it) {\n \t\tanimation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,\n \t\t600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;\n \t\t}\n\t\t</style>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shoelace dependencies
|
||||||
|
func Shoelace() templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var2 == nil {
|
||||||
|
templ_7745c5c3_Var2 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<link rel=\"stylesheet\" media=\"(prefers-color-scheme:light)\" href=\"https://cdn.jsdelivr.net/npm/sonr-shoelace/cdn/themes/light.css\"><link rel=\"stylesheet\" media=\"(prefers-color-scheme:dark)\" href=\"https://cdn.jsdelivr.net/npm/sonr-shoelace/cdn/themes/dark.css\" onload=\"document.documentElement.classList.add('sl-theme-dark');\"><script type=\"module\" src=\"https://cdn.jsdelivr.net/npm/sonr-shoelace/cdn/shoelace-autoloader.js\"></script>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = templruntime.GeneratedTemplate
|
||||||
72
main.go
Normal file
72
main.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
//go:build js && wasm
|
||||||
|
// +build js,wasm
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/sonr-io/motr/config"
|
||||||
|
"github.com/sonr-io/motr/middleware/database"
|
||||||
|
"github.com/sonr-io/motr/middleware/kvstore"
|
||||||
|
"github.com/sonr-io/motr/middleware/session"
|
||||||
|
"github.com/sonr-io/motr/middleware/webauthn"
|
||||||
|
"github.com/syumai/workers"
|
||||||
|
"github.com/syumai/workers/cloudflare/cron"
|
||||||
|
|
||||||
|
_ "github.com/syumai/workers/cloudflare/d1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ╭──────────────────────────────────────────────────╮
|
||||||
|
// │ Initialization │
|
||||||
|
// ╰──────────────────────────────────────────────────╯
|
||||||
|
|
||||||
|
// Setup the HTTP handler
|
||||||
|
func loadHandler() http.Handler {
|
||||||
|
e := echo.New()
|
||||||
|
e.Use(
|
||||||
|
session.Middleware(),
|
||||||
|
database.Middleware(),
|
||||||
|
kvstore.Middleware(),
|
||||||
|
webauthn.Middleware(),
|
||||||
|
)
|
||||||
|
config.RegisterViews(e)
|
||||||
|
config.RegisterPartials(e)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the cron task
|
||||||
|
func loadTask() cron.Task {
|
||||||
|
return func(ctx context.Context) error {
|
||||||
|
e, err := cron.NewEvent(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(e.ScheduledTime.Unix())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ╭─────────────────────────────────────────────────╮
|
||||||
|
// │ Main Function │
|
||||||
|
// ╰─────────────────────────────────────────────────╯
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Setup CRON jobs
|
||||||
|
e := loadHandler()
|
||||||
|
t := loadTask()
|
||||||
|
|
||||||
|
// Configure Worker
|
||||||
|
cron.ScheduleTaskNonBlock(t)
|
||||||
|
workers.ServeNonBlock(e)
|
||||||
|
workers.Ready()
|
||||||
|
|
||||||
|
// Block until handler/task is done
|
||||||
|
select {
|
||||||
|
case <-workers.Done():
|
||||||
|
case <-cron.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user