From 51abf59e952d654bb6acef1165c9bfbef60f09b4 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:43:48 -0700 Subject: [PATCH 01/25] read jwt and add to wazero env vars for auth --- go.mod | 1 + go.sum | 2 ++ httpserver/server.go | 3 ++- middleware/jwt.go | 50 ++++++++++++++++++++++++++++++++++++++++++++ wasmhost/wasmhost.go | 5 ++++- 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 middleware/jwt.go diff --git a/go.mod b/go.mod index aa9a44a19..ef310edb8 100644 --- a/go.mod +++ b/go.mod @@ -72,6 +72,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/google/pprof v0.0.0-20240925223930-fa3061bff0bc // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index 136674624..a216c6aff 100644 --- a/go.sum +++ b/go.sum @@ -113,6 +113,8 @@ github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/httpserver/server.go b/httpserver/server.go index dba89cd3c..e58006b84 100644 --- a/httpserver/server.go +++ b/httpserver/server.go @@ -19,6 +19,7 @@ import ( "hypruntime/graphql" "hypruntime/logger" "hypruntime/metrics" + "hypruntime/middleware" "hypruntime/utils" "github.com/rs/cors" @@ -107,7 +108,7 @@ func GetHandlerMux() http.Handler { mux := http.NewServeMux() // Register our main endpoints with instrumentation. - mux.Handle("/graphql", metrics.InstrumentHandler(graphql.HandleGraphQLRequest, "graphql")) + mux.Handle("/graphql", middleware.HandleJWT(metrics.InstrumentHandler(graphql.HandleGraphQLRequest, "graphql"))) mux.Handle("/admin", metrics.InstrumentHandler(handleAdminRequest, "admin")) // Register metrics endpoint which uses the Prometheus scraping protocol. diff --git a/middleware/jwt.go b/middleware/jwt.go new file mode 100644 index 000000000..27224a143 --- /dev/null +++ b/middleware/jwt.go @@ -0,0 +1,50 @@ +package middleware + +import ( + "context" + "hypruntime/config" + "hypruntime/logger" + "hypruntime/utils" + "net/http" + "os" + "strings" + + "github.com/golang-jwt/jwt/v5" +) + +type JWTClaimsKey string + +const JWTClaims JWTClaimsKey = "jwt_claims" + +func HandleJWT(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + tokenStr := r.Header.Get("Authorization") + + tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") + + token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, jwt.MapClaims{}) + if err != nil { + if config.IsDevEnvironment() { + logger.Debug(r.Context()).Err(err).Msg("JWT parse error") + next.ServeHTTP(w, r) + return + } + logger.Error(r.Context()).Err(err).Msg("JWT parse error") + } + + if claims, ok := token.Claims.(jwt.MapClaims); ok { + claimsJson, err := utils.JsonSerialize(claims) + if err != nil { + logger.Error(r.Context()).Err(err).Msg("JWT claims serialization error") + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + os.Setenv("JWT_CLAIMS", string(claimsJson)) + } + next.ServeHTTP(w, r) + }) +} + +func GetJWTClaims(ctx context.Context) string { + return os.Getenv("JWT_CLAIMS") +} diff --git a/wasmhost/wasmhost.go b/wasmhost/wasmhost.go index 4ce28c2cd..17bbeb245 100644 --- a/wasmhost/wasmhost.go +++ b/wasmhost/wasmhost.go @@ -12,6 +12,7 @@ import ( "hypruntime/functions" "hypruntime/logger" + "hypruntime/middleware" "hypruntime/plugins" "hypruntime/utils" @@ -110,11 +111,13 @@ func (host *wasmHost) GetModuleInstance(ctx context.Context, plugin *plugins.Plu // for concurrency and performance reasons. // See https://github.com/tetratelabs/wazero/pull/2275 // And https://gophers.slack.com/archives/C040AKTNTE0/p1719587772724619?thread_ts=1719522663.531579&cid=C040AKTNTE0 + jwtClaims := middleware.GetJWTClaims(ctx) cfg := wazero.NewModuleConfig(). WithName(""). WithSysWalltime().WithSysNanotime(). WithRandSource(rand.Reader). - WithStdout(wOut).WithStderr(wErr) + WithStdout(wOut).WithStderr(wErr). + WithEnv("JWT_CLAIMS", jwtClaims) // Instantiate the plugin as a module. // NOTE: This will also invoke the plugin's `_start` function, From bfdf8c4c1f42c721960cf7b241edaf7b2fe15723 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:39:28 -0700 Subject: [PATCH 02/25] make jwt storage threadsafe --- middleware/jwt.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/middleware/jwt.go b/middleware/jwt.go index 27224a143..16265f214 100644 --- a/middleware/jwt.go +++ b/middleware/jwt.go @@ -6,7 +6,6 @@ import ( "hypruntime/logger" "hypruntime/utils" "net/http" - "os" "strings" "github.com/golang-jwt/jwt/v5" @@ -18,6 +17,7 @@ const JWTClaims JWTClaimsKey = "jwt_claims" func HandleJWT(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") @@ -39,12 +39,15 @@ func HandleJWT(next http.Handler) http.Handler { http.Error(w, "Internal server error", http.StatusInternalServerError) return } - os.Setenv("JWT_CLAIMS", string(claimsJson)) + ctx = context.WithValue(ctx, JWTClaims, string(claimsJson)) } - next.ServeHTTP(w, r) + next.ServeHTTP(w, r.WithContext(ctx)) }) } func GetJWTClaims(ctx context.Context) string { - return os.Getenv("JWT_CLAIMS") + if claims, ok := ctx.Value(JWTClaims).(string); ok { + return claims + } + return "" } From edd7defd8d7561e76233e84d4a76cb155a4c7439 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:21:48 -0700 Subject: [PATCH 03/25] resolve conflicts --- runtime/go.mod | 1 + runtime/go.sum | 2 ++ runtime/httpserver/server.go | 5 +---- {middleware => runtime/middleware}/jwt.go | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename {middleware => runtime/middleware}/jwt.go (100%) diff --git a/runtime/go.mod b/runtime/go.mod index 126063110..19a060a65 100644 --- a/runtime/go.mod +++ b/runtime/go.mod @@ -23,6 +23,7 @@ require ( github.com/getsentry/sentry-go v0.29.0 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/goccy/go-json v0.10.3 + github.com/golang-jwt/jwt/v5 v5.2.0 github.com/google/renameio v1.0.1 github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.7.1 diff --git a/runtime/go.sum b/runtime/go.sum index aca603e60..8cb4fcfd7 100644 --- a/runtime/go.sum +++ b/runtime/go.sum @@ -111,6 +111,8 @@ github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/runtime/httpserver/server.go b/runtime/httpserver/server.go index 0a8da43e4..c27aa31d8 100644 --- a/runtime/httpserver/server.go +++ b/runtime/httpserver/server.go @@ -113,10 +113,7 @@ func GetHandlerMux() http.Handler { mux := http.NewServeMux() // Register our main endpoints with instrumentation. - mux.Handle("/graphql", middleware.HandleJWT(metrics.InstrumentHandler(graphql.HandleGraphQLRequest, "graphql"))) - mux.Handle("/admin", metrics.InstrumentHandler(handleAdminRequest, "admin")) - // Register our main endpoint with instrumentation. - mux.Handle("/graphql", metrics.InstrumentHandler(graphql.GraphQLRequestHandler, "graphql")) + mux.Handle("/graphql", metrics.InstrumentHandler(middleware.HandleJWT(graphql.GraphQLRequestHandler), "graphql")) // Register metrics endpoint which uses the Prometheus scraping protocol. // We do not instrument it with the InstrumentHandler so that any scraper (eg. OTel) diff --git a/middleware/jwt.go b/runtime/middleware/jwt.go similarity index 100% rename from middleware/jwt.go rename to runtime/middleware/jwt.go From 1f26b8c9e3c94cf0d4de998b3619bbb0aad210ce Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 19:42:35 -0700 Subject: [PATCH 04/25] add RSA public key verification --- runtime/middleware/jwt.go | 45 ++++++++++++++++++++++++++-------- sdk/go/examples/simple/main.go | 4 +++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 16265f214..21f1c93bd 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -2,12 +2,15 @@ package middleware import ( "context" - "hypruntime/config" - "hypruntime/logger" - "hypruntime/utils" + "encoding/json" "net/http" + "os" "strings" + "github.com/hypermodeinc/modus/runtime/config" + "github.com/hypermodeinc/modus/runtime/logger" + "github.com/hypermodeinc/modus/runtime/utils" + "github.com/golang-jwt/jwt/v5" ) @@ -20,16 +23,38 @@ func HandleJWT(next http.Handler) http.Handler { var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") - tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") + privKeysStr := os.Getenv("MODUS_PRIV_KEYS") + if privKeysStr == "" { + next.ServeHTTP(w, r) + return + } - token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, jwt.MapClaims{}) + var privKeysUnmarshalled []string + err := json.Unmarshal([]byte(privKeysStr), &privKeysUnmarshalled) if err != nil { - if config.IsDevEnvironment() { - logger.Debug(r.Context()).Err(err).Msg("JWT parse error") - next.ServeHTTP(w, r) - return + logger.Error(r.Context()).Err(err).Msg("JWT private keys unmarshalling error") + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + + var token *jwt.Token + + tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") + for _, privKey := range privKeysUnmarshalled { + token, err = jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { + return jwt.ParseRSAPublicKeyFromPEM([]byte(privKey)) + }) + if err != nil { + if config.IsDevEnvironment() { + logger.Debug(r.Context()).Err(err).Msg("JWT parse error") + next.ServeHTTP(w, r) + return + } + logger.Error(r.Context()).Err(err).Msg("JWT parse error") + continue + } else { + break } - logger.Error(r.Context()).Err(err).Msg("JWT parse error") } if claims, ok := token.Claims.(jwt.MapClaims); ok { diff --git a/sdk/go/examples/simple/main.go b/sdk/go/examples/simple/main.go index f478260dd..3bedc5896 100644 --- a/sdk/go/examples/simple/main.go +++ b/sdk/go/examples/simple/main.go @@ -182,3 +182,7 @@ func TestLogging() { // // The console functions also allow you to better control the reported logging level. } + +func TestEnvVars() string { + return os.Getenv("JWT_CLAIMS") +} From d33617b9c5857990d6422a78d9e447442ebafb24 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:37:47 -0700 Subject: [PATCH 05/25] add better local dev logic --- cspell.json | 6 +++++- runtime/middleware/jwt.go | 40 ++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/cspell.json b/cspell.json index 51fcc46f1..b02a4e574 100644 --- a/cspell.json +++ b/cspell.json @@ -1,7 +1,10 @@ { "version": "0.2", "language": "en", - "flagWords": ["hte", "teh"], + "flagWords": [ + "hte", + "teh" + ], "words": [ "abstractlogger", "Albus", @@ -153,6 +156,7 @@ "typedarray", "uids", "uncategorized", + "Unmarshalled", "unmarshalling", "unnest", "upsert", diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 21f1c93bd..6a03f1f0a 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -22,14 +22,30 @@ func HandleJWT(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") + tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") privKeysStr := os.Getenv("MODUS_PRIV_KEYS") if privKeysStr == "" { - next.ServeHTTP(w, r) - return + if tokenStr == "" { + next.ServeHTTP(w, r) + return + } + if config.IsDevEnvironment() { + token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, jwt.MapClaims{}) + if err != nil { + logger.Debug(r.Context()).Err(err).Msg("JWT parse error") + next.ServeHTTP(w, r) + return + } + if claims, ok := token.Claims.(jwt.MapClaims); ok { + ctx = AddClaimsToContext(ctx, claims) + } + next.ServeHTTP(w, r.WithContext(ctx)) + return + } } - var privKeysUnmarshalled []string + var privKeysUnmarshalled map[string]string err := json.Unmarshal([]byte(privKeysStr), &privKeysUnmarshalled) if err != nil { logger.Error(r.Context()).Err(err).Msg("JWT private keys unmarshalling error") @@ -39,7 +55,6 @@ func HandleJWT(next http.Handler) http.Handler { var token *jwt.Token - tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") for _, privKey := range privKeysUnmarshalled { token, err = jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { return jwt.ParseRSAPublicKeyFromPEM([]byte(privKey)) @@ -58,18 +73,21 @@ func HandleJWT(next http.Handler) http.Handler { } if claims, ok := token.Claims.(jwt.MapClaims); ok { - claimsJson, err := utils.JsonSerialize(claims) - if err != nil { - logger.Error(r.Context()).Err(err).Msg("JWT claims serialization error") - http.Error(w, "Internal server error", http.StatusInternalServerError) - return - } - ctx = context.WithValue(ctx, JWTClaims, string(claimsJson)) + ctx = AddClaimsToContext(ctx, claims) } next.ServeHTTP(w, r.WithContext(ctx)) }) } +func AddClaimsToContext(ctx context.Context, claims jwt.MapClaims) context.Context { + claimsJson, err := utils.JsonSerialize(claims) + if err != nil { + logger.Error(ctx).Err(err).Msg("JWT claims serialization error") + return ctx + } + return context.WithValue(ctx, JWTClaims, string(claimsJson)) +} + func GetJWTClaims(ctx context.Context) string { if claims, ok := ctx.Value(JWTClaims).(string); ok { return claims From cd919be13ec7d9ff5e439c2045efbe63f326b182 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:06:13 -0700 Subject: [PATCH 06/25] add assemblyscript sdk for auth --- runtime/middleware/jwt.go | 2 +- sdk/assemblyscript/examples/auth/.prettierrc | 3 + sdk/assemblyscript/examples/auth/README.md | 6 + .../examples/auth/asconfig.json | 6 + .../examples/auth/assembly/index.ts | 25 + .../examples/auth/assembly/tsconfig.json | 4 + .../examples/auth/eslint.config.js | 11 + .../examples/auth/hypermode.json | 12 + .../examples/auth/package-lock.json | 3391 +++++++++++++++++ sdk/assemblyscript/examples/auth/package.json | 32 + .../examples/simple/package-lock.json | 2 +- sdk/assemblyscript/src/assembly/auth.ts | 15 + sdk/assemblyscript/src/assembly/index.ts | 3 + 13 files changed, 3510 insertions(+), 2 deletions(-) create mode 100644 sdk/assemblyscript/examples/auth/.prettierrc create mode 100644 sdk/assemblyscript/examples/auth/README.md create mode 100644 sdk/assemblyscript/examples/auth/asconfig.json create mode 100644 sdk/assemblyscript/examples/auth/assembly/index.ts create mode 100644 sdk/assemblyscript/examples/auth/assembly/tsconfig.json create mode 100644 sdk/assemblyscript/examples/auth/eslint.config.js create mode 100644 sdk/assemblyscript/examples/auth/hypermode.json create mode 100644 sdk/assemblyscript/examples/auth/package-lock.json create mode 100644 sdk/assemblyscript/examples/auth/package.json create mode 100644 sdk/assemblyscript/src/assembly/auth.ts diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 6a03f1f0a..12a49ef07 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -24,7 +24,7 @@ func HandleJWT(next http.Handler) http.Handler { tokenStr := r.Header.Get("Authorization") tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") - privKeysStr := os.Getenv("MODUS_PRIV_KEYS") + privKeysStr := os.Getenv("MODUS_RSA_PEMS") if privKeysStr == "" { if tokenStr == "" { next.ServeHTTP(w, r) diff --git a/sdk/assemblyscript/examples/auth/.prettierrc b/sdk/assemblyscript/examples/auth/.prettierrc new file mode 100644 index 000000000..64cb35ca8 --- /dev/null +++ b/sdk/assemblyscript/examples/auth/.prettierrc @@ -0,0 +1,3 @@ +{ + "plugins": ["assemblyscript-prettier"] +} diff --git a/sdk/assemblyscript/examples/auth/README.md b/sdk/assemblyscript/examples/auth/README.md new file mode 100644 index 000000000..27e631817 --- /dev/null +++ b/sdk/assemblyscript/examples/auth/README.md @@ -0,0 +1,6 @@ +# Hypermode Simple Example Plugin + +This is a _very_ simple example showing how to write a Hypermode plugin. +It doesn't do very much, but it should illustrate how to write a function. + +See [./assembly/index.ts](./assembly/index.ts) for the implementation. diff --git a/sdk/assemblyscript/examples/auth/asconfig.json b/sdk/assemblyscript/examples/auth/asconfig.json new file mode 100644 index 000000000..d8372651f --- /dev/null +++ b/sdk/assemblyscript/examples/auth/asconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/@hypermode/modus-sdk-as/plugin.asconfig.json", + "options": { + "transform": ["@hypermode/modus-sdk-as/transform", "json-as/transform"] + } +} diff --git a/sdk/assemblyscript/examples/auth/assembly/index.ts b/sdk/assemblyscript/examples/auth/assembly/index.ts new file mode 100644 index 000000000..87a6ebf82 --- /dev/null +++ b/sdk/assemblyscript/examples/auth/assembly/index.ts @@ -0,0 +1,25 @@ +/* + * This example is part of the Modus project, licensed under the Apache License 2.0. + * You may modify and use this example in accordance with the license. + * See the LICENSE file that accompanied this code for further details. + */ + +import { auth } from "@hypermode/modus-sdk-as"; + + +@json +export class Claims { + public exp!: i64; + public iat!: i64; + public iss!: string; + public jti!: string; + public nbf!: i64; + public sub!: string; + + + @alias("user-id") + public userId!: string; +} +export function getJWTClaims(): Claims { + return auth.jwt.getClaims(); +} diff --git a/sdk/assemblyscript/examples/auth/assembly/tsconfig.json b/sdk/assemblyscript/examples/auth/assembly/tsconfig.json new file mode 100644 index 000000000..798b474ea --- /dev/null +++ b/sdk/assemblyscript/examples/auth/assembly/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "assemblyscript/std/assembly.json", + "include": ["./**/*.ts"] +} diff --git a/sdk/assemblyscript/examples/auth/eslint.config.js b/sdk/assemblyscript/examples/auth/eslint.config.js new file mode 100644 index 000000000..7ad50aead --- /dev/null +++ b/sdk/assemblyscript/examples/auth/eslint.config.js @@ -0,0 +1,11 @@ +// @ts-check + +import eslint from "@eslint/js"; +import tseslint from "typescript-eslint"; +import aseslint from "@hypermode/modus-sdk-as/tools/assemblyscript-eslint"; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, + aseslint.config, +); diff --git a/sdk/assemblyscript/examples/auth/hypermode.json b/sdk/assemblyscript/examples/auth/hypermode.json new file mode 100644 index 000000000..76c0b20a5 --- /dev/null +++ b/sdk/assemblyscript/examples/auth/hypermode.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://manifest.hypermode.com/hypermode.json", + "models": { + // No models are used by this example, but if you add any, they would go here. + }, + "hosts": { + // No hosts are used by this example, but if you add any, they would go here. + }, + "collections": { + // No collections are used by this example, but if you add any, they would go here. + } +} diff --git a/sdk/assemblyscript/examples/auth/package-lock.json b/sdk/assemblyscript/examples/auth/package-lock.json new file mode 100644 index 000000000..77ec981c6 --- /dev/null +++ b/sdk/assemblyscript/examples/auth/package-lock.json @@ -0,0 +1,3391 @@ +{ + "name": "simple-example", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "simple-example", + "license": "Apache-2.0", + "dependencies": { + "@hypermode/modus-sdk-as": "../../src", + "json-as": "^0.9.21" + }, + "devDependencies": { + "@eslint/js": "^9.11.1", + "@types/eslint__js": "^8.42.3", + "assemblyscript": "^0.27.30", + "assemblyscript-prettier": "^3.0.1", + "eslint": "^9.11.1", + "prettier": "^3.3.3", + "typescript": "^5.6.2", + "typescript-eslint": "^8.8.0", + "visitor-as": "^0.11.4" + } + }, + "../../src": { + "name": "@hypermode/modus-sdk-as", + "version": "0.12.0", + "license": "Apache-2.0", + "dependencies": { + "@assemblyscript/wasi-shim": "^0.1.0", + "json-as": "^0.9.21", + "semver": "^7.6.3", + "xid-ts": "^1.1.4" + }, + "devDependencies": { + "@eslint/js": "^9.12.0", + "@types/eslint__js": "^8.42.3", + "@types/node": "^20.16.10", + "as-test": "^0.3.5", + "assemblyscript": "^0.27.30", + "assemblyscript-prettier": "^3.0.1", + "eslint": "^9.12.0", + "prettier": "^3.3.3", + "typescript": "^5.6.2", + "typescript-eslint": "^8.8.0", + "visitor-as": "^0.11.4" + } + }, + "../../src/node_modules/@assemblyscript/wasi-shim": { + "version": "0.1.0", + "license": "Apache-2.0", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/assemblyscript" + } + }, + "../../src/node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "../../src/node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "../../src/node_modules/@eslint/config-array": { + "version": "0.18.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "../../src/node_modules/@eslint/core": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "../../src/node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../src/node_modules/@eslint/js": { + "version": "9.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "../../src/node_modules/@eslint/object-schema": { + "version": "2.1.4", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "../../src/node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "../../src/node_modules/@humanfs/core": { + "version": "0.19.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "../../src/node_modules/@humanfs/node": { + "version": "0.16.5", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "../../src/node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "../../src/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "../../src/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "../../src/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "../../src/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "../../src/node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "../../src/node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "../../src/node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "../../src/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "../../src/node_modules/@types/eslint": { + "version": "9.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "../../src/node_modules/@types/eslint__js": { + "version": "8.42.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*" + } + }, + "../../src/node_modules/@types/estree": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/@types/node": { + "version": "20.16.10", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "../../src/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/type-utils": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../../src/node_modules/@typescript-eslint/parser": { + "version": "8.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../../src/node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "../../src/node_modules/@typescript-eslint/type-utils": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../../src/node_modules/@typescript-eslint/types": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "../../src/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../../src/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../src/node_modules/@typescript-eslint/utils": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "../../src/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "../../src/node_modules/acorn": { + "version": "8.12.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "../../src/node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "../../src/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "../../src/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "../../src/node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "../../src/node_modules/as-console": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "as-rainbow": "^0.1.0", + "table-as": "^1.0.1" + } + }, + "../../src/node_modules/as-rainbow": { + "version": "0.1.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/as-test": { + "version": "0.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "as-console": "^7.0.0", + "as-rainbow": "^0.1.0", + "as-variant": "^0.4.1", + "chalk": "^5.3.0", + "glob": "^11.0.0", + "json-as": "^0.9.14", + "typer-diff": "^1.1.1" + }, + "bin": { + "as-test": "bin/index.js", + "ast": "bin/index.js" + } + }, + "../../src/node_modules/as-test/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "../../src/node_modules/as-test/node_modules/glob": { + "version": "11.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../src/node_modules/as-test/node_modules/minimatch": { + "version": "10.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../src/node_modules/as-variant": { + "version": "0.4.1", + "dev": true + }, + "../../src/node_modules/as-virtual": { + "version": "0.2.0", + "license": "MIT" + }, + "../../src/node_modules/assemblyscript": { + "version": "0.27.30", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "binaryen": "116.0.0-nightly.20240114", + "long": "^5.2.1" + }, + "bin": { + "asc": "bin/asc.js", + "asinit": "bin/asinit.js" + }, + "engines": { + "node": ">=16", + "npm": ">=7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/assemblyscript" + } + }, + "../../src/node_modules/assemblyscript-prettier": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "assemblyscript": "~0.27.0" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "../../src/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/binaryen": { + "version": "116.0.0-nightly.20240114", + "dev": true, + "license": "Apache-2.0", + "bin": { + "wasm-opt": "bin/wasm-opt", + "wasm2js": "bin/wasm2js" + } + }, + "../../src/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "../../src/node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "../../src/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "../../src/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "../../src/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "../../src/node_modules/debug": { + "version": "4.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "../../src/node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/eslint": { + "version": "9.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.12.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "../../src/node_modules/eslint-scope": { + "version": "8.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../src/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../src/node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../src/node_modules/espree": { + "version": "10.2.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../src/node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../src/node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "../../src/node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "../../src/node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "../../src/node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "../../src/node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "../../src/node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "../../src/node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "../../src/node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../../src/node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "../../src/node_modules/flatted": { + "version": "3.3.1", + "dev": true, + "license": "ISC" + }, + "../../src/node_modules/foreground-child": { + "version": "3.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../src/node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "../../src/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "../../src/node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "../../src/node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../src/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "../../src/node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "../../src/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "../../src/node_modules/jackspeak": { + "version": "4.0.1", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "../../src/node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "../../src/node_modules/json-as": { + "version": "0.9.21", + "license": "MIT", + "dependencies": { + "as-virtual": "^0.2.0" + } + }, + "../../src/node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "../../src/node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../../src/node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/lodash.clonedeep": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/long": { + "version": "5.2.3", + "dev": true, + "license": "Apache-2.0" + }, + "../../src/node_modules/lru-cache": { + "version": "11.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "../../src/node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "../../src/node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "../../src/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "../../src/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "../../src/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "../../src/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../../src/node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/package-json-from-dist": { + "version": "1.0.0", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "../../src/node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "../../src/node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/path-scurry": { + "version": "2.0.0", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../src/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "../../src/node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "../../src/node_modules/prettier": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "../../src/node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "../../src/node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "../../src/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "../../src/node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "../../src/node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "../../src/node_modules/semver": { + "version": "7.6.3", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "../../src/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../src/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "../../src/node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "../../src/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../src/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/table-as": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "../../src/node_modules/ts-api-utils": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "../../src/node_modules/ts-mixer": { + "version": "6.0.4", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../../src/node_modules/typer-diff": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "typescript": "^5.5.2" + } + }, + "../../src/node_modules/typescript": { + "version": "5.6.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "../../src/node_modules/typescript-eslint": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.8.0", + "@typescript-eslint/parser": "8.8.0", + "@typescript-eslint/utils": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../../src/node_modules/undici-types": { + "version": "6.19.8", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "../../src/node_modules/visitor-as": { + "version": "0.11.4", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "ts-mixer": "^6.0.2" + }, + "peerDependencies": { + "assemblyscript": "^0.25.0" + } + }, + "../../src/node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "../../src/node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../src/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "../../src/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "../../src/node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "../../src/node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../src/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "../../src/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "../../src/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "../../src/node_modules/xid-ts": { + "version": "1.1.4", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "../../src/node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.11.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@hypermode/modus-sdk-as": { + "resolved": "../../src", + "link": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint__js": { + "version": "8.42.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/type-utils": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/as-virtual": { + "version": "0.2.0", + "license": "MIT" + }, + "node_modules/assemblyscript": { + "version": "0.27.30", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "binaryen": "116.0.0-nightly.20240114", + "long": "^5.2.1" + }, + "bin": { + "asc": "bin/asc.js", + "asinit": "bin/asinit.js" + }, + "engines": { + "node": ">=16", + "npm": ">=7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/assemblyscript" + } + }, + "node_modules/assemblyscript-prettier": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "assemblyscript": "~0.27.0" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/binaryen": { + "version": "116.0.0-nightly.20240114", + "dev": true, + "license": "Apache-2.0", + "bin": { + "wasm-opt": "bin/wasm-opt", + "wasm2js": "bin/wasm2js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.11.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.11.1", + "@eslint/plugin-kit": "^0.2.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.0.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-as": { + "version": "0.9.21", + "license": "MIT", + "dependencies": { + "as-virtual": "^0.2.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.2.3", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.8.0", + "@typescript-eslint/parser": "8.8.0", + "@typescript-eslint/utils": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/visitor-as": { + "version": "0.11.4", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "ts-mixer": "^6.0.2" + }, + "peerDependencies": { + "assemblyscript": "^0.25.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/sdk/assemblyscript/examples/auth/package.json b/sdk/assemblyscript/examples/auth/package.json new file mode 100644 index 000000000..3ff4d6e84 --- /dev/null +++ b/sdk/assemblyscript/examples/auth/package.json @@ -0,0 +1,32 @@ +{ + "name": "simple-example", + "private": true, + "description": "Modus AssemblyScript Simple Example", + "author": "Hypermode Inc.", + "license": "Apache-2.0", + "type": "module", + "scripts": { + "build": "node ./node_modules/@hypermode/modus-sdk-as/bin/build-plugin.js", + "lint": "eslint .", + "pretty": "prettier --write .", + "pretty:check": "prettier --check ." + }, + "dependencies": { + "@hypermode/modus-sdk-as": "../../src", + "json-as": "^0.9.21" + }, + "devDependencies": { + "@eslint/js": "^9.11.1", + "@types/eslint__js": "^8.42.3", + "assemblyscript": "^0.27.30", + "assemblyscript-prettier": "^3.0.1", + "eslint": "^9.11.1", + "prettier": "^3.3.3", + "typescript": "^5.6.2", + "typescript-eslint": "^8.8.0", + "visitor-as": "^0.11.4" + }, + "overrides": { + "assemblyscript": "$assemblyscript" + } +} diff --git a/sdk/assemblyscript/examples/simple/package-lock.json b/sdk/assemblyscript/examples/simple/package-lock.json index 94e204712..77ec981c6 100644 --- a/sdk/assemblyscript/examples/simple/package-lock.json +++ b/sdk/assemblyscript/examples/simple/package-lock.json @@ -36,7 +36,7 @@ "@eslint/js": "^9.12.0", "@types/eslint__js": "^8.42.3", "@types/node": "^20.16.10", - "as-test": "^0.3.4", + "as-test": "^0.3.5", "assemblyscript": "^0.27.30", "assemblyscript-prettier": "^3.0.1", "eslint": "^9.12.0", diff --git a/sdk/assemblyscript/src/assembly/auth.ts b/sdk/assemblyscript/src/assembly/auth.ts new file mode 100644 index 000000000..2d8d6c93c --- /dev/null +++ b/sdk/assemblyscript/src/assembly/auth.ts @@ -0,0 +1,15 @@ +/* + * Copyright 2024 Hypermode Inc. + * Licensed under the terms of the Apache License, Version 2.0 + * See the LICENSE file that accompanied this code for further details. + * + * SPDX-FileCopyrightText: 2024 Hypermode Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import { JSON } from "json-as"; + +export class jwt { + public static getClaims(): T { + return JSON.parse(process.env.get("JWT_CLAIMS")); + } +} diff --git a/sdk/assemblyscript/src/assembly/index.ts b/sdk/assemblyscript/src/assembly/index.ts index 766edd82b..db4450e9e 100644 --- a/sdk/assemblyscript/src/assembly/index.ts +++ b/sdk/assemblyscript/src/assembly/index.ts @@ -30,3 +30,6 @@ export { models }; import * as vectors from "./vectors"; export { vectors }; + +import * as auth from "./auth"; +export { auth }; From 38878379d80f1b2aa6b7898adcb40d7a39615090 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:26:14 -0700 Subject: [PATCH 07/25] add go auth exmples and sdk code --- sdk/assemblyscript/examples/auth/README.md | 5 +--- .../examples/auth/assembly/index.ts | 2 +- sdk/assemblyscript/examples/auth/package.json | 2 +- sdk/assemblyscript/src/assembly/auth.ts | 8 +++--- sdk/go/examples/auth/build.cmd | 12 +++++++++ sdk/go/examples/auth/build.sh | 12 +++++++++ sdk/go/examples/auth/go.mod | 7 ++++++ sdk/go/examples/auth/hypermode.json | 12 +++++++++ sdk/go/examples/auth/main.go | 25 +++++++++++++++++++ sdk/go/examples/simple/main.go | 4 --- sdk/go/pkg/auth/jwt.go | 24 ++++++++++++++++++ 11 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 sdk/go/examples/auth/build.cmd create mode 100755 sdk/go/examples/auth/build.sh create mode 100644 sdk/go/examples/auth/go.mod create mode 100644 sdk/go/examples/auth/hypermode.json create mode 100644 sdk/go/examples/auth/main.go create mode 100644 sdk/go/pkg/auth/jwt.go diff --git a/sdk/assemblyscript/examples/auth/README.md b/sdk/assemblyscript/examples/auth/README.md index 27e631817..660f88143 100644 --- a/sdk/assemblyscript/examples/auth/README.md +++ b/sdk/assemblyscript/examples/auth/README.md @@ -1,6 +1,3 @@ # Hypermode Simple Example Plugin -This is a _very_ simple example showing how to write a Hypermode plugin. -It doesn't do very much, but it should illustrate how to write a function. - -See [./assembly/index.ts](./assembly/index.ts) for the implementation. +This is an example showing how to write a Hypermode plugin that uses auth. diff --git a/sdk/assemblyscript/examples/auth/assembly/index.ts b/sdk/assemblyscript/examples/auth/assembly/index.ts index 87a6ebf82..0217c1077 100644 --- a/sdk/assemblyscript/examples/auth/assembly/index.ts +++ b/sdk/assemblyscript/examples/auth/assembly/index.ts @@ -21,5 +21,5 @@ export class Claims { public userId!: string; } export function getJWTClaims(): Claims { - return auth.jwt.getClaims(); + return auth.getJWTClaims(); } diff --git a/sdk/assemblyscript/examples/auth/package.json b/sdk/assemblyscript/examples/auth/package.json index 3ff4d6e84..867a5a512 100644 --- a/sdk/assemblyscript/examples/auth/package.json +++ b/sdk/assemblyscript/examples/auth/package.json @@ -1,5 +1,5 @@ { - "name": "simple-example", + "name": "auth-example", "private": true, "description": "Modus AssemblyScript Simple Example", "author": "Hypermode Inc.", diff --git a/sdk/assemblyscript/src/assembly/auth.ts b/sdk/assemblyscript/src/assembly/auth.ts index 2d8d6c93c..b98013d55 100644 --- a/sdk/assemblyscript/src/assembly/auth.ts +++ b/sdk/assemblyscript/src/assembly/auth.ts @@ -8,8 +8,10 @@ */ import { JSON } from "json-as"; -export class jwt { - public static getClaims(): T { - return JSON.parse(process.env.get("JWT_CLAIMS")); +export function getJWTClaims(): T { + const claims = process.env.get("JWT_CLAIMS"); + if (!claims) { + throw new Error("JWT claims not found."); } + return JSON.parse(claims); } diff --git a/sdk/go/examples/auth/build.cmd b/sdk/go/examples/auth/build.cmd new file mode 100644 index 000000000..ed9d2952f --- /dev/null +++ b/sdk/go/examples/auth/build.cmd @@ -0,0 +1,12 @@ +@echo off + +:: This build script works best for examples that are in this repository. +:: If you are using this as a template for your own project, you may need to modify this script, +:: to invoke the modus-go-build tool with the correct path to your project. + +SET "PROJECTDIR=%~dp0" +pushd ..\..\tools\modus-go-build > nul +go run . "%PROJECTDIR%" +set "exit_code=%ERRORLEVEL%" +popd > nul +exit /b %exit_code% diff --git a/sdk/go/examples/auth/build.sh b/sdk/go/examples/auth/build.sh new file mode 100755 index 000000000..02743fecf --- /dev/null +++ b/sdk/go/examples/auth/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# This build script works best for examples that are in this repository. +# If you are using this as a template for your own project, you may need to modify this script, +# to invoke the modus-go-build tool with the correct path to your project. + +PROJECTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +pushd ../../tools/modus-go-build > /dev/null +go run . "$PROJECTDIR" +exit_code=$? +popd > /dev/null +exit $exit_code diff --git a/sdk/go/examples/auth/go.mod b/sdk/go/examples/auth/go.mod new file mode 100644 index 000000000..fa86200ac --- /dev/null +++ b/sdk/go/examples/auth/go.mod @@ -0,0 +1,7 @@ +module auth-example + +go 1.23.0 + +require github.com/hypermodeinc/modus/sdk/go v0.0.0 + +replace github.com/hypermodeinc/modus/sdk/go => ../../ diff --git a/sdk/go/examples/auth/hypermode.json b/sdk/go/examples/auth/hypermode.json new file mode 100644 index 000000000..76c0b20a5 --- /dev/null +++ b/sdk/go/examples/auth/hypermode.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://manifest.hypermode.com/hypermode.json", + "models": { + // No models are used by this example, but if you add any, they would go here. + }, + "hosts": { + // No hosts are used by this example, but if you add any, they would go here. + }, + "collections": { + // No collections are used by this example, but if you add any, they would go here. + } +} diff --git a/sdk/go/examples/auth/main.go b/sdk/go/examples/auth/main.go new file mode 100644 index 000000000..cc6e0da5f --- /dev/null +++ b/sdk/go/examples/auth/main.go @@ -0,0 +1,25 @@ +/* + * This example is part of the Modus project, licensed under the Apache License 2.0. + * You may modify and use this example in accordance with the license. + * See the LICENSE file that accompanied this code for further details. + */ + +package main + +import ( + "github.com/hypermodeinc/modus/sdk/go/pkg/auth" +) + +type Claims struct { + Exp int64 `json:"exp"` + Iat int64 `json:"iat"` + Iss string `json:"iss"` + Jti string `json:"jti"` + Nbf int64 `json:"nbf"` + Sub string `json:"sub"` + UserId string `json:"user-id"` +} + +func GetJWTClaims() (*Claims, error) { + return auth.GetJWTClaims[*Claims]() +} diff --git a/sdk/go/examples/simple/main.go b/sdk/go/examples/simple/main.go index 3bedc5896..f478260dd 100644 --- a/sdk/go/examples/simple/main.go +++ b/sdk/go/examples/simple/main.go @@ -182,7 +182,3 @@ func TestLogging() { // // The console functions also allow you to better control the reported logging level. } - -func TestEnvVars() string { - return os.Getenv("JWT_CLAIMS") -} diff --git a/sdk/go/pkg/auth/jwt.go b/sdk/go/pkg/auth/jwt.go new file mode 100644 index 000000000..84239357a --- /dev/null +++ b/sdk/go/pkg/auth/jwt.go @@ -0,0 +1,24 @@ +package auth + +import ( + "errors" + "os" + + "github.com/hypermodeinc/modus/sdk/go/pkg/utils" +) + +type JWT struct{} + +func GetJWTClaims[T any]() (T, error) { + var claims T + claimsStr := os.Getenv("JWT_CLAIMS") + if claimsStr == "" { + return claims, errors.New("JWT claims not found") + } + err := utils.JsonDeserialize([]byte(claimsStr), &claims) // Convert claimsStr to byte slice + if err != nil { + return claims, err + } + + return claims, nil +} From 22421bcc2c80eba4bcaeb3f615d6e48aa1650c49 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:30:17 -0700 Subject: [PATCH 08/25] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06eb26a86..e360a4c59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ _NOTE: This is the first fully open-source release, using the name "Modus" for t "Hypermode" still refers to the company and the commercial hosting platform - but not the framework. In previous releases, the name "Hypermode" was used for all three._ +- Support user defined jwt auth and sdk functions [#405](https://github.com/hypermodeinc/modus/pull/405) - Migrate from Hypermode to Modus [#412](https://github.com/hypermodeinc/modus/pull/412) - Import WasmExtractor code [#415](https://github.com/hypermodeinc/modus/pull/415) - Import Manifest code [#416](https://github.com/hypermodeinc/modus/pull/416) From 4b5c4a62fccdaeeb00ac22d87c2988709ac94280 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:38:06 -0700 Subject: [PATCH 09/25] better logic when no rsa --- runtime/middleware/jwt.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 12a49ef07..0eb85f6be 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -26,23 +26,22 @@ func HandleJWT(next http.Handler) http.Handler { privKeysStr := os.Getenv("MODUS_RSA_PEMS") if privKeysStr == "" { - if tokenStr == "" { + if !config.IsDevEnvironment() || tokenStr == "" { next.ServeHTTP(w, r) return } - if config.IsDevEnvironment() { - token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, jwt.MapClaims{}) - if err != nil { - logger.Debug(r.Context()).Err(err).Msg("JWT parse error") - next.ServeHTTP(w, r) - return - } - if claims, ok := token.Claims.(jwt.MapClaims); ok { - ctx = AddClaimsToContext(ctx, claims) - } - next.ServeHTTP(w, r.WithContext(ctx)) + token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, jwt.MapClaims{}) + if err != nil { + logger.Debug(r.Context()).Err(err).Msg("JWT parse error") + next.ServeHTTP(w, r) return } + if claims, ok := token.Claims.(jwt.MapClaims); ok { + ctx = AddClaimsToContext(ctx, claims) + } + next.ServeHTTP(w, r.WithContext(ctx)) + return + } var privKeysUnmarshalled map[string]string From 7e8663966007778af18c908f587651c34092c5ff Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:25:20 -0700 Subject: [PATCH 10/25] revs --- runtime/main.go | 4 ++ runtime/middleware/jwt.go | 68 ++++++++++++------- sdk/assemblyscript/examples/auth/README.md | 4 +- .../examples/auth/assembly/index.ts | 12 ++-- sdk/assemblyscript/examples/auth/package.json | 2 +- sdk/assemblyscript/src/assembly/auth.ts | 3 +- sdk/go/examples/auth/main.go | 8 ++- sdk/go/pkg/auth/jwt.go | 2 +- 8 files changed, 67 insertions(+), 36 deletions(-) diff --git a/runtime/main.go b/runtime/main.go index f7dd2309a..3b1dc07a5 100644 --- a/runtime/main.go +++ b/runtime/main.go @@ -20,6 +20,7 @@ import ( "github.com/hypermodeinc/modus/runtime/config" "github.com/hypermodeinc/modus/runtime/httpserver" "github.com/hypermodeinc/modus/runtime/logger" + "github.com/hypermodeinc/modus/runtime/middleware" "github.com/hypermodeinc/modus/runtime/services" "github.com/hypermodeinc/modus/runtime/utils" @@ -63,6 +64,9 @@ func main() { // Set local mode if debugging is enabled local := utils.DebugModeEnabled() + // Retrieve auth private keys + middleware.Init() + // Start the HTTP server to listen for requests. // Note, this function blocks, and handles shutdown gracefully. httpserver.Start(ctx, local) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 0eb85f6be..fc5c63180 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Hypermode Inc. + * Licensed under the terms of the Apache License, Version 2.0 + * See the LICENSE file that accompanied this code for further details. + * + * SPDX-FileCopyrightText: 2024 Hypermode Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + package middleware import ( @@ -14,48 +23,61 @@ import ( "github.com/golang-jwt/jwt/v5" ) -type JWTClaimsKey string +type jwtClaimsKey string + +const jwtClaims jwtClaimsKey = "jwt_claims" -const JWTClaims JWTClaimsKey = "jwt_claims" +var PrivKeys map[string]string + +func Init() { + privKeysStr := os.Getenv("MODUS_RSA_PEMS") + if privKeysStr == "" { + return + } + var PrivKeys map[string]string + err := json.Unmarshal([]byte(privKeysStr), &PrivKeys) + if err != nil { + logger.Error(context.Background()).Err(err).Msg("JWT private keys unmarshalling error") + return + } +} func HandleJWT(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") - tokenStr = strings.TrimPrefix(tokenStr, "Bearer ") + trimmedTokenStr := strings.TrimPrefix(tokenStr, "Bearer ") - privKeysStr := os.Getenv("MODUS_RSA_PEMS") - if privKeysStr == "" { - if !config.IsDevEnvironment() || tokenStr == "" { + if trimmedTokenStr == tokenStr { + logger.Error(ctx).Msg("Invalid JWT token format, Bearer required") + http.Error(w, "Invalid JWT token format, Bearer required", http.StatusUnauthorized) + return + } + + if PrivKeys == nil { + if !config.IsDevEnvironment() || trimmedTokenStr == "" { next.ServeHTTP(w, r) return } - token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, jwt.MapClaims{}) + token, _, err := new(jwt.Parser).ParseUnverified(trimmedTokenStr, jwt.MapClaims{}) if err != nil { - logger.Debug(r.Context()).Err(err).Msg("JWT parse error") + logger.Warn(ctx).Err(err).Msg("Error parsing JWT token. Continuing since running in development") next.ServeHTTP(w, r) return } if claims, ok := token.Claims.(jwt.MapClaims); ok { - ctx = AddClaimsToContext(ctx, claims) + ctx = addClaimsToContext(ctx, claims) } next.ServeHTTP(w, r.WithContext(ctx)) return } - var privKeysUnmarshalled map[string]string - err := json.Unmarshal([]byte(privKeysStr), &privKeysUnmarshalled) - if err != nil { - logger.Error(r.Context()).Err(err).Msg("JWT private keys unmarshalling error") - http.Error(w, "Internal server error", http.StatusInternalServerError) - return - } - var token *jwt.Token + var err error - for _, privKey := range privKeysUnmarshalled { - token, err = jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { + for _, privKey := range PrivKeys { + token, err = jwt.Parse(trimmedTokenStr, func(token *jwt.Token) (interface{}, error) { return jwt.ParseRSAPublicKeyFromPEM([]byte(privKey)) }) if err != nil { @@ -72,23 +94,23 @@ func HandleJWT(next http.Handler) http.Handler { } if claims, ok := token.Claims.(jwt.MapClaims); ok { - ctx = AddClaimsToContext(ctx, claims) + ctx = addClaimsToContext(ctx, claims) } next.ServeHTTP(w, r.WithContext(ctx)) }) } -func AddClaimsToContext(ctx context.Context, claims jwt.MapClaims) context.Context { +func addClaimsToContext(ctx context.Context, claims jwt.MapClaims) context.Context { claimsJson, err := utils.JsonSerialize(claims) if err != nil { logger.Error(ctx).Err(err).Msg("JWT claims serialization error") return ctx } - return context.WithValue(ctx, JWTClaims, string(claimsJson)) + return context.WithValue(ctx, jwtClaims, string(claimsJson)) } func GetJWTClaims(ctx context.Context) string { - if claims, ok := ctx.Value(JWTClaims).(string); ok { + if claims, ok := ctx.Value(jwtClaims).(string); ok { return claims } return "" diff --git a/sdk/assemblyscript/examples/auth/README.md b/sdk/assemblyscript/examples/auth/README.md index 660f88143..0de2e58c2 100644 --- a/sdk/assemblyscript/examples/auth/README.md +++ b/sdk/assemblyscript/examples/auth/README.md @@ -1,3 +1,3 @@ -# Hypermode Simple Example Plugin +# Modus Auth Example -This is an example showing how to write a Hypermode plugin that uses auth. +This is an example showing how to access auth claims from an incoming request. diff --git a/sdk/assemblyscript/examples/auth/assembly/index.ts b/sdk/assemblyscript/examples/auth/assembly/index.ts index 0217c1077..ef6aaedb8 100644 --- a/sdk/assemblyscript/examples/auth/assembly/index.ts +++ b/sdk/assemblyscript/examples/auth/assembly/index.ts @@ -6,9 +6,9 @@ import { auth } from "@hypermode/modus-sdk-as"; - +// This is a simple example of a claims class that can be used to parse the JWT claims. @json -export class Claims { +export class ExampleClaims { public exp!: i64; public iat!: i64; public iss!: string; @@ -16,10 +16,12 @@ export class Claims { public nbf!: i64; public sub!: string; - + // This is an example of a custom claim that can be used to parse the user ID. @alias("user-id") public userId!: string; } -export function getJWTClaims(): Claims { - return auth.getJWTClaims(); + +// This function can be used to get the JWT claims, and parse them into the Claims class. +export function getJWTClaims(): ExampleClaims { + return auth.getJWTClaims(); } diff --git a/sdk/assemblyscript/examples/auth/package.json b/sdk/assemblyscript/examples/auth/package.json index 867a5a512..cb934e6f5 100644 --- a/sdk/assemblyscript/examples/auth/package.json +++ b/sdk/assemblyscript/examples/auth/package.json @@ -1,7 +1,7 @@ { "name": "auth-example", "private": true, - "description": "Modus AssemblyScript Simple Example", + "description": "Modus AssemblyScript Auth Example", "author": "Hypermode Inc.", "license": "Apache-2.0", "type": "module", diff --git a/sdk/assemblyscript/src/assembly/auth.ts b/sdk/assemblyscript/src/assembly/auth.ts index b98013d55..781170a7b 100644 --- a/sdk/assemblyscript/src/assembly/auth.ts +++ b/sdk/assemblyscript/src/assembly/auth.ts @@ -11,7 +11,8 @@ import { JSON } from "json-as"; export function getJWTClaims(): T { const claims = process.env.get("JWT_CLAIMS"); if (!claims) { - throw new Error("JWT claims not found."); + console.warn("No JWT claims found."); + return instantiate(); } return JSON.parse(claims); } diff --git a/sdk/go/examples/auth/main.go b/sdk/go/examples/auth/main.go index cc6e0da5f..10e6a4cb1 100644 --- a/sdk/go/examples/auth/main.go +++ b/sdk/go/examples/auth/main.go @@ -10,7 +10,8 @@ import ( "github.com/hypermodeinc/modus/sdk/go/pkg/auth" ) -type Claims struct { +// This is a sample struct that represents the claims in a JWT token. +type ExampleClaims struct { Exp int64 `json:"exp"` Iat int64 `json:"iat"` Iss string `json:"iss"` @@ -20,6 +21,7 @@ type Claims struct { UserId string `json:"user-id"` } -func GetJWTClaims() (*Claims, error) { - return auth.GetJWTClaims[*Claims]() +// GetJWTClaims is a function that returns the claims in a JWT token, and parses them into the Claims struct. +func GetJWTClaims() (*ExampleClaims, error) { + return auth.GetJWTClaims[*ExampleClaims]() } diff --git a/sdk/go/pkg/auth/jwt.go b/sdk/go/pkg/auth/jwt.go index 84239357a..e99343c2b 100644 --- a/sdk/go/pkg/auth/jwt.go +++ b/sdk/go/pkg/auth/jwt.go @@ -15,7 +15,7 @@ func GetJWTClaims[T any]() (T, error) { if claimsStr == "" { return claims, errors.New("JWT claims not found") } - err := utils.JsonDeserialize([]byte(claimsStr), &claims) // Convert claimsStr to byte slice + err := utils.JsonDeserialize([]byte(claimsStr), &claims) if err != nil { return claims, err } From 8087920f50827728f92d3312bfdf28a674f95924 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:36:26 -0700 Subject: [PATCH 11/25] update --- runtime/middleware/jwt.go | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index fc5c63180..eb0c03dd7 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -34,7 +34,6 @@ func Init() { if privKeysStr == "" { return } - var PrivKeys map[string]string err := json.Unmarshal([]byte(privKeysStr), &PrivKeys) if err != nil { logger.Error(context.Background()).Err(err).Msg("JWT private keys unmarshalling error") From 887d2261d9c0def45b316350ca919eb9ad2d5973 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:38:10 -0700 Subject: [PATCH 12/25] move logic around --- runtime/middleware/jwt.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index eb0c03dd7..ce22c41cd 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -47,12 +47,6 @@ func HandleJWT(next http.Handler) http.Handler { tokenStr := r.Header.Get("Authorization") trimmedTokenStr := strings.TrimPrefix(tokenStr, "Bearer ") - if trimmedTokenStr == tokenStr { - logger.Error(ctx).Msg("Invalid JWT token format, Bearer required") - http.Error(w, "Invalid JWT token format, Bearer required", http.StatusUnauthorized) - return - } - if PrivKeys == nil { if !config.IsDevEnvironment() || trimmedTokenStr == "" { next.ServeHTTP(w, r) @@ -72,6 +66,12 @@ func HandleJWT(next http.Handler) http.Handler { } + if trimmedTokenStr == tokenStr { + logger.Error(ctx).Msg("Invalid JWT token format, Bearer required") + http.Error(w, "Invalid JWT token format, Bearer required", http.StatusUnauthorized) + return + } + var token *jwt.Token var err error From 41bc28dc0156544d7a69a084d893243e254f324d Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:41:51 -0700 Subject: [PATCH 13/25] improve logic on multiple rsas --- runtime/middleware/jwt.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index ce22c41cd..386561db6 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -79,18 +79,19 @@ func HandleJWT(next http.Handler) http.Handler { token, err = jwt.Parse(trimmedTokenStr, func(token *jwt.Token) (interface{}, error) { return jwt.ParseRSAPublicKeyFromPEM([]byte(privKey)) }) - if err != nil { - if config.IsDevEnvironment() { - logger.Debug(r.Context()).Err(err).Msg("JWT parse error") - next.ServeHTTP(w, r) - return - } - logger.Error(r.Context()).Err(err).Msg("JWT parse error") - continue - } else { + if err == nil { break } } + if err != nil { + if config.IsDevEnvironment() { + logger.Debug(r.Context()).Err(err).Msg("JWT parse error") + next.ServeHTTP(w, r) + return + } + logger.Error(r.Context()).Err(err).Msg("JWT parse error") + http.Error(w, "Invalid JWT token", http.StatusUnauthorized) + } if claims, ok := token.Claims.(jwt.MapClaims); ok { ctx = addClaimsToContext(ctx, claims) From da69464a4ad608f191e223cb2698e5256956da91 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:56:03 -0700 Subject: [PATCH 14/25] revs --- runtime/middleware/jwt.go | 46 ++++++++++++++++++++++++++------------- sdk/go/pkg/auth/jwt.go | 11 ++++++++-- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 386561db6..4d2e69b4d 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -11,6 +11,7 @@ package middleware import ( "context" + "crypto/rsa" "encoding/json" "net/http" "os" @@ -27,32 +28,52 @@ type jwtClaimsKey string const jwtClaims jwtClaimsKey = "jwt_claims" -var PrivKeys map[string]string +var rsaPublicKeys map[string]*rsa.PublicKey func Init() { privKeysStr := os.Getenv("MODUS_RSA_PEMS") if privKeysStr == "" { return } - err := json.Unmarshal([]byte(privKeysStr), &PrivKeys) + var publicKeysStr map[string]string + err := json.Unmarshal([]byte(privKeysStr), &publicKeysStr) if err != nil { logger.Error(context.Background()).Err(err).Msg("JWT private keys unmarshalling error") return } + rsaPublicKeys = make(map[string]*rsa.PublicKey) + for key, value := range publicKeysStr { + publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(value)) + if err != nil { + logger.Error(context.Background()).Err(err).Msg("JWT public key parsing error") + return + } + rsaPublicKeys[key] = publicKey + } } func HandleJWT(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") - trimmedTokenStr := strings.TrimPrefix(tokenStr, "Bearer ") + if tokenStr != "" { + if s, found := strings.CutPrefix(tokenStr, "Bearer "); found { + tokenStr = s + } else { + logger.Error(ctx).Msg("Invalid JWT token format, Bearer required") + http.Error(w, "Invalid JWT token format, Bearer required", http.StatusUnauthorized) + return + } + } + + jwtParser := new(jwt.Parser) - if PrivKeys == nil { - if !config.IsDevEnvironment() || trimmedTokenStr == "" { + if len(rsaPublicKeys) == 0 { + if !config.IsDevEnvironment() || tokenStr == "" { next.ServeHTTP(w, r) return } - token, _, err := new(jwt.Parser).ParseUnverified(trimmedTokenStr, jwt.MapClaims{}) + token, _, err := jwtParser.ParseUnverified(tokenStr, jwt.MapClaims{}) if err != nil { logger.Warn(ctx).Err(err).Msg("Error parsing JWT token. Continuing since running in development") next.ServeHTTP(w, r) @@ -66,20 +87,15 @@ func HandleJWT(next http.Handler) http.Handler { } - if trimmedTokenStr == tokenStr { - logger.Error(ctx).Msg("Invalid JWT token format, Bearer required") - http.Error(w, "Invalid JWT token format, Bearer required", http.StatusUnauthorized) - return - } - var token *jwt.Token var err error - for _, privKey := range PrivKeys { - token, err = jwt.Parse(trimmedTokenStr, func(token *jwt.Token) (interface{}, error) { - return jwt.ParseRSAPublicKeyFromPEM([]byte(privKey)) + for _, publicKey := range rsaPublicKeys { + token, err = jwtParser.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { + return publicKey, nil }) if err == nil { + logger.Info(ctx).Msg("JWT token parsed successfully") break } } diff --git a/sdk/go/pkg/auth/jwt.go b/sdk/go/pkg/auth/jwt.go index e99343c2b..84cc8f05e 100644 --- a/sdk/go/pkg/auth/jwt.go +++ b/sdk/go/pkg/auth/jwt.go @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Hypermode Inc. + * Licensed under the terms of the Apache License, Version 2.0 + * See the LICENSE file that accompanied this code for further details. + * + * SPDX-FileCopyrightText: 2024 Hypermode Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + package auth import ( @@ -7,8 +16,6 @@ import ( "github.com/hypermodeinc/modus/sdk/go/pkg/utils" ) -type JWT struct{} - func GetJWTClaims[T any]() (T, error) { var claims T claimsStr := os.Getenv("JWT_CLAIMS") From 338c2e701bba2f058ded35d9559c5b8ef1ba7522 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:59:28 -0700 Subject: [PATCH 15/25] . --- runtime/middleware/jwt.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 4d2e69b4d..f2e662306 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -52,6 +52,8 @@ func Init() { } } +var jwtParser = new(jwt.Parser) + func HandleJWT(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ctx context.Context = r.Context() @@ -66,8 +68,6 @@ func HandleJWT(next http.Handler) http.Handler { } } - jwtParser := new(jwt.Parser) - if len(rsaPublicKeys) == 0 { if !config.IsDevEnvironment() || tokenStr == "" { next.ServeHTTP(w, r) From 280a40496ef2c0553fff7c22443dacd0af35e35e Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Wed, 9 Oct 2024 23:49:29 -0700 Subject: [PATCH 16/25] support any public key verification, ec, rsa, and ed --- runtime/middleware/jwt.go | 40 ++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index f2e662306..0b731ef93 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -11,8 +11,9 @@ package middleware import ( "context" - "crypto/rsa" + "crypto/x509" "encoding/json" + "encoding/pem" "net/http" "os" "strings" @@ -28,33 +29,38 @@ type jwtClaimsKey string const jwtClaims jwtClaimsKey = "jwt_claims" -var rsaPublicKeys map[string]*rsa.PublicKey +var jwtPublicKeys map[string]any -func Init() { - privKeysStr := os.Getenv("MODUS_RSA_PEMS") - if privKeysStr == "" { +func Init(ctx context.Context) { + privKeysJson := os.Getenv("MODUS_RSA_PEMS") + if privKeysJson == "" { return } - var publicKeysStr map[string]string - err := json.Unmarshal([]byte(privKeysStr), &publicKeysStr) + var publicKeyStrings map[string]string + err := json.Unmarshal([]byte(privKeysJson), &publicKeyStrings) if err != nil { - logger.Error(context.Background()).Err(err).Msg("JWT private keys unmarshalling error") + logger.Error(ctx).Err(err).Msg("JWT private keys unmarshalling error") return } - rsaPublicKeys = make(map[string]*rsa.PublicKey) - for key, value := range publicKeysStr { - publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(value)) + jwtPublicKeys = make(map[string]any) + for key, value := range publicKeyStrings { + block, _ := pem.Decode([]byte(value)) + if block == nil { + logger.Error(ctx).Msg("Invalid PEM block") + return + } + + pubKey, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { - logger.Error(context.Background()).Err(err).Msg("JWT public key parsing error") + logger.Error(ctx).Err(err).Msg("JWT public key parsing error") return } - rsaPublicKeys[key] = publicKey + jwtPublicKeys[key] = pubKey } } -var jwtParser = new(jwt.Parser) - func HandleJWT(next http.Handler) http.Handler { + var jwtParser = new(jwt.Parser) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") @@ -68,7 +74,7 @@ func HandleJWT(next http.Handler) http.Handler { } } - if len(rsaPublicKeys) == 0 { + if len(jwtPublicKeys) == 0 { if !config.IsDevEnvironment() || tokenStr == "" { next.ServeHTTP(w, r) return @@ -90,7 +96,7 @@ func HandleJWT(next http.Handler) http.Handler { var token *jwt.Token var err error - for _, publicKey := range rsaPublicKeys { + for _, publicKey := range jwtPublicKeys { token, err = jwtParser.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { return publicKey, nil }) From b757b2cf8aa2f579ce2798f2adccf732c5bbd53f Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 00:36:05 -0700 Subject: [PATCH 17/25] . --- runtime/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/main.go b/runtime/main.go index 3b1dc07a5..c901029fc 100644 --- a/runtime/main.go +++ b/runtime/main.go @@ -65,7 +65,7 @@ func main() { local := utils.DebugModeEnabled() // Retrieve auth private keys - middleware.Init() + middleware.Init(ctx) // Start the HTTP server to listen for requests. // Note, this function blocks, and handles shutdown gracefully. From 897cfc16abbfd285fb5b1a886a1e7c053bbf3d0b Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:28:58 -0700 Subject: [PATCH 18/25] . --- runtime/middleware/jwt.go | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 0b731ef93..527d4ffa5 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -29,38 +29,47 @@ type jwtClaimsKey string const jwtClaims jwtClaimsKey = "jwt_claims" -var jwtPublicKeys map[string]any +var authPublicKeys map[string]any func Init(ctx context.Context) { - privKeysJson := os.Getenv("MODUS_RSA_PEMS") - if privKeysJson == "" { + publicKeysJson := os.Getenv("MODUS_PEMS") + if publicKeysJson == "" { return } var publicKeyStrings map[string]string - err := json.Unmarshal([]byte(privKeysJson), &publicKeyStrings) + err := json.Unmarshal([]byte(publicKeysJson), &publicKeyStrings) if err != nil { - logger.Error(ctx).Err(err).Msg("JWT private keys unmarshalling error") + if config.IsDevEnvironment() { + logger.Fatal(ctx).Err(err).Msg("JWT public keys deserializing error") + } + logger.Error(ctx).Err(err).Msg("JWT private keys deserializing error") return } - jwtPublicKeys = make(map[string]any) + authPublicKeys = make(map[string]any) for key, value := range publicKeyStrings { block, _ := pem.Decode([]byte(value)) if block == nil { - logger.Error(ctx).Msg("Invalid PEM block") + if config.IsDevEnvironment() { + logger.Fatal(ctx).Msg("Invalid PEM block for key: " + key) + } + logger.Error(ctx).Msg("Invalid PEM block for key: " + key) return } pubKey, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { - logger.Error(ctx).Err(err).Msg("JWT public key parsing error") + if config.IsDevEnvironment() { + logger.Fatal(ctx).Err(err).Msg("JWT public key parsing error for key: " + key) + } + logger.Error(ctx).Err(err).Msg("JWT public key parsing error for key: " + key) return } - jwtPublicKeys[key] = pubKey + authPublicKeys[key] = pubKey } } func HandleJWT(next http.Handler) http.Handler { - var jwtParser = new(jwt.Parser) + var jwtParser = jwt.NewParser() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ctx context.Context = r.Context() tokenStr := r.Header.Get("Authorization") @@ -74,7 +83,7 @@ func HandleJWT(next http.Handler) http.Handler { } } - if len(jwtPublicKeys) == 0 { + if len(authPublicKeys) == 0 { if !config.IsDevEnvironment() || tokenStr == "" { next.ServeHTTP(w, r) return @@ -96,7 +105,7 @@ func HandleJWT(next http.Handler) http.Handler { var token *jwt.Token var err error - for _, publicKey := range jwtPublicKeys { + for _, publicKey := range authPublicKeys { token, err = jwtParser.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { return publicKey, nil }) From 8cdbbc980e309ffd808114a31bf1016770dc3dff Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:53:58 -0700 Subject: [PATCH 19/25] revs --- runtime/middleware/jwt.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 527d4ffa5..06806b24a 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -83,23 +83,29 @@ func HandleJWT(next http.Handler) http.Handler { } } - if len(authPublicKeys) == 0 { - if !config.IsDevEnvironment() || tokenStr == "" { - next.ServeHTTP(w, r) + if config.IsDevEnvironment() { + if len(authPublicKeys) == 0 { + if tokenStr == "" { + next.ServeHTTP(w, r) + return + } + token, _, err := jwtParser.ParseUnverified(tokenStr, jwt.MapClaims{}) + if err != nil { + logger.Warn(ctx).Err(err).Msg("Error parsing JWT token. Continuing since running in development") + next.ServeHTTP(w, r) + return + } + if claims, ok := token.Claims.(jwt.MapClaims); ok { + ctx = addClaimsToContext(ctx, claims) + } + next.ServeHTTP(w, r.WithContext(ctx)) return } - token, _, err := jwtParser.ParseUnverified(tokenStr, jwt.MapClaims{}) - if err != nil { - logger.Warn(ctx).Err(err).Msg("Error parsing JWT token. Continuing since running in development") + } else { + if len(authPublicKeys) == 0 { next.ServeHTTP(w, r) return } - if claims, ok := token.Claims.(jwt.MapClaims); ok { - ctx = addClaimsToContext(ctx, claims) - } - next.ServeHTTP(w, r.WithContext(ctx)) - return - } var token *jwt.Token From a5a88cb2d3ca528dddee9d6cef16768cb70bb541 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:56:22 -0700 Subject: [PATCH 20/25] rename to claims --- runtime/middleware/jwt.go | 2 +- runtime/wasmhost/wasmhost.go | 2 +- sdk/assemblyscript/src/assembly/auth.ts | 2 +- sdk/go/pkg/auth/jwt.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 06806b24a..221360c72 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -27,7 +27,7 @@ import ( type jwtClaimsKey string -const jwtClaims jwtClaimsKey = "jwt_claims" +const jwtClaims jwtClaimsKey = "claims" var authPublicKeys map[string]any diff --git a/runtime/wasmhost/wasmhost.go b/runtime/wasmhost/wasmhost.go index 8552ccfae..58d9fa41c 100644 --- a/runtime/wasmhost/wasmhost.go +++ b/runtime/wasmhost/wasmhost.go @@ -122,7 +122,7 @@ func (host *wasmHost) GetModuleInstance(ctx context.Context, plugin *plugins.Plu WithSysWalltime().WithSysNanotime(). WithRandSource(rand.Reader). WithStdout(wOut).WithStderr(wErr). - WithEnv("JWT_CLAIMS", jwtClaims) + WithEnv("CLAIMS", jwtClaims) // Instantiate the plugin as a module. // NOTE: This will also invoke the plugin's `_start` function, diff --git a/sdk/assemblyscript/src/assembly/auth.ts b/sdk/assemblyscript/src/assembly/auth.ts index 781170a7b..e29f49293 100644 --- a/sdk/assemblyscript/src/assembly/auth.ts +++ b/sdk/assemblyscript/src/assembly/auth.ts @@ -9,7 +9,7 @@ import { JSON } from "json-as"; export function getJWTClaims(): T { - const claims = process.env.get("JWT_CLAIMS"); + const claims = process.env.get("CLAIMS"); if (!claims) { console.warn("No JWT claims found."); return instantiate(); diff --git a/sdk/go/pkg/auth/jwt.go b/sdk/go/pkg/auth/jwt.go index 84cc8f05e..33e8f20fb 100644 --- a/sdk/go/pkg/auth/jwt.go +++ b/sdk/go/pkg/auth/jwt.go @@ -18,7 +18,7 @@ import ( func GetJWTClaims[T any]() (T, error) { var claims T - claimsStr := os.Getenv("JWT_CLAIMS") + claimsStr := os.Getenv("CLAIMS") if claimsStr == "" { return claims, errors.New("JWT claims not found") } From b97ae072b922bdd25a5cb35f0c68e7ff528b5511 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:44:20 -0700 Subject: [PATCH 21/25] cspell --- cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.json b/cspell.json index b02a4e574..b5ac5939c 100644 --- a/cspell.json +++ b/cspell.json @@ -122,6 +122,7 @@ "omitnull", "openai", "operationreport", + "PEMS", "pgconn", "pgxpool", "picsum", From 5691e49c2058bfa9f16145b95b7b9d2cc62db3df Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:45:25 -0700 Subject: [PATCH 22/25] . --- runtime/middleware/jwt.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 221360c72..ea5e2e970 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -40,9 +40,9 @@ func Init(ctx context.Context) { err := json.Unmarshal([]byte(publicKeysJson), &publicKeyStrings) if err != nil { if config.IsDevEnvironment() { - logger.Fatal(ctx).Err(err).Msg("JWT public keys deserializing error") + logger.Fatal(ctx).Err(err).Msg("Auth public keys deserializing error") } - logger.Error(ctx).Err(err).Msg("JWT private keys deserializing error") + logger.Error(ctx).Err(err).Msg("Auth public keys deserializing error") return } authPublicKeys = make(map[string]any) From 2b595ef4e1c5bfd0b9b4e7fb71b3f76d79e7a45d Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:47:01 -0700 Subject: [PATCH 23/25] . --- runtime/middleware/jwt.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index ea5e2e970..8ab2ee51c 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -83,8 +83,8 @@ func HandleJWT(next http.Handler) http.Handler { } } - if config.IsDevEnvironment() { - if len(authPublicKeys) == 0 { + if len(authPublicKeys) == 0 { + if config.IsDevEnvironment() { if tokenStr == "" { next.ServeHTTP(w, r) return @@ -100,9 +100,8 @@ func HandleJWT(next http.Handler) http.Handler { } next.ServeHTTP(w, r.WithContext(ctx)) return - } - } else { - if len(authPublicKeys) == 0 { + + } else { next.ServeHTTP(w, r) return } From 152a0d1311a90074b8526ca61bdb0b37467dff01 Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:02:53 -0700 Subject: [PATCH 24/25] . --- runtime/middleware/jwt.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 8ab2ee51c..40c7ea9a3 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -78,7 +78,7 @@ func HandleJWT(next http.Handler) http.Handler { tokenStr = s } else { logger.Error(ctx).Msg("Invalid JWT token format, Bearer required") - http.Error(w, "Invalid JWT token format, Bearer required", http.StatusUnauthorized) + http.Error(w, "Invalid JWT token format, Bearer required", http.StatusBadRequest) return } } @@ -109,24 +109,23 @@ func HandleJWT(next http.Handler) http.Handler { var token *jwt.Token var err error + var found bool for _, publicKey := range authPublicKeys { token, err = jwtParser.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { return publicKey, nil }) if err == nil { - logger.Info(ctx).Msg("JWT token parsed successfully") + if utils.DebugModeEnabled() { + logger.Debug(ctx).Msg("JWT token parsed successfully") + } + found = true break } } - if err != nil { - if config.IsDevEnvironment() { - logger.Debug(r.Context()).Err(err).Msg("JWT parse error") - next.ServeHTTP(w, r) - return - } - logger.Error(r.Context()).Err(err).Msg("JWT parse error") - http.Error(w, "Invalid JWT token", http.StatusUnauthorized) + if !found { + logger.Error(ctx).Err(err).Msg("JWT parse error") + http.Error(w, "Access Denied", http.StatusUnauthorized) } if claims, ok := token.Claims.(jwt.MapClaims); ok { From f953bb20b4e2d1a771bf2923422addb2c9a2e70d Mon Sep 17 00:00:00 2001 From: Jai Radhakrishnan <55522316+jairad26@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:03:40 -0700 Subject: [PATCH 25/25] . --- runtime/middleware/jwt.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/middleware/jwt.go b/runtime/middleware/jwt.go index 40c7ea9a3..45c090589 100644 --- a/runtime/middleware/jwt.go +++ b/runtime/middleware/jwt.go @@ -107,6 +107,12 @@ func HandleJWT(next http.Handler) http.Handler { } } + if tokenStr == "" { + logger.Error(ctx).Msg("JWT token not found") + http.Error(w, "Access Denied", http.StatusUnauthorized) + return + } + var token *jwt.Token var err error var found bool