feature/simplify ucan mpc did (#1195)

* feat: enable DID auth middleware

* feat: implement passkey creation flow

* feat: persist user address in cookie and retrieve user profile using address cookie

* feat: implement human verification challenge during session initialization

* refactor: remove unnecessary random number generation in profile creation

* refactor: rename credential validation handler and update related routes

* feat: improve profile validation and user experience

* feat: add page rendering for profile and passkey creation

* refactor: remove unused register handler and update routes

* refactor: remove unused imports and simplify credential validation

* fix: Correct insecure gRPC client connection

* refactor: rename models files for better organization

* refactor: refactor grpc client creation and management

* refactor: refactor common clients package

* <no value>

* feat: add CapAccount, CapInterchain, CapVault enums

* feat: add ChainId to ResAccount and ResInterchain

* feat: add asset code to resource account enumeration

* refactor: rename services package to providers

* feat: implement gateway database interactions

* refactor: move gateway repository to internal/gateway

* refactor: Migrate database provider to use sqlx

* refactor: Rename Vaults to VaultProvider in HTTPContext struct

* refactor: Migrate from GORM to sqlc Queries in database context methods

* refactor: Replace GORM with standard SQL and simplify database initialization

* refactor: Migrate session management from GORM to sqlc with type conversion

* refactor: Update import paths and model references in context package

* fix: Resolve session type conversion and middleware issues

* refactor: Migrate database from GORM to sqlx

* refactor: Move models to pkg/common, improve code structure

* refactor: move repository package to internal directory

* refactor: move gateway internal packages to context directory

* refactor: migrate database provider to use sqlx queries

* feat: add session ID to HTTP context and use it to load session data

* feat: implement vault creation API endpoint

* feat: add DIDKey generation from PubKey

* refactor: remove unused DIDAuth components

* refactor: move DID auth controller to vault context

* chore: remove unused DIDAuth package

* refactor: improve clarity of enclave refresh function

* feat: implement nonce-based key encryption for improved security

* feat: Add Export and Import methods with comprehensive tests for Enclave

* fix: Validate AES key length in keyshare encryption and decryption

* fix: Resolve key length validation by hashing input keys

* refactor: Update keyshare import to use protocol decoding

* feat: Refactor enclave encryption to support full enclave export/import

* refactor: Simplify Enclave interface methods by removing role parameter

* refactor: remove unnecessary serialization from enclave interface

* refactor: rename models package in gateway context

* refactor: rename keystore vault constants

* refactor: remove context parameter from Resolver methods

* feat: add CurrentBlock context function and update related components

* refactor: rename resolver.go to resolvers.go

* feat: Add SQLite random() generation for session and profile initialization

* refactor: Update SQL queries to use SQLite-style parameter placeholders

* refactor: Replace '?' placeholders with '$n' PostgreSQL parameter syntax

* <no value>

* refactor: refactor gateway to use middleware for database interactions and improve modularity

* feat: implement gateway for Sonr highway

* refactor: Remove unused gateway context and refactor cookie/header handling

* refactor: improve server initialization and middleware handling

* feat: implement human verification for profile creation

* feat: implement session management middleware

* refactor: refactor common models and config to internal package

* refactor: move env config to internal/config

* refactor: move database-related code to  directory

* refactor: move IPFS client to common package and improve code structure

* refactor: move querier to common package and rename to chain_query

* refactor: move webworker model to internal/models

* feat: add initial view template for Sonr.ID

* docs(concepts): Add documentation for cosmos-proto

* docs: move IBC transfer documentation to tools section

* refactor: rename initpkl.go to pkl_init.go for better naming consistency

* docs(theme): update dark mode toggle icons

* refactor: update sqlite3 driver to ncruces/go-sqlite3

* feat: add Vault model and database interactions

* refactor: Improve SQLite schema with better constraints and indexes

* chore: update project dependencies

* fix: use grpc.WithInsecure() for gRPC connection

* config: set localhost as default Sonr gRPC URL

* refactor: improve gateway middleware and refactor server initialization

* refactor: Remove foreign key pragma from schema SQL

* refactor: Remove foreign key constraints from database schema

* refactor: Convert primary key columns from INTEGER to TEXT

* refactor: Remove unnecessary redirect in error handling
This commit is contained in:
Prad Nukala
2024-12-16 20:29:54 +00:00
committed by GitHub
parent 6d27b926f6
commit 7c4586ce90
196 changed files with 4480 additions and 3192 deletions
+80
View File
@@ -0,0 +1,80 @@
package common
import (
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
nodev1beta1 "github.com/cosmos/cosmos-sdk/client/grpc/node"
didv1 "github.com/onsonr/sonr/api/did/v1"
dwnv1 "github.com/onsonr/sonr/api/dwn/v1"
svcv1 "github.com/onsonr/sonr/api/svc/v1"
"google.golang.org/grpc"
)
type (
StatusResponse = nodev1beta1.StatusResponse // StatusResponse is the response type for the Service.Status RPC method.
StatusRequest = nodev1beta1.StatusRequest // StatusRequest is the request type for the Service.Status RPC method.
BalanceRequest = bankv1beta1.QueryBalanceRequest // BalanceRequest is the request type for the Bank.Balance RPC method.
BalanceResponse = bankv1beta1.QueryBalanceResponse // BalanceResponse is the response type for the Bank.Balance RPC method.
AllBalancesRequest = bankv1beta1.QueryAllBalancesRequest // AllBalancesRequest is the request type for the Bank.AllBalances RPC method.
AllBalancesResponse = bankv1beta1.QueryAllBalancesResponse // AllBalancesResponse is the response type for the Bank.AllBalances RPC method.
TotalSupplyRequest = bankv1beta1.QueryTotalSupplyRequest // TotalSupplyRequest is the request type for the Bank.TotalSupply RPC method.
TotalSupplyResponse = bankv1beta1.QueryTotalSupplyResponse // TotalSupplyResponse is the response type for the Bank.TotalSupply RPC method.
DenomMetadataRequest = bankv1beta1.QueryDenomMetadataRequest // DenomMetadataRequest is the request type for the Bank.DenomMetadata RPC method.
DenomMetadataResponse = bankv1beta1.QueryDenomMetadataResponse // DenomMetadataResponse is the response type for the Bank.DenomMetadata RPC method.
BankParamsRequest = bankv1beta1.QueryParamsRequest // BankParamsRequest is the request type for the Bank.Params RPC method.
BankParamsResponse = bankv1beta1.QueryParamsResponse // BankParamsResponse is the response type for the Bank.Params RPC method.
DIDParamsRequest = didv1.QueryRequest // DIDParamsRequest is the request type for the DID.Params RPC method.
DIDParamsResponse = didv1.QueryParamsResponse // DIDParamsResponse is the response type for the DID.Params RPC method.
DIDResolveResponse = didv1.QueryResolveResponse // DIDResolveResponse is the response type for the DID.Resolve RPC method.
DWNParamsRequest = dwnv1.QueryParamsRequest // DWNParamsRequest is the request type for the DWN.Params RPC method.
DWNParamsResponse = dwnv1.QueryParamsResponse // DWNParamsResponse is the response type for the DWN.Params RPC method.
SVCParamsRequest = svcv1.QueryParamsRequest // SVCParamsRequest is the request type for the SVC.Params RPC method.
SVCParamsResponse = svcv1.QueryParamsResponse // SVCParamsResponse is the response type for the SVC.Params RPC method.
)
func conn(addr string) (*grpc.ClientConn, error) {
grpcConn, err := grpc.NewClient(addr, grpc.WithInsecure())
if err != nil {
return nil, err
}
return grpcConn, nil
}
func NewBankClient(addr string) (bankv1beta1.QueryClient, error) {
conn, err := conn(addr)
if err != nil {
return nil, err
}
return bankv1beta1.NewQueryClient(conn), nil
}
func NewDIDClient(addr string) (didv1.QueryClient, error) {
conn, err := conn(addr)
if err != nil {
return nil, err
}
return didv1.NewQueryClient(conn), nil
}
func NewDWNClient(addr string) (dwnv1.QueryClient, error) {
conn, err := conn(addr)
if err != nil {
return nil, err
}
return dwnv1.NewQueryClient(conn), nil
}
func NewNodeClient(addr string) (nodev1beta1.ServiceClient, error) {
conn, err := conn(addr)
if err != nil {
return nil, err
}
return nodev1beta1.NewServiceClient(conn), nil
}
func NewSVCClient(addr string) (svcv1.QueryClient, error) {
conn, err := conn(addr)
if err != nil {
return nil, err
}
return svcv1.NewQueryClient(conn), nil
}
-49
View File
@@ -1,49 +0,0 @@
package common
import (
"encoding/base64"
)
type Payment struct {
IsPayment bool `json:"isPayment"`
}
type LargeBlob struct {
Support string `json:"support"`
Write string `json:"write"`
}
type BrowserName string
const (
BrowserNameUnknown BrowserName = " Not A;Brand"
BrowserNameChromium BrowserName = "Chromium"
)
func (n BrowserName) String() string {
return string(n)
}
type PeerRole string
const (
RoleUnknown PeerRole = "none"
RoleHway PeerRole = "hway"
RoleMotr PeerRole = "motr"
)
func (r PeerRole) Is(role PeerRole) bool {
return r == role
}
func (r PeerRole) String() string {
return string(r)
}
func Base64Encode(data []byte) string {
return base64.RawURLEncoding.EncodeToString(data)
}
func Base64Decode(data string) ([]byte, error) {
return base64.RawURLEncoding.DecodeString(data)
}
-124
View File
@@ -1,124 +0,0 @@
package common
import (
"encoding/base64"
"net/http"
"time"
"github.com/labstack/echo/v4"
)
// CookieKey is a type alias for string.
type CookieKey string
const (
// SessionID is the key for the session ID cookie.
SessionID CookieKey = "session.id"
// SessionChallenge is the key for the session challenge cookie.
SessionChallenge CookieKey = "session.challenge"
// SessionRole is the key for the session role cookie.
SessionRole CookieKey = "session.role"
// SonrAddress is the key for the Sonr address cookie.
SonrAddress CookieKey = "sonr.address"
// SonrDID is the key for the Sonr DID cookie.
SonrDID CookieKey = "sonr.did"
// UserAvatar is the key for the User Avatar cookie.
UserAvatar CookieKey = "user.avatar"
// UserHandle is the key for the User Handle cookie.
UserHandle CookieKey = "user.handle"
// UserName is the key for the User Name cookie.
UserName CookieKey = "user.full_name"
// VaultAddress is the key for the Vault address cookie.
VaultAddress CookieKey = "vault.address"
// VaultCID is the key for the Vault CID cookie.
VaultCID CookieKey = "vault.cid"
// VaultSchema is the key for the Vault schema cookie.
VaultSchema CookieKey = "vault.schema"
)
// String returns the string representation of the CookieKey.
func (c CookieKey) String() string {
return string(c)
}
// ╭───────────────────────────────────────────────────────────╮
// │ Utility Methods │
// ╰───────────────────────────────────────────────────────────╯
func CookieExists(c echo.Context, key CookieKey) bool {
ck, err := c.Cookie(key.String())
if err != nil {
return false
}
return ck != nil
}
func ReadCookie(c echo.Context, key CookieKey) (string, error) {
cookie, err := c.Cookie(key.String())
if err != nil {
// Cookie not found or other error
return "", err
}
if cookie == nil || cookie.Value == "" {
// Cookie is empty
return "", http.ErrNoCookie
}
return cookie.Value, nil
}
func ReadCookieBytes(c echo.Context, key CookieKey) ([]byte, error) {
cookie, err := c.Cookie(key.String())
if err != nil {
// Cookie not found or other error
return nil, err
}
if cookie == nil || cookie.Value == "" {
// Cookie is empty
return nil, http.ErrNoCookie
}
return base64.RawURLEncoding.DecodeString(cookie.Value)
}
func ReadCookieUnsafe(c echo.Context, key CookieKey) string {
ck, err := c.Cookie(key.String())
if err != nil {
return ""
}
return ck.Value
}
func WriteCookie(c echo.Context, key CookieKey, value string) error {
cookie := &http.Cookie{
Name: key.String(),
Value: value,
Expires: time.Now().Add(24 * time.Hour),
HttpOnly: true,
Path: "/",
// Add Secure and SameSite attributes as needed
}
c.SetCookie(cookie)
return nil
}
func WriteCookieBytes(c echo.Context, key CookieKey, value []byte) error {
cookie := &http.Cookie{
Name: key.String(),
Value: base64.RawURLEncoding.EncodeToString(value),
Expires: time.Now().Add(24 * time.Hour),
HttpOnly: true,
Path: "/",
// Add Secure and SameSite attributes as needed
}
c.SetCookie(cookie)
return nil
}
-52
View File
@@ -1,52 +0,0 @@
package common
import "github.com/labstack/echo/v4"
type HeaderKey string
const (
Authorization HeaderKey = "Authorization"
// User Agent
Architecture HeaderKey = "Sec-CH-UA-Arch"
Bitness HeaderKey = "Sec-CH-UA-Bitness"
FullVersionList HeaderKey = "Sec-CH-UA-Full-Version-List"
Mobile HeaderKey = "Sec-CH-UA-Mobile"
Model HeaderKey = "Sec-CH-UA-Model"
Platform HeaderKey = "Sec-CH-UA-Platform"
PlatformVersion HeaderKey = "Sec-CH-UA-Platform-Version"
UserAgent HeaderKey = "Sec-CH-UA"
// Sonr Injected
SonrAPIURL HeaderKey = "X-Sonr-API"
SonrgRPCURL HeaderKey = "X-Sonr-GRPC"
SonrRPCURL HeaderKey = "X-Sonr-RPC"
SonrWSURL HeaderKey = "X-Sonr-WS"
)
func (h HeaderKey) String() string {
return string(h)
}
// ╭───────────────────────────────────────────────────────────╮
// │ Utility Methods │
// ╰───────────────────────────────────────────────────────────╯
func HeaderEquals(c echo.Context, key HeaderKey, value string) bool {
return c.Response().Header().Get(key.String()) == value
}
// HeaderExists returns true if the request has the header Key.
func HeaderExists(c echo.Context, key HeaderKey) bool {
return c.Response().Header().Get(key.String()) != ""
}
// HeaderRead returns the header value for the Key.
func HeaderRead(c echo.Context, key HeaderKey) string {
return c.Response().Header().Get(key.String())
}
// HeaderWrite sets the header value for the Key.
func HeaderWrite(c echo.Context, key HeaderKey, value string) {
c.Response().Header().Set(key.String(), value)
}
+136
View File
@@ -0,0 +1,136 @@
package common
import (
"bytes"
"context"
"fmt"
"io"
"github.com/ipfs/boxo/files"
"github.com/ipfs/boxo/path"
"github.com/ipfs/kubo/client/rpc"
"github.com/ipfs/kubo/core/coreiface/options"
)
// IPFS represents a wrapper interface abstracting the localhost api
type IPFS interface {
Add(data []byte) (string, error)
AddFile(file File) (string, error)
AddFolder(folder Folder) (string, error)
Exists(cid string) (bool, error)
Get(cid string) ([]byte, error)
IsPinned(ipns string) (bool, error)
Ls(cid string) ([]string, error)
Pin(cid string, name string) error
Unpin(cid string) error
}
type File interface {
files.File
Name() string
}
func NewFileMap(vs []File) map[string]files.Node {
m := make(map[string]files.Node)
for _, f := range vs {
m[f.Name()] = f
}
return m
}
type client struct {
api *rpc.HttpApi
}
func NewIPFS() (IPFS, error) {
api, err := rpc.NewLocalApi()
if err != nil {
return nil, err
}
return &client{api: api}, nil
}
func (c *client) Add(data []byte) (string, error) {
file := files.NewBytesFile(data)
cidFile, err := c.api.Unixfs().Add(context.Background(), file)
if err != nil {
return "", err
}
return cidFile.String(), nil
}
func (c *client) Get(cid string) ([]byte, error) {
p, err := path.NewPath(cid)
if err != nil {
return nil, err
}
node, err := c.api.Unixfs().Get(context.Background(), p)
if err != nil {
return nil, err
}
file, ok := node.(files.File)
if !ok {
return nil, fmt.Errorf("unexpected node type: %T", node)
}
buf := new(bytes.Buffer)
if _, err := io.Copy(buf, file); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (c *client) IsPinned(ipns string) (bool, error) {
_, err := c.api.Name().Resolve(context.Background(), ipns)
if err != nil {
return false, nil
}
return true, nil
}
func (c *client) Exists(cid string) (bool, error) {
p, err := path.NewPath(cid)
if err != nil {
return false, err
}
_, err = c.api.Block().Stat(context.Background(), p)
if err != nil {
return false, nil
}
return true, nil
}
func (c *client) Pin(cid string, name string) error {
p, err := path.NewPath(cid)
if err != nil {
return err
}
return c.api.Pin().Add(context.Background(), p, options.Pin.Name(name))
}
func (c *client) Unpin(cid string) error {
p, err := path.NewPath(cid)
if err != nil {
return err
}
return c.api.Pin().Rm(context.Background(), p)
}
func (c *client) Ls(cid string) ([]string, error) {
p, err := path.NewPath(cid)
if err != nil {
return nil, err
}
node, err := c.api.Unixfs().Ls(context.Background(), p)
if err != nil {
return nil, err
}
var files []string
for entry := range node {
files = append(files, entry.Name)
}
return files, nil
}
+28
View File
@@ -0,0 +1,28 @@
package common
import (
"context"
"github.com/ipfs/boxo/files"
)
type file struct {
files.File
name string
}
func (f *file) Name() string {
return f.name
}
func NewFile(name string, data []byte) File {
return &file{File: files.NewBytesFile(data), name: name}
}
func (c *client) AddFile(file File) (string, error) {
cidFile, err := c.api.Unixfs().Add(context.Background(), file)
if err != nil {
return "", err
}
return cidFile.String(), nil
}
+21
View File
@@ -0,0 +1,21 @@
package common
import (
"context"
"github.com/ipfs/boxo/files"
)
type Folder = files.Directory
func NewFolder(fs ...File) Folder {
return files.NewMapDirectory(NewFileMap(fs))
}
func (c *client) AddFolder(folder Folder) (string, error) {
cidFile, err := c.api.Unixfs().Add(context.Background(), folder)
if err != nil {
return "", err
}
return cidFile.String(), nil
}
-20
View File
@@ -1,20 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Account struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Name string `pkl:"name" json:"name,omitempty"`
Address any `pkl:"address" json:"address,omitempty"`
PublicKey string `pkl:"publicKey" json:"publicKey,omitempty"`
ChainCode uint `pkl:"chainCode" json:"chainCode,omitempty"`
Index int `pkl:"index" json:"index,omitempty"`
Controller string `pkl:"controller" json:"controller,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
}
-16
View File
@@ -1,16 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Asset struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Name string `pkl:"name" json:"name,omitempty"`
Symbol string `pkl:"symbol" json:"symbol,omitempty"`
Decimals int `pkl:"decimals" json:"decimals,omitempty"`
ChainCode uint `pkl:"chainCode" json:"chainCode,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
}
-14
View File
@@ -1,14 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Chain struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Name string `pkl:"name" json:"name,omitempty"`
NetworkId string `pkl:"networkId" json:"networkId,omitempty"`
ChainCode uint `pkl:"chainCode" json:"chainCode,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
}
-40
View File
@@ -1,40 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Credential struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Subject string `pkl:"subject" json:"subject,omitempty"`
Controller string `pkl:"controller" json:"controller,omitempty"`
AttestationType string `pkl:"attestationType" json:"attestationType,omitempty"`
Origin string `pkl:"origin" json:"origin,omitempty"`
Label *string `pkl:"label" json:"label,omitempty"`
DeviceId *string `pkl:"deviceId" json:"deviceId,omitempty"`
CredentialId string `pkl:"credentialId" json:"credentialId,omitempty"`
PublicKey string `pkl:"publicKey" json:"publicKey,omitempty"`
Transport []string `pkl:"transport" json:"transport,omitempty"`
SignCount uint `pkl:"signCount" json:"signCount,omitempty"`
UserPresent bool `pkl:"userPresent" json:"userPresent,omitempty"`
UserVerified bool `pkl:"userVerified" json:"userVerified,omitempty"`
BackupEligible bool `pkl:"backupEligible" json:"backupEligible,omitempty"`
BackupState bool `pkl:"backupState" json:"backupState,omitempty"`
CloneWarning bool `pkl:"cloneWarning" json:"cloneWarning,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
UpdatedAt *string `pkl:"updatedAt" json:"updatedAt,omitempty"`
}
-28
View File
@@ -1,28 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
import (
"github.com/onsonr/sonr/pkg/common/models/keyalgorithm"
"github.com/onsonr/sonr/pkg/common/models/keycurve"
"github.com/onsonr/sonr/pkg/common/models/keyencoding"
"github.com/onsonr/sonr/pkg/common/models/keyrole"
"github.com/onsonr/sonr/pkg/common/models/keytype"
)
type DID struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Role keyrole.KeyRole `pkl:"role"`
Algorithm keyalgorithm.KeyAlgorithm `pkl:"algorithm"`
Encoding keyencoding.KeyEncoding `pkl:"encoding"`
Curve keycurve.KeyCurve `pkl:"curve"`
KeyType keytype.KeyType `pkl:"key_type"`
Raw string `pkl:"raw"`
Jwk *JWK `pkl:"jwk"`
}
-20
View File
@@ -1,20 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Grant struct {
Id uint `pkl:"id" json:"id,omitempty" query:"id"`
Subject string `pkl:"subject" json:"subject,omitempty"`
Controller string `pkl:"controller" json:"controller,omitempty"`
Origin string `pkl:"origin" json:"origin,omitempty"`
Token string `pkl:"token" json:"token,omitempty"`
Scopes []string `pkl:"scopes" json:"scopes,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
UpdatedAt *string `pkl:"updatedAt" json:"updatedAt,omitempty"`
}
-16
View File
@@ -1,16 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type JWK struct {
Kty string `pkl:"kty" json:"kty,omitempty"`
Crv string `pkl:"crv" json:"crv,omitempty"`
X string `pkl:"x" json:"x,omitempty"`
Y string `pkl:"y" json:"y,omitempty"`
N string `pkl:"n" json:"n,omitempty"`
E string `pkl:"e" json:"e,omitempty"`
}
-14
View File
@@ -1,14 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Keyshare struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Data string `pkl:"data" json:"data,omitempty"`
Role int `pkl:"role" json:"role,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
LastRefreshed *string `pkl:"lastRefreshed" json:"lastRefreshed,omitempty"`
}
-39
View File
@@ -1,39 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
import (
"context"
"github.com/apple/pkl-go/pkl"
)
type Models struct {
DbName string `pkl:"db_name"`
DbVersion int `pkl:"db_version"`
}
// LoadFromPath loads the pkl module at the given path and evaluates it into a Models
func LoadFromPath(ctx context.Context, path string) (ret *Models, err error) {
evaluator, err := pkl.NewEvaluator(ctx, pkl.PreconfiguredOptions)
if err != nil {
return nil, err
}
defer func() {
cerr := evaluator.Close()
if err == nil {
err = cerr
}
}()
ret, err = Load(ctx, evaluator, pkl.FileSource(path))
return ret, err
}
// Load loads the pkl module at the given source and evaluates it with the given evaluator into a Models
func Load(ctx context.Context, evaluator pkl.Evaluator, source *pkl.ModuleSource) (*Models, error) {
var ret Models
if err := evaluator.EvaluateModule(ctx, source, &ret); err != nil {
return nil, err
}
return &ret, nil
}
-20
View File
@@ -1,20 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
type Profile struct {
Id string `pkl:"id" json:"id,omitempty" query:"id"`
Subject string `pkl:"subject" json:"subject,omitempty"`
Controller string `pkl:"controller" json:"controller,omitempty"`
OriginUri *string `pkl:"originUri" json:"originUri,omitempty"`
PublicMetadata *string `pkl:"publicMetadata" json:"publicMetadata,omitempty"`
PrivateMetadata *string `pkl:"privateMetadata" json:"privateMetadata,omitempty"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty"`
UpdatedAt *string `pkl:"updatedAt" json:"updatedAt,omitempty"`
}
@@ -1,46 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package assettype
import (
"encoding"
"fmt"
)
type AssetType string
const (
Native AssetType = "native"
Wrapped AssetType = "wrapped"
Staking AssetType = "staking"
Pool AssetType = "pool"
Ibc AssetType = "ibc"
Cw20 AssetType = "cw20"
)
// String returns the string representation of AssetType
func (rcv AssetType) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(AssetType)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for AssetType.
func (rcv *AssetType) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "native":
*rcv = Native
case "wrapped":
*rcv = Wrapped
case "staking":
*rcv = Staking
case "pool":
*rcv = Pool
case "ibc":
*rcv = Ibc
case "cw20":
*rcv = Cw20
default:
return fmt.Errorf(`illegal: "%s" is not a valid AssetType`, str)
}
return nil
}
@@ -1,52 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package didmethod
import (
"encoding"
"fmt"
)
type DIDMethod string
const (
Ipfs DIDMethod = "ipfs"
Sonr DIDMethod = "sonr"
Bitcoin DIDMethod = "bitcoin"
Ethereum DIDMethod = "ethereum"
Ibc DIDMethod = "ibc"
Webauthn DIDMethod = "webauthn"
Dwn DIDMethod = "dwn"
Service DIDMethod = "service"
)
// String returns the string representation of DIDMethod
func (rcv DIDMethod) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(DIDMethod)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for DIDMethod.
func (rcv *DIDMethod) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "ipfs":
*rcv = Ipfs
case "sonr":
*rcv = Sonr
case "bitcoin":
*rcv = Bitcoin
case "ethereum":
*rcv = Ethereum
case "ibc":
*rcv = Ibc
case "webauthn":
*rcv = Webauthn
case "dwn":
*rcv = Dwn
case "service":
*rcv = Service
default:
return fmt.Errorf(`illegal: "%s" is not a valid DIDMethod`, str)
}
return nil
}
-17
View File
@@ -1,17 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package models
import "github.com/apple/pkl-go/pkl"
func init() {
pkl.RegisterMapping("sonr.orm.Models", Models{})
pkl.RegisterMapping("sonr.orm.Models#Account", Account{})
pkl.RegisterMapping("sonr.orm.Models#Asset", Asset{})
pkl.RegisterMapping("sonr.orm.Models#Chain", Chain{})
pkl.RegisterMapping("sonr.orm.Models#Credential", Credential{})
pkl.RegisterMapping("sonr.orm.Models#DID", DID{})
pkl.RegisterMapping("sonr.orm.Models#JWK", JWK{})
pkl.RegisterMapping("sonr.orm.Models#Grant", Grant{})
pkl.RegisterMapping("sonr.orm.Models#Keyshare", Keyshare{})
pkl.RegisterMapping("sonr.orm.Models#Profile", Profile{})
}
@@ -1,46 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package keyalgorithm
import (
"encoding"
"fmt"
)
type KeyAlgorithm string
const (
Es256 KeyAlgorithm = "es256"
Es384 KeyAlgorithm = "es384"
Es512 KeyAlgorithm = "es512"
Eddsa KeyAlgorithm = "eddsa"
Es256k KeyAlgorithm = "es256k"
Ecdsa KeyAlgorithm = "ecdsa"
)
// String returns the string representation of KeyAlgorithm
func (rcv KeyAlgorithm) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(KeyAlgorithm)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for KeyAlgorithm.
func (rcv *KeyAlgorithm) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "es256":
*rcv = Es256
case "es384":
*rcv = Es384
case "es512":
*rcv = Es512
case "eddsa":
*rcv = Eddsa
case "es256k":
*rcv = Es256k
case "ecdsa":
*rcv = Ecdsa
default:
return fmt.Errorf(`illegal: "%s" is not a valid KeyAlgorithm`, str)
}
return nil
}
@@ -1,58 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package keycurve
import (
"encoding"
"fmt"
)
type KeyCurve string
const (
P256 KeyCurve = "p256"
P384 KeyCurve = "p384"
P521 KeyCurve = "p521"
X25519 KeyCurve = "x25519"
X448 KeyCurve = "x448"
Ed25519 KeyCurve = "ed25519"
Ed448 KeyCurve = "ed448"
Secp256k1 KeyCurve = "secp256k1"
Bls12381 KeyCurve = "bls12381"
Keccak256 KeyCurve = "keccak256"
)
// String returns the string representation of KeyCurve
func (rcv KeyCurve) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(KeyCurve)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for KeyCurve.
func (rcv *KeyCurve) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "p256":
*rcv = P256
case "p384":
*rcv = P384
case "p521":
*rcv = P521
case "x25519":
*rcv = X25519
case "x448":
*rcv = X448
case "ed25519":
*rcv = Ed25519
case "ed448":
*rcv = Ed448
case "secp256k1":
*rcv = Secp256k1
case "bls12381":
*rcv = Bls12381
case "keccak256":
*rcv = Keccak256
default:
return fmt.Errorf(`illegal: "%s" is not a valid KeyCurve`, str)
}
return nil
}
@@ -1,37 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package keyencoding
import (
"encoding"
"fmt"
)
type KeyEncoding string
const (
Raw KeyEncoding = "raw"
Hex KeyEncoding = "hex"
Multibase KeyEncoding = "multibase"
)
// String returns the string representation of KeyEncoding
func (rcv KeyEncoding) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(KeyEncoding)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for KeyEncoding.
func (rcv *KeyEncoding) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "raw":
*rcv = Raw
case "hex":
*rcv = Hex
case "multibase":
*rcv = Multibase
default:
return fmt.Errorf(`illegal: "%s" is not a valid KeyEncoding`, str)
}
return nil
}
-40
View File
@@ -1,40 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package keyrole
import (
"encoding"
"fmt"
)
type KeyRole string
const (
Authentication KeyRole = "authentication"
Assertion KeyRole = "assertion"
Delegation KeyRole = "delegation"
Invocation KeyRole = "invocation"
)
// String returns the string representation of KeyRole
func (rcv KeyRole) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(KeyRole)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for KeyRole.
func (rcv *KeyRole) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "authentication":
*rcv = Authentication
case "assertion":
*rcv = Assertion
case "delegation":
*rcv = Delegation
case "invocation":
*rcv = Invocation
default:
return fmt.Errorf(`illegal: "%s" is not a valid KeyRole`, str)
}
return nil
}
@@ -1,34 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package keysharerole
import (
"encoding"
"fmt"
)
type KeyShareRole string
const (
User KeyShareRole = "user"
Validator KeyShareRole = "validator"
)
// String returns the string representation of KeyShareRole
func (rcv KeyShareRole) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(KeyShareRole)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for KeyShareRole.
func (rcv *KeyShareRole) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "user":
*rcv = User
case "validator":
*rcv = Validator
default:
return fmt.Errorf(`illegal: "%s" is not a valid KeyShareRole`, str)
}
return nil
}
-55
View File
@@ -1,55 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package keytype
import (
"encoding"
"fmt"
)
type KeyType string
const (
Octet KeyType = "octet"
Elliptic KeyType = "elliptic"
Rsa KeyType = "rsa"
Symmetric KeyType = "symmetric"
Hmac KeyType = "hmac"
Mpc KeyType = "mpc"
Zk KeyType = "zk"
Webauthn KeyType = "webauthn"
Bip32 KeyType = "bip32"
)
// String returns the string representation of KeyType
func (rcv KeyType) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(KeyType)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for KeyType.
func (rcv *KeyType) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "octet":
*rcv = Octet
case "elliptic":
*rcv = Elliptic
case "rsa":
*rcv = Rsa
case "symmetric":
*rcv = Symmetric
case "hmac":
*rcv = Hmac
case "mpc":
*rcv = Mpc
case "zk":
*rcv = Zk
case "webauthn":
*rcv = Webauthn
case "bip32":
*rcv = Bip32
default:
return fmt.Errorf(`illegal: "%s" is not a valid KeyType`, str)
}
return nil
}
@@ -1,46 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package permissiongrant
import (
"encoding"
"fmt"
)
type PermissionGrant string
const (
None PermissionGrant = "none"
Read PermissionGrant = "read"
Write PermissionGrant = "write"
Verify PermissionGrant = "verify"
Broadcast PermissionGrant = "broadcast"
Admin PermissionGrant = "admin"
)
// String returns the string representation of PermissionGrant
func (rcv PermissionGrant) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(PermissionGrant)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for PermissionGrant.
func (rcv *PermissionGrant) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "none":
*rcv = None
case "read":
*rcv = Read
case "write":
*rcv = Write
case "verify":
*rcv = Verify
case "broadcast":
*rcv = Broadcast
case "admin":
*rcv = Admin
default:
return fmt.Errorf(`illegal: "%s" is not a valid PermissionGrant`, str)
}
return nil
}
@@ -1,49 +0,0 @@
// Code generated from Pkl module `sonr.orm.Models`. DO NOT EDIT.
package permissionscope
import (
"encoding"
"fmt"
)
type PermissionScope string
const (
Profile PermissionScope = "profile"
Metadata PermissionScope = "metadata"
Permissions PermissionScope = "permissions"
Wallets PermissionScope = "wallets"
Transactions PermissionScope = "transactions"
User PermissionScope = "user"
Validator PermissionScope = "validator"
)
// String returns the string representation of PermissionScope
func (rcv PermissionScope) String() string {
return string(rcv)
}
var _ encoding.BinaryUnmarshaler = new(PermissionScope)
// UnmarshalBinary implements encoding.BinaryUnmarshaler for PermissionScope.
func (rcv *PermissionScope) UnmarshalBinary(data []byte) error {
switch str := string(data); str {
case "profile":
*rcv = Profile
case "metadata":
*rcv = Metadata
case "permissions":
*rcv = Permissions
case "wallets":
*rcv = Wallets
case "transactions":
*rcv = Transactions
case "user":
*rcv = User
case "validator":
*rcv = Validator
default:
return fmt.Errorf(`illegal: "%s" is not a valid PermissionScope`, str)
}
return nil
}
-18
View File
@@ -1,18 +0,0 @@
package response
import (
"net/http"
"github.com/labstack/echo/v4"
)
func RedirectOnError(target string) echo.HTTPErrorHandler {
return func(err error, c echo.Context) {
if he, ok := err.(*echo.HTTPError); ok {
// Log the error if needed
c.Logger().Errorf("Error: %v", he.Message)
}
// Redirect to main site
c.Redirect(http.StatusFound, target)
}
}
-19
View File
@@ -1,19 +0,0 @@
package response
import (
"net/http"
"github.com/labstack/echo/v4"
)
func RedirectLanding(c echo.Context) error {
return c.Redirect(http.StatusFound, "http://localhost:3000")
}
func RedirectIPFS(c echo.Context, cid string) error {
return c.Redirect(http.StatusFound, cid)
}
func RedirectAuth(c echo.Context) error {
return c.Redirect(http.StatusFound, "http://auth.localhost:3000")
}
-67
View File
@@ -1,67 +0,0 @@
package response
import (
"bytes"
"context"
"github.com/a-h/templ"
"github.com/labstack/echo/v4"
)
// Templ renders a component to the response
func Templ(cmp templ.Component) echo.HandlerFunc {
return func(c echo.Context) error {
// Create a buffer to store the rendered HTML
buf := &bytes.Buffer{}
// Render the component to the buffer
err := cmp.Render(c.Request().Context(), buf)
if err != nil {
return err
}
// Set the content type
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
// Write the buffered content to the response
_, err = c.Response().Write(buf.Bytes())
if err != nil {
return err
}
c.Response().WriteHeader(200)
return nil
}
}
// TemplEcho renders a component to the response
func TemplEcho(c echo.Context, cmp templ.Component) error {
// Create a buffer to store the rendered HTML
buf := &bytes.Buffer{}
// Render the component to the buffer
err := cmp.Render(c.Request().Context(), buf)
if err != nil {
return err
}
// Set the content type
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
// Write the buffered content to the response
_, err = c.Response().Write(buf.Bytes())
if err != nil {
return err
}
c.Response().WriteHeader(200)
return nil
}
// / TemplRawBytes renders a component to a byte slice
func TemplRawBytes(cmp templ.Component) ([]byte, error) {
// Create a buffer to store the rendered HTML
w := bytes.NewBuffer(nil)
err := cmp.Render(context.Background(), w)
if err != nil {
return nil, err
}
dat := w.Bytes()
return dat, nil
}
+142
View File
@@ -0,0 +1,142 @@
package common
import (
"context"
"fmt"
"sort"
"sync"
"github.com/golang-jwt/jwt"
"github.com/ipfs/go-cid"
"github.com/onsonr/sonr/crypto/keys"
"github.com/onsonr/sonr/crypto/ucan"
)
type IPFSTokenStore interface {
ucan.TokenStore
ResolveCIDBytes(ctx context.Context, id cid.Cid) ([]byte, error)
ResolveDIDKey(ctx context.Context, did string) (keys.DID, error)
}
// ipfsUCANStore is a token store that uses IPFS to store tokens. It uses the memory store as a cache
// for CID strings to be used as keys for retrieving tokens.
type ipfsUCANStore struct {
sync.Mutex
ipfs IPFS
cache map[string]string
}
// NewUCANStore creates a new IPFS-backed token store
func NewUCANStore(ipfsClient IPFS) IPFSTokenStore {
return &ipfsUCANStore{
ipfs: ipfsClient,
cache: make(map[string]string),
}
}
func (st *ipfsUCANStore) PutToken(ctx context.Context, key string, raw string) error {
// Validate token format
p := &jwt.Parser{
UseJSONNumber: true,
SkipClaimsValidation: false,
}
if _, _, err := p.ParseUnverified(raw, jwt.MapClaims{}); err != nil {
return fmt.Errorf("%w: %s", ucan.ErrInvalidToken, err)
}
// Store token in IPFS
cid, err := st.ipfs.Add([]byte(raw))
if err != nil {
return fmt.Errorf("failed to store token in IPFS: %w", err)
}
// Update cache
st.Lock()
defer st.Unlock()
st.cache[key] = cid
return nil
}
func (st *ipfsUCANStore) RawToken(ctx context.Context, key string) (string, error) {
st.Lock()
cid, exists := st.cache[key]
st.Unlock()
if !exists {
return "", ucan.ErrTokenNotFound
}
// Retrieve token from IPFS
data, err := st.ipfs.Get(cid)
if err != nil {
return "", fmt.Errorf("failed to retrieve token from IPFS: %w", err)
}
return string(data), nil
}
func (st *ipfsUCANStore) DeleteToken(ctx context.Context, key string) error {
st.Lock()
defer st.Unlock()
cid, exists := st.cache[key]
if !exists {
return ucan.ErrTokenNotFound
}
// Unpin from IPFS
if err := st.ipfs.Unpin(cid); err != nil {
return fmt.Errorf("failed to unpin token from IPFS: %w", err)
}
delete(st.cache, key)
return nil
}
func (st *ipfsUCANStore) ListTokens(ctx context.Context, offset, limit int) ([]ucan.RawToken, error) {
st.Lock()
defer st.Unlock()
tokens := make(ucan.RawTokens, 0, len(st.cache))
for key, cid := range st.cache {
data, err := st.ipfs.Get(cid)
if err != nil {
continue // Skip invalid tokens
}
tokens = append(tokens, ucan.RawToken{
Key: key,
Raw: string(data),
})
}
// Sort tokens
sort.Sort(tokens)
// Apply pagination
if offset >= len(tokens) {
return []ucan.RawToken{}, nil
}
end := offset + limit
if end > len(tokens) || limit <= 0 {
end = len(tokens)
}
return tokens[offset:end], nil
}
func (st *ipfsUCANStore) ResolveCIDBytes(ctx context.Context, id cid.Cid) ([]byte, error) {
data, err := st.ipfs.Get(id.String())
if err != nil {
return nil, fmt.Errorf("failed to resolve CID bytes: %w", err)
}
return data, nil
}
func (st *ipfsUCANStore) ResolveDIDKey(ctx context.Context, did string) (keys.DID, error) {
id, err := keys.Parse(did)
if err != nil {
return keys.DID{}, fmt.Errorf("failed to parse DID: %w", err)
}
return id, nil
}
-211
View File
@@ -1,211 +0,0 @@
//go:build js && wasm
// +build js,wasm
package wasm
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"sync"
"syscall/js"
)
var (
// Global buffer pool to reduce allocations
bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
// Cached JS globals
jsGlobal = js.Global()
jsUint8Array = jsGlobal.Get("Uint8Array")
jsResponse = jsGlobal.Get("Response")
jsPromise = jsGlobal.Get("Promise")
jsWasmHTTP = jsGlobal.Get("wasmhttp")
)
// ServeFetch serves HTTP requests with optimized handler management
func ServeFetch(handler http.Handler) func() {
h := handler
if h == nil {
h = http.DefaultServeMux
}
// Optimize prefix handling
prefix := strings.TrimRight(jsWasmHTTP.Get("path").String(), "/")
if prefix != "" {
mux := http.NewServeMux()
mux.Handle(prefix+"/", http.StripPrefix(prefix, h))
h = mux
}
// Create request handler function
cb := js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
promise, resolve, reject := newPromiseOptimized()
go handleRequest(h, args[1], resolve, reject)
return promise
})
jsWasmHTTP.Call("setHandler", cb)
return cb.Release
}
// handleRequest processes the request with panic recovery
func handleRequest(h http.Handler, jsReq js.Value, resolve, reject func(interface{})) {
defer func() {
if r := recover(); r != nil {
var errMsg string
if err, ok := r.(error); ok {
errMsg = fmt.Sprintf("wasmhttp: panic: %+v", err)
} else {
errMsg = fmt.Sprintf("wasmhttp: panic: %v", r)
}
reject(errMsg)
}
}()
recorder := newResponseRecorder()
h.ServeHTTP(recorder, buildRequest(jsReq))
resolve(recorder.jsResponse())
}
// buildRequest creates an http.Request from JS Request
func buildRequest(jsReq js.Value) *http.Request {
// Get request body
arrayBuffer, err := awaitPromiseOptimized(jsReq.Call("arrayBuffer"))
if err != nil {
panic(err)
}
// Create body buffer
jsBody := jsUint8Array.New(arrayBuffer)
bodyLen := jsBody.Get("length").Int()
body := make([]byte, bodyLen)
js.CopyBytesToGo(body, jsBody)
// Create request
req := httptest.NewRequest(
jsReq.Get("method").String(),
jsReq.Get("url").String(),
bytes.NewReader(body),
)
// Set headers efficiently
headers := jsReq.Get("headers")
headersIt := headers.Call("entries")
for {
entry := headersIt.Call("next")
if entry.Get("done").Bool() {
break
}
pair := entry.Get("value")
req.Header.Set(pair.Index(0).String(), pair.Index(1).String())
}
return req
}
// ResponseRecorder with optimized buffer handling
type ResponseRecorder struct {
*httptest.ResponseRecorder
buffer *bytes.Buffer
}
func newResponseRecorder() *ResponseRecorder {
return &ResponseRecorder{
ResponseRecorder: httptest.NewRecorder(),
buffer: bufferPool.Get().(*bytes.Buffer),
}
}
// jsResponse creates a JS Response with optimized memory usage
func (rr *ResponseRecorder) jsResponse() js.Value {
defer func() {
rr.buffer.Reset()
bufferPool.Put(rr.buffer)
}()
res := rr.Result()
defer res.Body.Close()
// Prepare response body
body := js.Undefined()
if res.ContentLength != 0 {
if _, err := io.Copy(rr.buffer, res.Body); err != nil {
panic(err)
}
bodyBytes := rr.buffer.Bytes()
body = jsUint8Array.New(len(bodyBytes))
js.CopyBytesToJS(body, bodyBytes)
}
// Prepare response init object
init := make(map[string]interface{}, 3)
if res.StatusCode != 0 {
init["status"] = res.StatusCode
}
if len(res.Header) > 0 {
headers := make(map[string]interface{}, len(res.Header))
for k, v := range res.Header {
if len(v) > 0 {
headers[k] = v[0]
}
}
init["headers"] = headers
}
return jsResponse.New(body, init)
}
// newPromiseOptimized creates a new JavaScript Promise with optimized callback handling
func newPromiseOptimized() (js.Value, func(interface{}), func(interface{})) {
var (
resolve func(interface{})
reject func(interface{})
promiseFunc = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
resolve = func(v interface{}) { args[0].Invoke(v) }
reject = func(v interface{}) { args[1].Invoke(v) }
return js.Undefined()
})
)
defer promiseFunc.Release()
return jsPromise.New(promiseFunc), resolve, reject
}
// awaitPromiseOptimized waits for Promise resolution with optimized channel handling
func awaitPromiseOptimized(promise js.Value) (js.Value, error) {
done := make(chan struct{})
var (
result js.Value
err error
)
thenFunc := js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
result = args[0]
close(done)
return nil
})
defer thenFunc.Release()
catchFunc := js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
err = js.Error{Value: args[0]}
close(done)
return nil
})
defer catchFunc.Release()
promise.Call("then", thenFunc).Call("catch", catchFunc)
<-done
return result, err
}
-34
View File
@@ -1,34 +0,0 @@
//go:build js && wasm
// +build js,wasm
package wasm
import (
"encoding/base64"
"encoding/json"
"github.com/labstack/echo/v4"
)
func ContextMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Extract WASM context from headers
if wasmCtx := c.Request().Header.Get("X-Wasm-Context"); wasmCtx != "" {
if ctx, err := DecodeWasmContext(wasmCtx); err == nil {
c.Set("wasm_context", ctx)
}
}
return next(c)
}
}
// decodeWasmContext decodes the WASM context from a base64 encoded string
func DecodeWasmContext(ctx string) (map[string]any, error) {
decoded, err := base64.StdEncoding.DecodeString(ctx)
if err != nil {
return nil, err
}
var ctxData map[string]any
err = json.Unmarshal(decoded, &ctxData)
return ctxData, err
}